diff --git a/.agents/skills/gh-stack/SKILL.md b/.agents/skills/gh-stack/SKILL.md new file mode 100644 index 00000000..b38a7559 --- /dev/null +++ b/.agents/skills/gh-stack/SKILL.md @@ -0,0 +1,194 @@ +--- +name: gh-stack +description: > + Manages stacked PRs and splits multi-part work into reviewable branches with gh-stack. + Use for stack creation, viewing, edits, push, submit, sync, rebase, merge, or checkout; + when asked to split or isolate work for review; whenever a user mentions a stack, + branch layers, dependent PRs, or gh stack; or when a stack is checked out. +metadata: + author: github + version: '0.2.0' +--- + +# gh-stack + +`gh stack` is a [GitHub CLI](https://cli.github.com/) extension for stacked branches and pull +requests. A stack is an ordered chain of branches rooted on a trunk, where each branch has one PR +based on the branch below it, so a reviewer sees only that layer's diff. + +`gh stack` prints a stack trunk-first, left to right: + +``` +(main) <- auth <- api <- frontend +``` + +Left is the **bottom**, right is the **top**. `auth` is based on `main` and merges first; +`frontend` merges last. `up` moves toward the top, away from trunk; `down` moves toward it. +Foundational work belongs at the bottom, code that depends on it above. For how to choose the +layers, read `references/stack-design.md`. + +## Setup + +Requires Git 2.36+ and an authenticated GitHub CLI. + +```bash +gh extension install github/gh-stack +git config rerere.enabled true # remember conflict resolutions +git config remote.pushDefault origin # required if the repo has more than one remote +``` + +## Non-interactive use + +`gh stack` branches on whether **stdout is a TTY**. Piped, most commands error cleanly or print +static text; under a PTY the same commands open a prompt or a full-screen TUI and block forever. +Agent harnesses differ, so always pass the flags below instead of relying on that detection. + +**Multiple remotes:** never run `push`, `submit`, `sync`, `rebase`, or `link` without +`--remote ` unless `remote.pushDefault` is configured. `checkout` and `trunk` have no +`--remote` flag and require the config. + +| Always run | Never run bare | Why | +| ----------------------------------------- | ------------------- | --------------------------------------------- | +| `gh stack view --json` | `gh stack view` | opens a TUI under a PTY | +| `gh stack submit --auto` | `gh stack submit` | prompts for a title per new PR | +| `gh stack merge --yes` | `gh pr merge` | `gh pr merge` cannot merge a stack | +| `gh stack init ...` | `gh stack init` | prompts for branch names | +| `gh stack add ` | `gh stack add` | prompts for a name, and fails even when piped | +| `gh stack checkout ` | `gh stack checkout` | opens a selection menu | +| `gh stack up` / `down` / `top` / `bottom` | `gh stack switch` | `switch` is menu-only | +| — | `gh stack modify` | TUI-only, no non-interactive path | + +- `view --short` is safe in both modes, but it is formatted for humans. Use `--json` to parse. +- **`checkout ` when a different local stack already covers those branches** cannot be forced. + Run `gh stack unstack --local` first (this keeps the stack on GitHub), then retry. +- **Worktrees:** local stacks share one common-directory catalog. Use `--print-path` with + navigation or explicit-target `checkout` to locate a foreign-owned branch without stealing its + checkout. Unoccupied targets are checked out here first. Check the exit status before changing + directories; parse only successful path-mode stdout, never status messages. + +## Branch placement + +- **Starting multi-part work:** create the stack before writing files. Do not implement every + concern on trunk and split it later. Put one dependent concern in each layer, bottom to top. +- **Editing an existing stack:** check out the layer that owns the change before editing. Never + commit a lower layer's concern on the current top branch. Run `gh stack view --json`; if + ownership is unclear, inspect `git log --all -- `. Then check out the owner, edit, commit, + rebase upstack, and return to top. + +```bash +gh stack down # or: gh stack checkout api +git add ... && git commit -m "Add get-user endpoint" +gh stack rebase --upstack # replay every branch above onto the change +gh stack top # return to where you were +gh stack push +``` + +## Core loop + +```bash +gh stack init auth # create the stack and check out its branch +git add ... && git commit -m "Add auth middleware" +gh stack add api # next layer, branched from the current one +git add ... && git commit -m "Add API routes" +gh stack submit --auto # push every branch and open draft PRs +gh stack view --json # confirm +``` + +Add `--open` to `submit` to create PRs ready for review instead of drafts. Branch names are +verbatim — `gh stack add refactor/foo` creates `refactor/foo`. + +## Staying in sync + +```bash +gh stack sync # fetch, reconcile with GitHub, rebase, push, refresh PR state +gh stack sync --prune # also delete local branches for merged PRs +``` + +Pruning never happens without `--prune` when non-interactive. If the local and remote stacks have +diverged, `sync` prints both chains, makes no changes, and exits 0 with `Sync aborted` — see +`references/troubleshooting.md`. + +## Merging + +Scope the merge with an argument: + +```bash +gh stack merge 42 --yes # PR #42 plus every unmerged PR below it +gh stack merge 7 --yes # every unmerged PR in stack #7 +gh stack merge 42 --yes --squash # or --merge, --rebase, --merge-method +``` + +Pass a PR number to merge that PR and every unmerged PR below it, or a stack number to merge every +unmerged PR in that stack. The operation is all-or-nothing: if any PR in that set cannot merge, +none do. + +Without a method flag the last-used method is reused. If the base branch uses a merge queue, the +stack is queued instead and the queue picks the method, ignoring any flag you passed with a +warning; queued PRs may land in separate groups. + +## Reading state + +`gh stack view --json` writes JSON to **stdout**. Status messages go to **stderr** — do not parse +them, branch on exit codes instead. + +``` +trunk string +currentBranch string +branches[] name, head, base, isCurrent, isMerged, isQueued, needsRebase +branches[].pr number, url, state ("OPEN" | "MERGED" | "QUEUED"); absent when no PR exists +``` + +`base` is the saved SHA of the parent branch that this branch was last known to contain. It may be +older than the parent's current tip. `needsRebase` is true when the current parent tip is no longer +an ancestor of the branch. + +## Exit codes + +| Code | Meaning | Recovery | +| ---- | -------------------------- | ---------------------------------------------------------- | +| 0 | Success | — | +| 1 | Generic error | Read stderr | +| 2 | Not in a stack | `gh stack init`, or `gh stack checkout ` | +| 3 | Rebase conflict | Follow the Exit 3 recovery below | +| 4 | GitHub API failure | Check `gh auth status`, retry | +| 5 | Invalid arguments | Fix the invocation; see ` --help` | +| 6 | Disambiguation required | Branch is in several stacks; check out a non-shared branch | +| 7 | Rebase already in progress | `gh stack rebase --continue` or `--abort` | +| 8 | Stack file locked | Another `gh stack` process is writing; retry after ~5s | +| 9 | Stacked PRs unavailable | Not enabled on the repository; tell the user | +| 10 | Modify recovery required | `gh stack modify --abort` | + +**Exit 3 recovery:** + +- After `gh stack rebase`: resolve the files, run `git add`, then + `gh stack rebase --continue`; use `gh stack rebase --abort` to restore the stack. +- After `gh stack sync`: the stack has already been restored. Run `gh stack rebase` to recreate the + conflict, then resolve and continue as above. + +## Constraints + +- Stacks are strictly linear: one parent, at most one child. Use separate stacks for parallel work. +- `rebase` and `sync` automatically update affected clean worktrees; they never auto-stash or + create/remove worktrees. Mutations serialize across the clone, and paused operations require + recovery in their recorded owners. +- `modify` supports distributed stack branches, but its editor remains TUI-only. Actions run in + affected clean owners; unoccupied branches use the origin. Drop/fold source branches and + worktrees are preserved. Recovery flags may run from any worktree and use recorded native + operation owners; never resolve/stage in the caller's tree unless the diagnostic names it. +- There is no non-interactive reorder or removal. Errors may suggest `gh stack modify`, but it is + TUI-only — restructure with `unstack` then `init` instead. +- PR titles and bodies are auto-generated. Use `gh pr edit` afterwards to change them. + +## More detail + +`gh stack --help` is authoritative for flags and arguments. Note that +`gh stack help ` does **not** work — it prints the top-level help. + +Open the reference whose trigger matches the task; no need to preload all three. + +- `references/stack-design.md` — read before creating a stack, when deciding how many layers to + use, what belongs in each one, or whether work belongs in a new stack. +- `references/commands.md` — read when a command fails unexpectedly or you need its preconditions, + side effects, atomicity, or ordering guarantees. +- `references/troubleshooting.md` — read on a rebase conflict, after a squash-merge, on local and + remote divergence, when restructuring a stack, or when driving stacks from another tool. diff --git a/.agents/skills/gh-stack/references/commands.md b/.agents/skills/gh-stack/references/commands.md new file mode 100644 index 00000000..35393225 --- /dev/null +++ b/.agents/skills/gh-stack/references/commands.md @@ -0,0 +1,212 @@ +# Command behavior + +`gh stack --help` is authoritative for flags and arguments. (`gh stack help ` only prints the top-level help.) This file only covers behavior `--help` does not +explain: preconditions, side effects, atomicity, and failure modes. + +## Contents + +- [init](#init) +- [add](#add) +- [push](#push) +- [submit](#submit) +- [link](#link) +- [sync](#sync) +- [rebase](#rebase) +- [view](#view) +- [checkout](#checkout) +- [unstack](#unstack) +- [merge](#merge) +- [Navigation](#navigation) + +## init + +Creates the stack and checks out the **last** branch in the list, so a single `init` can lay down +the whole chain: `gh stack init auth api frontend`. + +If the final existing branch is already checked out in another worktree, adoption still succeeds: +the command reports its owner and leaves the invoking checkout unchanged. + +`init` processes branch arguments from bottom to top. Existing branches are adopted. If the first +branch does not exist, it is created from the trunk; each later new branch is created from the +branch immediately before it. There is no separate adopt mode — existence decides. `--base` +selects a non-default trunk. + +`init` also enables `git rerere`. Under a TTY the first run in a repo asks for confirmation; set +`git config rerere.enabled true` beforehand to skip it. + +## add + +- **Must run from the top branch** of the stack (or the trunk when the stack is still empty). + Anywhere else it exits **5** with `can only add branches on top of the stack`. Run `gh stack top` + first. +- **Uncommitted changes carry over.** Without `-Am`, `add` does not touch the working tree, so + staged and unstaged changes follow you onto the new branch. Commit or stash first for a clean start. +- **`add -Am` commits in place when the current branch has no commits yet** — for example + immediately after `init` — instead of creating a branch. This is deliberate: the first layer + usually needs its content before a second layer exists. +- `-A` and `-u` are mutually exclusive, and both require `-m`. +- Existing branches owned by another worktree may be adopted without checkout. Commit/stage + shortcuts are rejected before staging or membership changes; they never commit another + worktree's files. + +## push + +Pushes every active (non-merged, non-queued) branch in one multi-ref push with per-branch +`--force-with-lease`. + +**Not atomic.** Some branches may update while another is rejected. A rejection means that branch +moved on the remote; fix that branch and rerun — rerunning is safe and skips what already landed. + +`push` never creates or updates pull requests. Use `submit` for that. + +## submit + +Pushes each active branch, then creates a PR for every branch that lacks one, basing it on the +first non-merged ancestor, then links them into a Stack on GitHub. + +- **Not atomic.** Branches are pushed sequentially with per-branch `--force-with-lease`. If a later + push is rejected, earlier pushes and PR updates stand. Fix the rejection and rerun the same command. +- **A fully merged stack cannot be extended.** When every PR in the current stack is already merged, + `submit` forks the remaining unmerged branches into a **new** stack rooted at the trunk and creates + it on GitHub, leaving the merged stack untouched. +- **Title generation with `--auto`:** a branch with a single commit uses that commit's subject as + the title and its body as the PR body. A branch with multiple commits humanizes the branch name + (hyphens and underscores become spaces). There is no flag for a custom title or body; use + `gh pr edit` afterwards. +- `--open` marks new _and existing_ PRs ready for review; without it new PRs are drafts. +- Requires stacked PRs to be enabled on the repository. If not, `submit` exits **9** when + non-interactive (under a TTY it offers to create ordinary unstacked PRs instead). + +## link + +Creates or updates a stack on GitHub **without any local tracking state**. This is the path for +branches managed by another tool. Worktrees alone do not require `link`: local tracking is shared. + +- Arguments are given bottom to top. Each is a branch name or a PR number; a numeric argument is + tried as a PR number first and falls back to a branch name. +- **A numeric first argument is treated as a stack number only when a stack with that number + exists.** In that case the remaining arguments are appended to the top of that stack and you do + not re-list its current PRs: `gh stack link 7 feature-c`. Arguments already in the stack are + skipped; arguments belonging to a different stack are rejected. +- Branch arguments are pushed automatically (non-force, atomic). Missing PRs are created with + auto-generated titles and correctly chained bases; existing PRs with a wrong base are corrected. +- Stack membership is **additive only** — `link` never removes a PR from a stack. + +## sync + +The routine command. Steps, in order: + +1. **Fetch** from the remote. +2. **Reconcile with the GitHub stack.** PRs added to the stack on github.com are pulled down and + appended locally. On divergence, aborts when non-interactive (see `troubleshooting.md`). +3. **Fast-forward the trunk.** Skipped when already current; warns when diverged. +4. **Cascade rebase when needed.** This runs if the trunk moved, a stack branch was fast-forwarded + from its remote, or a branch no longer contains its expected parent. Merged PRs are handled + automatically. On conflict, **all branches are restored** to their pre-rebase state and the + command exits **3**. +5. **Push** all active branches, atomically. +6. **Refresh PR state** from GitHub. +7. **Sync the stack object** — link open PRs into a stack, additively. Only when two or more PRs + exist. `sync` never opens PRs; that is `submit`. +8. **Prune** local branches for merged PRs, only when `--prune` is passed in a non-interactive + environment. + +Affected clean worktrees are updated automatically. Dirty/busy/unavailable owners stop unsafe +updates, and pruning skips branches occupied elsewhere. Cascade rollback does not undo prior +fetches or completed fast-forwards; partial restoration failures retain recovery state. + +## rebase + +Pulls from the remote and cascade-rebases. Use it when `sync` reported a conflict or when you need +to rebase only part of the stack. + +- `--upstack` rebases from the current branch to the top. This is what you run after editing a + lower layer. +- `--downstack` rebases from the trunk to the current branch. +- `--no-trunk` skips fetching and the trunk rebase entirely, aligning stack branches with each + other only. +- `--continue` after staging resolutions; `--abort` restores every branch. +- A merged PR is detected automatically and replayed with `--onto` against the correct target, so a + squash-merged parent does not produce spurious conflicts. +- Starting a rebase while one is in progress exits **7**. +- Occupied branches are rebased in their clean owning worktrees; unoccupied branches use the + origin. Resolve/stage conflicts at the reported path. `--continue`/`--abort` may run from any + linked worktree and use the recorded owners. No auto-stash or worktree lifecycle management. + +## view + +- `--json` writes the machine-readable payload to stdout. Its schema is in `SKILL.md`. +- Bare `view` opens a full-screen TUI when stdout is a TTY, and prints static text when piped. +- `--short` prints a compact one-line-per-branch summary and never opens the TUI, but it is + formatted for humans; parse `--json` instead. +- `view` refreshes PR state from GitHub as a side effect, best-effort — it does not fail when the + API is unreachable. + +## checkout + +Accepts a stack number, PR number, PR URL, or branch name. + +- A bare number resolves as a **stack number first**, then a PR number, then a branch name. +- Stack numbers, PR numbers, and PR URLs fetch from GitHub, pull the branches down, and set the + stack up locally. +- If a local stack already exists over those branches with a different composition, `checkout` + cannot be forced past it. Run `gh stack unstack --local` first, then retry. +- `checkout` relies on `remote.pushDefault` when several remotes exist. +- `--print-path` requires an explicit target and never prompts. It prints a foreign owner's path + without switching, or checks out an unoccupied target here before printing the current root. + Without path mode, a foreign-owned target is a nonzero error, not a successful switch. + +## unstack + +Removes the stack **grouping** only. It never deletes pull requests or branches. + +- With no argument it targets the active stack — the one containing the current branch — removing + it on GitHub and locally. +- With a stack number it works from anywhere in the repository, tracked locally or not, via the API. + Local tracking is also removed when present. +- `--local` removes local tracking only and never contacts GitHub. Combining `--local` with a stack + number that is not tracked locally is an error. +- An unknown stack number exits **2**. + +## merge + +- Scope with an argument: pass a PR number to merge that PR and every unmerged PR below it in the + stack, or pass a stack number to merge every unmerged PR in that stack. +- **All-or-nothing.** If any PR in that exact merge set cannot be merged, none are, and the reason + is reported. +- The method comes from `--squash`, `--rebase`, `--merge`, or `--merge-method `. Without + one, the last-used method is reused. +- Only basic PR state is checked before merging: open and not a draft. Bypassing merge requirements + is not supported for stacks. +- **A merge queue on the base branch overrides everything.** The stack is added to the queue rather + than merged; the queue chooses the method and any method flag you passed is ignored with a + warning. Queued PRs are submitted together but land as the queue processes them, so they may merge + in separate groups rather than all at once. +- `gh pr merge` cannot merge a stack. Always use `gh stack merge`. + +## Navigation + +`up`, `down`, `top`, `bottom`, and `trunk` are always non-interactive. `up` and `down` accept a +count (`gh stack up 3`). Movement clamps at the stack bounds, and merged branches are skipped when +navigating from an active branch, so `bottom` lands on the lowest _unmerged_ branch. + +`gh stack switch` is a selection menu with no non-interactive path. Use the commands above instead. + +All five navigation commands support `--print-path`, as does explicit-target `checkout`. Success +writes only an absolute raw path and newline to stdout; diagnostics go to stderr and errors leave +stdout empty. Check the exit status before using the path: + +```bash +gscd() { + local target + target=$(gh stack "$@" --print-path) || return $? + if [ -z "$target" ]; then + printf '%s\n' 'gh stack returned an empty path' >&2 + return 1 + fi + cd -- "$target" +} +gscd checkout auth +``` + +This is a Bash/Zsh function, not something gh-stack installs. Never use `eval` on path output. diff --git a/.agents/skills/gh-stack/references/stack-design.md b/.agents/skills/gh-stack/references/stack-design.md new file mode 100644 index 00000000..f64543ac --- /dev/null +++ b/.agents/skills/gh-stack/references/stack-design.md @@ -0,0 +1,97 @@ +# Designing a stack + +How to decide what goes in each layer. Read this before running `gh stack init`. + +## Contents + +- [Plan the layers before writing code](#plan-the-layers-before-writing-code) +- [Branch naming](#branch-naming) +- [Staging changes deliberately](#staging-changes-deliberately) +- [When to add a layer](#when-to-add-a-layer) +- [One stack, one story](#one-stack-one-story) + +## Plan the layers before writing code + +A stack is a dependency chain. If code in one layer depends on code in another, the dependency must +live in the same branch or a lower one. That constraint is much cheaper to satisfy by planning than +by restructuring later, because there is no non-interactive in-place reorder — fixing the order +means`unstack` and `init` again. + +Decide the layers first, then write code into them: + +``` +(main) <- todo-app/models <- todo-app/api <- todo-app/frontend <- todo-app/integration +``` + +- `todo-app/models` — shared types and schema +- `todo-app/api` — routes that use the models +- `todo-app/frontend` — components that call the routes +- `todo-app/integration` — tests exercising the whole feature + +This is illustrative. Infer the stack topic and layer names from the actual task; do not reuse +`todo-app` or these layer names literally. + +The failure mode to avoid is writing everything on one branch and trying to split it afterwards. +If a task is large enough to warrant a stack, create the stack at the start. + +## Branch naming + +Prefer a shared topic prefix plus the layer's concern: +`/` — for example, `billing/schema`, `billing/api`, `billing/ui`. +This keeps related branches recognizable without using generic names that could belong to any +stack. **User and repository branch naming conventions take precedence; follow them instead.** + +Names are used exactly as given — nothing is prepended or transformed, and slashes are kept, so +`gh stack add refactor/foo` creates a branch literally named `refactor/foo`. + +If you pass `-m` without a branch name, the name is generated from the commit message in +date-and-slug form (for example `03-24-add_api_routes`). Prefer naming the branch yourself. + +## Staging changes deliberately + +Use `git add` and `git commit` directly rather than the `add -Am` shortcut. The point is control +over which changes land in which branch. With several modified files in the working tree, stage the +subset that belongs to the current layer, commit it, then create the next branch and stage the rest +there: + +```bash +git add internal/models/user.go internal/models/session.go +git commit -m "Add user and session models" + +gh stack add api-routes +git add internal/api/routes.go internal/api/handlers.go +git commit -m "Add user API routes" +``` + +Multiple commits per branch are fine. What matters is that every commit in a branch serves the same +concern, and that a change belonging to a different concern goes in a different branch. + +Note that `gh stack add ` without `-Am` does not touch the working tree, so uncommitted +changes carry over to the new branch. Commit or stash first if you want the new layer to start clean. + +## When to add a layer + +Add a branch when you start a **different concern that depends on what you have built so far**. +Signals: + +- Moving from backend to frontend, or from core logic to tests or documentation +- The next changes have a different reviewer audience +- The current branch's diff is already large enough to review on its own + +A layer that cannot be described in one sentence is usually two layers. + +## One stack, one story + +A stack should read as a coherent progression: a reviewer walks the PRs bottom to top and sees the +feature being built. + +**Use a single stack** when every branch serves the same feature or project, even if the layers span +different concerns. + +**Start a separate stack** for unrelated work — a different feature, an unrelated bug fix, an +independent refactor. Do not mix efforts into one stack just because you happened to work on both. +Use `gh stack init` for the new effort, or `gh stack checkout ` to move between existing +stacks. + +A trivial incidental fix can ride along in the current stack. Once it grows into its own project, it +deserves its own stack. diff --git a/.agents/skills/gh-stack/references/troubleshooting.md b/.agents/skills/gh-stack/references/troubleshooting.md new file mode 100644 index 00000000..3bd45fb7 --- /dev/null +++ b/.agents/skills/gh-stack/references/troubleshooting.md @@ -0,0 +1,186 @@ +# Troubleshooting and recovery + +## Contents + +- [Rebase conflicts (exit 3)](#rebase-conflicts-exit-3) +- [After a squash merge](#after-a-squash-merge) +- [Local and remote stacks have diverged](#local-and-remote-stacks-have-diverged) +- [Restructuring a stack](#restructuring-a-stack) +- [Branch belongs to several stacks (exit 6)](#branch-belongs-to-several-stacks-exit-6) +- [Driving stacks from another tool or worktree](#driving-stacks-from-another-tool-or-worktree) +- [Stack file is locked (exit 8)](#stack-file-is-locked-exit-8) +- [An interrupted modify session (exit 10)](#an-interrupted-modify-session-exit-10) + +## Rebase conflicts (exit 3) + +`rebase` and `sync` both exit 3 on conflict. `sync` restores every branch to its pre-rebase state +first, so a failed `sync` leaves nothing half-applied; a failed `rebase` stops mid-flight and waits. + +```bash +gh stack rebase +# exit 3 — conflicted paths are listed on stderr +git add +gh stack rebase --continue # repeat if the next branch also conflicts +``` + +`gh stack rebase --abort` restores every branch in the stack, not just the current one. + +Because `init` enables `git rerere`, a conflict you resolve once is replayed automatically the next +time the same conflict appears — which is common, since a change low in the stack is rebased through +every branch above it. Without `rerere`, repeated conflicts may need manual resolution on each +affected layer. + +## After a squash merge + +A squash merge replaces the branch's commits with one new commit, so the originals no longer exist +in the trunk's history and an ordinary rebase would try to replay them again. + +`gh stack sync` detects this and rebases with `--onto` against the correct target, skipping the +merged branch: + +```bash +gh stack sync +gh stack view --json # merged branch reports "isMerged": true, "state": "MERGED" +``` + +No manual action is needed. If the replay conflicts, `sync` restores all branches and exits 3. +Run `gh stack rebase` to rerun the rebase, which will stop at the conflict and allow you to resolve +and then `--continue` until complete. Use `gh stack sync --prune` to also delete local branches for +merged PRs. + +## Local and remote stacks have diverged + +Divergence means the local stack and the stack on GitHub changed in different ways — for example +branches were added locally while a PR was added to the stack on github.com. + +When non-interactive, `sync` prints both chains, changes nothing, and exits **0** with +`Sync aborted`. Success here does not mean the sync happened; check for that message, or re-run +`gh stack view --json` and compare. + +Two resolution paths: + +- **Keep the remote version.** Drop local tracking and pull the stack back down. + + ```bash + gh stack unstack --local # keeps the stack on GitHub + gh stack checkout # or a PR number + ``` + +- **Keep the local version.** Remove the grouping on GitHub, then recreate it from local state. + + ```bash + gh stack unstack # removes the grouping; PRs and branches survive + gh stack submit --auto + ``` + +Neither path deletes pull requests or branches. +Remote unstacking leaves PRs that are merging (auto-merge enabled) or are queued (in a merge queue) +stacked. If needed, clear that state before retrying. + +## Restructuring a stack + +There is no non-interactive reorder, rename, or removal. `add` run from the wrong branch suggests +`gh stack modify`, but that is TUI-only. Tear the stack down and rebuild it instead: + +```bash +gh stack unstack # removes local tracking and the GitHub grouping +# Rename or drop branches, and rewrite ancestry as needed. +gh stack init --base main branch-1 branch-2 branch-3 +gh stack submit --auto # re-link on GitHub +``` + +`init` adopts branches that already exist, so the rebuild reuses them rather than creating new ones. +Existing PRs survive. Once Git ancestry is correct, `submit` updates their base branches and +re-links the stack on GitHub. + +Changing metadata does **not** change Git ancestry. Reorder commits first, then rebuild the stack. +For example, to change `main <- models <- migration <- ui` into +`main <- migration <- models <- ui`: + +```bash +old_models=$(git rev-parse models) +old_migration=$(git rev-parse migration) +git rebase --onto main "$old_models" migration +git rebase --onto migration main models +git rebase --onto models "$old_migration" ui +gh stack unstack +gh stack init --base main migration models ui +``` + +The first rebase moves migration-only commits onto trunk, the second replays model commits above +them, and the third replays UI-only commits above models. Preserve the old boundary SHAs before +moving any branch. For a different reorder, identify each layer's range with +`git log ..`, then replay the ranges bottom to top. + +## Branch belongs to several stacks (exit 6) + +Commands exit 6 when the current branch cannot identify a single stack — typically because it is the +trunk of more than one stack. There is no flag to disambiguate. + +```bash +gh stack checkout +``` + +Then rerun. Commands that take an explicit stack number (`merge 7`, `unstack 7`) sidestep the +problem entirely, since they do not infer the stack from the current branch. + +## Driving stacks from another tool or worktree + +`gh stack link` creates and updates stacks purely through the API, with no local tracking state. +Use it when branches are managed by jj, Sapling, git-town, or another external workflow that does +not use gh-stack's local catalog. Linked worktrees themselves are supported: they share +`/gh-stack` and do not require `link`. + +```bash +gh stack link branch-a branch-b branch-c # bottom to top +gh stack link --base develop --open a b c # non-default trunk, ready for review +gh stack link 10 20 30 # by PR number +gh stack link 7 feature-d # append to existing stack #7 +``` + +Because `link` writes no local state, the local navigation commands (`up`, `down`, `top`, `bottom`) +will not work on the result. Use `gh stack checkout ` if you later want local tracking. + +Git 2.36+ is required. Legacy worktree catalogs are consolidated automatically only when their +definitions agree or are disjoint; originals are preserved. On migration conflicts, reconcile the +reported source definitions rather than choosing the newest file. Finish legacy operations in +their original worktree first, and do not mix old and new gh-stack writers in one clone. + +Navigation does not take over another worktree's checkout. Use `--print-path` with an explicit +target, check the exit status, and change directory to the quoted output. Only affected clean +owners are updated by rebase/sync; commit or stash manually when those owners are dirty. gh-stack +does not automatically stash or create/remove worktrees. + +For `git init --separate-git-dir` repositories, main invocation and existing absolute/relative +`core.worktree` backlinks are supported, including settings in the main `config.worktree`. The +discovery caveat is only linked invocation without a main-worktree backlink. A required unresolved +main owner produces actionable guidance to run from the main worktree or supply the backlink; +unaffected worktrees continue. Never navigate to an administration directory or guess its checkout. +Existing backlinks are read without adding a private registry or changing Git configuration. + +## Stack file is locked (exit 8) + +Another `gh stack` process holds either the short catalog lock (`/gh-stack.lock`) or +the clone-wide mutation lock (`/gh-stack-operation.lock`). Wait and retry; read-only +views remain available. Do not delete lock files to bypass coordination. Paused operations are +also guarded by shared recovery journals after their process lock has been released. + +## An interrupted modify session (exit 10) + +`gh stack modify` is TUI-only and should never be invoked by an agent. If a repository is left in +this state by someone else, restore it: + +```bash +gh stack modify --abort +``` + +Related: `submit` also detects a pending modify state, and under a TTY asks before overwriting the +matching stack on GitHub with local state. An unrelated stack cannot consume or clear that journal. + +Modify supports stacks distributed across worktrees, but agents must still not launch its TUI. +Renames, fold-down cherry-picks, and rebases execute in the appropriate clean owners; only the +origin switches for unoccupied branches. Drop/fold sources and their worktrees remain intact. +Resolve and stage in the worktree reported by the conflict, then invoke `modify --continue` from +any linked worktree. A later conflict can be in a different owner. Abort reverses owner-local +renames, restores only operation-touched refs, and deletes only proven operation-created refs, +never worktrees. Missing owners, externally changed refs, or save failures retain the journal. diff --git a/.agents/skills/mergify-stack/SKILL.md b/.agents/skills/mergify-stack/SKILL.md deleted file mode 100644 index 970ca30b..00000000 --- a/.agents/skills/mergify-stack/SKILL.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -name: mergify-stack -description: Use Mergify stacks for git push, commit, branch, and PR creation. ALWAYS use this skill when pushing code, creating commits, creating branches, or creating PRs. Triggers on push, commit, branch, PR, pull request, stack, stacked, git, rebase, checkout, reorder, move, sync, amend, note, revision history. ---- - -# Mergify Stack Workflow - -## Stack Philosophy - -A branch is a stack. Keep stacks short and focused: - -- A stack should only contain commits that **depend on each other** -- Rationale: longer stacks take longer to merge - -**Proactive stack management:** - -- If an existing stack can be split into independent stacks, offer to do so -- When asked to do something new: if it can be done on a separate branch, either do so or ask if in doubt -- Default to creating a new branch for unrelated changes - -## Core Conventions - -- **Push**: Use `mergify stack push` (never `git push`) -- **Fixes**: Use `git commit --amend` (never create new commits to fix issues) -- **Amend notes**: When amending a commit that already has a PR (i.e. has been pushed), attach a `mergify stack note` BEFORE `mergify stack push` to record _why_ the commit was amended. The note appears in the PR's "Revision history" comment and JSON marker, so reviewers can see the reason without diffing. -- **Mid-stack fixes**: Stash any local changes first (`git stash -u`), then use `git rebase -i` to edit the specific commit, amend it, continue rebase, then `mergify stack push`, then `git stash pop` -- **Reordering**: Stash any local changes first (`git stash -u`), then use `mergify stack reorder` (list all commits in desired order) or `mergify stack move` (move a single commit) instead of manual `git rebase -i` — non-interactive and avoids `GIT_SEQUENCE_EDITOR` quoting issues -- **Fixup**: Stash any local changes first (`git stash -u`), then use `mergify stack fixup ...` to fold a commit into its parent (drops the listed commit's message). Non-interactive — never use `git rebase -i` for this. -- **Squash**: Stash any local changes first (`git stash -u`), then use `mergify stack squash SRC... into TARGET [-m "msg"]` to combine multiple commits into one, with an optional custom message. Non-interactive — never use `git rebase -i` for this. -- **Commit titles**: Follow [Conventional Commits](https://www.conventionalcommits.org/) (e.g., `feat:`, `fix:`, `docs:`) -- **PR title & body**: `mergify stack` copies the commit message title to the PR title and the commit message body to the PR body — so write commit messages as if they were PR descriptions. **Everything that should appear in the PR (ticket references, context, test plans) MUST go in the commit message.** -- **Ticket references**: Include ticket/issue references (e.g., `MRGFY-1234`, `Fixes #123`) in the commit message body, not added separately to the PR. -- **PR lifecycle is fully managed by `mergify stack`**: NEVER edit PR titles, bodies, or labels with `gh pr edit` or the GitHub MCP — they will be overwritten on the next push. NEVER close or merge PRs manually — `mergify stack` handles the entire PR lifecycle (creation, updates, and cleanup). -- **Draft PRs**: NEVER mark a PR as ready-for-review — all PRs stay as drafts. The user will manually move them out of draft after reviewing. -- **Each commit must pass CI independently**: Every commit in a stack becomes its own PR. Each PR runs CI separately, so every commit must be self-contained — it must compile, pass linters, and pass tests on its own without depending on later commits in the stack. When formatting or linting fixes are needed, they must be included in the commit that introduced the issue, not deferred to a later commit. - -## Common Mistakes - -| Wrong | Right | Why | -| ------------------------------------------------ | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| `git push` | `mergify stack push` | Git push bypasses stack management and breaks PR relationships | -| New commit to fix lint/typo | `git commit --amend` (HEAD) or `git commit --fixup ` + `git rebase --autosquash` (mid-stack) | Each commit = a PR; fix commits create unwanted extra PRs | -| `gh pr edit --title "..."` | Edit the commit message, then `mergify stack push` | PR title/body are overwritten from commit messages on every push | -| `gh pr merge` or `gh pr close` | PR lifecycle is fully managed — do nothing | PR lifecycle is fully managed by the stack tool | -| `git commit` on `main` | `mergify stack new ` first | `mergify stack push` will fail on the default branch | -| `git rebase -i` to fixup a commit | `mergify stack fixup ` | Non-interactive — works inside LLM/agent sessions; no editor spawned | -| `git rebase -i` to squash commits | `mergify stack squash A B into X [-m "..."]` | Non-interactive — works inside LLM/agent sessions; no editor spawned | -| Deferring lint fixes to a later commit | Include the fix in the commit that caused it | Each commit runs CI independently; later commits won't save earlier ones | -| Rebase/reorder/checkout/sync with dirty worktree | `git stash -u` first, then `git stash pop` after | Uncommitted changes are lost or cause conflicts during these operations | -| Amending a pushed commit with no explanation | `mergify stack note -m "why"` before `mergify stack push` | The reason is recorded in the PR's Revision history table and JSON marker, so reviewers don't need to diff to understand the change | - -## Commands - -```bash -mergify stack new NAME # Create a new stack/branch for new work -mergify stack push # Push and create/update PRs -mergify stack checkout NAME # Checkout an existing stack from GitHub (e.g. someone else's) -mergify stack sync # Fetch trunk, remove merged commits, rebase -mergify stack list # Show commit <-> PR mapping for current stack -mergify stack list --json # Same, but machine-readable JSON output -mergify stack reorder C A B # Reorder all commits (pass SHA or Change-Id prefixes) -mergify stack move X first # Move commit X to the top of the stack -mergify stack move X last # Move commit X to the bottom of the stack -mergify stack move X before Y # Move commit X before commit Y -mergify stack move X after Y # Move commit X after commit Y -mergify stack fixup X # Fold commit X into its parent (drops X's message) -mergify stack fixup X Y Z # Fold each into its parent (multi-fixup) -mergify stack squash X into Y # Reorder X adjacent to Y, fold X into Y (keeps Y's message) -mergify stack squash X Y into Z -m "msg" # Fold X Y into Z with a custom message -mergify stack note -m "why" # Attach an amend reason to HEAD (shown in PR revision history) -mergify stack note -m "why" # Attach to a specific commit in the stack -mergify stack note --append -m "more" # Append to an existing note -mergify stack note --remove # Remove the note from a commit -``` - -Use `mergify stack checkout NAME` to check out a stack that exists on GitHub (e.g. a colleague's stack). NAME is the remote branch name of the stack. It fetches all stacked PRs, creates a local branch, and sets up tracking. Use `--branch` to override the local branch name. - -Use `mergify stack sync` to bring your stack up to date. It fetches the latest trunk, detects which PRs have been merged, removes those commits from your local branch, and rebases the remaining commits. Run this before starting new work on an existing stack. - -Use `mergify stack list` to see which commits have been pushed, which PRs they map to, and whether the stack is up to date with the remote. It also shows CI status, review status, and merge conflicts for each PR. Use `--verbose` for detailed check names and reviewer names. Use `--json` when you need to parse the output programmatically — it includes full CI check details and review data. - -## Amend Notes - -`mergify stack note` records _why_ a commit was amended. The note travels with the stack: - -- Stored locally under `refs/notes/mergify/stack` against the commit SHA. -- Pushed automatically by `mergify stack push` (alongside the commit refspecs, with `--force-with-lease`). -- Surfaced in the PR's **Revision history** comment as the `Reason` column of the markdown table, and embedded in the `` JSON marker (key `reason`) so it can be parsed programmatically. - -**When to attach a note** — any time you amend or rewrite a commit that already has a PR open (i.e. it has been pushed at least once). The note answers "why is this revision different?" so the reviewer doesn't have to diff old vs new SHAs to find out. - -**Workflow** — attach the note BEFORE `mergify stack push`: - -```bash -# Edit HEAD, then: -git commit --amend -mergify stack note -m "address review: rename foo() to bar()" -mergify stack push - -# Or for a mid-stack commit (after the rebase that amended it): -mergify stack note -m "fix lint reported in CI" -mergify stack push -``` - -A note is per-commit, not per-revision. Each amend (or other history rewrite) creates a new commit SHA, so you must run `mergify stack note` again for the new SHA — the previous note stays attached to the old SHA and won't carry over. Use `--append` only when the current target commit already has a note and you want to add another reason; use `--remove` to clear it. Notes on commits that haven't changed since the last push are preserved but won't add a new revision row. - -## CRITICAL: Check Branch Before ANY Commit - -**BEFORE staging or committing anything**, always check the current branch and assess stack state: - -```bash -git branch --show-current -mergify stack list -``` - -- If you're on `main` (or the repo's default branch): you **MUST** create a feature branch first -- **NEVER commit directly on `main`** — `mergify stack push` will fail -- This check must happen before `git add`, not after `git commit` - -## CRITICAL: Stash Local Changes Before Worktree-Modifying Operations - -**BEFORE running any operation that rewrites history or switches branches**, check for uncommitted changes and stash them: - -```bash -git status --short # Check for uncommitted changes -git stash -u # Stash tracked + untracked changes if any -``` - -**Operations that require this check:** - -- `git rebase -i` (mid-stack fixes) -- `mergify stack reorder` / `mergify stack move` -- `mergify stack fixup` -- `mergify stack squash` -- `mergify stack checkout` -- `mergify stack sync` -- `mergify stack new` (switches to new branch) -- `git checkout ` - -**After the operation completes**, restore the stashed changes: - -```bash -git stash pop -``` - -If you skip this step, uncommitted work will be **silently lost** or cause rebase conflicts. - -## Starting New Work - -When asked to start a new piece of work, create a new feature, or work on something unrelated to the current stack: - -1. **Check current branch**: `git branch --show-current` -2. **Create a new stack**: `mergify stack new ` - - Use descriptive branch names following the pattern: `type/short-description` (e.g., `feat/add-login`, `fix/memory-leak`) -3. **Make commits** following conventional commits -4. **Push**: `mergify stack push` - -## Adding to Existing Stack - -When continuing work on an existing feature branch: - -1. **Check current branch**: `git branch --show-current` - - If on the right branch: proceed with commits - - If on `main`: switch to the feature branch first with `git checkout ` or create a new stack - -## Conflict Resolution - -When a rebase causes conflicts (during `git rebase -i` or `mergify stack push`): - -1. Resolve conflicts in your editor -2. Stage resolved files with `git add` -3. Continue with `git rebase --continue` - -To abort instead: `git rebase --abort` - -After resolving, run `mergify stack push` to sync the updated stack. diff --git a/.agents/skills/proof/SKILL.md b/.agents/skills/proof/SKILL.md index cfe62e0f..f4d75e3c 100644 --- a/.agents/skills/proof/SKILL.md +++ b/.agents/skills/proof/SKILL.md @@ -10,8 +10,8 @@ repository. It has eight record types: **Effort**, **Issue**, **Finding**, **Decision**, **Constraint**, and **Risk** capture the work and reasoning; **Citation** stores a source or reference; and **Blob** stores attached content such as a document, JSON, or image. Every record belongs to one -Effort. Create and update records through 17 typed mutations, and read them -through 5 bounded queries. Do not hand-edit record frontmatter, although you +Effort. Create and update records through 18 typed mutations, and read them +through 6 bounded queries. Do not hand-edit record frontmatter, although you may edit record bodies freely. Read [glossary.md](./glossary.md) for the primitive and edge semantics before @@ -78,13 +78,16 @@ reasoning: 4. **Unique signal:** Does it add a reason or link that code, docs, Git, the PR or tracker issue, and retained records do not already make clear? +`WriteCompaction` restates claims that live records already hold, so it +skips the unique-signal test. The other three tests still apply to its body. + Do not create a record or add body claims unless the information scores **4/4**. An existing or open record does not bypass this gate; appending low-value text still consumes bounded reads. Keep failed candidates in the PR, tracker issue, commit, or run artifact. Citations and Blobs persist only when they support a 4/4 record. -One command for all 17 mutations — pass the payload as a single JSON argument: +One command for all 18 mutations — pass the payload as a single JSON argument: ```bash flatbread proof write '{"type":"WriteDecision","effort":"","title":"...","body":"...","derives_from":[""]}' @@ -94,7 +97,7 @@ flatbread proof write '{"type":"WriteDecision","effort":"","title":"..." For creates, **capture `artifacts[0].id`** to wire later edges. Keep the returned `generation` for strict read-your-writes. -Full payload shapes for all 17 mutations: read [reference.md](./reference.md). +Full payload shapes for all 18 mutations: read [reference.md](./reference.md). Critical semantics: - Creates always start in the initial lifecycle state: `WriteDecision` → @@ -107,8 +110,9 @@ Critical semantics: including foreign `derives_from` links, so reads do not fail closed. Use it for session noise that should never have been journaled. Do not `git rm` records or hand-edit frontmatter. `proof get` still returns a retracted - record. Efforts cannot - be retracted; abandon them instead. + record, and `proof records --retracted only` lists an Effort's + retracted records, each marked **RETRACTED** with its date and reason. + Efforts cannot be retracted; abandon them instead. - `AcceptDecision` defaults `rejectSiblings: true`, which rejects only proposed Decisions derived from the same `question` Issue, even if the Issue is closed. Use @@ -139,6 +143,25 @@ Critical semantics: [effort-modeling](../effort-modeling/SKILL.md) when the decision is still being grilled. +### Compactions + +A compaction is a Finding that gives one short, current account of an Effort +and names the records behind it. Write one with `WriteCompaction` when +`proof brief ` reports `compaction.recompact: true`. Do not write +one after every mutation; between compactions, `brief` lists what changed. + +1. Read the live records, not the previous compaction, and write a body that + stands on its own: what is accepted, what is still open or proposed, and + which constraints and risks bind the work. +2. Put in `derives_from` only the records its sentences rest on, at most 10. + Never name another compaction there. +3. Let the writer do the rest. It records which records were live (`covers`) + and supersedes the previous compaction, so the history stays one + `--resolve head` or `brief` away. + +To correct a compaction, write a new one. Edit its body by hand only to fix +wording, or while the branch is unmerged. + ## Reading (recall) Every read returns a bounded envelope, not records: a ≤160-token `summary`, @@ -170,6 +193,9 @@ flatbread proof relations --relations derives_from,supersede # Single record with full body; --resolve head follows supersession to the tip flatbread proof get [--resolve head] + +# Where an Effort stands: head compaction in full, then what changed since +flatbread proof brief ``` Flags shared by reads: `--strict-min-generation ` (with optional @@ -195,7 +221,10 @@ server-side. `proof records --kinds issue,decision` and read each record's status/state from that one digest. Run `proof blocking-decisions ` only for an Effort whose digest shows an open `blocker` Issue — skip it - otherwise. Do not open raw `.flatbread-proof/**/*.md` for briefing; + otherwise. When `proof brief ` returns a head compaction that is + not stale (`compaction.head_id` set, `compaction.stale` false), its digest + can stand in for the `records` read: it holds the current account and + every change since. Do not open raw `.flatbread-proof/**/*.md` for briefing; browse digests are authoritative for status/state. Budget ≈ (1 + number of active Efforts) digest reads. A 12-run experiment across three model families showed this roughly halves recall tool calls with no loss of diff --git a/.agents/skills/proof/glossary.md b/.agents/skills/proof/glossary.md index 6d805676..4ddbc0ee 100644 --- a/.agents/skills/proof/glossary.md +++ b/.agents/skills/proof/glossary.md @@ -30,6 +30,13 @@ Findings cite evidence, resolve Issues, inform Decisions, surface Risks, and may invalidate past Findings or Decisions. A retrospective Finding is evidence gathered after a decision shipped. +A **compaction** is a Finding with `kind: compaction`, written only through +`WriteCompaction`. It gives one short, current account of an Effort and links +to the records behind it through `derives_from`. Its `covers` field, set by +the writer, records which records were live and where each stood, so a later +read can list exactly what changed. Each compaction supersedes the one before +it. + ### Decision A commitment among alternatives. A proposed Decision is an active alternative; @@ -87,8 +94,9 @@ express. on disk with `retracted: true` so ids remain resolvable and `PROOF_DANGLING_RELATION` does not fire. The writer strips inbound relation ids across every Effort in one transaction, including foreign `derives_from` -references. Browse reads omit retracted records. `proof get` still returns -the body and the reason. This is not +references. Browse reads omit retracted records unless asked: +`proof records --retracted only` lists them, each marked as retracted. +`proof get` still returns the body and the reason. This is not supersession (a better same-kind claim) and not invalidation (a Finding that the target was wrong). Git is the undo path for Retract; `ReopenDecision` only returns a rejected Decision to proposed. There is no generic Restore mutation. diff --git a/.agents/skills/proof/reference.md b/.agents/skills/proof/reference.md index fdeeb436..6adf5d9d 100644 --- a/.agents/skills/proof/reference.md +++ b/.agents/skills/proof/reference.md @@ -11,7 +11,7 @@ Generated as `---<16-char-crockford>` with prefixes `eff`, identity. Let the writer generate ids; capture them from mutation results (`artifacts[0].id` for creates). -## The 17 mutations (`flatbread proof write ''`) +## The 18 mutations (`flatbread proof write ''`) Common optional fields on all creates: `id`, `created_at` (ISO with offset), `produced_in`, `created_by` (opaque provenance strings). Forward edge fields @@ -53,6 +53,48 @@ A Citation body alone is valid (commonly a URL). `blob` is optional; use it only when you need to attach stored content such as a document or JSON. When provided, `blob` must be the id of a Blob in the same Effort as the Citation. +### Compaction + +```json +{ + "type": "WriteCompaction", + "effort": "", + "title": "...", + "body": "...", + "derives_from": [""], + "cites": [""] +} +``` + +A compaction is a Finding with `kind: compaction`: one short, current account +of where an Effort stands. Only `WriteCompaction` creates one; `WriteFinding` +rejects `kind: compaction`. The writer does two things the payload cannot: + +- It stores `covers`, a sorted list of `@` entries for every + live Issue, Finding, Decision, Constraint, and Risk in the Effort, plus each + `derives_from` target. A standing is a Decision's or Risk's `state`, an + Issue's `status`, or `live` for a Finding or Constraint. `retracted`, + `superseded`, and `invalidated` take precedence over all of these. Live means + an open Issue, a proposed or accepted Decision, an open or realized Risk, + or a Finding or Constraint that nothing has superseded or invalidated. + Compactions are never live records. +- It sets `supersedes` to every head compaction (a live compaction that + nothing supersedes) and adds the new id to each head's `superseded_by`. A + Git merge can bring in two heads, one from each branch; the next + `WriteCompaction` supersedes both. + +The payload rejects `supersedes`, `invalidates`, `covers`, and `kind`. +`derives_from` holds at most 10 ids from the same Effort: the records the +body's sentences rest on. None may be another compaction; compactions link to +earlier compactions only through `supersedes`. `Supersede` can neither start +from nor target a compaction, and a compaction cannot `Invalidate` anything. +A Finding may `Invalidate` a compaction that was wrong. + +Write the body from the live records, never from the previous compaction, and +make it complete on its own. To correct a compaction, write a new one. Edit +its body by hand only to fix wording, or while the branch is unmerged: a hand +edit cannot update `covers` and does not advance `generation`. + ### Add links between existing records ```json @@ -109,7 +151,10 @@ written. It is not a hard delete and not a fold into a survivor: and strips its id from every other record across all Efforts in the same journal transaction. - Browse reads (`list`, `records`, `blocking-decisions`) omit retracted - records. `proof get` still returns them. `relations` follows stored edges + records. `proof get` still returns them, and `records --retracted include|only` lists them on request. Every digest marks a retracted + record: its index line ends in `(retracted)`, a **RETRACTED** banner with + the date and reason sits under its heading, and the envelope summary + counts `retracted N`. `relations` follows stored edges that remain; after a successful Retract, survivors should have none. - Efforts cannot be retracted. Set status to `abandoned` instead. - Later creates, `Supersede`, `Invalidate`, and lifecycle mutations reject @@ -137,7 +182,7 @@ survivor (score 4/4 if it adds claims) plus `Retract` on the rest. `generation` is a durable, monotonic journal token — the input to strict reads. -## The 5 read queries +## The 6 read queries All reads execute through Flatbread's query engine (in-process GraphQL over the generated schema) and return a `ReadEnvelope`: @@ -162,6 +207,8 @@ lists), one-hop related records, and an edge table. Body policy: - **`proof get`:** full record body (the normal zoom-in path), including Blob payloads and Citation bodies (URLs / short notes). +- **`proof brief`:** full body of the head compaction only. Every other + record appears as one line. - **`list` / `records` / `relations` / `blocking-decisions`:** body excerpt capped at 600 chars / 12 lines (`[…truncated]`). **Blob bodies are omitted** from these digests — use `proof get` for the payload. Citation bodies @@ -196,12 +243,23 @@ digest or `summary` as a data feed. ```bash flatbread proof get [--resolve exact|head] [consistency flags] flatbread proof list [--status active,paused,...] [--limit n] [--cursor c] [consistency flags] -flatbread proof records [--kinds k1,k2] [--state s1,s2] [--status s1,s2] [--kind k1,k2] [--since iso] [--until iso] [--limit n] [--cursor c] [consistency flags] +flatbread proof records [--kinds k1,k2] [--state s1,s2] [--status s1,s2] [--kind k1,k2] [--since iso] [--until iso] [--retracted exclude|include|only] [--limit n] [--cursor c] [consistency flags] flatbread proof relations --relations r1,r2 [--limit n] [--cursor c] [consistency flags] flatbread proof blocking-decisions [consistency flags] +flatbread proof brief [consistency flags] flatbread proof cache prune +flatbread proof serve [--socket .flatbread/proof/serve.sock] ``` +- `proof serve` keeps the graph loaded in one process and answers the six + reads above (`list`, `records`, `get`, `relations`, `blocking-decisions`, + `brief`); it serves nothing that writes. Set `FLATBREAD_PROOF_SERVER` to its + socket and those read commands go to it, in any folder whose graph root + resolves to the same files. Each later read then takes a fraction of a + second instead of rebuilding the graph. A write bumps the journal + generation, and the next served read rebuilds from disk. If the socket is + unreachable, reads run locally as before. + - `--kinds`: `effort|issue|finding|decision|constraint|risk|citation|blob`. `records` includes every non-Effort kind except Blob by default. Add `--kinds blob` when you need Blob records. @@ -232,6 +290,20 @@ flatbread proof cache prune same effort with `kind: blocker` and `status: open`. For "what blockers are open at all", use `records --kinds issue --kind blocker --status open`. +- `brief`: where an Effort stands. The digest holds the head compaction with + its full body, then up to 5 older compactions as one-line + `## Lineage checkpoints`, then `## Changes since compaction`: one line per + record that was `added` to the live set, `changed` standing, or `left` it + since `covers` was taken, written as + `- | | | -> | `. + `## Stale derivations` lists `derives_from` targets whose standing moved. + With no compaction yet, `## Live records (no compaction yet)` lists every + live record instead. Digests never print `covers`. The envelope adds + `compaction`: `{"head_id","heads","stale","changes","recompact"}`. + `stale` is true when a `derives_from` target moved or a Finding invalidated + the head. `recompact` is true when there is no head, more than one head, a + stale head, or at least 5 changes. Programs read these fields, not the + digest. ### Consistency flags diff --git a/.flatbread-proof/citations/cit-agentlore-repo-memory-with-a-ci-staleness-gate--qhgtb5kf0v1chhp6.md b/.flatbread-proof/citations/cit-agentlore-repo-memory-with-a-ci-staleness-gate--qhgtb5kf0v1chhp6.md new file mode 100644 index 00000000..a5ecc426 --- /dev/null +++ b/.flatbread-proof/citations/cit-agentlore-repo-memory-with-a-ci-staleness-gate--qhgtb5kf0v1chhp6.md @@ -0,0 +1,11 @@ +--- +id: cit-agentlore-repo-memory-with-a-ci-staleness-gate--qhgtb5kf0v1chhp6 +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: 'agentlore: repo memory with a CI staleness gate' +role: evidence +created_at: '2026-10-18T09:36:30.331Z' +--- + +https://github.com/Rudra5417/agentlore + +Typed decisions and dead ends live in the repo, land in the pull request that motivated them, and a CI check fails when the code they anchor changes. diff --git a/.flatbread-proof/citations/cit-anchored-memory-code-change-staleness-for-agent--pmca309ve03tkdvv.md b/.flatbread-proof/citations/cit-anchored-memory-code-change-staleness-for-agent--pmca309ve03tkdvv.md new file mode 100644 index 00000000..ec317300 --- /dev/null +++ b/.flatbread-proof/citations/cit-anchored-memory-code-change-staleness-for-agent--pmca309ve03tkdvv.md @@ -0,0 +1,11 @@ +--- +id: cit-anchored-memory-code-change-staleness-for-agent--pmca309ve03tkdvv +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: 'anchored-memory: code-change staleness for agent notes' +role: evidence +created_at: '2026-10-18T09:36:32.538Z' +--- + +https://github.com/HT0710/anchored-memory + +Experimental. Marks notes stale when the code they reference changes; symbol anchors for Python only, file anchors elsewhere. diff --git a/.flatbread-proof/citations/cit-delivery-not-storage-cue-anchored-working-memory--v3am6s6wa24gydsa.md b/.flatbread-proof/citations/cit-delivery-not-storage-cue-anchored-working-memory--v3am6s6wa24gydsa.md new file mode 100644 index 00000000..cf07beb2 --- /dev/null +++ b/.flatbread-proof/citations/cit-delivery-not-storage-cue-anchored-working-memory--v3am6s6wa24gydsa.md @@ -0,0 +1,11 @@ +--- +id: cit-delivery-not-storage-cue-anchored-working-memory--v3am6s6wa24gydsa +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: 'Delivery, Not Storage: cue-anchored working memory for coding agents' +role: evidence +created_at: '2026-10-18T09:36:36.692Z' +--- + +https://arxiv.org/pdf/2607.20972 + +Reports that agents almost never query memory unprompted (0 operations in 114 turns, even when seeded) and that deterministic delivery worked. Read from a search summary only; the paper itself was unreachable. diff --git a/.flatbread-proof/citations/cit-ea-graph-artifact-anchored-verification-memory--jh3vnn38h34av2re.md b/.flatbread-proof/citations/cit-ea-graph-artifact-anchored-verification-memory--jh3vnn38h34av2re.md new file mode 100644 index 00000000..326e0eb1 --- /dev/null +++ b/.flatbread-proof/citations/cit-ea-graph-artifact-anchored-verification-memory--jh3vnn38h34av2re.md @@ -0,0 +1,11 @@ +--- +id: cit-ea-graph-artifact-anchored-verification-memory--jh3vnn38h34av2re +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: 'EA-Graph: artifact-anchored verification memory' +role: evidence +created_at: '2026-10-18T09:36:34.578Z' +--- + +https://arxiv.org/pdf/2608.04278 + +Argues memory must tie each claim to the artifact that verified it, and withdraw the claim when that artifact drifts. Read from a search summary only; the paper itself was unreachable. diff --git a/.flatbread-proof/constraints/con-mutation-enum-stays-deliberately-small--2pggn03xasqjs9bp.md b/.flatbread-proof/constraints/con-mutation-enum-stays-deliberately-small--2pggn03xasqjs9bp.md index 98febf7e..5f70f559 100644 --- a/.flatbread-proof/constraints/con-mutation-enum-stays-deliberately-small--2pggn03xasqjs9bp.md +++ b/.flatbread-proof/constraints/con-mutation-enum-stays-deliberately-small--2pggn03xasqjs9bp.md @@ -6,6 +6,8 @@ kind: hard created_at: '2026-09-25T10:36:35.462Z' supersedes: - con-mutation-enum-stays-deliberately-small--3hw451bsedfj6khs +superseded_by: + - con-mutation-enum-stays-deliberately-small--996zbtny5gv21ngy --- V1 has exactly seventeen named mutations. Every operation has a Zod schema, validates against a committed index generation, and owns a defined semantic transition. The seventeenth mutation exists because an Effort-wide Decision rejection could silently discard unrelated proposals and could not be undone through Proof. diff --git a/.flatbread-proof/constraints/con-mutation-enum-stays-deliberately-small--996zbtny5gv21ngy.md b/.flatbread-proof/constraints/con-mutation-enum-stays-deliberately-small--996zbtny5gv21ngy.md new file mode 100644 index 00000000..46893681 --- /dev/null +++ b/.flatbread-proof/constraints/con-mutation-enum-stays-deliberately-small--996zbtny5gv21ngy.md @@ -0,0 +1,28 @@ +--- +id: con-mutation-enum-stays-deliberately-small--996zbtny5gv21ngy +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: Mutation enum stays deliberately small +kind: hard +created_at: '2026-10-17T09:00:12.814Z' +derives_from: + - dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a + - fnd-brief-is-84-percent-smaller-than-the-status-brie--qhgmcvqdma6rq4rq +supersedes: + - con-mutation-enum-stays-deliberately-small--2pggn03xasqjs9bp +--- + +Changed: the set grows from seventeen to eighteen mutations with +`WriteCompaction`. It exists because a compaction is only trustworthy when +the writer, not the agent, records which records were live (`covers`) and +supersedes the previous head. A `WriteFinding` payload could not guarantee +either. + +V1 has exactly eighteen named mutations. Every operation has a Zod schema, validates against a committed index generation, and owns a defined semantic transition. The seventeenth mutation exists because an Effort-wide Decision rejection could silently discard unrelated proposals and could not be undone through Proof. + +The surface consists of Effort lifecycle (`CreateEffort`, `SetEffortStatus`); one creation mutation for each primitive (`WriteIssue`, `WriteFinding`, `WriteDecision`, `WriteConstraint`, `WriteRisk`, `WriteCitation`, `WriteBlob`); `WriteCompaction`, which creates a compaction Finding; edge retro-linking (`Supersede`, `Invalidate`); lifecycle transitions (`ResolveIssue`, `AcceptDecision`, `ReopenDecision`, `MitigateRisk`, `SetRiskState`); and `Retract` for records that should not stay on the live graph. + +`AcceptDecision` rejects only explicit alternatives: proposed Decisions derived from a shared question Issue, regardless of whether that Issue remains open, or proposed Decisions named in `rejects`. It names every changed and rejected Decision in the result, and a dry run previews the same changes without committing them. It must not accept a second answer to a shared question or a reopened Decision still rejected by an accepted alternative. `ReopenDecision` restores only a rejected Decision to proposed and retains the earlier rejection in history. + +`Retract` remains the named archive operation. It tombstones a file in place, strips inbound relation references to that id from records across every Effort in the same journal transaction, and drops the record from browse reads. The global strip includes foreign `derives_from` references now that causal links can cross Efforts. It is not a generic frontmatter patch, hard delete, or fold into a survivor. Git is the undo path for Retract; there is no generic Restore mutation. + +No generic frontmatter patch, hard delete, standalone `RejectDecision`, or body-edit mutation is part of v1. Bodies remain ordinary editable markdown while the platform owns frontmatter semantics. Additive mutations require dogfood evidence; removing or reshaping one is a breaking migration. diff --git a/.flatbread-proof/decisions/dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a.md b/.flatbread-proof/decisions/dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a.md new file mode 100644 index 00000000..0571061e --- /dev/null +++ b/.flatbread-proof/decisions/dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a.md @@ -0,0 +1,71 @@ +--- +id: dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: 'Compact an Effort with writer-built, superseding compaction records' +state: accepted +created_at: '2026-10-17T08:50:35.230Z' +derives_from: + - dec-route-agent-reads-through-the-flatbread-query-en--476qb9qk878yfg62 + - fnd-filtered-retrieval-is-94-percent-smaller--qpvz4vch5hygye20 +--- + +## Context + +An agent that resumes an Effort reads its live records to learn where the work +stands. The largest Effort in this repository holds 49 records, about 63 KB of +Markdown, and one `records` read cannot show them all: the page cap is 25. +Agents need one short, current account of an Effort that never hides the +records behind it, so they can still question any Decision it reports. + +## Decision + +1. A compaction is a Finding with `kind: compaction`. Only the new + `WriteCompaction` mutation creates one; `WriteFinding` rejects that kind. +2. The writer, not the agent, stores the compaction's `covers` snapshot: one + `<id>@<standing>` entry for every live record in the Effort and for each + `derives_from` target. A standing is the record's state or status, or + `live`, `superseded`, or `invalidated`. +3. Each compaction supersedes every current head compaction. Compactions never + `derive_from` one another. `derives_from` holds at most 10 ids: the records + the body's sentences rest on. +4. The body is a complete account written from the live records, never a diff + on the previous compaction. +5. A new read, `proof brief <effortId>`, prints the head compaction in full, + older compactions as one-line checkpoints, and each record whose standing + changed since `covers` was taken. It marks the compaction stale when a + `derives_from` target changed standing, and asks for a new compaction after + 5 changes. Reads never print `covers` itself. +6. Supersede when the live set or a claim changes. Edit the body by hand only + to fix wording, or while the branch is unmerged. +7. A compaction restates other records, so the write gate's unique-signal test + does not apply to it. The other three tests still do. + +## Alternatives considered + +- **Generate the summary when someone reads:** rejected. The read-routing + Decision keeps model output out of the read path, and generated text can be + neither cached nor checked. +- **Accept natural-language queries inside Proof:** rejected. The calling + agent is already a language model; it maps a prompt onto the fixed reads. +- **Chain compactions through `derives_from`:** rejected. An old compaction is + an earlier version, not evidence. Summaries of summaries compound errors and + make the model read the same claims many times. +- **Link every record ever written:** rejected. Each id costs about 75 bytes + per read, and the list would grow with the Effort. +- **Use the journal generation as the watermark:** rejected. The journal is + gitignored, so each clone counts generations separately. A `covers` + snapshot travels with the record through Git. +- **Edit one compaction in place:** rejected. No mutation updates + frontmatter, and hand edits do not advance the generation. + +## Consequences + +Proof gains an 18th mutation and a 6th read, beyond the five reads the +read-routing Decision named. A Git merge can leave two head compactions; +`brief` reports the fork, and the next `WriteCompaction` supersedes both. + +## Reversal criteria + +Revisit if agents answer questions about an Effort no better from `brief` +than from filtered `records` reads, or if `covers` grows large enough to slow +writes. diff --git a/.flatbread-proof/decisions/dec-list-retracted-records-on-request-always-marked--s1anz1zm1psvgmyy.md b/.flatbread-proof/decisions/dec-list-retracted-records-on-request-always-marked--s1anz1zm1psvgmyy.md new file mode 100644 index 00000000..dc9e5705 --- /dev/null +++ b/.flatbread-proof/decisions/dec-list-retracted-records-on-request-always-marked--s1anz1zm1psvgmyy.md @@ -0,0 +1,17 @@ +--- +id: dec-list-retracted-records-on-request-always-marked--s1anz1zm1psvgmyy +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: 'List retracted records on request, always marked' +state: accepted +created_at: '2026-10-18T20:20:07.119Z' +derives_from: + - fnd-on-every-question-brief-cuts-reading-but-not-mis--9r1f6caywmytjr0w +--- + +Browse reads still hide retracted records by default. `proof records <effortId> --retracted only` lists an Effort's retracted records, and `--retracted include` lists them beside live ones. + +A retracted record must never pass for a live one, so every digest marks it in three places: its index line ends in `(retracted)`, a **RETRACTED** banner with the date and reason sits under its heading, and the envelope summary counts `retracted N`. `get` carries the same banner. + +Why: retraction keeps a record for audit, but no read could find one without already knowing its id, because Retract strips the id from every other record. In the recall benchmark, every run answered "unknown" to all eight questions about retracted records. With the flag, a rerun answered 7 of 8 in each strategy. + +Revisit if agents start citing retracted records as live evidence despite the banner. diff --git a/.flatbread-proof/findings/fnd-a-graph-ten-times-larger-hides-answers-from-both--f9h4wcrg4jpzczzg.md b/.flatbread-proof/findings/fnd-a-graph-ten-times-larger-hides-answers-from-both--f9h4wcrg4jpzczzg.md new file mode 100644 index 00000000..37300864 --- /dev/null +++ b/.flatbread-proof/findings/fnd-a-graph-ten-times-larger-hides-answers-from-both--f9h4wcrg4jpzczzg.md @@ -0,0 +1,20 @@ +--- +id: fnd-a-graph-ten-times-larger-hides-answers-from-both--f9h4wcrg4jpzczzg +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: A graph ten times larger hides answers from both strategies alike +kind: measurement +created_at: '2026-10-18T22:31:30.062Z' +derives_from: + - dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a + - fnd-on-every-question-brief-cuts-reading-but-not-mis--9r1f6caywmytjr0w +--- + +The leading theory for why `proof brief` did not raise accuracy was that the benchmark graph was small enough for an agent to read whole. To test it, the benchmark was rebuilt ten times larger (498 to 4,980 records) with inert filler that changes no answer but one, and all 246 questions were asked again on Haiku. + +On the 237 questions comparable with the original run: + +- Accuracy fell about ten points in both strategies: 220.4 to 197.4 with `brief`, 225.3 to 198.7 without. "Unknown" answers nearly doubled (27 to 49, 22 to 43); agents named a filler record once. +- `brief` gained nothing measurable. Per question it held up better on 26 and worse on 22 (sign test p = 0.67). +- Agents read about the same amount at both sizes (26,000 and 36,000 tokens), so more noise meant more misses. `brief` still read 28 percent less. + +So graph size is not why `brief` fails to raise accuracy. The limit is finding a record by what it says: a summary does not hold most details, and paging through ten times more records finds fewer of them. The next test is a text search read. The compaction Decision stands on its cost saving. diff --git a/.flatbread-proof/findings/fnd-brief-is-84-percent-smaller-than-the-status-brie--qhgmcvqdma6rq4rq.md b/.flatbread-proof/findings/fnd-brief-is-84-percent-smaller-than-the-status-brie--qhgmcvqdma6rq4rq.md new file mode 100644 index 00000000..56c28bb7 --- /dev/null +++ b/.flatbread-proof/findings/fnd-brief-is-84-percent-smaller-than-the-status-brie--qhgmcvqdma6rq4rq.md @@ -0,0 +1,21 @@ +--- +id: fnd-brief-is-84-percent-smaller-than-the-status-brie--qhgmcvqdma6rq4rq +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: Brief is 84 percent smaller than the status-briefing read +kind: measurement +created_at: '2026-10-17T08:59:45.101Z' +derives_from: + - dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a + - fnd-where-agent-memory-stands--ax1zwj832660kjrq +--- + +On this Effort (33 live records), the first compaction made `proof brief` +return a 4,395-byte digest. The status-briefing read the skill recommends, +`proof records <effortId> --kinds issue,decision`, returned 28,244 bytes: +`brief` is 84 percent smaller. The default `records` read needed two pages +and 55,415 bytes. Measured at generation 3, with the compaction +`fnd-where-agent-memory-stands--ax1zwj832660kjrq` as the head. + +This measures digest size, not answer quality. The compaction Decision's +reversal test, whether agents answer as well from `brief` as from +`records`, is still open. diff --git a/.flatbread-proof/findings/fnd-on-every-question-brief-cuts-reading-but-not-mis--9r1f6caywmytjr0w.md b/.flatbread-proof/findings/fnd-on-every-question-brief-cuts-reading-but-not-mis--9r1f6caywmytjr0w.md new file mode 100644 index 00000000..fdca4021 --- /dev/null +++ b/.flatbread-proof/findings/fnd-on-every-question-brief-cuts-reading-but-not-mis--9r1f6caywmytjr0w.md @@ -0,0 +1,21 @@ +--- +id: fnd-on-every-question-brief-cuts-reading-but-not-mis--9r1f6caywmytjr0w +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: 'On every question, brief cuts reading but not misses' +kind: measurement +created_at: '2026-10-18T19:24:09.600Z' +derives_from: + - dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a + - fnd-per-question-runs-show-brief-saves-reads-but-not--8js7ncer2qh9tf5h +supersedes: + - fnd-on-haiku-brief-saves-reads-and-misses-fewer-ques--0xje5qq08853hjxd +--- + +The recall benchmark's full run asked all 246 questions on Haiku, one fresh headless session per question, once starting from `proof brief` and once without it. Sessions could use only Bash, Read, and Write. + +- Accuracy: 221.4 correct with `brief`, 226.3 without. Twelve questions were right only without `brief` and six only with it (sign test p = 0.24). Nine of the twelve were "unknown" answers, where the `brief` agent gave up on a fact the other agent found. +- Reading: graph reads cost 25,949 tokens per question with `brief` and 33,703 without, 23 percent less. The median question saved 5,300 tokens, and `brief` was cheaper on 157 of 246. On the 20 compaction questions it read 13,100 tokens against 44,000. + +The third pilot's claim that `brief` avoids misses came from its 46-question sample. On the 44 sound questions both runs asked, each strategy changed its result on only 1 or 2, so the full run reverses that claim. The compaction Decision was made to cut reading cost, and the full run confirms that it does. Its stated reversal test, whether agents answer better from `brief`, is met: they do not. Whether to keep the Decision on cost alone is the owner's call. + +Eight questions ask about retracted records, which no read command can list. Both strategies answered "unknown" to all eight, as every earlier run did. diff --git a/.flatbread-proof/findings/fnd-on-haiku-brief-saves-reads-and-misses-fewer-ques--0xje5qq08853hjxd.md b/.flatbread-proof/findings/fnd-on-haiku-brief-saves-reads-and-misses-fewer-ques--0xje5qq08853hjxd.md new file mode 100644 index 00000000..7ea69b62 --- /dev/null +++ b/.flatbread-proof/findings/fnd-on-haiku-brief-saves-reads-and-misses-fewer-ques--0xje5qq08853hjxd.md @@ -0,0 +1,21 @@ +--- +id: fnd-on-haiku-brief-saves-reads-and-misses-fewer-ques--0xje5qq08853hjxd +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: 'On Haiku, brief saves reads and misses fewer questions' +kind: measurement +created_at: '2026-10-18T17:56:17.706Z' +derives_from: + - dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a + - fnd-per-question-runs-show-brief-saves-reads-but-not--8js7ncer2qh9tf5h +superseded_by: + - fnd-on-every-question-brief-cuts-reading-but-not-mis--9r1f6caywmytjr0w +--- + +The recall benchmark's third pilot repeated the second on Haiku: the same 46 questions, one fresh session per question, once starting from `proof brief` and once without it. Two questions proved flawed and are left out. + +On the other 44: + +- `brief` first: 44 correct. No `brief`: 41 correct. Each of the three misses was a question the `brief` arm got right. One was a count of records changed since the head compaction, which `brief` reports directly and which the agent could not rebuild from browse reads, because a record changed in place leaves no dated trace. In the other two the agent gave up and answered "unknown". +- Graph reads cost 31,918 tokens per question with `brief` and 43,391 without, a 26 percent saving. The median question saved about 4,000 tokens, and `brief` was cheaper on 25 of 44. + +The second pilot met the letter of the compaction Decision's reversal test, because Sonnet answered as well without `brief`. On a weaker model `brief` both cut reading and avoided misses, so the Decision stands. Three paired misses are still too few to rule out chance (sign test p = 0.25); a run of every question would settle it. diff --git a/.flatbread-proof/findings/fnd-one-session-runs-put-the-recall-benchmark-at-its--b91xm78y7dk2x84b.md b/.flatbread-proof/findings/fnd-one-session-runs-put-the-recall-benchmark-at-its--b91xm78y7dk2x84b.md new file mode 100644 index 00000000..6d824302 --- /dev/null +++ b/.flatbread-proof/findings/fnd-one-session-runs-put-the-recall-benchmark-at-its--b91xm78y7dk2x84b.md @@ -0,0 +1,34 @@ +--- +id: fnd-one-session-runs-put-the-recall-benchmark-at-its--b91xm78y7dk2x84b +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: One-session runs put the recall benchmark at its ceiling +kind: measurement +created_at: '2026-10-18T10:41:18.945Z' +created_by: Claude +derives_from: + - dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a + - iss-proof-has-no-recall-benchmark-to-test-reads-agai--a63fn3b7vskv3psy +--- + +The recall benchmark now exists in `benchmarks/proof-recall`: 498 records and +246 questions about a fictional game, across five Efforts, each answer proved +against the built graph. Its first pilot shows that the obvious way to run it +measures nothing. + +Two fresh agents each answered the same stratified sample of 46 questions in +one session. Starting from `proof brief`, one scored 46 of 46 with 46 tool +calls and 203,004 tokens. Without `brief`, the other scored 45 of 46 with 27 +tool calls and 239,556 tokens. Both read most of the graph early and answered +from it, so the tiers stopped mattering. The only miss was an exact count of +records changed since a compaction, which the `brief` envelope reports +directly. + +Two rules follow for any run that is meant to compare read strategies: + +1. One fresh session per question, so the cost of finding the answer is paid + each time instead of once. +2. Tokens and tool calls come from the agent harness. The agents' own tallies + were 2.4 and 4.5 times the harness counts. + +If per-question runs still score at the ceiling, cap tool calls per question +or grow the graph past what one agent can read whole. diff --git a/.flatbread-proof/findings/fnd-per-question-runs-show-brief-saves-reads-but-not--8js7ncer2qh9tf5h.md b/.flatbread-proof/findings/fnd-per-question-runs-show-brief-saves-reads-but-not--8js7ncer2qh9tf5h.md new file mode 100644 index 00000000..94b12756 --- /dev/null +++ b/.flatbread-proof/findings/fnd-per-question-runs-show-brief-saves-reads-but-not--8js7ncer2qh9tf5h.md @@ -0,0 +1,37 @@ +--- +id: fnd-per-question-runs-show-brief-saves-reads-but-not--8js7ncer2qh9tf5h +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: Per-question runs show brief saves reads but not accuracy +kind: measurement +created_at: '2026-10-18T17:16:55.799Z' +created_by: Claude +derives_from: + - dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a + - fnd-one-session-runs-put-the-recall-benchmark-at-its--b91xm78y7dk2x84b + - iss-proof-has-no-recall-benchmark-to-test-reads-agai--a63fn3b7vskv3psy +--- + +The recall benchmark's second pilot ran one fresh Sonnet session per +question: the same 46 questions as the first pilot, once starting from +`proof brief` and once without `brief`. Costs come from the session +transcripts. + +Five questions turned out not to name their Effort, so agents could not +tell which Effort they meant; both arms missed all five. They are fixed, and +`check.mjs` now warns about any question like them. On the other 41: + +- `brief` first: 38 correct. One of its three misses gave the right record's + id where the question asked for its title. +- No `brief`: 39 correct. +- Graph reads cost 15,365 tokens per question with `brief` and 18,624 + without, a 17.5 percent saving. The saving is not steady: the median + question saved about 1,000 tokens, and `brief` was cheaper on only 22 of 41. Tool calls were the same (12.3 against 12.1). Each session also spent + about 19,300 tokens before its first read. + +The compaction Decision says to revisit it if agents answer no better from +`brief` than from `records`. On this evidence they do not, so the test as +written is met. But the Decision was made to cut reading cost, not to raise +accuracy, and the saving is real if small. One run of 41 questions on one +model cannot settle either point. A model that answers less reliably, or a +larger graph, would show whether `brief` helps where accuracy is not +already near the ceiling. diff --git a/.flatbread-proof/findings/fnd-where-agent-memory-stands--ax1zwj832660kjrq.md b/.flatbread-proof/findings/fnd-where-agent-memory-stands--ax1zwj832660kjrq.md new file mode 100644 index 00000000..7318bfe0 --- /dev/null +++ b/.flatbread-proof/findings/fnd-where-agent-memory-stands--ax1zwj832660kjrq.md @@ -0,0 +1,89 @@ +--- +id: fnd-where-agent-memory-stands--ax1zwj832660kjrq +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: Where agent memory stands +kind: compaction +created_at: '2026-10-17T08:59:05.871Z' +derives_from: + - dec-adopt-a-bounded-status-briefing-fast-path-for-ef--kcw0rw39g3b2ym2h + - dec-canonical-forward-edges-and-journaled-save-or-un--sv9x93svkfz4a98r + - dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a + - dec-distribute-the-effort-graph-as-a-versioned-agent--8as4sybr34zcqyqh + - dec-lead-flatbread-1-0-with-effort-graph-agent-memor--nhxsqm8sd43s2avx + - dec-make-the-effort-graph-the-planning-authority--gq4xegmc0hhbqjf7 + - dec-route-agent-reads-through-the-flatbread-query-en--476qb9qk878yfg62 + - dec-use-semantic-mutations-and-a-standalone-writer--2d0m3tkqhad4yyhr + - iss-skill-scoped-records-filter-example-over-constra--vd0gcnpc9cm6jzjh +superseded_by: + - fnd-where-agent-memory-stands-three-gaps-open--ywyw5wet9abt1ggp +covers: + - con-mutation-enum-stays-deliberately-small--3hw451bsedfj6khs@live + - con-packaged-proof-skill-markdown-must-not-contain-m--a9gse08fkv7zcrxq@live + - >- + dec-adopt-a-bounded-status-briefing-fast-path-for-ef--kcw0rw39g3b2ym2h@proposed + - dec-bridge-committed-generations-into-live-reads--mc3728t4w1kyqcqq@accepted + - >- + dec-canonical-forward-edges-and-journaled-save-or-un--sv9x93svkfz4a98r@accepted + - >- + dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a@accepted + - dec-defer-shared-flatbread-write-extraction--xxa1ge2chw6x3xx0@accepted + - >- + dec-distribute-the-effort-graph-as-a-versioned-agent--8as4sybr34zcqyqh@accepted + - >- + dec-effort-get-digests-always-include-the-full-recor--xs7rnbha3zx8qdj9@accepted + - >- + dec-lead-flatbread-1-0-with-effort-graph-agent-memor--nhxsqm8sd43s2avx@accepted + - dec-make-the-effort-graph-the-planning-authority--gq4xegmc0hhbqjf7@accepted + - dec-name-citeable-longform-payloads-blob--9b11q14fgsx2ytve@accepted + - dec-published-proof-skill-bytes-are-consumer-only--9frae0w0nq6wgqm3@accepted + - dec-retract-noise-instead-of-deleting-proof-files--k6jk0d2bdp1m9jw9@accepted + - >- + dec-route-agent-reads-through-the-flatbread-query-en--476qb9qk878yfg62@accepted + - dec-ship-citation-collection-with-optional-blob--fyga3x876n7rcnmn@accepted + - >- + dec-specify-blockingdecisions-over-effort-scoped-edg--pxwaenyra0aa365j@accepted + - dec-store-graph-artifacts-in-repo-by-default--xxpgwm9sv25j07z7@accepted + - dec-use-prefixed-random-ids-with-reviewable-slugs--xdg764ejat1kacd2@accepted + - dec-use-profiles-not-separate-schemas--27p0wakkyxj0kfc1@accepted + - >- + dec-use-semantic-mutations-and-a-standalone-writer--2d0m3tkqhad4yyhr@accepted + - fnd-adrs-created-a-second-planning-authority--j1waeg8qh900sqee@live + - fnd-bounded-status-briefing-protocol-halves-effort-g--ht1jd1hsssf7mv2y@live + - fnd-citation-and-blob-records-now-match-the-current--p6c37v29mx4jjfr2@live + - fnd-citation-collection-keeps-flatbread-refs-intact--z33ar5vyjxzr7ys0@live + - fnd-dogfooding-the-read-cli-surfaced-three-real-defe--g21hg77x72hdty56@live + - fnd-filtered-retrieval-is-94-percent-smaller--qpvz4vch5hygye20@live + - fnd-getrecord-digests-call-the-same-excerpt-as-brows--q5rbnhpxc697x2dv@live + - fnd-one-canonical-schema-needs-mapping-profiles--k2yvq5e9rcpsm1s1@live + - fnd-root-readme-roadmap-reference-is-already-removed--w56t43aa10v311hj@live + - fnd-supersession-transitions-decision-state-on-the-r--2m807tcfjz2jz9gt@live + - fnd-versioned-skill-distribution-passes-full-reposit--hm5cy9j2zts96dg4@live + - iss-skill-scoped-records-filter-example-over-constra--vd0gcnpc9cm6jzjh@open +--- + +Proof is Git-native memory for coding agents, and Flatbread 1.0 leads with it; +static relational content stays a first-class use. Proof records are the only +durable authority for this project's decisions, and they live in the +repository beside the code. + +Writes go through one standalone writer and a small, fixed set of typed +mutations. A hard Constraint keeps that set small: each addition needs +evidence from real use. The writer stores forward edges, adds the reverse +links itself, and saves each change through a journal that it can roll back +or finish. Ids carry a kind prefix, a readable slug, and a random suffix. +Wrong records are retracted, never deleted. Citations name sources and may +attach a Blob. + +Reads run through the Flatbread query engine. Each returns a bounded JSON +envelope and a cached Markdown digest. Browse reads excerpt bodies; `get` +returns one full body; `blocking-decisions` finds proposals tied to open +blockers. `brief` returns this compaction and every record that changed +since. + +The skill ships as a versioned package. Its published files are for +consumers and hold no maintainer-only notes. + +Open work: the status-briefing fast path is still a proposed Decision, +although the skill already teaches it. The Issue about the over-constrained +filter example is still open, although the skill now tells agents to query +each kind separately. Both look done and wait only on a lifecycle change. diff --git a/.flatbread-proof/findings/fnd-where-agent-memory-stands-three-gaps-open--ywyw5wet9abt1ggp.md b/.flatbread-proof/findings/fnd-where-agent-memory-stands-three-gaps-open--ywyw5wet9abt1ggp.md new file mode 100644 index 00000000..686a40f0 --- /dev/null +++ b/.flatbread-proof/findings/fnd-where-agent-memory-stands-three-gaps-open--ywyw5wet9abt1ggp.md @@ -0,0 +1,97 @@ +--- +id: fnd-where-agent-memory-stands-three-gaps-open--ywyw5wet9abt1ggp +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: 'Where agent memory stands: three gaps open' +kind: compaction +created_at: '2026-10-18T09:37:15.540Z' +derives_from: + - con-mutation-enum-stays-deliberately-small--996zbtny5gv21ngy + - dec-adopt-a-bounded-status-briefing-fast-path-for-ef--kcw0rw39g3b2ym2h + - dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a + - dec-lead-flatbread-1-0-with-effort-graph-agent-memor--nhxsqm8sd43s2avx + - dec-route-agent-reads-through-the-flatbread-query-en--476qb9qk878yfg62 + - dec-use-semantic-mutations-and-a-standalone-writer--2d0m3tkqhad4yyhr + - iss-proof-has-no-recall-benchmark-to-test-reads-agai--a63fn3b7vskv3psy + - iss-proof-memory-reaches-an-agent-only-when-the-agen--xzk3cfypamafeqag + - iss-records-are-not-tied-to-the-code-they-govern--zke3s5f2rhz8kqnd + - iss-skill-scoped-records-filter-example-over-constra--vd0gcnpc9cm6jzjh +supersedes: + - fnd-where-agent-memory-stands--ax1zwj832660kjrq +covers: + - con-mutation-enum-stays-deliberately-small--996zbtny5gv21ngy@live + - con-packaged-proof-skill-markdown-must-not-contain-m--a9gse08fkv7zcrxq@live + - >- + dec-adopt-a-bounded-status-briefing-fast-path-for-ef--kcw0rw39g3b2ym2h@proposed + - dec-bridge-committed-generations-into-live-reads--mc3728t4w1kyqcqq@accepted + - >- + dec-canonical-forward-edges-and-journaled-save-or-un--sv9x93svkfz4a98r@accepted + - >- + dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a@accepted + - dec-defer-shared-flatbread-write-extraction--xxa1ge2chw6x3xx0@accepted + - >- + dec-distribute-the-effort-graph-as-a-versioned-agent--8as4sybr34zcqyqh@accepted + - >- + dec-effort-get-digests-always-include-the-full-recor--xs7rnbha3zx8qdj9@accepted + - >- + dec-lead-flatbread-1-0-with-effort-graph-agent-memor--nhxsqm8sd43s2avx@accepted + - dec-make-the-effort-graph-the-planning-authority--gq4xegmc0hhbqjf7@accepted + - dec-name-citeable-longform-payloads-blob--9b11q14fgsx2ytve@accepted + - dec-published-proof-skill-bytes-are-consumer-only--9frae0w0nq6wgqm3@accepted + - dec-retract-noise-instead-of-deleting-proof-files--k6jk0d2bdp1m9jw9@accepted + - >- + dec-route-agent-reads-through-the-flatbread-query-en--476qb9qk878yfg62@accepted + - dec-ship-citation-collection-with-optional-blob--fyga3x876n7rcnmn@accepted + - >- + dec-specify-blockingdecisions-over-effort-scoped-edg--pxwaenyra0aa365j@accepted + - dec-store-graph-artifacts-in-repo-by-default--xxpgwm9sv25j07z7@accepted + - dec-use-prefixed-random-ids-with-reviewable-slugs--xdg764ejat1kacd2@accepted + - dec-use-profiles-not-separate-schemas--27p0wakkyxj0kfc1@accepted + - >- + dec-use-semantic-mutations-and-a-standalone-writer--2d0m3tkqhad4yyhr@accepted + - fnd-adrs-created-a-second-planning-authority--j1waeg8qh900sqee@live + - fnd-bounded-status-briefing-protocol-halves-effort-g--ht1jd1hsssf7mv2y@live + - fnd-brief-is-84-percent-smaller-than-the-status-brie--qhgmcvqdma6rq4rq@live + - fnd-citation-and-blob-records-now-match-the-current--p6c37v29mx4jjfr2@live + - fnd-citation-collection-keeps-flatbread-refs-intact--z33ar5vyjxzr7ys0@live + - fnd-dogfooding-the-read-cli-surfaced-three-real-defe--g21hg77x72hdty56@live + - fnd-filtered-retrieval-is-94-percent-smaller--qpvz4vch5hygye20@live + - fnd-getrecord-digests-call-the-same-excerpt-as-brows--q5rbnhpxc697x2dv@live + - fnd-one-canonical-schema-needs-mapping-profiles--k2yvq5e9rcpsm1s1@live + - fnd-root-readme-roadmap-reference-is-already-removed--w56t43aa10v311hj@live + - fnd-supersession-transitions-decision-state-on-the-r--2m807tcfjz2jz9gt@live + - fnd-versioned-skill-distribution-passes-full-reposit--hm5cy9j2zts96dg4@live + - iss-proof-has-no-recall-benchmark-to-test-reads-agai--a63fn3b7vskv3psy@open + - iss-proof-memory-reaches-an-agent-only-when-the-agen--xzk3cfypamafeqag@open + - iss-records-are-not-tied-to-the-code-they-govern--zke3s5f2rhz8kqnd@open + - iss-skill-scoped-records-filter-example-over-constra--vd0gcnpc9cm6jzjh@open +--- + +Proof is Git-native memory for coding agents, and Flatbread 1.0 leads with it; +static relational content stays a first-class use. Proof records are the only +durable authority for this project's decisions, and they live in the +repository beside the code. + +Writes go through one standalone writer and a fixed set of eighteen typed +mutations. A hard Constraint keeps that set small: each addition needs +evidence from real use. The eighteenth, `WriteCompaction`, exists so that the +writer, not the agent, records which records a compaction covers and +supersedes the one before it. The writer stores forward edges, adds the +reverse links itself, and saves each change through a journal that it can +roll back or finish. Wrong records are retracted, never deleted. + +Reads run through the Flatbread query engine. Each returns a bounded JSON +envelope and a cached Markdown digest. `brief` returns the current compaction +and every record that changed since; on this Effort it is 84 percent smaller +than the status-briefing `records` read. Nobody has yet measured whether +answers stay as good. + +Open work: + +1. No recall benchmark exists, so no change to reads can show that answers + stay correct. This blocks judging `brief` against its reversal criteria. +2. Records are not tied to the code they govern, so a Decision can describe + code that has changed without anyone noticing. +3. Memory reaches an agent only when the agent asks for it. +4. The status-briefing fast path is still a proposed Decision, and the Issue + about the over-constrained filter example is still open. The skill already + follows both; each waits only on a lifecycle change. diff --git a/.flatbread-proof/issues/iss-proof-has-no-recall-benchmark-to-test-reads-agai--a63fn3b7vskv3psy.md b/.flatbread-proof/issues/iss-proof-has-no-recall-benchmark-to-test-reads-agai--a63fn3b7vskv3psy.md new file mode 100644 index 00000000..255b0031 --- /dev/null +++ b/.flatbread-proof/issues/iss-proof-has-no-recall-benchmark-to-test-reads-agai--a63fn3b7vskv3psy.md @@ -0,0 +1,22 @@ +--- +id: iss-proof-has-no-recall-benchmark-to-test-reads-agai--a63fn3b7vskv3psy +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: Proof has no recall benchmark to test reads against +kind: gap +status: open +created_at: '2026-10-18T09:36:38.806Z' +derives_from: + - dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a + - fnd-bounded-status-briefing-protocol-halves-effort-g--ht1jd1hsssf7mv2y + - fnd-brief-is-84-percent-smaller-than-the-status-brie--qhgmcvqdma6rq4rq +--- + +The compaction Decision can be reversed if agents answer no better from `brief` than from filtered `records` reads, but nothing measures answer quality. The size measurement shows `brief` is 84 percent smaller; it says nothing about whether answers stay correct. Every later change to reads or memory has the same problem. + +Public memory benchmarks such as LongMemEval test recall of chat history, not of project decisions, so none fits. + +Close this Issue with a repo-local benchmark, run like the earlier 12-run status-briefing experiment: + +1. 20 to 40 questions with answers fixed by the graph: current rules, open work, why an alternative was rejected. +2. Agents answer under each read strategy: `brief`, `records`, and raw files. +3. Each run is scored on correct answers, tokens, and tool calls. diff --git a/.flatbread-proof/issues/iss-proof-memory-reaches-an-agent-only-when-the-agen--xzk3cfypamafeqag.md b/.flatbread-proof/issues/iss-proof-memory-reaches-an-agent-only-when-the-agen--xzk3cfypamafeqag.md new file mode 100644 index 00000000..a252715b --- /dev/null +++ b/.flatbread-proof/issues/iss-proof-memory-reaches-an-agent-only-when-the-agen--xzk3cfypamafeqag.md @@ -0,0 +1,22 @@ +--- +id: iss-proof-memory-reaches-an-agent-only-when-the-agen--xzk3cfypamafeqag +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: Proof memory reaches an agent only when the agent asks +kind: gap +status: open +created_at: '2026-10-18T09:36:42.776Z' +derives_from: + - fnd-bounded-status-briefing-protocol-halves-effort-g--ht1jd1hsssf7mv2y +cites: + - cit-delivery-not-storage-cue-anchored-working-memory--v3am6s6wa24gydsa +--- + +Every Proof read starts with the agent. If the agent does not think to run one, the graph does nothing for that session. A 2026 study reports that coding agents almost never query memory on their own, and that delivering it automatically worked; its figures come from a search summary and are not yet checked. + +Candidate ways to deliver memory without changing the read contract: + +1. A session-start hook prints `brief` for each active Effort. +2. Once records carry code anchors, an edit hook prints the Decisions anchored to a file before the agent changes it. +3. A generated, clearly marked section of `AGENTS.md` holds the head compactions. It must stay a projection of the graph, never a second place where decisions are made. + +Measure any of these with the recall benchmark before adopting it. diff --git a/.flatbread-proof/issues/iss-records-are-not-tied-to-the-code-they-govern--zke3s5f2rhz8kqnd.md b/.flatbread-proof/issues/iss-records-are-not-tied-to-the-code-they-govern--zke3s5f2rhz8kqnd.md new file mode 100644 index 00000000..9f3cdb49 --- /dev/null +++ b/.flatbread-proof/issues/iss-records-are-not-tied-to-the-code-they-govern--zke3s5f2rhz8kqnd.md @@ -0,0 +1,25 @@ +--- +id: iss-records-are-not-tied-to-the-code-they-govern--zke3s5f2rhz8kqnd +effort: eff-effort-graph-memory-and-agent-wedge--szeqvmgqjqnhd002 +title: Records are not tied to the code they govern +kind: gap +status: open +created_at: '2026-10-18T09:36:40.801Z' +derives_from: + - dec-compact-an-effort-with-writer-built-superseding--v37k0ef5evtrd59a +cites: + - cit-agentlore-repo-memory-with-a-ci-staleness-gate--qhgtb5kf0v1chhp6 + - cit-anchored-memory-code-change-staleness-for-agent--pmca309ve03tkdvv + - cit-ea-graph-artifact-anchored-verification-memory--jh3vnn38h34av2re +--- + +A Decision can describe code that has since changed, and nothing notices. Agents learn of the drift only by reading the code. Repo-memory tools and research in 2026 converge on the same fix: anchor each claim to the code it rests on and flag it when that code changes. + +Proof can do this better than those tools, because Git already gives every file a content hash. A possible shape, which keeps the mutation count fixed: + +1. Creates accept `anchors`, such as `path#symbol`. The writer stamps each with the file's Git blob hash, as it stamps `covers` on compactions. +2. `brief` flags live records whose anchored files changed since they were written. +3. A read such as `proof for-path <file>` lists the Decisions that govern a file. +4. A check such as `proof check --verify` fails a pull request that changes anchored code without touching the record, as `bootstrap --verify` fails setup. + +The same check should cover graph evidence. At generation 5, 48 live records have `derives_from`; 4 rest on a superseded support and none on an invalidated one. Today that is mostly a pointer to the newer version, but it is the same staleness signal and costs little to add. diff --git a/.husky/commit-msg b/.husky/commit-msg deleted file mode 100755 index b9c900bc..00000000 --- a/.husky/commit-msg +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# Mergify CLI Hook Wrapper -# This file is managed by mergify-cli. You can add custom logic below the marker. - -MERGIFY_HOOKS_DIR="$(dirname "$0")/mergify-hooks" -if [ -f "$MERGIFY_HOOKS_DIR/commit-msg.sh" ]; then - "$MERGIFY_HOOKS_DIR/commit-msg.sh" "$@" || exit $? -fi - -# --- USER CUSTOM LOGIC BELOW --- -# Add your custom hook logic here (preserved during upgrades) diff --git a/.husky/mergify-hooks/commit-msg.sh b/.husky/mergify-hooks/commit-msg.sh deleted file mode 100755 index 12bbe591..00000000 --- a/.husky/mergify-hooks/commit-msg.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/sh -# Mergify CLI Hook Script -# This file is managed by mergify-cli and will be auto-upgraded. -# Do not modify - add custom logic to the wrapper file instead. -# -# Based on Gerrit Code Review 3.1.3 -# -# Part of Gerrit Code Review (https://www.gerritcodereview.com/) -# -# Copyright (C) 2009 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# avoid [[ which is not POSIX sh. -if test "$#" != 1 ; then - echo "$0 requires an argument." - exit 1 -fi - -if test ! -f "$1" ; then - echo "file does not exist: $1" - exit 1 -fi - -# $RANDOM will be undefined if not using bash, so don't use set -u -# $RANDOM is undefined in POSIX sh (dash), so include HEAD's SHA for entropy -# to prevent collisions when two commits have the same message in the same second -random=$( (whoami ; hostname ; date; cat $1 ; echo $RANDOM; git rev-parse HEAD 2>/dev/null) | git hash-object --stdin) -dest="$1.tmp.${random}" - -trap 'rm -f "${dest}"' EXIT - -# Reuse a Change-Id from a prior commit on this branch with the same subject. -# Handles amends and reset-and-recreate cycles (where a branch is reset to main -# and the same stack is rebuilt from scratch, which would otherwise generate new -# Change-Ids and break PR tracking). -if ! grep -q "^Change-Id:" "$1"; then - subject=$(head -1 "$1") - branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) - if test -n "$branch" && test "$branch" != "HEAD"; then - reuse_cid="" - for sha in $(git reflog "$branch" --format='%H' -n 50 2>/dev/null); do - s=$(git log -1 --format=%s "$sha" 2>/dev/null) - if test "$s" = "$subject"; then - # Only reuse from commits no longer in the branch (reset away). - # Skip commits still reachable from HEAD to avoid giving two - # active stack commits the same Change-Id. - git merge-base --is-ancestor "$sha" HEAD 2>/dev/null && continue - reuse_cid=$(git log -1 --format=%B "$sha" 2>/dev/null | grep "^Change-Id: I[0-9a-f]\{40\}$" | tail -1 | sed 's/^Change-Id: I//') - test -n "$reuse_cid" && break - fi - done - if test -n "$reuse_cid"; then - random="$reuse_cid" - fi - fi -fi - -# cut everything from the scissor marker downwards, then strip comments/whitespace -if ! (sed '/^# -\{24\} >8 -\{24\}$/,$d' | git stripspace --strip-comments) < "$1" > "${dest}" ; then - echo "cannot strip comments from $1" - exit 1 -fi - -if test ! -s "${dest}" ; then - echo "file is empty: $1" - exit 1 -fi - -# Avoid the --in-place option which only appeared in Git 2.8 -# Avoid the --if-exists option which only appeared in Git 2.15 -if ! git -c trailer.ifexists=doNothing interpret-trailers \ - --trailer "Change-Id: I${random}" < "$1" > "${dest}" ; then - echo "cannot insert change-id line in $1" - exit 1 -fi - -if ! mv "${dest}" "$1" ; then - echo "cannot mv ${dest} to $1" - exit 1 -fi diff --git a/.husky/mergify-hooks/post-commit.sh b/.husky/mergify-hooks/post-commit.sh deleted file mode 100755 index e9856e3f..00000000 --- a/.husky/mergify-hooks/post-commit.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -# Mergify CLI Hook Script -# This file is managed by mergify-cli and will be auto-upgraded. -# Do not modify - add custom logic to the wrapper file instead. -# -# Safety net: if the commit-msg hook did not run or failed to add a Change-Id, -# this hook generates one and amends the commit to include it. - -# Prevent recursion from our own amend below -if test -n "$MERGIFY_POST_COMMIT_RUNNING"; then - exit 0 -fi - -# Read the commit message once -body=$(git log -1 --format=%B 2>/dev/null) - -# Check if the commit already has a Change-Id — nothing to do -if echo "$body" | grep -q "^Change-Id: I[0-9a-f]\{40\}$"; then - exit 0 -fi - -# Generate a Change-Id the same way the commit-msg hook does -random=$( (whoami ; hostname ; date; echo "$body" ; echo $RANDOM) | git hash-object --stdin) - -# Build the amended message: original message + blank line + Change-Id -msg_file=$(mktemp "${TMPDIR:-/tmp}/mergify-post-commit.XXXXXX") || { - echo "mergify: warning: could not create temporary file for Change-Id amend" >&2 - exit 0 -} -trap 'rm -f "$msg_file"' EXIT - -echo "$body" > "$msg_file" -printf '\nChange-Id: I%s\n' "$random" >> "$msg_file" - -# Amend the commit with --no-verify to avoid re-triggering hooks -export MERGIFY_POST_COMMIT_RUNNING=1 -if git commit --amend -F "$msg_file" --no-verify --allow-empty 2>/dev/null; then - echo "mergify: added missing Change-Id to commit" >&2 -else - echo "mergify: warning: could not add Change-Id to commit" >&2 -fi diff --git a/.husky/mergify-hooks/pre-push.sh b/.husky/mergify-hooks/pre-push.sh deleted file mode 100755 index 9a0bbaeb..00000000 --- a/.husky/mergify-hooks/pre-push.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh -# Mergify CLI Hook Script -# This file is managed by mergify-cli and will be auto-upgraded. -# Do not modify - add custom logic to the wrapper file instead. -# -# Intercepts `git push` and suggests `mergify stack push` when on a stack branch. - -# Skip if called from `mergify stack push` (which invokes git push internally) -if test -n "$MERGIFY_STACK_PUSH"; then - exit 0 -fi - -# Only intercept if mergify stack is available -if ! command -v mergify >/dev/null 2>&1; then - exit 0 -fi - -branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) - -# Skip if not on a branch (detached HEAD) -if test -z "$branch"; then - exit 0 -fi - -# Skip if on main/master/develop (not a stack branch) -case "$branch" in - main|master|develop) exit 0 ;; -esac - -# Check if this branch has a Change-Id (indicator it's a stack branch) -base_branch=$(git config --get "branch.${branch}.merge" 2>/dev/null | sed 's|refs/heads/||') -if test -z "$base_branch"; then - exit 0 -fi - -# Check if any commit in the stack has a Change-Id -has_change_id=$(git log --format=%B "${base_branch}..HEAD" 2>/dev/null | grep -c "^Change-Id:") -if test "$has_change_id" -eq 0; then - exit 0 -fi - -echo "" -echo "This branch is managed by Mergify stacks." -echo " Use 'mergify stack push' instead of 'git push'." -echo "" -echo " 'mergify stack push' will:" -echo " - Create/update PRs for each commit" -echo " - Handle rebasing automatically" -echo " - Keep the stack in sync" -echo "" -echo " To proceed with 'git push' anyway, use: git push --no-verify" -echo "" -exit 1 diff --git a/.husky/mergify-hooks/prepare-commit-msg.sh b/.husky/mergify-hooks/prepare-commit-msg.sh deleted file mode 100755 index 810243cb..00000000 --- a/.husky/mergify-hooks/prepare-commit-msg.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/bin/sh -# Mergify CLI Hook Script -# This file is managed by mergify-cli and will be auto-upgraded. -# Do not modify - add custom logic to the wrapper file instead. -# -# Copyright © 2021-2026 Mergify SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# This hook preserves Change-Id during amend operations -# where the message is provided via -m or -F flags (which would otherwise lose -# this trailer). -# -# Arguments: -# $1 - Path to the commit message file -# $2 - Source of the commit message: message, template, merge, squash, or commit -# $3 - Commit SHA (only for squash or commit source) - -if test "$#" -lt 1; then - exit 0 -fi - -MSG_FILE="$1" -SOURCE="${2:-}" - -# If source is "commit" (from --amend or -c/-C), git already preserves the -# original message content including trailers, so we don't need to do anything. -# This hook is specifically for the case where -m or -F is used with --amend, -# which sets source to "message" and loses the original trailers. - -# Only act if we have a message file -if test ! -f "$MSG_FILE"; then - exit 0 -fi - -# Check if HEAD exists (not initial commit) -if ! git rev-parse --verify HEAD >/dev/null 2>&1; then - exit 0 -fi - -# Function to detect if this is an amend operation with -m flag -is_amend_with_m_flag() { - # Heuristic to detect amend: During --amend, git sets GIT_AUTHOR_DATE to preserve - # the original author date. This date should exactly match HEAD's author date. - # For a regular commit, GIT_AUTHOR_DATE is not set by git. - # We also check that source is "message" (set by git for both -m and -F flags). - if test "$SOURCE" != "message" || test -z "$GIT_AUTHOR_DATE"; then - return 1 - fi - - # Get HEAD's author date in the same format git uses internally (raw format) - # The raw format is: seconds-since-epoch timezone (e.g., "1234567890 +0000") - HEAD_AUTHOR_DATE_RAW=$(git log -1 --format=%ad --date=raw HEAD 2>/dev/null) - if test -z "$HEAD_AUTHOR_DATE_RAW"; then - return 1 - fi - - # Extract epoch from GIT_AUTHOR_DATE (handles various formats) - # During amend, GIT_AUTHOR_DATE is in format: "@epoch tz" (e.g., "@1234567890 +0000") - # Remove the @ prefix if present - GIT_AUTHOR_EPOCH=$(echo "$GIT_AUTHOR_DATE" | cut -d' ' -f1 | tr -d '@') - HEAD_AUTHOR_EPOCH=$(echo "$HEAD_AUTHOR_DATE_RAW" | cut -d' ' -f1) - - # If the epoch timestamps match, this is likely an amend operation. - # Additional check: the author date should be at least 2 seconds in the past. - # This prevents false positives when commits happen in quick succession - # (e.g., in automated tests or scripts) where timestamps might match by coincidence. - if test "$GIT_AUTHOR_EPOCH" != "$HEAD_AUTHOR_EPOCH"; then - return 1 - fi - - CURRENT_EPOCH=$(date +%s) - AGE=$((CURRENT_EPOCH - GIT_AUTHOR_EPOCH)) - if test "$AGE" -lt 2; then - return 1 - fi - - return 0 -} - -# Only proceed if this is an amend with -m flag -if ! is_amend_with_m_flag; then - exit 0 -fi - -# Track if we need to add a blank line before trailers -NEED_BLANK_LINE=false - -# Preserve Change-Id if missing from current message but present in HEAD -if ! grep -q "^Change-Id: I[0-9a-f]\{40\}$" "$MSG_FILE"; then - HEAD_CHANGEID=$(git log -1 --format=%B HEAD 2>/dev/null | grep "^Change-Id: I[0-9a-f]\{40\}$" | tail -1) - if test -n "$HEAD_CHANGEID"; then - if test "$NEED_BLANK_LINE" = "false"; then - echo "" >> "$MSG_FILE" - NEED_BLANK_LINE=true - fi - echo "$HEAD_CHANGEID" >> "$MSG_FILE" - fi -fi diff --git a/.husky/post-commit b/.husky/post-commit deleted file mode 100755 index 324c7d60..00000000 --- a/.husky/post-commit +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# Mergify CLI Hook Wrapper -# This file is managed by mergify-cli. You can add custom logic below the marker. - -# Skip if this is a recursive call from the post-commit safety net amend -[ -n "$MERGIFY_POST_COMMIT_RUNNING" ] && exit 0 - -MERGIFY_HOOKS_DIR="$(dirname "$0")/mergify-hooks" -if [ -f "$MERGIFY_HOOKS_DIR/post-commit.sh" ]; then - "$MERGIFY_HOOKS_DIR/post-commit.sh" "$@" || exit $? -fi - -# --- USER CUSTOM LOGIC BELOW --- -# Add your custom hook logic here (preserved during upgrades) diff --git a/.husky/pre-push b/.husky/pre-push deleted file mode 100755 index 650f002f..00000000 --- a/.husky/pre-push +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# Mergify CLI Hook Wrapper -# This file is managed by mergify-cli. You can add custom logic below the marker. - -MERGIFY_HOOKS_DIR="$(dirname "$0")/mergify-hooks" -if [ -f "$MERGIFY_HOOKS_DIR/pre-push.sh" ]; then - "$MERGIFY_HOOKS_DIR/pre-push.sh" "$@" || exit $? -fi - -# --- USER CUSTOM LOGIC BELOW --- -# Add your custom hook logic here (preserved during upgrades) diff --git a/.husky/prepare-commit-msg b/.husky/prepare-commit-msg deleted file mode 100755 index 2e38d59d..00000000 --- a/.husky/prepare-commit-msg +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -# Mergify CLI Hook Wrapper -# This file is managed by mergify-cli. You can add custom logic below the marker. - -MERGIFY_HOOKS_DIR="$(dirname "$0")/mergify-hooks" -if [ -f "$MERGIFY_HOOKS_DIR/prepare-commit-msg.sh" ]; then - "$MERGIFY_HOOKS_DIR/prepare-commit-msg.sh" "$@" || exit $? -fi - -# --- USER CUSTOM LOGIC BELOW --- -# Add your custom hook logic here (preserved during upgrades) diff --git a/.prettierignore b/.prettierignore index 759cf406..071961d2 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,3 +5,5 @@ **/node_modules/** **/pnpm-lock.yaml examples/** +# Built by benchmarks/proof-recall/scripts/build.mjs; must match the writer byte for byte. +benchmarks/proof-recall/.flatbread-proof/** diff --git a/AGENTS.md b/AGENTS.md index f7088d75..49ac91f5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -51,13 +51,31 @@ See `CONTRIBUTING.md` for full details. Quick reference: - **Proof**: agent memory in this repo. CLI is `flatbread proof …`; records live under `.flatbread-proof/`. - **Dev server**: `pnpm play` (GraphQL on port 5057, Next.js on port 3000). From `examples/nextjs`, prefer `pnpm exec flatbread start -- next dev --turbopack`. Use `flatbread start` — `flatbread dev` is not a CLI command. -### Mergify Stacks - -The repo uses Mergify stacks for PR management. The `mergify-cli` is installed via `pip install mergify-cli` (included in the update script). Key points: - -- Use `mergify stack push` instead of `git push` on feature branches (the `.husky/pre-push` hook will remind you). -- The commit-msg hook (`.husky/commit-msg`) auto-appends a `Change-Id` trailer for stack tracking. -- See `.agents/skills/mergify-stack/SKILL.md` for the full workflow. +### Stacked pull requests + +The repo uses GitHub's own stacked pull requests through `gh stack`, an +extension to the GitHub CLI. A stack is a chain of branches. Each branch gets +one pull request based on the branch below it, so a reviewer sees one layer at +a time. + +1. Install the extension once: `gh extension install github/gh-stack`. It + needs Git 2.36 or later, and stacked pull requests must be enabled for the + repository on GitHub. +2. Start a stack with `gh stack init <branch>` and add each layer on top with + `gh stack add <branch>`. +3. Open or update every pull request in the stack with + `gh stack submit --auto`. A single branch can still use plain `git push`. +4. Keep the stack current with `gh stack sync`. After you change a lower + layer, run `gh stack rebase --upstack`. + +Agents must pass the non-interactive flags listed in +`.agents/skills/gh-stack/SKILL.md`: bare `gh stack view`, `submit`, and +`modify` open full-screen prompts that never return. + +Merging still goes through Mergify's merge queue, which `.mergify.yml` +configures. `gh stack merge` knows only GitHub's own merge queue, so it would +merge directly and skip Mergify. Keep `mergify-cli` installed: the +`mergify-*` skills use its `mergify queue` commands. ### PR review models diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-codec-benchmark-cold-cache-on-skiff-january-2026--wczvq0srnnzjs407.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-codec-benchmark-cold-cache-on-skiff-january-2026--wczvq0srnnzjs407.md new file mode 100644 index 00000000..10915788 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-codec-benchmark-cold-cache-on-skiff-january-2026--wczvq0srnnzjs407.md @@ -0,0 +1,21 @@ +--- +id: blb-codec-benchmark-cold-cache-on-skiff-january-2026--wczvq0srnnzjs407 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'Codec benchmark, cold cache on Skiff, January 2026' +kind: markdown +created_at: '2026-01-09T15:00:00Z' +created_by: Kenji Arakawa +--- +# Codec benchmark, cold cache (Skiff retail unit, one core) + +Caches flushed before each asset. Decode rate in GB/s of output. + +| Asset class | Kelp 4 MB dict GB/s | Zstandard GB/s | +| --- | --- | --- | +| Textures | 1.2 | 1.4 | +| Geometry | 0.8 | 1.2 | +| Audio banks | 1.0 | 1.1 | +| Navigation | 1.3 | 1.5 | +| All assets (weighted) | 1.1 | 1.3 | + +LZ4 was not rerun. Spread across three retail units was under 4%. diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-codec-benchmark-warm-cache-october-2025--kcybvms2ttten909.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-codec-benchmark-warm-cache-october-2025--kcybvms2ttten909.md new file mode 100644 index 00000000..bfe35a7e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-codec-benchmark-warm-cache-october-2025--kcybvms2ttten909.md @@ -0,0 +1,21 @@ +--- +id: blb-codec-benchmark-warm-cache-october-2025--kcybvms2ttten909 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'Codec benchmark, warm cache, October 2025' +kind: markdown +created_at: '2025-10-13T15:00:00Z' +created_by: Kenji Arakawa +--- +# Codec benchmark, warm cache (PC dev box, one core) + +Decode rate in GB/s of output; ratio is uncompressed over compressed. + +| Asset class | Kelp ratio | Kelp GB/s | Zstandard ratio | Zstandard GB/s | LZ4 ratio | LZ4 GB/s | +| --- | --- | --- | --- | --- | --- | --- | +| Textures | 3.4 | 3.1 | 3.0 | 1.5 | 2.2 | 3.9 | +| Geometry | 2.9 | 2.8 | 2.7 | 1.3 | 2.0 | 3.8 | +| Audio banks | 1.6 | 2.4 | 1.7 | 1.2 | 1.4 | 3.6 | +| Navigation | 4.1 | 3.0 | 3.8 | 1.6 | 2.6 | 4.0 | +| All assets (weighted) | 3.1 | 2.9 | 2.8 | 1.4 | 2.1 | 3.8 | + +Zstandard at level 9; LZ4 in high-compression mode. Kelp dictionary: 4 MB, loaded once before the run. diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-delta-save-sizes-by-hours-played--x6mda6tam40w26t5.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-delta-save-sizes-by-hours-played--x6mda6tam40w26t5.md new file mode 100644 index 00000000..69006898 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-delta-save-sizes-by-hours-played--x6mda6tam40w26t5.md @@ -0,0 +1,14 @@ +--- +id: blb-delta-save-sizes-by-hours-played--x6mda6tam40w26t5 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Delta save sizes by hours played +kind: csv +created_at: '2026-05-18T15:00:00Z' +created_by: Marta Lindqvist +--- +hours_played,delta_count,save_mb,load_s_skiff +2,1840,0.4,0.6 +10,9120,1.6,1.1 +20,17900,3.1,1.7 +40,35400,6.2,2.9 +80,69800,12.3,5.4 diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-ecs-storage-microbenchmark-profile-september-202--csvrtfr7ce23yzz5.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-ecs-storage-microbenchmark-profile-september-202--csvrtfr7ce23yzz5.md new file mode 100644 index 00000000..47fd62d9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-ecs-storage-microbenchmark-profile-september-202--csvrtfr7ce23yzz5.md @@ -0,0 +1,35 @@ +--- +id: blb-ecs-storage-microbenchmark-profile-september-202--csvrtfr7ce23yzz5 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'ECS storage microbenchmark profile, September 2025' +kind: json +created_at: '2025-09-09T14:00:00Z' +created_by: Rhea Valdés +--- +{ + "capture": "ecs-bench run-0909", + "machine": "PC dev box, 16 cores, DDR5-5600", + "entities": 1000000, + "spawn_templates": 1, + "archetype_count": 3, + "layouts": [ + { + "layout": "archetype_tables", + "iterate_transforms_ms": 1.9, + "add_remove_component_ns": 380, + "memory_mb": 212 + }, + { + "layout": "sparse_sets", + "iterate_transforms_ms": 4.6, + "add_remove_component_ns": 45, + "memory_mb": 340 + }, + { + "layout": "hybrid", + "iterate_transforms_ms": 2.1, + "add_remove_component_ns": 52, + "memory_mb": 236 + } + ] +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-forward-on-the-cliffs-benchmark-meri--f1jwxdgx0fpe0wvs.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-forward-on-the-cliffs-benchmark-meri--f1jwxdgx0fpe0wvs.md new file mode 100644 index 00000000..2acd08e3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-forward-on-the-cliffs-benchmark-meri--f1jwxdgx0fpe0wvs.md @@ -0,0 +1,25 @@ +--- +id: blb-gpu-capture-forward-on-the-cliffs-benchmark-meri--f1jwxdgx0fpe0wvs +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'GPU capture: forward+ on the cliffs benchmark, Meridian' +kind: json +created_at: '2025-09-09T14:00:00Z' +created_by: Tomasz Brandt +--- +{ + "build": "lantern-2025.09.08-r4411", + "platform": "Meridian devkit", + "scene": "cliffs_bench_02", + "resolution": "2560x1440", + "passes_ms": { + "depth_prepass": 1.1, + "light_cull": 0.6, + "forward_opaque": 7.9, + "saltglass_forward": 2.3, + "post": 1.4 + }, + "quad_overdraw": 3.4, + "triangles_visible": 14200000, + "worst_tile_lights": 212, + "notes": "Overdraw measured with the helper-lane counter; cliff face LOD0 dominates." +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-sdf-gi-on-a-meridian-devkit-dunes-be--9r2nk13cja7s06cx.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-sdf-gi-on-a-meridian-devkit-dunes-be--9r2nk13cja7s06cx.md new file mode 100644 index 00000000..4d7ebaf7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-sdf-gi-on-a-meridian-devkit-dunes-be--9r2nk13cja7s06cx.md @@ -0,0 +1,23 @@ +--- +id: blb-gpu-capture-sdf-gi-on-a-meridian-devkit-dunes-be--9r2nk13cja7s06cx +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'GPU capture: SDF GI on a Meridian devkit, dunes benchmark' +kind: json +created_at: '2026-02-02T15:00:00Z' +created_by: Tomasz Brandt +--- +{ + "build": "lantern-2026.02.01-r5840", + "device": "Meridian devkit MRD-0031, retail clocks", + "scene": "dunes_bench_01", + "resolution": "2560x1440", + "clipmap_cascades": 4, + "passes_ms": { + "sdf_update": 0.6, + "trace": 3.2, + "filter": 0.5, + "apply": 0.4 + }, + "total_ms": 4.7, + "l2_hit_rate": 0.52 +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-sdf-gi-on-the-dunes-benchmark--h1szrk86b69n5b26.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-sdf-gi-on-the-dunes-benchmark--h1szrk86b69n5b26.md new file mode 100644 index 00000000..0f937232 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-sdf-gi-on-the-dunes-benchmark--h1szrk86b69n5b26.md @@ -0,0 +1,24 @@ +--- +id: blb-gpu-capture-sdf-gi-on-the-dunes-benchmark--h1szrk86b69n5b26 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'GPU capture: SDF GI on the dunes benchmark' +kind: json +created_at: '2025-10-13T15:00:00Z' +created_by: Tomasz Brandt +--- +{ + "build": "lantern-2025.10.10-r4630", + "device": "PC workstation (Meridian clock profile)", + "scene": "dunes_bench_01", + "resolution": "2560x1440", + "clipmap_cascades": 4, + "clipmap_size": "64^3", + "passes_ms": { + "sdf_update": 0.4, + "trace": 1.3, + "filter": 0.3, + "apply": 0.2 + }, + "total_ms": 2.2, + "l2_hit_rate": 0.81 +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-virtual-shadow-map-prototype-dunes-b--cknjqzqy2mqz93mf.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-virtual-shadow-map-prototype-dunes-b--cknjqzqy2mqz93mf.md new file mode 100644 index 00000000..cd53e0a8 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-virtual-shadow-map-prototype-dunes-b--cknjqzqy2mqz93mf.md @@ -0,0 +1,25 @@ +--- +id: blb-gpu-capture-virtual-shadow-map-prototype-dunes-b--cknjqzqy2mqz93mf +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'GPU capture: virtual shadow map prototype, dunes benchmark' +kind: json +created_at: '2025-09-25T15:00:00Z' +created_by: Tomasz Brandt +--- +{ + "build": "lantern-2025.09.24-r4561", + "platform": "Meridian devkit", + "scene": "dunes_bench_01", + "virtual_resolution": 16384, + "page_size": 128, + "pool_pages": 4096, + "page_pool_clear": "every_frame", + "pages_rendered_per_frame": 3870, + "passes_ms": { + "page_mark": 0.3, + "page_raster": 2.4, + "page_sample": 0.4 + }, + "total_ms": 3.1, + "csm_reference_ms": 1.6 +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-virtual-shadow-maps-with-page-cachin--sf5pzwgx8fv8gbpb.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-virtual-shadow-maps-with-page-cachin--sf5pzwgx8fv8gbpb.md new file mode 100644 index 00000000..720681f7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-virtual-shadow-maps-with-page-cachin--sf5pzwgx8fv8gbpb.md @@ -0,0 +1,22 @@ +--- +id: blb-gpu-capture-virtual-shadow-maps-with-page-cachin--sf5pzwgx8fv8gbpb +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'GPU capture: virtual shadow maps with page caching, dunes benchmark' +kind: json +created_at: '2025-11-22T15:00:00Z' +created_by: Tomasz Brandt +--- +{ + "build": "lantern-2025.11.21-r5310", + "platform": "Meridian devkit", + "scene": "dunes_bench_01", + "page_pool_clear": "on_invalidation", + "pages_rendered_per_frame": 212, + "passes_ms": { + "page_mark": 0.3, + "page_raster": 0.7, + "page_sample": 0.4 + }, + "total_ms": 1.4, + "csm_reference_ms": 1.6 +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-visibility-buffer-on-skiff-cliffs-be--x1ynk37229baj5vt.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-visibility-buffer-on-skiff-cliffs-be--x1ynk37229baj5vt.md new file mode 100644 index 00000000..88311bfd --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-gpu-capture-visibility-buffer-on-skiff-cliffs-be--x1ynk37229baj5vt.md @@ -0,0 +1,24 @@ +--- +id: blb-gpu-capture-visibility-buffer-on-skiff-cliffs-be--x1ynk37229baj5vt +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'GPU capture: visibility buffer on Skiff, cliffs benchmark' +kind: json +created_at: '2026-04-07T15:00:00Z' +created_by: Tomasz Brandt +--- +{ + "build": "lantern-2026.04.06-r6120", + "build_config": "debug-gpu-validation", + "platform": "Skiff devkit SKF-0007", + "scene": "cliffs_bench_02", + "resolution": "1280x720", + "passes_ms": { + "visibility_raster": 2.6, + "material_resolve": 5, + "saltglass_forward": 2.1, + "post": 1.5 + }, + "total_vb_ms": 11.2, + "forward_plus_reference_ms": 8.9, + "notes": "First capture on the new Skiff devkits." +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-highlight-histogram-caustic-pixels-under-the-sto--bv0tyatpe22kxqkq.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-highlight-histogram-caustic-pixels-under-the-sto--bv0tyatpe22kxqkq.md new file mode 100644 index 00000000..10487c3c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-highlight-histogram-caustic-pixels-under-the-sto--bv0tyatpe22kxqkq.md @@ -0,0 +1,17 @@ +--- +id: blb-highlight-histogram-caustic-pixels-under-the-sto--bv0tyatpe22kxqkq +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Highlight histogram: caustic pixels under the stock filmic curve' +kind: json +created_at: '2026-01-15T15:00:00Z' +created_by: Yusuf Demir +--- +{ + "build": "lantern-2026.01.14-r5650", + "scene": "dunes_noon", + "curve": "kestrel_filmic_v2", + "caustic_pixels": 182000, + "clipped_caustic_pixels": 69160, + "clipped_pct": 38, + "white_point_nits_equiv": 11.2 +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-luminance-trace-caustics-under-tern-dunes-at-noo--hg2t94dx5wv08a7r.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-luminance-trace-caustics-under-tern-dunes-at-noo--hg2t94dx5wv08a7r.md new file mode 100644 index 00000000..3bee4c1a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-luminance-trace-caustics-under-tern-dunes-at-noo--hg2t94dx5wv08a7r.md @@ -0,0 +1,23 @@ +--- +id: blb-luminance-trace-caustics-under-tern-dunes-at-noo--hg2t94dx5wv08a7r +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Luminance trace: caustics under Tern, dunes at noon' +kind: json +created_at: '2026-01-22T15:00:00Z' +created_by: Yusuf Demir +--- +{ + "build": "lantern-2026.01.21-r5720", + "platform": "Meridian devkit", + "scene": "dunes_noon", + "internal_resolution": "1280x720", + "output_resolution": "2560x1440", + "frames": 600, + "peak_flicker_hz": 4.7, + "flicker_band_hz": [ + 3, + 6 + ], + "max_luma_delta": 0.31, + "pixels_over_threshold_pct": 6.2 +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-meridian-hdr-certification-pre-check-report-july--6r648dzqhh44mkq7.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-meridian-hdr-certification-pre-check-report-july--6r648dzqhh44mkq7.md new file mode 100644 index 00000000..fababecf --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-meridian-hdr-certification-pre-check-report-july--6r648dzqhh44mkq7.md @@ -0,0 +1,19 @@ +--- +id: blb-meridian-hdr-certification-pre-check-report-july--6r648dzqhh44mkq7 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Meridian HDR certification pre-check report, July' +kind: markdown +created_at: '2026-07-14T15:00:00Z' +created_by: Priya Natarajan +--- +# HDR pre-check, build lantern-2026.07.13-r7400 + +| Test | Name | Result | +| --- | --- | --- | +| HDR-01 | Starts in HDR when system is HDR | PASS | +| HDR-03 | Peak luminance follows calibration | PASS | +| HDR-05 | Test ramp does not clip below peak | PASS | +| HDR-07 | Paper white follows system setting and range | FAIL | +| HDR-09 | SDR and HDR content match | PASS | + +HDR-07 note: paper white stayed at 200 nits for system values of 100 and 350. No in-game control found. diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-meshlet-size-sweep-on-the-cliffs-benchmark--4shwgvp9x310epk7.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-meshlet-size-sweep-on-the-cliffs-benchmark--4shwgvp9x310epk7.md new file mode 100644 index 00000000..21af538a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-meshlet-size-sweep-on-the-cliffs-benchmark--4shwgvp9x310epk7.md @@ -0,0 +1,15 @@ +--- +id: blb-meshlet-size-sweep-on-the-cliffs-benchmark--4shwgvp9x310epk7 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Meshlet size sweep on the cliffs benchmark +kind: markdown +created_at: '2025-11-18T15:00:00Z' +created_by: Tomasz Brandt +--- +| Max vertices | Max triangles | Meshlets (cliffs) | Raster ms | Culled triangles | +| --- | --- | --- | --- | --- | +| 32 | 60 | 412,000 | 1.42 | 58% | +| 64 | 124 | 208,000 | 1.18 | 54% | +| 128 | 256 | 104,000 | 1.25 | 47% | + +Build lantern-2025.11.17-r5260, Meridian devkit, 1440p. diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-page-pool-trace-virtual-shadow-maps-across-a-spr--6qdd5aahwkcmhyg8.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-page-pool-trace-virtual-shadow-maps-across-a-spr--6qdd5aahwkcmhyg8.md new file mode 100644 index 00000000..5241f1fa --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-page-pool-trace-virtual-shadow-maps-across-a-spr--6qdd5aahwkcmhyg8.md @@ -0,0 +1,35 @@ +--- +id: blb-page-pool-trace-virtual-shadow-maps-across-a-spr--6qdd5aahwkcmhyg8 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Page-pool trace: virtual shadow maps across a spring tide' +kind: json +created_at: '2026-06-12T15:00:00Z' +created_by: Tomasz Brandt +--- +{ + "build": "lantern-2026.06.11-r7020", + "platform": "Meridian devkit", + "scene": "flats_spring_tide", + "pool_pages": 4096, + "samples": [ + { + "tide_phase": "spring high", + "pages_requested": 1880 + }, + { + "tide_phase": "mid ebb", + "pages_requested": 3410 + }, + { + "tide_phase": "spring low", + "pages_requested": 5912 + }, + { + "tide_phase": "mid flood", + "pages_requested": 3120 + } + ], + "peak_pages_requested": 5912, + "frames_over_pool": 1430, + "worst_tide_phase": "spring low, 31 minutes into the 40-minute cycle" +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-shader-cache-hit-rate-report-four-weeks-after-th--g0383kwnqtjdh4jz.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-shader-cache-hit-rate-report-four-weeks-after-th--g0383kwnqtjdh4jz.md new file mode 100644 index 00000000..8ab2cacd --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-shader-cache-hit-rate-report-four-weeks-after-th--g0383kwnqtjdh4jz.md @@ -0,0 +1,40 @@ +--- +id: blb-shader-cache-hit-rate-report-four-weeks-after-th--g0383kwnqtjdh4jz +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: 'Shader cache hit-rate report, four weeks after the binary-hash key' +kind: json +created_at: '2026-01-26T10:00:00Z' +created_by: Liam O'Connell +--- +{ + "report": "farm shader compile cache, weekly", + "key_version": "binary-hash key", + "weeks": [ + { + "week": 1, + "builds": 118, + "hit_rate": 71, + "median_build_minutes": 12.5 + }, + { + "week": 2, + "builds": 124, + "hit_rate": 84.6, + "median_build_minutes": 9.1 + }, + { + "week": 3, + "builds": 131, + "hit_rate": 89.9, + "median_build_minutes": 7.8 + }, + { + "week": 4, + "builds": 127, + "hit_rate": 92.4, + "median_build_minutes": 7.2 + } + ], + "p95_fetch_ms": 180, + "storage_used_tb": 1.4 +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-skiff-first-visit-pipeline-compile-capture-build--wfpq5kvqxddn0a9w.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-skiff-first-visit-pipeline-compile-capture-build--wfpq5kvqxddn0a9w.md new file mode 100644 index 00000000..dca08f50 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-skiff-first-visit-pipeline-compile-capture-build--wfpq5kvqxddn0a9w.md @@ -0,0 +1,34 @@ +--- +id: blb-skiff-first-visit-pipeline-compile-capture-build--wfpq5kvqxddn0a9w +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Skiff first-visit pipeline compile capture, build 3810' +kind: json +created_at: '2025-12-09T10:00:00Z' +created_by: Priya Natarajan +--- +{ + "capture": "first-visit-pipeline-compiles", + "platform": "Skiff", + "firmware": "1.0", + "build": 3810, + "districts": { + "harbor": { + "unique_pipelines": 1460, + "first_visit_hitches_over_33ms": 212 + }, + "dunes": { + "unique_pipelines": 820, + "first_visit_hitches_over_33ms": 96 + }, + "ruins": { + "unique_pipelines": 1110, + "first_visit_hitches_over_33ms": 147 + } + }, + "compile_ms": { + "p50": 72, + "p90": 141, + "p99": 190, + "min": 45 + } +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-skiff-harbor-district-memory-capture-build-4127--t40rdrfffc5q5e89.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-skiff-harbor-district-memory-capture-build-4127--t40rdrfffc5q5e89.md new file mode 100644 index 00000000..6aaa5146 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-skiff-harbor-district-memory-capture-build-4127--t40rdrfffc5q5e89.md @@ -0,0 +1,35 @@ +--- +id: blb-skiff-harbor-district-memory-capture-build-4127--t40rdrfffc5q5e89 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Skiff harbor district memory capture, build 4127' +kind: json +created_at: '2026-02-16T10:00:00Z' +created_by: Kenji Arakawa +--- +{ + "capture": "harbor-district-peak", + "platform": "Skiff", + "firmware": "1.2", + "build": 4127, + "captured_on": "2026-02-17", + "route": "Fast travel to the harbor at low tide, then walk the fish market to the lighthouse", + "budget_mb": 8192, + "peak_mb": 8806, + "over_budget_mb": 614, + "categories_mb": { + "textures": 3184, + "streaming_pool": 2048, + "meshes": 1106, + "render_targets": 1012, + "audio_banks": 912, + "tide_sim": 330, + "gull_heap": 214 + }, + "growth_since_slice_mb": { + "audio_banks": 388, + "tide_sim": 214, + "textures": 96, + "meshes": 41 + }, + "notes": "Peak lasts about 4 seconds while two tide cells are double buffered." +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-skiff-pre-certification-report-build-5530--1q6hz38801fy3tqk.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-skiff-pre-certification-report-build-5530--1q6hz38801fy3tqk.md new file mode 100644 index 00000000..b28b63a0 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-skiff-pre-certification-report-build-5530--1q6hz38801fy3tqk.md @@ -0,0 +1,19 @@ +--- +id: blb-skiff-pre-certification-report-build-5530--1q6hz38801fy3tqk +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Skiff pre-certification report, build 5530' +kind: markdown +created_at: '2026-05-18T09:00:00Z' +created_by: Dara Whitlock +--- +# Skiff pre-certification report: Saltglass Reach build 5530 + +Submitted 2026-05-11. Reviewed by the platform holder lot check team on 2026-05-15. + +| Code | Area | Result | Detail | +| --- | --- | --- | --- | +| SKF-ST-012 | Storage | Fail | Autosave writes 11.2 MB per minute; the limit is 4 MB per minute. | +| SKF-UI-031 | Interface | Fail | HUD stamina and tide labels are 6 px tall at 720p; the minimum is 9 px. | +| SKF-DSP-004 | Display | Advisory | Docked 30 Hz mode shows judder on some 50 Hz TVs. | + +Fails must be fixed before a full submission. Advisories may be waived on request. diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-skiff-rollback-profile-capture-6-frame-window-ti--ffqejdktg6fmth3c.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-skiff-rollback-profile-capture-6-frame-window-ti--ffqejdktg6fmth3c.md new file mode 100644 index 00000000..b3f5f654 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-skiff-rollback-profile-capture-6-frame-window-ti--ffqejdktg6fmth3c.md @@ -0,0 +1,22 @@ +--- +id: blb-skiff-rollback-profile-capture-6-frame-window-ti--ffqejdktg6fmth3c +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: 'Skiff rollback profile capture, 6-frame window, tides on' +kind: json +created_at: '2026-03-18T10:00:00Z' +created_by: Priya Natarajan +--- +{ + "capture": "skiff-devkit-04, Shoal-01, four players, 40 Hz mode", + "window_frames": 6, + "per_rollback_ms": { + "tide_resim": 4.8, + "physics_resim": 1.9, + "gull_resim": 0.7, + "snapshot_restore": 0.3, + "total": 7.7 + }, + "tide_step_ms": 0.8, + "frame_budget_ms": 25, + "rollbacks_per_second_p50": 22 +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-streaming-pool-occupancy-alpha-playtest--bahqk0svngyshny0.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-streaming-pool-occupancy-alpha-playtest--bahqk0svngyshny0.md new file mode 100644 index 00000000..3e54e09c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-streaming-pool-occupancy-alpha-playtest--bahqk0svngyshny0.md @@ -0,0 +1,23 @@ +--- +id: blb-streaming-pool-occupancy-alpha-playtest--bahqk0svngyshny0 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'Streaming pool occupancy, alpha playtest' +kind: json +created_at: '2026-03-03T15:00:00Z' +created_by: Kenji Arakawa +--- +{ + "capture": "pool-occupancy-0303", + "sessions": 12, + "hours": 19.5, + "pool_gb": 2, + "mean_occupancy_gb": 1.71, + "peak_occupancy_gb": 1.98, + "reloads": { + "lru_replay": 4120, + "forecast": 3214, + "reduction": 0.22 + }, + "player_reversals_per_min": 3.4, + "evicted_then_reloaded_within_60s": 0.19 +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-streaming-read-trace-retail-skiff-against-dev-ki--5pj5rh05kbsc6gcj.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-streaming-read-trace-retail-skiff-against-dev-ki--5pj5rh05kbsc6gcj.md new file mode 100644 index 00000000..631aff74 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-streaming-read-trace-retail-skiff-against-dev-ki--5pj5rh05kbsc6gcj.md @@ -0,0 +1,33 @@ +--- +id: blb-streaming-read-trace-retail-skiff-against-dev-ki--5pj5rh05kbsc6gcj +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'Streaming read trace, retail Skiff against dev kit' +kind: json +created_at: '2026-02-17T15:00:00Z' +created_by: Priya Natarajan +--- +{ + "capture": "stream-trace-0217", + "route": "coast loop, 10 minutes", + "units": [ + { + "unit": "Skiff dev kit", + "storage": "dev kit SSD", + "sustained_mb_s": 262, + "p99_latency_ms": 9 + }, + { + "unit": "Skiff retail A", + "storage": "retail flash", + "sustained_mb_s": 191, + "p99_latency_ms": 24 + }, + { + "unit": "Skiff retail B", + "storage": "retail flash", + "sustained_mb_s": 188, + "p99_latency_ms": 27 + } + ], + "note": "Dev kits ship a faster SSD than retail units." +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-streaming-trace-inland-sprint-during-a-falling-t--91wvax8b1e5f0qvw.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-streaming-trace-inland-sprint-during-a-falling-t--91wvax8b1e5f0qvw.md new file mode 100644 index 00000000..4610311c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-streaming-trace-inland-sprint-during-a-falling-t--91wvax8b1e5f0qvw.md @@ -0,0 +1,19 @@ +--- +id: blb-streaming-trace-inland-sprint-during-a-falling-t--91wvax8b1e5f0qvw +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'Streaming trace: inland sprint during a falling tide on Skiff' +kind: json +created_at: '2026-08-07T15:00:00Z' +created_by: Kenji Arakawa +--- +{ + "capture": "stream-trace-0807-skiff", + "cell_size_m": 192, + "player_speed_m_s": 7.5, + "tide_event": "falling, spring tide", + "tide_cells_queued": 11, + "proximity_reads_delayed": 46, + "max_untextured_s": 6.8, + "worst_location": "Glassreef inlet", + "queue_depth_max": 32 +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-streaming-trace-of-a-falling-tide-on-skiff-256-m--g5wcgz9426mk1y45.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-streaming-trace-of-a-falling-tide-on-skiff-256-m--g5wcgz9426mk1y45.md new file mode 100644 index 00000000..eaf9700d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-streaming-trace-of-a-falling-tide-on-skiff-256-m--g5wcgz9426mk1y45.md @@ -0,0 +1,26 @@ +--- +id: blb-streaming-trace-of-a-falling-tide-on-skiff-256-m--g5wcgz9426mk1y45 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'Streaming trace of a falling tide on Skiff, 256 m cells' +kind: json +created_at: '2025-11-10T15:00:00Z' +created_by: Kenji Arakawa +--- +{ + "capture": "stream-trace-1110-skiff", + "platform": "Skiff dev kit", + "cell_size_m": 256, + "tide_event": "falling, high to low", + "duration_s": 40, + "cells_reloaded": 18, + "peak_read_mb_s": 410, + "mean_read_mb_s": 236, + "stall_frames": 37, + "worst_cell": "c(14,-3)", + "read_share_by_type": { + "textures": 0.61, + "geometry": 0.27, + "navigation": 0.07, + "audio": 0.05 + } +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-tern-preset-table-render-scale-and-cost-per-plat--vzvzz16jyhnr937h.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-tern-preset-table-render-scale-and-cost-per-plat--vzvzz16jyhnr937h.md new file mode 100644 index 00000000..577b5e32 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-tern-preset-table-render-scale-and-cost-per-plat--vzvzz16jyhnr937h.md @@ -0,0 +1,35 @@ +--- +id: blb-tern-preset-table-render-scale-and-cost-per-plat--vzvzz16jyhnr937h +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Tern preset table: render scale and cost per platform' +kind: json +created_at: '2026-02-23T15:00:00Z' +created_by: Tomasz Brandt +--- +{ + "build": "lantern-2026.02.22-r5990", + "output": "4K on PC and Meridian, 720p on Skiff", + "presets": { + "quality": { + "scale": 0.67, + "meridian_ms": 1.4, + "skiff_ms": 3.9 + }, + "balanced": { + "scale": 0.58, + "meridian_ms": 1.3, + "skiff_ms": 3 + }, + "performance": { + "scale": 0.5, + "meridian_ms": 1.2, + "skiff_ms": 2.1 + }, + "ultra_performance": { + "scale": 0.33, + "meridian_ms": 1, + "skiff_ms": null + } + }, + "notes": "Ultra Performance is untested on Skiff." +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-tide-drift-log-pc-meridian-and-skiff-over-6-minu--vyzb37vz3nrts95v.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-tide-drift-log-pc-meridian-and-skiff-over-6-minu--vyzb37vz3nrts95v.md new file mode 100644 index 00000000..53514c3f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-tide-drift-log-pc-meridian-and-skiff-over-6-minu--vyzb37vz3nrts95v.md @@ -0,0 +1,41 @@ +--- +id: blb-tide-drift-log-pc-meridian-and-skiff-over-6-minu--vyzb37vz3nrts95v +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'Tide drift log: PC, Meridian, and Skiff over 6 minutes' +kind: json +created_at: '2025-10-28T15:00:00Z' +created_by: Marta Lindqvist +--- +{ + "capture": "tide-drift-1028", + "threshold_cm": 1, + "pairs": [ + { + "pair": "PC vs Meridian", + "first_over_threshold_min": 8.7, + "max_delta_cm_at_6_min": 0.4 + }, + { + "pair": "PC vs Skiff", + "first_over_threshold_min": 5.6, + "max_delta_cm_at_6_min": 3.8 + }, + { + "pair": "Meridian vs Skiff", + "first_over_threshold_min": 5.9, + "max_delta_cm_at_6_min": 2.9 + } + ], + "first_walkable_flip": { + "pair": "PC vs Skiff", + "tile": [ + 212, + 87 + ], + "minute": 5.8 + }, + "suspected_causes": [ + "fused multiply-add contraction", + "sin() differs by 1 ulp on Skiff" + ] +} diff --git a/benchmarks/proof-recall/.flatbread-proof/blobs/blb-timing-table-visibility-buffer-prototype-against--8debfkdp7fz7nwjp.md b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-timing-table-visibility-buffer-prototype-against--8debfkdp7fz7nwjp.md new file mode 100644 index 00000000..bde4aa86 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/blobs/blb-timing-table-visibility-buffer-prototype-against--8debfkdp7fz7nwjp.md @@ -0,0 +1,18 @@ +--- +id: blb-timing-table-visibility-buffer-prototype-against--8debfkdp7fz7nwjp +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Timing table: visibility buffer prototype against forward+' +kind: markdown +created_at: '2025-09-22T15:00:00Z' +created_by: Tomasz Brandt +--- +| Pass (cliffs_bench_02, Meridian, 1440p) | Forward+ (ms) | Visibility buffer (ms) | +| --- | --- | --- | +| Depth prepass | 1.1 | - | +| Visibility raster | - | 1.2 | +| Material resolve | - | 1.9 | +| Opaque shading | 7.9 | 1.5 | +| Total opaque | 9.0 | 4.6 | + +Extra memory for a 64-bit visibility target at 4K: 96 MB. The 32-bit target used here costs 48 MB at 4K. +Build lantern-2025.09.19-r4520, captured by hand on devkit MRD-0031. diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-forward-cliffs-benchmark--2ykf7yxr2qmwjz23.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-forward-cliffs-benchmark--2ykf7yxr2qmwjz23.md new file mode 100644 index 00000000..05d98774 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-forward-cliffs-benchmark--2ykf7yxr2qmwjz23.md @@ -0,0 +1,10 @@ +--- +id: cit-capture-forward-cliffs-benchmark--2ykf7yxr2qmwjz23 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Capture: forward+ cliffs benchmark' +role: evidence +blob: blb-gpu-capture-forward-on-the-cliffs-benchmark-meri--f1jwxdgx0fpe0wvs +created_at: '2025-09-09T14:05:00Z' +created_by: Tomasz Brandt +--- +https://captures.tidewater.example/lantern/r4411/cliffs_bench_02 diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-sdf-gi-dunes-benchmark--3q4n5ewn42faqaeb.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-sdf-gi-dunes-benchmark--3q4n5ewn42faqaeb.md new file mode 100644 index 00000000..4d9e54a4 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-sdf-gi-dunes-benchmark--3q4n5ewn42faqaeb.md @@ -0,0 +1,10 @@ +--- +id: cit-capture-sdf-gi-dunes-benchmark--3q4n5ewn42faqaeb +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Capture: SDF GI dunes benchmark' +role: evidence +blob: blb-gpu-capture-sdf-gi-on-the-dunes-benchmark--h1szrk86b69n5b26 +created_at: '2025-10-13T15:05:00Z' +created_by: Tomasz Brandt +--- +https://captures.tidewater.example/lantern/r4630/sdf_gi diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-sdf-gi-on-a-meridian-devkit--1hjqjkb1e7z7tryy.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-sdf-gi-on-a-meridian-devkit--1hjqjkb1e7z7tryy.md new file mode 100644 index 00000000..9028c4a2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-sdf-gi-on-a-meridian-devkit--1hjqjkb1e7z7tryy.md @@ -0,0 +1,10 @@ +--- +id: cit-capture-sdf-gi-on-a-meridian-devkit--1hjqjkb1e7z7tryy +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Capture: SDF GI on a Meridian devkit' +role: evidence +blob: blb-gpu-capture-sdf-gi-on-a-meridian-devkit-dunes-be--9r2nk13cja7s06cx +created_at: '2026-02-02T15:05:00Z' +created_by: Tomasz Brandt +--- +https://captures.tidewater.example/lantern/r5840/sdf_gi_devkit diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-virtual-shadow-map-prototype--4122x7gedhmg5v15.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-virtual-shadow-map-prototype--4122x7gedhmg5v15.md new file mode 100644 index 00000000..6a9a2485 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-virtual-shadow-map-prototype--4122x7gedhmg5v15.md @@ -0,0 +1,10 @@ +--- +id: cit-capture-virtual-shadow-map-prototype--4122x7gedhmg5v15 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Capture: virtual shadow map prototype' +role: evidence +blob: blb-gpu-capture-virtual-shadow-map-prototype-dunes-b--cknjqzqy2mqz93mf +created_at: '2025-09-25T15:05:00Z' +created_by: Tomasz Brandt +--- +https://captures.tidewater.example/lantern/r4561/vsm_proto diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-virtual-shadow-maps-with-page-caching--xjxn0ftjsfe4dhcq.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-virtual-shadow-maps-with-page-caching--xjxn0ftjsfe4dhcq.md new file mode 100644 index 00000000..ec4b64e4 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-virtual-shadow-maps-with-page-caching--xjxn0ftjsfe4dhcq.md @@ -0,0 +1,10 @@ +--- +id: cit-capture-virtual-shadow-maps-with-page-caching--xjxn0ftjsfe4dhcq +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Capture: virtual shadow maps with page caching' +role: evidence +blob: blb-gpu-capture-virtual-shadow-maps-with-page-cachin--sf5pzwgx8fv8gbpb +created_at: '2025-11-22T15:05:00Z' +created_by: Tomasz Brandt +--- +https://captures.tidewater.example/lantern/r5310/vsm_cached diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-visibility-buffer-on-skiff--ymeda5m6p45hba8f.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-visibility-buffer-on-skiff--ymeda5m6p45hba8f.md new file mode 100644 index 00000000..cbddf15c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-capture-visibility-buffer-on-skiff--ymeda5m6p45hba8f.md @@ -0,0 +1,10 @@ +--- +id: cit-capture-visibility-buffer-on-skiff--ymeda5m6p45hba8f +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Capture: visibility buffer on Skiff' +role: evidence +blob: blb-gpu-capture-visibility-buffer-on-skiff-cliffs-be--x1ynk37229baj5vt +created_at: '2026-04-07T15:05:00Z' +created_by: Tomasz Brandt +--- +https://captures.tidewater.example/lantern/r6120/skiff_cliffs diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-codec-benchmark-table-january-2026-skiff-cold-ca--sztretts5cxatw6c.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-codec-benchmark-table-january-2026-skiff-cold-ca--sztretts5cxatw6c.md new file mode 100644 index 00000000..11a38979 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-codec-benchmark-table-january-2026-skiff-cold-ca--sztretts5cxatw6c.md @@ -0,0 +1,10 @@ +--- +id: cit-codec-benchmark-table-january-2026-skiff-cold-ca--sztretts5cxatw6c +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'Codec benchmark table, January 2026, Skiff cold cache' +role: evidence +blob: blb-codec-benchmark-cold-cache-on-skiff-january-2026--wczvq0srnnzjs407 +created_at: '2026-01-09T15:10:00Z' +created_by: Kenji Arakawa +--- +https://perf.tidewater.internal/kestrel/codec/bench-0109-skiff.md diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-codec-benchmark-table-october-2025--wg58ryzjhtpaca3x.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-codec-benchmark-table-october-2025--wg58ryzjhtpaca3x.md new file mode 100644 index 00000000..9b60d88a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-codec-benchmark-table-october-2025--wg58ryzjhtpaca3x.md @@ -0,0 +1,10 @@ +--- +id: cit-codec-benchmark-table-october-2025--wg58ryzjhtpaca3x +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'Codec benchmark table, October 2025' +role: evidence +blob: blb-codec-benchmark-warm-cache-october-2025--kcybvms2ttten909 +created_at: '2025-10-13T15:10:00Z' +created_by: Kenji Arakawa +--- +https://perf.tidewater.internal/kestrel/codec/bench-1013.md diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-ecs-bench-profile-run-0909--m0zy2gppwwgsv5zh.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-ecs-bench-profile-run-0909--m0zy2gppwwgsv5zh.md new file mode 100644 index 00000000..104e1b41 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-ecs-bench-profile-run-0909--m0zy2gppwwgsv5zh.md @@ -0,0 +1,10 @@ +--- +id: cit-ecs-bench-profile-run-0909--m0zy2gppwwgsv5zh +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: ecs-bench profile run-0909 +role: evidence +blob: blb-ecs-storage-microbenchmark-profile-september-202--csvrtfr7ce23yzz5 +created_at: '2025-09-09T14:10:00Z' +created_by: Rhea Valdés +--- +https://perf.tidewater.internal/kestrel/ecs-bench/run-0909.json diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-histogram-caustic-highlights-under-filmic--rr06d7k5s8c05gdw.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-histogram-caustic-highlights-under-filmic--rr06d7k5s8c05gdw.md new file mode 100644 index 00000000..c8fd32c9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-histogram-caustic-highlights-under-filmic--rr06d7k5s8c05gdw.md @@ -0,0 +1,10 @@ +--- +id: cit-histogram-caustic-highlights-under-filmic--rr06d7k5s8c05gdw +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Histogram: caustic highlights under filmic' +role: evidence +blob: blb-highlight-histogram-caustic-pixels-under-the-sto--bv0tyatpe22kxqkq +created_at: '2026-01-15T15:05:00Z' +created_by: Yusuf Demir +--- +https://captures.tidewater.example/lantern/r5650/filmic_highlights diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-lantern-overhaul-wiki-page--jz6a6zyvexf2fk8e.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-lantern-overhaul-wiki-page--jz6a6zyvexf2fk8e.md new file mode 100644 index 00000000..2ba692ee --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-lantern-overhaul-wiki-page--jz6a6zyvexf2fk8e.md @@ -0,0 +1,9 @@ +--- +id: cit-lantern-overhaul-wiki-page--jz6a6zyvexf2fk8e +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Lantern overhaul wiki page +role: context +created_at: '2025-09-04T09:00:00Z' +created_by: Ines Okafor +--- +https://wiki.tidewater.example/lantern/overhaul diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-meridian-technical-requirements-checklist-2-4--xv7xnma0egx0119s.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-meridian-technical-requirements-checklist-2-4--xv7xnma0egx0119s.md new file mode 100644 index 00000000..236dbfaf --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-meridian-technical-requirements-checklist-2-4--xv7xnma0egx0119s.md @@ -0,0 +1,9 @@ +--- +id: cit-meridian-technical-requirements-checklist-2-4--xv7xnma0egx0119s +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Meridian technical requirements checklist 2.4 +role: context +created_at: '2025-10-24T11:00:00Z' +created_by: Priya Natarajan +--- +https://partners.meridian.example/trc/2.4 diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-pool-occupancy-capture-pool-occupancy-0303--5k8w8xj2a4g21wtm.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-pool-occupancy-capture-pool-occupancy-0303--5k8w8xj2a4g21wtm.md new file mode 100644 index 00000000..eb4c5336 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-pool-occupancy-capture-pool-occupancy-0303--5k8w8xj2a4g21wtm.md @@ -0,0 +1,10 @@ +--- +id: cit-pool-occupancy-capture-pool-occupancy-0303--5k8w8xj2a4g21wtm +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Pool occupancy capture pool-occupancy-0303 +role: evidence +blob: blb-streaming-pool-occupancy-alpha-playtest--bahqk0svngyshny0 +created_at: '2026-03-03T15:10:00Z' +created_by: Kenji Arakawa +--- +https://perf.tidewater.internal/kestrel/pool/pool-occupancy-0303.json diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-report-meridian-hdr-pre-check-july--mqw9w3jm6srcm3x0.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-report-meridian-hdr-pre-check-july--mqw9w3jm6srcm3x0.md new file mode 100644 index 00000000..18e92454 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-report-meridian-hdr-pre-check-july--mqw9w3jm6srcm3x0.md @@ -0,0 +1,10 @@ +--- +id: cit-report-meridian-hdr-pre-check-july--mqw9w3jm6srcm3x0 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Report: Meridian HDR pre-check, July' +role: evidence +blob: blb-meridian-hdr-certification-pre-check-report-july--6r648dzqhh44mkq7 +created_at: '2026-07-14T15:05:00Z' +created_by: Priya Natarajan +--- +https://cert.tidewater.example/meridian/precheck/r7400 diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-retail-skiff-streaming-trace-stream-trace-0217--gsdd04w1pck5s0am.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-retail-skiff-streaming-trace-stream-trace-0217--gsdd04w1pck5s0am.md new file mode 100644 index 00000000..c62dd29c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-retail-skiff-streaming-trace-stream-trace-0217--gsdd04w1pck5s0am.md @@ -0,0 +1,10 @@ +--- +id: cit-retail-skiff-streaming-trace-stream-trace-0217--gsdd04w1pck5s0am +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Retail Skiff streaming trace stream-trace-0217 +role: evidence +blob: blb-streaming-read-trace-retail-skiff-against-dev-ki--5pj5rh05kbsc6gcj +created_at: '2026-02-17T15:10:00Z' +created_by: Priya Natarajan +--- +https://perf.tidewater.internal/kestrel/stream-traces/stream-trace-0217.json diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-save-size-sweep-from-the-playtest-save-corpus--5d385vtvgmy4qtmz.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-save-size-sweep-from-the-playtest-save-corpus--5d385vtvgmy4qtmz.md new file mode 100644 index 00000000..e6c803ae --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-save-size-sweep-from-the-playtest-save-corpus--5d385vtvgmy4qtmz.md @@ -0,0 +1,10 @@ +--- +id: cit-save-size-sweep-from-the-playtest-save-corpus--5d385vtvgmy4qtmz +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Save size sweep from the playtest save corpus +role: evidence +blob: blb-delta-save-sizes-by-hours-played--x6mda6tam40w26t5 +created_at: '2026-05-18T15:10:00Z' +created_by: Marta Lindqvist +--- +https://perf.tidewater.internal/kestrel/saves/size-sweep-0518.csv diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-shader-compiler-release-notes-for-build-1-8-2407--j9egrx9rnpp9ne9x.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-shader-compiler-release-notes-for-build-1-8-2407--j9egrx9rnpp9ne9x.md new file mode 100644 index 00000000..1342db8b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-shader-compiler-release-notes-for-build-1-8-2407--j9egrx9rnpp9ne9x.md @@ -0,0 +1,9 @@ +--- +id: cit-shader-compiler-release-notes-for-build-1-8-2407--j9egrx9rnpp9ne9x +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Shader compiler release notes for build 1.8.2407 +role: context +created_at: '2026-01-12T10:00:00Z' +created_by: Liam O'Connell +--- +https://github.com/microsoft/DirectXShaderCompiler/releases diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-harbor-memory-capture-build-4127--20svcfra9jy1hd1d.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-harbor-memory-capture-build-4127--20svcfra9jy1hd1d.md new file mode 100644 index 00000000..3eef6d61 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-harbor-memory-capture-build-4127--20svcfra9jy1hd1d.md @@ -0,0 +1,10 @@ +--- +id: cit-skiff-harbor-memory-capture-build-4127--20svcfra9jy1hd1d +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Skiff harbor memory capture, build 4127' +role: evidence +blob: blb-skiff-harbor-district-memory-capture-build-4127--t40rdrfffc5q5e89 +created_at: '2026-02-16T10:05:00Z' +created_by: Kenji Arakawa +--- +Per-category memory capture at the harbor district peak, Skiff firmware 1.2 emulation. diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-lot-check-guidelines-v3--2sc7w8gq1ckc26p5.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-lot-check-guidelines-v3--2sc7w8gq1ckc26p5.md new file mode 100644 index 00000000..08b3ee44 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-lot-check-guidelines-v3--2sc7w8gq1ckc26p5.md @@ -0,0 +1,9 @@ +--- +id: cit-skiff-lot-check-guidelines-v3--2sc7w8gq1ckc26p5 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff lot check guidelines v3 +role: context +created_at: '2026-05-11T10:00:00Z' +created_by: Priya Natarajan +--- +https://devportal.skiff.example/lotcheck/guidelines-v3 diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-pipeline-compile-capture-build-3810--2ybmweekyepbf8s4.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-pipeline-compile-capture-build-3810--2ybmweekyepbf8s4.md new file mode 100644 index 00000000..620c9baf --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-pipeline-compile-capture-build-3810--2ybmweekyepbf8s4.md @@ -0,0 +1,10 @@ +--- +id: cit-skiff-pipeline-compile-capture-build-3810--2ybmweekyepbf8s4 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Skiff pipeline compile capture, build 3810' +role: evidence +blob: blb-skiff-first-visit-pipeline-compile-capture-build--wfpq5kvqxddn0a9w +created_at: '2025-12-09T10:05:00Z' +created_by: Priya Natarajan +--- +Capture of first-visit pipeline compiles in three districts on Skiff firmware 1.0. diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-pre-certification-report-build-5530--caakwntpfm63vy97.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-pre-certification-report-build-5530--caakwntpfm63vy97.md new file mode 100644 index 00000000..1dd14872 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-pre-certification-report-build-5530--caakwntpfm63vy97.md @@ -0,0 +1,10 @@ +--- +id: cit-skiff-pre-certification-report-build-5530--caakwntpfm63vy97 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Skiff pre-certification report, build 5530' +role: evidence +blob: blb-skiff-pre-certification-report-build-5530--1q6hz38801fy3tqk +created_at: '2026-05-18T09:05:00Z' +created_by: Dara Whitlock +--- +Platform holder pre-check results for build 5530, received 2026-05-15. diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-rollback-profile-capture--qhbe4rs9ax0h3z3d.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-rollback-profile-capture--qhbe4rs9ax0h3z3d.md new file mode 100644 index 00000000..371a4236 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-rollback-profile-capture--qhbe4rs9ax0h3z3d.md @@ -0,0 +1,10 @@ +--- +id: cit-skiff-rollback-profile-capture--qhbe4rs9ax0h3z3d +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Skiff rollback profile capture +role: evidence +blob: blb-skiff-rollback-profile-capture-6-frame-window-ti--ffqejdktg6fmth3c +created_at: '2026-03-18T10:10:00Z' +created_by: Priya Natarajan +--- +Per-system rollback timings from a Skiff devkit with tides in the snapshot. Full numbers in the attached capture. diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-sdk-0-9-memory-map--nk82yq60vqfa2g4b.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-sdk-0-9-memory-map--nk82yq60vqfa2g4b.md new file mode 100644 index 00000000..77bffa7c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-sdk-0-9-memory-map--nk82yq60vqfa2g4b.md @@ -0,0 +1,9 @@ +--- +id: cit-skiff-sdk-0-9-memory-map--nk82yq60vqfa2g4b +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff SDK 0.9 memory map +role: evidence +created_at: '2025-10-16T10:00:00Z' +created_by: Priya Natarajan +--- +https://devportal.skiff.example/sdk/0.9/memory-map diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe.md new file mode 100644 index 00000000..be20f293 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe.md @@ -0,0 +1,9 @@ +--- +id: cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff SDK 1.2 release notes +role: evidence +created_at: '2026-02-10T11:00:00Z' +created_by: Priya Natarajan +--- +https://devportal.skiff.example/sdk/1.2/release-notes diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-storage-benchmark-sheet--rszq3fw5c7eps8a2.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-storage-benchmark-sheet--rszq3fw5c7eps8a2.md new file mode 100644 index 00000000..61ecac65 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-storage-benchmark-sheet--rszq3fw5c7eps8a2.md @@ -0,0 +1,9 @@ +--- +id: cit-skiff-storage-benchmark-sheet--rszq3fw5c7eps8a2 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff storage benchmark sheet +role: evidence +created_at: '2026-03-04T10:00:00Z' +created_by: Kenji Arakawa +--- +https://docs.tidewaterforge.example/ports/skiff-storage-bench diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-streaming-trace-stream-trace-0807--e4vdxvga0amqyzjb.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-streaming-trace-stream-trace-0807--e4vdxvga0amqyzjb.md new file mode 100644 index 00000000..3599ee5a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-streaming-trace-stream-trace-0807--e4vdxvga0amqyzjb.md @@ -0,0 +1,10 @@ +--- +id: cit-skiff-streaming-trace-stream-trace-0807--e4vdxvga0amqyzjb +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Skiff streaming trace stream-trace-0807 +role: evidence +blob: blb-streaming-trace-inland-sprint-during-a-falling-t--91wvax8b1e5f0qvw +created_at: '2026-08-07T15:10:00Z' +created_by: Kenji Arakawa +--- +https://perf.tidewater.internal/kestrel/stream-traces/stream-trace-0807-skiff.json diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-streaming-trace-stream-trace-1110--fn7z3ms8hsz2tw9c.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-streaming-trace-stream-trace-1110--fn7z3ms8hsz2tw9c.md new file mode 100644 index 00000000..903b7e0d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-skiff-streaming-trace-stream-trace-1110--fn7z3ms8hsz2tw9c.md @@ -0,0 +1,10 @@ +--- +id: cit-skiff-streaming-trace-stream-trace-1110--fn7z3ms8hsz2tw9c +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Skiff streaming trace stream-trace-1110 +role: evidence +blob: blb-streaming-trace-of-a-falling-tide-on-skiff-256-m--g5wcgz9426mk1y45 +created_at: '2025-11-10T15:10:00Z' +created_by: Kenji Arakawa +--- +https://perf.tidewater.internal/kestrel/stream-traces/stream-trace-1110-skiff.json diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-studio-wiki-primer-on-rollback-netcode--mktyz3g3cwfc7xa7.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-studio-wiki-primer-on-rollback-netcode--mktyz3g3cwfc7xa7.md new file mode 100644 index 00000000..60eae170 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-studio-wiki-primer-on-rollback-netcode--mktyz3g3cwfc7xa7.md @@ -0,0 +1,9 @@ +--- +id: cit-studio-wiki-primer-on-rollback-netcode--mktyz3g3cwfc7xa7 +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Studio wiki primer on rollback netcode +role: context +created_at: '2025-12-05T10:00:00Z' +created_by: Sofia Marchetti +--- +https://wiki.tidewater-forge.example/netcode/rollback-primer diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-table-meshlet-size-sweep--gw92j9g9071gj8v8.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-table-meshlet-size-sweep--gw92j9g9071gj8v8.md new file mode 100644 index 00000000..1b0bbd81 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-table-meshlet-size-sweep--gw92j9g9071gj8v8.md @@ -0,0 +1,10 @@ +--- +id: cit-table-meshlet-size-sweep--gw92j9g9071gj8v8 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Table: meshlet size sweep' +role: evidence +blob: blb-meshlet-size-sweep-on-the-cliffs-benchmark--4shwgvp9x310epk7 +created_at: '2025-11-18T15:05:00Z' +created_by: Tomasz Brandt +--- +https://captures.tidewater.example/lantern/r5260/meshlet_sweep diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-tern-preset-table--6bbg3evqt1zz6smb.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-tern-preset-table--6bbg3evqt1zz6smb.md new file mode 100644 index 00000000..e72b9104 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-tern-preset-table--6bbg3evqt1zz6smb.md @@ -0,0 +1,10 @@ +--- +id: cit-tern-preset-table--6bbg3evqt1zz6smb +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Tern preset table +role: evidence +blob: blb-tern-preset-table-render-scale-and-cost-per-plat--vzvzz16jyhnr937h +created_at: '2026-02-23T15:05:00Z' +created_by: Tomasz Brandt +--- +https://captures.tidewater.example/lantern/r5990/tern_presets diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-tide-drift-log-tide-drift-1028--3dpqqgs1ep6qm1wc.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-tide-drift-log-tide-drift-1028--3dpqqgs1ep6qm1wc.md new file mode 100644 index 00000000..a5892c41 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-tide-drift-log-tide-drift-1028--3dpqqgs1ep6qm1wc.md @@ -0,0 +1,10 @@ +--- +id: cit-tide-drift-log-tide-drift-1028--3dpqqgs1ep6qm1wc +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Tide drift log tide-drift-1028 +role: evidence +blob: blb-tide-drift-log-pc-meridian-and-skiff-over-6-minu--vyzb37vz3nrts95v +created_at: '2025-10-28T15:10:00Z' +created_by: Marta Lindqvist +--- +https://perf.tidewater.internal/kestrel/tide/tide-drift-1028.json diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-timing-table-visibility-buffer-prototype--njktyg0k8aej7kpf.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-timing-table-visibility-buffer-prototype--njktyg0k8aej7kpf.md new file mode 100644 index 00000000..03f4de04 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-timing-table-visibility-buffer-prototype--njktyg0k8aej7kpf.md @@ -0,0 +1,10 @@ +--- +id: cit-timing-table-visibility-buffer-prototype--njktyg0k8aej7kpf +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Timing table: visibility buffer prototype' +role: evidence +blob: blb-timing-table-visibility-buffer-prototype-against--8debfkdp7fz7nwjp +created_at: '2025-09-22T15:05:00Z' +created_by: Tomasz Brandt +--- +https://captures.tidewater.example/lantern/r4520/vb_proto diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-trace-caustic-luminance-under-tern--55mm8xmemz44s5ah.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-trace-caustic-luminance-under-tern--55mm8xmemz44s5ah.md new file mode 100644 index 00000000..c434b49b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-trace-caustic-luminance-under-tern--55mm8xmemz44s5ah.md @@ -0,0 +1,10 @@ +--- +id: cit-trace-caustic-luminance-under-tern--55mm8xmemz44s5ah +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Trace: caustic luminance under Tern' +role: evidence +blob: blb-luminance-trace-caustics-under-tern-dunes-at-noo--hg2t94dx5wv08a7r +created_at: '2026-01-22T15:05:00Z' +created_by: Yusuf Demir +--- +https://captures.tidewater.example/lantern/r5720/caustic_flicker diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-trace-vsm-page-pool-across-a-spring-tide--mhwdj0xh0k2wrnpq.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-trace-vsm-page-pool-across-a-spring-tide--mhwdj0xh0k2wrnpq.md new file mode 100644 index 00000000..6a193ce5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-trace-vsm-page-pool-across-a-spring-tide--mhwdj0xh0k2wrnpq.md @@ -0,0 +1,10 @@ +--- +id: cit-trace-vsm-page-pool-across-a-spring-tide--mhwdj0xh0k2wrnpq +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Trace: VSM page pool across a spring tide' +role: evidence +blob: blb-page-pool-trace-virtual-shadow-maps-across-a-spr--6qdd5aahwkcmhyg8 +created_at: '2026-06-12T15:05:00Z' +created_by: Tomasz Brandt +--- +https://captures.tidewater.example/lantern/r7020/vsm_spring_tide diff --git a/benchmarks/proof-recall/.flatbread-proof/citations/cit-weekly-shader-cache-hit-rate-report--821p29gvf3dtcssg.md b/benchmarks/proof-recall/.flatbread-proof/citations/cit-weekly-shader-cache-hit-rate-report--821p29gvf3dtcssg.md new file mode 100644 index 00000000..be4b3daa --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/citations/cit-weekly-shader-cache-hit-rate-report--821p29gvf3dtcssg.md @@ -0,0 +1,10 @@ +--- +id: cit-weekly-shader-cache-hit-rate-report--821p29gvf3dtcssg +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Weekly shader cache hit-rate report +role: evidence +blob: blb-shader-cache-hit-rate-report-four-weeks-after-th--g0383kwnqtjdh4jz +created_at: '2026-01-26T10:10:00Z' +created_by: Liam O'Connell +--- +Weekly hit rate, build time and storage for the farm shader compile cache. Full series in the attached report. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-a-cache-hit-must-give-the-same-bytes-as-a-fresh--3gmcswztxzpmpz83.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-a-cache-hit-must-give-the-same-bytes-as-a-fresh--3gmcswztxzpmpz83.md new file mode 100644 index 00000000..9b79c2f3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-a-cache-hit-must-give-the-same-bytes-as-a-fresh--3gmcswztxzpmpz83.md @@ -0,0 +1,9 @@ +--- +id: con-a-cache-hit-must-give-the-same-bytes-as-a-fresh--3gmcswztxzpmpz83 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: A cache hit must give the same bytes as a fresh compile +kind: soft +created_at: '2025-11-10T10:00:00Z' +created_by: Ines Okafor +--- +Ines Okafor will not debug rendering bugs that only appear on cached builds. Bytecode served from the cache must match a fresh compile byte for byte, or the cache is not trusted. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-archetype-changes-happen-only-at-frame-sync-poin--kcsrz5g8g8yndwnx.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-archetype-changes-happen-only-at-frame-sync-poin--kcsrz5g8g8yndwnx.md new file mode 100644 index 00000000..69ad435a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-archetype-changes-happen-only-at-frame-sync-poin--kcsrz5g8g8yndwnx.md @@ -0,0 +1,11 @@ +--- +id: con-archetype-changes-happen-only-at-frame-sync-poin--kcsrz5g8g8yndwnx +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Archetype changes happen only at frame sync points +kind: soft +created_at: '2025-09-26T09:00:00Z' +created_by: Rhea Valdés +derives_from: + - dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9 +--- +Jobs never move entities between archetype tables directly. They record structural changes in command buffers, and the scheduler flushes those buffers at two sync points per frame: after simulation and after streaming. Sparse tag flips are exempt. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-cell-load-deadline--m20x64m5eh7q2bh6.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-cell-load-deadline--m20x64m5eh7q2bh6.md new file mode 100644 index 00000000..976c8774 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-cell-load-deadline--m20x64m5eh7q2bh6.md @@ -0,0 +1,11 @@ +--- +id: con-cell-load-deadline--m20x64m5eh7q2bh6 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Cell load deadline +kind: soft +created_at: '2025-11-25T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-a-falling-tide-reloads-18-cells-at-410-mb-s-peak--tjz5vscfrdtazcms +--- +A cell that the tide is about to expose must be resident 8 seconds before exposure. The tide forecast is exact, so the deadline is known a full cycle ahead. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-co-op-must-stay-playable-at-150-ms-round-trip--q330d4g95q7jtt4q.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-co-op-must-stay-playable-at-150-ms-round-trip--q330d4g95q7jtt4q.md new file mode 100644 index 00000000..2965c642 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-co-op-must-stay-playable-at-150-ms-round-trip--q330d4g95q7jtt4q.md @@ -0,0 +1,9 @@ +--- +id: con-co-op-must-stay-playable-at-150-ms-round-trip--q330d4g95q7jtt4q +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Co-op must stay playable at 150 ms round trip +kind: soft +created_at: '2025-11-06T10:00:00Z' +created_by: Dara Whitlock +--- +Dara Whitlock set the target: co-op between two continents must feel playable at 150 ms round trip. Above 250 ms we may show a warning. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g.md new file mode 100644 index 00000000..f2eca17b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g.md @@ -0,0 +1,9 @@ +--- +id: con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Co-op peers must agree on tide state bit for bit +kind: hard +created_at: '2025-11-05T10:00:00Z' +created_by: Rhea Valdés +--- +Tides decide which saltglass paths are walkable. If two peers disagree on the water line by a single cell, one player walks on sand that another sees as sea. Rhea Valdés requires tide state to match exactly on every peer, whatever sync model co-op uses. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--0n9dv0tmytdn3dq6.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--0n9dv0tmytdn3dq6.md new file mode 100644 index 00000000..314315fa --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--0n9dv0tmytdn3dq6.md @@ -0,0 +1,14 @@ +--- +id: con-frame-budget--0n9dv0tmytdn3dq6 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Frame budget +kind: hard +created_at: '2026-06-02T10:00:00Z' +created_by: Priya Natarajan +retracted: true +retracted_at: '2026-06-02T16:00:00.000Z' +retracted_reason: >- + Written to the render Effort by mistake. The Skiff 40 Hz budget belongs to the + Frame budget record in the ports Effort. +--- +Skiff 40 Hz mode: 25 ms per frame for CPU and GPU together. Skiff becomes a launch platform at beta, so Lantern passes on Skiff must fit inside 25 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--br0qszfg8fys908n.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--br0qszfg8fys908n.md new file mode 100644 index 00000000..532975bc --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--br0qszfg8fys908n.md @@ -0,0 +1,13 @@ +--- +id: con-frame-budget--br0qszfg8fys908n +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Frame budget +kind: hard +created_at: '2026-01-15T09:00:00Z' +created_by: Priya Natarajan +derives_from: + - dec-offer-a-40-hz-mode-on-skiff-alongside-30-hz--xhcgs101g1stnf05 +supersedes: + - con-frame-budget--wt5rfqh5z444g2cg +--- +Skiff 40 Hz mode: 25 ms per frame, CPU and GPU. Skiff 30 Hz mode keeps 33.3 ms and stays the cert target. Meridian keeps 60 Hz at 16.6 ms. The Meridian 120 Hz performance mode and its budget belong to the render Effort, not here. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--f5qxxq5572878wrp.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--f5qxxq5572878wrp.md new file mode 100644 index 00000000..160aaaf4 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--f5qxxq5572878wrp.md @@ -0,0 +1,11 @@ +--- +id: con-frame-budget--f5qxxq5572878wrp +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Frame budget +kind: hard +created_at: '2025-09-02T09:00:00Z' +created_by: Ines Okafor +superseded_by: + - con-frame-budget--j6vneva1g2ywj86m +--- +Lantern must finish a Meridian frame in 16.6 ms, which is 60 Hz. For pre-production the GPU passes may use the whole 16.6 ms; the render thread on the CPU runs in parallel and is budgeted elsewhere. Every pass owner reports against this number in the weekly capture review. Numbers come from the cliffs and dunes benchmarks, never from the menu scene. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--fzdrbxns6dmrrmy3.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--fzdrbxns6dmrrmy3.md new file mode 100644 index 00000000..4b53b4d5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--fzdrbxns6dmrrmy3.md @@ -0,0 +1,11 @@ +--- +id: con-frame-budget--fzdrbxns6dmrrmy3 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Frame budget +kind: hard +created_at: '2026-04-02T10:00:00Z' +created_by: Ines Okafor +supersedes: + - con-frame-budget--j6vneva1g2ywj86m +--- +Meridian quality mode stays at 60 Hz: 16.6 ms per frame, of which Lantern GPU passes get 15.0 ms and 1.6 ms is headroom. The headroom grew by 0.2 ms because the new system overlay costs more than the old one. The 120 Hz performance mode has its own Constraint with an 8.3 ms frame; this record covers quality mode only. Skiff budgets belong to the ports Effort. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--j6vneva1g2ywj86m.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--j6vneva1g2ywj86m.md new file mode 100644 index 00000000..9fadeed2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--j6vneva1g2ywj86m.md @@ -0,0 +1,13 @@ +--- +id: con-frame-budget--j6vneva1g2ywj86m +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Frame budget +kind: hard +created_at: '2025-12-19T10:00:00Z' +created_by: Ines Okafor +supersedes: + - con-frame-budget--f5qxxq5572878wrp +superseded_by: + - con-frame-budget--fzdrbxns6dmrrmy3 +--- +After the vertical slice the 16.6 ms Meridian frame is split: 15.2 ms for Lantern GPU passes and 1.4 ms held back for system overlays and dynamic-resolution headroom. The slice ran passes to the full 16.6 ms and the system overlay pushed two capture runs over. Pass owners must give back time to fit 15.2 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--k8j04jebm2kx9apw.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--k8j04jebm2kx9apw.md new file mode 100644 index 00000000..2148a8d7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--k8j04jebm2kx9apw.md @@ -0,0 +1,15 @@ +--- +id: con-frame-budget--k8j04jebm2kx9apw +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Frame budget +kind: hard +created_at: '2026-07-06T10:00:00Z' +created_by: Tomasz Brandt +retracted: true +retracted_at: '2026-07-06T15:00:00.000Z' +retracted_reason: >- + Copied from the render Effort's Frame budget by mistake. The Meridian 120 Hz + mode belongs to render; this Effort's Frame budget covers Skiff and Meridian + 60 Hz. +--- +Meridian 120 Hz performance mode: 8.3 ms per frame on CPU and GPU. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--wt5rfqh5z444g2cg.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--wt5rfqh5z444g2cg.md new file mode 100644 index 00000000..c48e128f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-frame-budget--wt5rfqh5z444g2cg.md @@ -0,0 +1,11 @@ +--- +id: con-frame-budget--wt5rfqh5z444g2cg +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Frame budget +kind: hard +created_at: '2025-10-28T10:00:00Z' +created_by: Priya Natarajan +superseded_by: + - con-frame-budget--br0qszfg8fys908n +--- +Skiff runs at 30 Hz, so each frame gets 33.3 ms of CPU and of GPU time. Meridian runs at 60 Hz and gets 16.6 ms. Captures that miss these numbers on the harbor route block a merge to the console branch. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-gull-script-tick-budget--4p9jp4dj1njf7q9m.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-gull-script-tick-budget--4p9jp4dj1njf7q9m.md new file mode 100644 index 00000000..d1534070 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-gull-script-tick-budget--4p9jp4dj1njf7q9m.md @@ -0,0 +1,9 @@ +--- +id: con-gull-script-tick-budget--4p9jp4dj1njf7q9m +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Gull script tick budget +kind: soft +created_at: '2025-10-21T10:00:00Z' +created_by: Marta Lindqvist +--- +All Gull scripts together get 2.0 ms per frame on Meridian and 3.0 ms per frame on Skiff. Scripts over budget are time-sliced across frames. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-meridian-120-hz-performance-mode-budget--h9zg6vmd70sr78by.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-meridian-120-hz-performance-mode-budget--h9zg6vmd70sr78by.md new file mode 100644 index 00000000..85ddda9d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-meridian-120-hz-performance-mode-budget--h9zg6vmd70sr78by.md @@ -0,0 +1,11 @@ +--- +id: con-meridian-120-hz-performance-mode-budget--h9zg6vmd70sr78by +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Meridian 120 Hz performance mode budget +kind: soft +created_at: '2026-03-20T10:00:00Z' +created_by: Dara Whitlock +superseded_by: + - con-meridian-120-hz-performance-mode-budget--khgjmq18bfr40tyj +--- +Marketing asked for a 120 Hz performance mode on Meridian. A 120 Hz frame is 8.3 ms. For now this is a stretch goal: Lantern will try to hit 8.3 ms with a lower internal resolution and cheaper GI, but Dara Whitlock can still cut the mode if it does not fit by beta. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-meridian-120-hz-performance-mode-budget--khgjmq18bfr40tyj.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-meridian-120-hz-performance-mode-budget--khgjmq18bfr40tyj.md new file mode 100644 index 00000000..9295a6a2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-meridian-120-hz-performance-mode-budget--khgjmq18bfr40tyj.md @@ -0,0 +1,11 @@ +--- +id: con-meridian-120-hz-performance-mode-budget--khgjmq18bfr40tyj +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Meridian 120 Hz performance mode budget +kind: hard +created_at: '2026-06-03T10:00:00Z' +created_by: Dara Whitlock +supersedes: + - con-meridian-120-hz-performance-mode-budget--h9zg6vmd70sr78by +--- +As of beta the 120 Hz performance mode is a launch commitment on Meridian. Each frame gets 8.3 ms: Lantern GPU passes get 7.4 ms and 0.9 ms is headroom. The mode may drop GI quality and run Tern's lowest preset, but it must not drop saltglass refraction. GI gets at most 1.0 ms of the 7.4 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-meridian-hdr-certification-requirements--nx9pmkwjjvxy1smf.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-meridian-hdr-certification-requirements--nx9pmkwjjvxy1smf.md new file mode 100644 index 00000000..ee716fc3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-meridian-hdr-certification-requirements--nx9pmkwjjvxy1smf.md @@ -0,0 +1,13 @@ +--- +id: con-meridian-hdr-certification-requirements--nx9pmkwjjvxy1smf +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Meridian HDR certification requirements +kind: hard +created_at: '2025-11-18T10:00:00Z' +created_by: Priya Natarajan +--- +Meridian certification runs an HDR test pass on every submission, and a failure blocks release. Priya Natarajan summarized the parts that touch Lantern. The game must read the display peak luminance from the system calibration and never exceed it, so a curve that assumes a fixed peak fails on dimmer panels. The 10,000-nit test ramp must not clip below the calibrated peak. The game must start in HDR when the system is in HDR, without asking. The user must be able to choose paper white anywhere from 80 to 400 nits, and the game must start from the system paper-white value on first boot. + +Black level must follow the system setting as well; crushing the bottom 1 percent of the ramp is a failure. The test also checks that SDR and HDR screenshots match in content, so the HDR path cannot hide or add effects. + +A title may fail the HDR pass at most twice per release candidate; a third failure sends the whole submission back for a full re-review. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-meridian-memory-budget--99q6099e423wdtqn.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-meridian-memory-budget--99q6099e423wdtqn.md new file mode 100644 index 00000000..795727ad --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-meridian-memory-budget--99q6099e423wdtqn.md @@ -0,0 +1,11 @@ +--- +id: con-meridian-memory-budget--99q6099e423wdtqn +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Meridian memory budget +kind: hard +created_at: '2025-10-24T11:20:00Z' +created_by: Priya Natarajan +cites: + - cit-meridian-technical-requirements-checklist-2-4--xv7xnma0egx0119s +--- +Meridian gives the game 13.5 GB. That is enough headroom that Meridian shares PC memory settings at the High preset. The checklist also requires the game to survive a suspend of 8 hours or more. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73.md new file mode 100644 index 00000000..b0062aff --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73.md @@ -0,0 +1,9 @@ +--- +id: con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: No runtime code generation on consoles +kind: hard +created_at: '2025-10-07T10:00:00Z' +created_by: Priya Natarajan +--- +Meridian and Skiff never grant game processes writable executable memory. Nothing may generate machine code at run time on consoles: no JIT compilers, no runtime-patched code. PC builds may, but shipping one code path is preferred. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-one-upscaler-path-on-every-platform--f91bgj6n66kwc5d3.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-one-upscaler-path-on-every-platform--f91bgj6n66kwc5d3.md new file mode 100644 index 00000000..91768748 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-one-upscaler-path-on-every-platform--f91bgj6n66kwc5d3.md @@ -0,0 +1,9 @@ +--- +id: con-one-upscaler-path-on-every-platform--f91bgj6n66kwc5d3 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: One upscaler path on every platform +kind: soft +created_at: '2025-10-02T09:00:00Z' +created_by: Ines Okafor +--- +Lantern should carry one temporal upscaler across PC, Meridian and Skiff. Every reactive mask, motion vector fix and saltglass special case otherwise has to be done twice. Ines Okafor will bend this only for a large quality gain. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-render-target-memory-on-meridian--q4szajxse9c1csdv.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-render-target-memory-on-meridian--q4szajxse9c1csdv.md new file mode 100644 index 00000000..7d95834e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-render-target-memory-on-meridian--q4szajxse9c1csdv.md @@ -0,0 +1,9 @@ +--- +id: con-render-target-memory-on-meridian--q4szajxse9c1csdv +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Render-target memory on Meridian +kind: hard +created_at: '2025-09-02T10:00:00Z' +created_by: Ines Okafor +--- +Lantern's render targets, transient attachments, shadow pages and GI volumes must fit in 1.8 GB of the 13.5 GB Meridian gives the game. Streaming owns the rest. An allocation over 1.8 GB fails the nightly memory check and blocks the build. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-saltglass-must-read-at-2-km--65a67jbwhr7r73qw.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-saltglass-must-read-at-2-km--65a67jbwhr7r73qw.md new file mode 100644 index 00000000..b4603d1d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-saltglass-must-read-at-2-km--65a67jbwhr7r73qw.md @@ -0,0 +1,9 @@ +--- +id: con-saltglass-must-read-at-2-km--65a67jbwhr7r73qw +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Saltglass must read at 2 km +kind: soft +created_at: '2025-09-03T09:00:00Z' +created_by: Yusuf Demir +--- +Art direction wants refraction through saltglass dunes, cliffs and ruins to read out to 2 km. Caustics may fade past 800 m, but the glass must still bend what is behind it. This is an art target, not a platform rule. Yusuf Demir will accept a cheaper look past 1.2 km if it keeps the silhouette. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-saves-from-beta-onward-must-load-in-every-later--v6z856sxtgc5sb09.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-saves-from-beta-onward-must-load-in-every-later--v6z856sxtgc5sb09.md new file mode 100644 index 00000000..17a9a4ac --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-saves-from-beta-onward-must-load-in-every-later--v6z856sxtgc5sb09.md @@ -0,0 +1,9 @@ +--- +id: con-saves-from-beta-onward-must-load-in-every-later--v6z856sxtgc5sb09 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Saves from beta onward must load in every later build +kind: hard +created_at: '2026-03-10T10:00:00Z' +created_by: Dara Whitlock +--- +Beta players keep their progress into launch. Any save written by the beta build (2026-06-01) or later must load in every later build, including the release candidate and patches. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-has-no-mesh-shader-support--zz4xpaqy1n0zzrj7.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-has-no-mesh-shader-support--zz4xpaqy1n0zzrj7.md new file mode 100644 index 00000000..f64d9bd9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-has-no-mesh-shader-support--zz4xpaqy1n0zzrj7.md @@ -0,0 +1,9 @@ +--- +id: con-skiff-has-no-mesh-shader-support--zz4xpaqy1n0zzrj7 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Skiff has no mesh shader support +kind: hard +created_at: '2025-10-15T09:00:00Z' +created_by: Tomasz Brandt +--- +Skiff's GPU and driver do not support mesh or amplification shaders, and the platform holder has no plans to add them. Any meshlet path needs a fallback through the classic vertex pipeline on Skiff. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-memory-budget--8ngr8fep3gxdfy80.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-memory-budget--8ngr8fep3gxdfy80.md new file mode 100644 index 00000000..4aa4d29a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-memory-budget--8ngr8fep3gxdfy80.md @@ -0,0 +1,13 @@ +--- +id: con-skiff-memory-budget--8ngr8fep3gxdfy80 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff memory budget +kind: hard +created_at: '2025-10-22T09:00:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-skiff-dev-kit-gives-the-game-9-gb--e6h71skfna4ttpd0 +superseded_by: + - con-skiff-memory-budget--nf7qbhsnmcn6v479 +--- +Saltglass Reach may use at most 9 GB on Skiff, CPU and GPU combined. Every pool size on Skiff is set against this number. Keep 300 MB of it free as a safety margin. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-memory-budget--nf7qbhsnmcn6v479.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-memory-budget--nf7qbhsnmcn6v479.md new file mode 100644 index 00000000..92bd9d73 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-memory-budget--nf7qbhsnmcn6v479.md @@ -0,0 +1,13 @@ +--- +id: con-skiff-memory-budget--nf7qbhsnmcn6v479 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff memory budget +kind: hard +created_at: '2026-02-12T09:00:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-skiff-sdk-1-2-takes-1-gb-back-from-games--a0ybdgjzw64hwfqa +supersedes: + - con-skiff-memory-budget--8ngr8fep3gxdfy80 +--- +Saltglass Reach may use at most 8 GB on Skiff, CPU and GPU combined, from firmware 1.2 on. Keep 300 MB of it free as a safety margin. Pools sized against the old 9 GB figure must be cut. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-minimum-text-height--hhc7n09kx88203zh.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-minimum-text-height--hhc7n09kx88203zh.md new file mode 100644 index 00000000..f3cb079e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-minimum-text-height--hhc7n09kx88203zh.md @@ -0,0 +1,11 @@ +--- +id: con-skiff-minimum-text-height--hhc7n09kx88203zh +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff minimum text height +kind: hard +created_at: '2026-05-11T10:40:00Z' +created_by: Priya Natarajan +cites: + - cit-skiff-lot-check-guidelines-v3--2sc7w8gq1ckc26p5 +--- +Skiff lot check requires all readable text to be at least 9 px tall at 720p in handheld mode. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-storage-write-limit--39sn09p505a1s8j7.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-storage-write-limit--39sn09p505a1s8j7.md new file mode 100644 index 00000000..36069347 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-skiff-storage-write-limit--39sn09p505a1s8j7.md @@ -0,0 +1,11 @@ +--- +id: con-skiff-storage-write-limit--39sn09p505a1s8j7 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff storage write limit +kind: hard +created_at: '2026-05-11T10:20:00Z' +created_by: Priya Natarajan +cites: + - cit-skiff-lot-check-guidelines-v3--2sc7w8gq1ckc26p5 +--- +Skiff lot check allows a game to write at most 4 MB per minute to storage, averaged over 10 minutes. Saves, the pipeline cache, and logs all count. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-i-o-budget--a99y4h0e7xmhp5qk.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-i-o-budget--a99y4h0e7xmhp5qk.md new file mode 100644 index 00000000..0473f711 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-i-o-budget--a99y4h0e7xmhp5qk.md @@ -0,0 +1,13 @@ +--- +id: con-streaming-i-o-budget--a99y4h0e7xmhp5qk +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Streaming I/O budget +kind: soft +created_at: '2025-12-09T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-skiff-streaming-reads-sustain-260-mb-s--s1gkt975grre2ewr +superseded_by: + - con-streaming-i-o-budget--vhc7mrmpqv9qcfdc +--- +Sustained streaming reads stay under 220 MB/s on Skiff, leaving headroom below the measured 260 MB/s for saves and audio. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-i-o-budget--vhc7mrmpqv9qcfdc.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-i-o-budget--vhc7mrmpqv9qcfdc.md new file mode 100644 index 00000000..9c693259 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-i-o-budget--vhc7mrmpqv9qcfdc.md @@ -0,0 +1,13 @@ +--- +id: con-streaming-i-o-budget--vhc7mrmpqv9qcfdc +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Streaming I/O budget +kind: soft +created_at: '2026-02-24T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-retail-skiff-units-sustain-only-190-mb-s-of-stre--485sdcmm3gweevvn +supersedes: + - con-streaming-i-o-budget--a99y4h0e7xmhp5qk +--- +Sustained streaming reads stay under 160 MB/s on Skiff, measured on retail units, not dev kits. The rest of the 190 MB/s is reserved for saves, audio, and the tide-turn burst. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-pool-budget--632bkbs79bwj4cr5.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-pool-budget--632bkbs79bwj4cr5.md new file mode 100644 index 00000000..8135fdee --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-pool-budget--632bkbs79bwj4cr5.md @@ -0,0 +1,11 @@ +--- +id: con-streaming-pool-budget--632bkbs79bwj4cr5 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Streaming pool budget +kind: hard +created_at: '2025-09-12T10:00:00Z' +created_by: Kenji Arakawa +superseded_by: + - con-streaming-pool-budget--kca88sgh2j6sxvd5 +--- +The streaming pool, which holds every resident cell's textures, geometry, navigation, and audio, may use at most 2.0 GB on every platform. Streaming must evict before it allocates past that line. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-pool-budget--8czwb4fjr5p5vpy7.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-pool-budget--8czwb4fjr5p5vpy7.md new file mode 100644 index 00000000..d9219ed4 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-pool-budget--8czwb4fjr5p5vpy7.md @@ -0,0 +1,14 @@ +--- +id: con-streaming-pool-budget--8czwb4fjr5p5vpy7 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Streaming pool budget +kind: hard +created_at: '2026-07-15T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - con-streaming-pool-budget--kca88sgh2j6sxvd5 + - fnd-tide-band-cells-need-320-mb-resident-during-a-sp--0erj5eqw3ved35t0 +supersedes: + - con-streaming-pool-budget--kca88sgh2j6sxvd5 +--- +The streaming pool may use at most 1.6 GB on every platform. Of that, 320 MB is reserved for tide-band cells during a tide turn; outside a turn the reservation is free for any cell. The total is unchanged from the June cut. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-pool-budget--kca88sgh2j6sxvd5.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-pool-budget--kca88sgh2j6sxvd5.md new file mode 100644 index 00000000..637e7ed2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-pool-budget--kca88sgh2j6sxvd5.md @@ -0,0 +1,21 @@ +--- +id: con-streaming-pool-budget--kca88sgh2j6sxvd5 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Streaming pool budget +kind: hard +created_at: '2026-06-04T11:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-ports-cut-the-skiff-memory-total-and-streaming-m--1p8b10ttb07jkznx +supersedes: + - con-streaming-pool-budget--632bkbs79bwj4cr5 +superseded_by: + - con-streaming-pool-budget--8czwb4fjr5p5vpy7 +--- +The streaming pool may use at most 1.6 GB on every platform, down from 2.0 GB. The reason is the ports Constraint "Skiff memory budget", which fell from 9 GB to 8 GB in February and now binds the world because Skiff became a launch platform; streaming's share of that cut is 400 MB. One budget for all platforms keeps content tuning in one place, so PC and Meridian take the same 1.6 GB. + +How the 400 MB comes back: Kenji Arakawa lowers texture mip residency in the outer ring, compacts audio banks per cell, and drops navigation detail for cells the player cannot reach until the tide falls. + +The forecast eviction policy keeps tide-exposed cells resident, so the cut falls on cells behind the player. Expect more reloads when players double back. + +Of the 400 MB, texture mips give back 260 MB, audio banks 90 MB, and navigation 50 MB. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-pool-budget-draft--kx5m370w3w6mxz7d.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-pool-budget-draft--kx5m370w3w6mxz7d.md new file mode 100644 index 00000000..0365f5b3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-streaming-pool-budget-draft--kx5m370w3w6mxz7d.md @@ -0,0 +1,12 @@ +--- +id: con-streaming-pool-budget-draft--kx5m370w3w6mxz7d +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Streaming pool budget (draft) +kind: hard +created_at: '2026-06-04T09:00:00Z' +created_by: Kenji Arakawa +retracted: true +retracted_at: '2026-06-04T10:00:00.000Z' +retracted_reason: Draft figure written before the ports team set the final cut. +--- +Draft: streaming pool at most 1.8 GB on every platform. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-the-build-farm-stays-at-12-agents-until-alpha--w7e1xfex9z2ycpx1.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-the-build-farm-stays-at-12-agents-until-alpha--w7e1xfex9z2ycpx1.md new file mode 100644 index 00000000..2fa89bc5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-the-build-farm-stays-at-12-agents-until-alpha--w7e1xfex9z2ycpx1.md @@ -0,0 +1,9 @@ +--- +id: con-the-build-farm-stays-at-12-agents-until-alpha--w7e1xfex9z2ycpx1 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: The build farm stays at 12 agents until alpha +kind: hard +created_at: '2025-09-12T16:00:00Z' +created_by: Dara Whitlock +--- +Dara Whitlock confirmed there is no hardware budget for more farm agents before alpha on 2026-03-02. Any fix for shader build time has to fit the 12 agents and the 4 TB shared volume we already own. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-tide-state-must-be-bit-identical-on-every-peer--zrpnp8qjyxzkas7t.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-tide-state-must-be-bit-identical-on-every-peer--zrpnp8qjyxzkas7t.md new file mode 100644 index 00000000..c051cd5b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-tide-state-must-be-bit-identical-on-every-peer--zrpnp8qjyxzkas7t.md @@ -0,0 +1,11 @@ +--- +id: con-tide-state-must-be-bit-identical-on-every-peer--zrpnp8qjyxzkas7t +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Tide state must be bit-identical on every peer +kind: hard +created_at: '2025-10-31T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss +--- +Given the same inputs, every machine must produce the same tide state bit for bit, on PC, Meridian, and Skiff, for an entire session. Close enough is not enough: a 1 cm difference flips walkable ground. diff --git a/benchmarks/proof-recall/.flatbread-proof/constraints/con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s.md b/benchmarks/proof-recall/.flatbread-proof/constraints/con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s.md new file mode 100644 index 00000000..8ce0b0eb --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/constraints/con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s.md @@ -0,0 +1,9 @@ +--- +id: con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: UI composites at a fixed 203 nits in HDR +kind: soft +created_at: '2025-10-22T10:00:00Z' +created_by: Yusuf Demir +--- +In HDR output the HUD and menus composite at a fixed 203 nits so text looks the same on every display. UI art is authored against that level. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b.md new file mode 100644 index 00000000..c8075574 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b.md @@ -0,0 +1,25 @@ +--- +id: dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Abandon rollback netcode for co-op +state: accepted +created_at: '2026-04-01T10:00:00Z' +created_by: Sofia Marchetti +derives_from: + - con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g + - fnd-quarter-resolution-tide-re-simulation-desyncs-pe--064cvn1d3t35bnra + - fnd-re-running-tides-every-rollback-frame-costs-4-8--tp4gxe8prh0bh9h4 +supersedes: + - dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4 +--- +We stop the rollback prototype. Co-op will not ship with rollback. + +The reason is the tides. The world Effort's Decision "Run the tide simulation in 32.32 fixed point" keeps tides deterministic, and co-op needs that. But rollback must re-run tides every frame it rolls back, which costs 4.8 ms on Skiff. That is a fifth of the 25 ms frame before physics, Gull and rendering. + +What we tried before giving up: +- Shrinking the window: below 6 frames, p95 Skiff Wi-Fi stalls. +- Re-simulating tides at quarter resolution: desynced within 90 seconds. +- Leaving tides out of the snapshot: breaks the bit-for-bit tide Constraint. + +The checksum tooling and the 1-frame input delay result carry over to whatever replaces rollback. +The rollback code is archived on branch netcode/rollback-archive and will not be maintained. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-add-a-second-tide-harmonic-for-spring-and-neap-t--1c3s7dtyxvj70gvw.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-add-a-second-tide-harmonic-for-spring-and-neap-t--1c3s7dtyxvj70gvw.md new file mode 100644 index 00000000..76478f5c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-add-a-second-tide-harmonic-for-spring-and-neap-t--1c3s7dtyxvj70gvw.md @@ -0,0 +1,12 @@ +--- +id: dec-add-a-second-tide-harmonic-for-spring-and-neap-t--1c3s7dtyxvj70gvw +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Add a second tide harmonic for spring and neap tides +state: accepted +created_at: '2026-07-06T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e + - iss-tides-feel-identical-every-cycle--e8kc5aah7z7ff50z +--- +Add a second harmonic with a period of seven 40-minute cycles to the fixed-point tide simulation. The tide state gains one more 32.32 phase value. The sine table is reused, so determinism holds. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-add-an-in-game-paper-white-slider-from-80-to-400--1phfvxby983z8tjf.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-add-an-in-game-paper-white-slider-from-80-to-400--1phfvxby983z8tjf.md new file mode 100644 index 00000000..e9918d38 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-add-an-in-game-paper-white-slider-from-80-to-400--1phfvxby983z8tjf.md @@ -0,0 +1,11 @@ +--- +id: dec-add-an-in-game-paper-white-slider-from-80-to-400--1phfvxby983z8tjf +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Add an in-game paper-white slider from 80 to 400 nits +state: proposed +created_at: '2026-07-21T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - iss-meridian-hdr-certification-fails-the-paper-white--bper6nwencgtgf7b +--- +Add a paper-white slider to the display menu, from 80 to 400 nits, starting at the system value. Covers the range half of the test. UI art needs checking at both ends. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4.md new file mode 100644 index 00000000..456fdad2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4.md @@ -0,0 +1,15 @@ +--- +id: dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Adopt a visibility buffer for all opaque geometry +state: superseded +created_at: '2025-09-26T10:00:00Z' +created_by: Ines Okafor +derives_from: + - con-frame-budget--f5qxxq5572878wrp + - fnd-visibility-buffer-prototype-timings--qcfzqvyxbxkf2spw + - iss-should-lantern-replace-clustered-forward-with-a--7c8zxrdsj59q8hmd +superseded_by: + - dec-adopt-a-visibility-buffer-with-64-bit-instance-a--zwmywxyvnqzvw5xq +--- +Lantern replaces clustered forward+ with a visibility buffer for all opaque geometry. Rasterize instance and triangle ids, then shade each visible pixel once in a resolve pass. The prototype saves 4.4 ms on the cliffs benchmark, which is the single biggest win available against the Frame budget. Saltglass, being transparent, is not opaque geometry and is out of scope here. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-adopt-a-visibility-buffer-for-all-opaque-geometr--p6xa9a990esdt2ej.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-adopt-a-visibility-buffer-for-all-opaque-geometr--p6xa9a990esdt2ej.md new file mode 100644 index 00000000..9c83b76d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-adopt-a-visibility-buffer-for-all-opaque-geometr--p6xa9a990esdt2ej.md @@ -0,0 +1,14 @@ +--- +id: dec-adopt-a-visibility-buffer-for-all-opaque-geometr--p6xa9a990esdt2ej +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Adopt a visibility buffer for all opaque geometry +state: proposed +created_at: '2025-09-26T10:01:00Z' +created_by: Ines Okafor +retracted: true +retracted_at: '2025-09-26T15:00:00.000Z' +retracted_reason: >- + Duplicate write from a retried session; the Decision written a minute earlier + is the real one. +--- +Lantern replaces clustered forward+ with a visibility buffer for all opaque geometry. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-adopt-a-visibility-buffer-with-64-bit-instance-a--zwmywxyvnqzvw5xq.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-adopt-a-visibility-buffer-with-64-bit-instance-a--zwmywxyvnqzvw5xq.md new file mode 100644 index 00000000..1e2bec94 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-adopt-a-visibility-buffer-with-64-bit-instance-a--zwmywxyvnqzvw5xq.md @@ -0,0 +1,15 @@ +--- +id: dec-adopt-a-visibility-buffer-with-64-bit-instance-a--zwmywxyvnqzvw5xq +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Adopt a visibility buffer with 64-bit instance and triangle ids +state: superseded +created_at: '2025-10-20T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-32-bit-visibility-ids-overflow-on-the-dunes-benc--eyjs4sekprhhtddp +supersedes: + - dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4 +superseded_by: + - dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9 +--- +Same visibility buffer for all opaque geometry, but the id target is 64-bit: 32 bits of instance and 32 of triangle. The extra 28 MB at 1440p fits inside the render-target memory budget. Material resolve is unchanged. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e.md new file mode 100644 index 00000000..4805add3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e.md @@ -0,0 +1,15 @@ +--- +id: dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Brine curve with a separate HDR shoulder at 1,000 nits' +state: superseded +created_at: '2026-05-06T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - iss-banding-in-the-dusk-sky-with-the-brine-curve-on--qyfqbggg14ckxvc9 +supersedes: + - dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86 +superseded_by: + - dec-brine-curve-with-an-hdr-shoulder-at-800-nits--fpznx0cnj4avsxk1 +--- +Split the Brine curve: SDR keeps the original shoulder, HDR gets its own gentler shoulder starting at 1,000 nits. The gentler slope removes the dusk banding on 10-bit output without dithering. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-brine-curve-with-an-hdr-shoulder-at-800-nits--fpznx0cnj4avsxk1.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-brine-curve-with-an-hdr-shoulder-at-800-nits--fpznx0cnj4avsxk1.md new file mode 100644 index 00000000..75f2648f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-brine-curve-with-an-hdr-shoulder-at-800-nits--fpznx0cnj4avsxk1.md @@ -0,0 +1,13 @@ +--- +id: dec-brine-curve-with-an-hdr-shoulder-at-800-nits--fpznx0cnj4avsxk1 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Brine curve with an HDR shoulder at 800 nits +state: accepted +created_at: '2026-09-08T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - fnd-brine-hdr-shoulder-clips-caustics-on-800-nit-pan--xe75a0mm3sqmtk4r +supersedes: + - dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e +--- +Move the Brine HDR shoulder down to start at 800 nits, and scale it to the calibrated peak on brighter panels. Dusk banding stays fixed at the new slope. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh.md new file mode 100644 index 00000000..11a8cf35 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh.md @@ -0,0 +1,12 @@ +--- +id: dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Build a content-addressed shader compile cache shared by all farm agents +state: accepted +created_at: '2025-09-16T10:00:00Z' +created_by: Liam O'Connell +derives_from: + - fnd-most-shader-compile-time-on-the-farm-repeats-ide--n7mr2yxxxtzpak35 + - iss-how-should-the-farm-stop-recompiling-unchanged-s--b2kcgasfccnydkjp +--- +Store each compiled permutation on the shared volume under a hash of its inputs. Any agent that needs a permutation fetches it if the hash exists, and compiles and uploads it if not. This attacks the 61% of repeat work directly and needs no new hardware. The hard part is the key: a key that misses an input ships stale bytecode, and a key that over-includes gets no hits. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7.md new file mode 100644 index 00000000..9859b0e8 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7.md @@ -0,0 +1,26 @@ +--- +id: dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Build an on-device pipeline cache for Skiff +state: accepted +created_at: '2025-12-12T10:20:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-harbor-district-needs-1-460-pipelines-on-skiff--dwd5ry1wqaeacmpn + - iss-how-should-skiff-avoid-first-use-pipeline-compil--5nvhn8xzyz2d7y7k +supersedes: + - dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn +reopen_history: + - at: '2026-03-23T10:00:00.000Z' + reason: >- + Prebuilt blobs go stale on every Skiff driver update; a cache on the + device survives updates by rebuilding. + rejected_by: dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn +--- +Keep compiled graphics pipelines on the Skiff itself. The first time the game needs a pipeline, it compiles it and writes the result to a cache file in the save partition. The next session reads it back instead of compiling. Everyone on the team calls this the shader cache. It is not the build farm's shader compile cache, which speeds up our own builds and never ships to players. + +To hide the first compile, the game warms the cache during load screens and fast travel. Each district has a list of the pipelines it drew in our playtests. While a load screen is up, the game compiles any pipeline on that list that is not in the cache yet. Priya Natarajan estimates that covers 95 percent of first visits. + +The cache is keyed by pipeline hash plus the Skiff driver version. A firmware update that changes the driver throws the cache away and the game rebuilds it from the district lists over the next few load screens. + +Size: the cache is capped at 384 MB on the Skiff storage. When it fills, the game drops the least recently used district first. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-buy-eight-more-build-agents-for-shader-compiles--a1sr7ek33s1jr1rv.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-buy-eight-more-build-agents-for-shader-compiles--a1sr7ek33s1jr1rv.md new file mode 100644 index 00000000..c69c8dc9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-buy-eight-more-build-agents-for-shader-compiles--a1sr7ek33s1jr1rv.md @@ -0,0 +1,12 @@ +--- +id: dec-buy-eight-more-build-agents-for-shader-compiles--a1sr7ek33s1jr1rv +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Buy eight more build agents for shader compiles +state: rejected +created_at: '2025-09-16T10:30:00Z' +created_by: Dara Whitlock +derives_from: + - iss-how-should-the-farm-stop-recompiling-unchanged-s--b2kcgasfccnydkjp +rejected_by: dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh +--- +Twenty agents instead of 12 would cut a clean rebuild from 47 minutes to about 29. It is the simplest fix, but it scales cost with permutation count and breaks the 12-agent limit before alpha. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-cap-each-farm-agent-at-6-parallel-shader-compile--q5w4sfjm73tsj8x8.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-cap-each-farm-agent-at-6-parallel-shader-compile--q5w4sfjm73tsj8x8.md new file mode 100644 index 00000000..ce433dd2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-cap-each-farm-agent-at-6-parallel-shader-compile--q5w4sfjm73tsj8x8.md @@ -0,0 +1,11 @@ +--- +id: dec-cap-each-farm-agent-at-6-parallel-shader-compile--q5w4sfjm73tsj8x8 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Cap each farm agent at 6 parallel shader compile jobs +state: accepted +created_at: '2026-02-26T10:00:00Z' +created_by: Liam O'Connell +derives_from: + - fnd-flaky-nightly-builds-are-compiler-processes-runn--1sabnpb1s7004jkb +--- +The remote execution scheduler now caps every agent at 6 parallel shader compiles, whatever its core count. On agents 7 and 11 this keeps peak compiler memory under 26 GB. Cold builds get about 50 seconds slower; flaky failures should stop. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1.md new file mode 100644 index 00000000..4f81c9a1 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1.md @@ -0,0 +1,12 @@ +--- +id: dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Cap tide-storm particles at 6,000 on Skiff' +state: proposed +created_at: '2026-08-13T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - con-frame-budget--br0qszfg8fys908n + - iss-skiff-cert-blocker-40-hz-mode-misses-frames-in-t--8r81ajkewab5gymr +--- +Cap storm particles at 6,000 on Skiff, down from 14,000, and skip tide collision for particles more than 40 m away. Yusuf Demir estimates a 3.8 ms CPU saving. The storm will look thinner on Skiff. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676.md new file mode 100644 index 00000000..c3227ae9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676.md @@ -0,0 +1,11 @@ +--- +id: dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Capture the cliffs and dunes benchmarks on every nightly Meridian build +state: accepted +created_at: '2025-10-06T15:00:00Z' +created_by: Liam O'Connell +derives_from: + - iss-no-automated-gpu-captures-on-nightly-builds--k3vncp4qwzdwc2m6 +--- +The build farm runs the cliffs and dunes benchmarks on a Meridian devkit after each nightly build and stores the GPU capture with the build number and devkit serial. Hand captures stay allowed for exploration, but a number that drives a Decision should come from a nightly capture. Liam O'Connell owns the job; the first nightly capture is planned for build r4700. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3.md new file mode 100644 index 00000000..7c17bc2c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3.md @@ -0,0 +1,19 @@ +--- +id: dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Compile Gull to bytecode for a register VM +state: accepted +created_at: '2025-10-16T11:00:00Z' +created_by: Rhea Valdés +derives_from: + - con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73 + - fnd-gull-s-tree-walking-interpreter-spends-1-8-ms-on--bj1ge76d3wy5aqq3 + - iss-should-gull-run-on-a-tree-walking-interpreter-or--dkfsjk9enx1myhff +supersedes: + - dec-keep-gull-on-the-tree-walking-interpreter--br1kgzfmw57xmm9m +reopen_history: + - at: '2026-01-16T10:00:00.000Z' + reason: Alpha content needs three times the Gull tick budget on the interpreter. + rejected_by: dec-keep-gull-on-the-tree-walking-interpreter--br1kgzfmw57xmm9m +--- +Compile Gull to compact bytecode and run it on a register-based VM with no JIT, which the consoles forbid. Rhea Valdés expects a 3x to 5x speed-up over the interpreter. Hot reload needs new work: swapping compiled functions safely. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m.md new file mode 100644 index 00000000..b4768780 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m.md @@ -0,0 +1,12 @@ +--- +id: dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Compress streamed assets with Kelp +state: accepted +created_at: '2025-10-16T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-kelp-decodes-streamed-assets-at-2-9-gb-s-per-cor--32tjx83v8ky28sz4 + - iss-which-codec-should-compress-streamed-assets--9gnh870e1qwzd28r +--- +Use Kelp for every streamed asset class. It decodes twice as fast as Zstandard with a better ratio, and the studio owns the code, so console-specific tuning is in our hands. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-compress-streamed-assets-with-lz4--v1pfsgfp0b3yjv4s.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-compress-streamed-assets-with-lz4--v1pfsgfp0b3yjv4s.md new file mode 100644 index 00000000..61714ce6 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-compress-streamed-assets-with-lz4--v1pfsgfp0b3yjv4s.md @@ -0,0 +1,13 @@ +--- +id: dec-compress-streamed-assets-with-lz4--v1pfsgfp0b3yjv4s +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Compress streamed assets with LZ4 +state: rejected +created_at: '2025-10-16T11:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-kelp-decodes-streamed-assets-at-2-9-gb-s-per-cor--32tjx83v8ky28sz4 + - iss-which-codec-should-compress-streamed-assets--9gnh870e1qwzd28r +rejected_by: dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m +--- +Use LZ4 for the fastest decode and accept the larger install. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-compress-streamed-assets-with-zstandard--bs1t15cygc51cpje.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-compress-streamed-assets-with-zstandard--bs1t15cygc51cpje.md new file mode 100644 index 00000000..64c1d419 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-compress-streamed-assets-with-zstandard--bs1t15cygc51cpje.md @@ -0,0 +1,19 @@ +--- +id: dec-compress-streamed-assets-with-zstandard--bs1t15cygc51cpje +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Compress streamed assets with Zstandard +state: rejected +created_at: '2025-10-16T10:30:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-kelp-decodes-streamed-assets-at-2-9-gb-s-per-cor--32tjx83v8ky28sz4 + - iss-which-codec-should-compress-streamed-assets--9gnh870e1qwzd28r +rejected_by: dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew +reopen_history: + - at: '2026-01-15T10:00:00.000Z' + reason: >- + The Kelp benchmark that beat Zstandard ran with a warm cache; cold on + Skiff, Zstandard is faster. + rejected_by: dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m +--- +Use Zstandard, an off-the-shelf codec with years of fuzzing and platform ports behind it. Rhea Valdés would rather not own a codec, even at half the decode speed. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-cut-navigation-tiles-to-64-m-so-three-fit-along--snvepk8ygeb3qsjs.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-cut-navigation-tiles-to-64-m-so-three-fit-along--snvepk8ygeb3qsjs.md new file mode 100644 index 00000000..72768eae --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-cut-navigation-tiles-to-64-m-so-three-fit-along--snvepk8ygeb3qsjs.md @@ -0,0 +1,11 @@ +--- +id: dec-cut-navigation-tiles-to-64-m-so-three-fit-along--snvepk8ygeb3qsjs +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Cut navigation tiles to 64 m so three fit along each cell edge +state: accepted +created_at: '2026-04-16T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - rsk-192-m-cells-split-the-128-m-navigation-tiles--dwyy783vnxfshkfd +--- +Rebuild navigation tiles at 64 m. Three tiles fit along each 192 m edge, so every tile belongs to exactly one cell. Nav build time rises by 18%, which Marta Lindqvist accepts. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-delay-autosaves-until-the-tide-turn-finishes--4agcgjjj70djdv6b.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-delay-autosaves-until-the-tide-turn-finishes--4agcgjjj70djdv6b.md new file mode 100644 index 00000000..f7680f69 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-delay-autosaves-until-the-tide-turn-finishes--4agcgjjj70djdv6b.md @@ -0,0 +1,11 @@ +--- +id: dec-delay-autosaves-until-the-tide-turn-finishes--4agcgjjj70djdv6b +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Delay autosaves until the tide turn finishes +state: accepted +created_at: '2026-05-08T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - fnd-3-of-200-saves-taken-mid-turn-fail-to-load--4j1kafsdeq0wedhf +--- +An autosave requested during a tide turn waits until the turn's terrain changes finish, at most 40 seconds. Manual saves show a short "the tide is turning" notice and wait the same way. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw.md new file mode 100644 index 00000000..162bd546 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw.md @@ -0,0 +1,12 @@ +--- +id: dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Derive the missing harmonic phase from each save's world clock +state: proposed +created_at: '2026-07-17T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w + - iss-beta-saves-lack-the-second-tide-harmonic-s-phase--gmhrjdy35pjfq651 +--- +Add an upgrade step that computes the second harmonic's phase from the save's world clock, as if the harmonic had always existed, and replays each delta against the two-harmonic tide. Deltas made on a sand bar that the new tide never exposes are dropped and listed in the save log. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-drop-effect-quality-tiers-on-skiff-instead-of-re--jbfzm4ezpd6m7e8a.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-drop-effect-quality-tiers-on-skiff-instead-of-re--jbfzm4ezpd6m7e8a.md new file mode 100644 index 00000000..357ab320 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-drop-effect-quality-tiers-on-skiff-instead-of-re--jbfzm4ezpd6m7e8a.md @@ -0,0 +1,12 @@ +--- +id: dec-drop-effect-quality-tiers-on-skiff-instead-of-re--jbfzm4ezpd6m7e8a +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Drop effect quality tiers on Skiff instead of resolution +state: rejected +created_at: '2025-11-05T10:20:00Z' +created_by: Yusuf Demir +derives_from: + - iss-how-should-skiff-hold-its-frame-budget-when-the--1zdpg3npqmscp42d +rejected_by: dec-scale-skiff-resolution-dynamically-between-540p--jtytvgh2erd32x68 +--- +Keep 720p and step caustics, fog, and foam down one tier when the GPU runs over. Yusuf Demir prefers this because the saltglass look depends on a sharp image. The tier changes pop visibly, though, and need art sign-off for every biome. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc.md new file mode 100644 index 00000000..cee72970 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc.md @@ -0,0 +1,12 @@ +--- +id: dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Drop Skiff to 30 Hz while a tide storm is on screen +state: proposed +created_at: '2026-08-13T10:30:00Z' +created_by: Priya Natarajan +derives_from: + - con-frame-budget--br0qszfg8fys908n + - iss-skiff-cert-blocker-40-hz-mode-misses-frames-in-t--8r81ajkewab5gymr +--- +While a storm runs, switch the 40 Hz mode to 30 Hz and switch back when it ends. Lot check may still flag it as not holding the advertised rate; Dara Whitlock has asked the platform holder. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-drop-the-far-sdf-gi-cascade-for-the-vertical-sli--0af6sjseeftc621j.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-drop-the-far-sdf-gi-cascade-for-the-vertical-sli--0af6sjseeftc621j.md new file mode 100644 index 00000000..92c49b35 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-drop-the-far-sdf-gi-cascade-for-the-vertical-sli--0af6sjseeftc621j.md @@ -0,0 +1,12 @@ +--- +id: dec-drop-the-far-sdf-gi-cascade-for-the-vertical-sli--0af6sjseeftc621j +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Drop the far SDF GI cascade for the vertical slice build +state: accepted +created_at: '2025-12-03T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - dec-use-signed-distance-field-gi--yn366zmp3k7snd9w + - iss-vertical-slice-runs-at-19-4-ms-on-the-dunes-flyo--p26gahekvspjmv06 +--- +For the slice build only, SDF GI traces three clipmap cascades instead of four. The far cascade covers 512 m to 2 km, where the probe-free fallback looks flat but acceptable. Tomasz Brandt measured the flyover at 16.1 ms with the cut. The fourth cascade comes back after the slice. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2.md new file mode 100644 index 00000000..0932eff9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2.md @@ -0,0 +1,11 @@ +--- +id: dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Enable meshlet cone culling on all platforms +state: accepted +created_at: '2026-02-03T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-meshlet-cone-culling-rejects-31-percent-of-trian--7qqt9dr77xyptb85 +--- +Turn on per-meshlet normal-cone culling everywhere, including the Skiff compute expansion. A 31 percent cut in triangles for 0.1 ms is an easy win. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg.md new file mode 100644 index 00000000..f8aff980 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg.md @@ -0,0 +1,14 @@ +--- +id: dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Evict cells by distance and tide forecast +state: accepted +created_at: '2026-01-12T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-lru-eviction-thrashes-during-tide-turns--0tvj4hmg42jy5d3f + - fnd-simulated-forecast-eviction-cuts-reloads-by-63--7c086ee2h8dw247k +supersedes: + - dec-evict-the-least-recently-used-cells-first--4eap3mr9tkafxy2p +--- +Score each resident cell by distance from the nearest player and by how soon the tide forecast needs it. Evict the lowest score first. Cells the tide will expose within one turn are never evicted. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-evict-cells-in-the-order-they-were-loaded--xyp7a3e2cyjgfkcq.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-evict-cells-in-the-order-they-were-loaded--xyp7a3e2cyjgfkcq.md new file mode 100644 index 00000000..603d7876 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-evict-cells-in-the-order-they-were-loaded--xyp7a3e2cyjgfkcq.md @@ -0,0 +1,12 @@ +--- +id: dec-evict-cells-in-the-order-they-were-loaded--xyp7a3e2cyjgfkcq +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Evict cells in the order they were loaded +state: rejected +created_at: '2025-10-27T11:00:00Z' +created_by: Marta Lindqvist +derives_from: + - iss-how-should-the-streaming-pool-choose-cells-to-ev--4j47zrsgtxncn9dk +rejected_by: dec-evict-the-least-recently-used-cells-first--4eap3mr9tkafxy2p +--- +Evict the oldest-loaded cell first. Simpler than LRU and needs no per-frame bookkeeping. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-evict-the-least-recently-used-cells-first--4eap3mr9tkafxy2p.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-evict-the-least-recently-used-cells-first--4eap3mr9tkafxy2p.md new file mode 100644 index 00000000..684e3085 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-evict-the-least-recently-used-cells-first--4eap3mr9tkafxy2p.md @@ -0,0 +1,15 @@ +--- +id: dec-evict-the-least-recently-used-cells-first--4eap3mr9tkafxy2p +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Evict the least recently used cells first +state: superseded +created_at: '2025-10-27T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - iss-how-should-the-streaming-pool-choose-cells-to-ev--4j47zrsgtxncn9dk +superseded_by: + - dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg +invalidated_by: + - fnd-lru-eviction-thrashes-during-tide-turns--0tvj4hmg42jy5d3f +--- +Evict the cell that was touched longest ago. Cheap to track and well understood. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4.md new file mode 100644 index 00000000..6db9ecfc --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4.md @@ -0,0 +1,11 @@ +--- +id: dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Exclude caustic luminance from Tern's history clamp +state: proposed +created_at: '2026-02-12T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5 +--- +Write caustic light to a separate buffer that Tern accumulates without neighborhood clamping, then add it back after upscaling. Tern then averages the jitter instead of fighting it. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-expand-meshlets-to-index-buffers-in-compute-on-s--bpbtr54dgzgsjgme.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-expand-meshlets-to-index-buffers-in-compute-on-s--bpbtr54dgzgsjgme.md new file mode 100644 index 00000000..71063094 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-expand-meshlets-to-index-buffers-in-compute-on-s--bpbtr54dgzgsjgme.md @@ -0,0 +1,12 @@ +--- +id: dec-expand-meshlets-to-index-buffers-in-compute-on-s--bpbtr54dgzgsjgme +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Expand meshlets to index buffers in compute on Skiff +state: accepted +created_at: '2025-12-05T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - con-skiff-has-no-mesh-shader-support--zz4xpaqy1n0zzrj7 + - dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h +--- +On Skiff, a compute pass writes the surviving meshlets into an index buffer each frame, and the classic vertex pipeline draws it with one indirect call. Culling stays per meshlet. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-fan-shader-cache-misses-out-to-every-farm-agent--pwrf9w720rf4hd27.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-fan-shader-cache-misses-out-to-every-farm-agent--pwrf9w720rf4hd27.md new file mode 100644 index 00000000..3efc3509 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-fan-shader-cache-misses-out-to-every-farm-agent--pwrf9w720rf4hd27.md @@ -0,0 +1,12 @@ +--- +id: dec-fan-shader-cache-misses-out-to-every-farm-agent--pwrf9w720rf4hd27 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Fan shader cache misses out to every farm agent through remote execution +state: accepted +created_at: '2025-11-04T10:00:00Z' +created_by: Liam O'Connell +derives_from: + - con-the-build-farm-stays-at-12-agents-until-alpha--w7e1xfex9z2ycpx1 + - fnd-remote-execution-spreads-cache-misses-across-all--120mx6z98n6qfmwh +--- +Every shader compile that misses the cache becomes a remote job any idle agent can take. Results upload to the cache, so the next build hits. This keeps us inside the 12-agent limit while making a cold build tolerable. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k.md new file mode 100644 index 00000000..1ebee69c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k.md @@ -0,0 +1,12 @@ +--- +id: dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Feed a saltglass reactive mask into Tern +state: accepted +created_at: '2026-05-18T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-a-saltglass-reactive-mask-removes-90-percent-of--p2mmqg2yj8nz43st + - iss-tern-ghosting-on-moving-saltglass--2yr3q6zf476wajqp +--- +Saltglass writes a reactive mask each frame and Tern trusts the current frame where the mask is set. This fixes the ghosting inside Tern, so there is no case for switching to Halcyon; the reopened Halcyon proposal is rejected again. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-force-strict-ieee-float-mode-for-the-tide-simula--ecwmqt7ncjngysqw.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-force-strict-ieee-float-mode-for-the-tide-simula--ecwmqt7ncjngysqw.md new file mode 100644 index 00000000..81e120d2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-force-strict-ieee-float-mode-for-the-tide-simula--ecwmqt7ncjngysqw.md @@ -0,0 +1,12 @@ +--- +id: dec-force-strict-ieee-float-mode-for-the-tide-simula--ecwmqt7ncjngysqw +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Force strict IEEE float mode for the tide simulation +state: rejected +created_at: '2025-11-02T11:00:00Z' +created_by: Marta Lindqvist +derives_from: + - iss-how-do-we-make-the-tide-simulation-deterministic--48yc2jreapt0n7jf +rejected_by: dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e +--- +Compile the tide simulation with strict floating point: no fused multiply-add contraction and no reassociation. This keeps the float code and needs only compiler flags. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-give-reads-for-tide-exposed-cells-top-priority--8ftkvqhawbdf5djh.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-give-reads-for-tide-exposed-cells-top-priority--8ftkvqhawbdf5djh.md new file mode 100644 index 00000000..f60fea27 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-give-reads-for-tide-exposed-cells-top-priority--8ftkvqhawbdf5djh.md @@ -0,0 +1,14 @@ +--- +id: dec-give-reads-for-tide-exposed-cells-top-priority--8ftkvqhawbdf5djh +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Give reads for tide-exposed cells top priority +state: accepted +created_at: '2026-05-11T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - con-cell-load-deadline--m20x64m5eh7q2bh6 + - dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc +invalidated_by: + - fnd-tide-priority-reads-starve-player-proximity-load--by0d7b0bk39xz3rk +--- +Reads for cells the tide is about to expose jump to the head of the request queue, ahead of all other streaming reads. This is the simplest way to meet the 8-second cell load deadline. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-group-archetype-chunks-by-tide-band-to-cut-fragm--qxnkv5bxqz1r7afv.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-group-archetype-chunks-by-tide-band-to-cut-fragm--qxnkv5bxqz1r7afv.md new file mode 100644 index 00000000..49616424 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-group-archetype-chunks-by-tide-band-to-cut-fragm--qxnkv5bxqz1r7afv.md @@ -0,0 +1,12 @@ +--- +id: dec-group-archetype-chunks-by-tide-band-to-cut-fragm--qxnkv5bxqz1r7afv +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Group archetype chunks by tide band to cut fragmentation +state: accepted +created_at: '2026-01-27T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9 + - fnd-archetype-iteration-takes-3-4-ms-in-the-alpha-wo--dawb9m0pa999mhpe +--- +Allocate archetype chunks per tide band (dry, intertidal, submerged) so that entities a tide query visits sit in the same chunks. This keeps the hybrid layout and attacks the join cost directly. Expected effect: the Skiff crab join drops below 3.5 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-hard-code-hdr-paper-white-at-200-nits-on-meridia--k481dkkr69gf77rr.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-hard-code-hdr-paper-white-at-200-nits-on-meridia--k481dkkr69gf77rr.md new file mode 100644 index 00000000..02447d15 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-hard-code-hdr-paper-white-at-200-nits-on-meridia--k481dkkr69gf77rr.md @@ -0,0 +1,13 @@ +--- +id: dec-hard-code-hdr-paper-white-at-200-nits-on-meridia--k481dkkr69gf77rr +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Hard-code HDR paper white at 200 nits on Meridian +state: accepted +created_at: '2025-12-08T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s +invalidated_by: + - fnd-meridian-hdr-certification-pre-check-failed-on-p--qz0rr1cqqmcr6kh9 +--- +Set paper white to a fixed 200 nits on Meridian, close to the 203-nit UI level, and skip the system setting for now. One less setting to test before the slice. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-hash-tide-physics-and-gull-state-every-30-frames--yqf2m6hqbjhwvkzq.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-hash-tide-physics-and-gull-state-every-30-frames--yqf2m6hqbjhwvkzq.md new file mode 100644 index 00000000..90ae27f9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-hash-tide-physics-and-gull-state-every-30-frames--yqf2m6hqbjhwvkzq.md @@ -0,0 +1,11 @@ +--- +id: dec-hash-tide-physics-and-gull-state-every-30-frames--yqf2m6hqbjhwvkzq +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: 'Hash tide, physics and Gull state every 30 frames and compare across peers' +state: accepted +created_at: '2026-02-11T10:00:00Z' +created_by: Sofia Marchetti +derives_from: + - iss-nothing-shows-which-system-caused-a-desync--k7w6rvkptez9d48k +--- +Each peer hashes the three state blocks separately every 30 frames and sends 12 bytes to the others. A mismatch names the block that diverged and the frame window it happened in. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-have-the-host-stream-tide-heights-to-every-peer--a3rb1seedn2bj7k8.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-have-the-host-stream-tide-heights-to-every-peer--a3rb1seedn2bj7k8.md new file mode 100644 index 00000000..4d3e2b7c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-have-the-host-stream-tide-heights-to-every-peer--a3rb1seedn2bj7k8.md @@ -0,0 +1,12 @@ +--- +id: dec-have-the-host-stream-tide-heights-to-every-peer--a3rb1seedn2bj7k8 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Have the host stream tide heights to every peer +state: rejected +created_at: '2025-11-02T12:00:00Z' +created_by: Sofia Marchetti +derives_from: + - iss-how-do-we-make-the-tide-simulation-deterministic--48yc2jreapt0n7jf +rejected_by: dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e +--- +Only the host simulates tides; peers receive the height field over the network. Determinism stops mattering because there is one source of truth. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42.md new file mode 100644 index 00000000..5d2c4bce --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42.md @@ -0,0 +1,12 @@ +--- +id: dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Hot-reload Gull functions by swapping bytecode at frame boundaries +state: accepted +created_at: '2026-02-24T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - fnd-bytecode-swap-at-frame-boundaries-reloads-94-of--rqrk03vvef5jgv2x + - iss-gull-hot-reload-rejects-struct-layout-changes--3v2w2f9hg2gwy6aj +--- +Between frames, replace the bytecode of every edited function. Running code picks up the new version on its next call. Struct layout changes still need a restart of the level. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-keep-a-local-incremental-shader-build-on-each-ag--5zr06bg4kpth9ha3.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-keep-a-local-incremental-shader-build-on-each-ag--5zr06bg4kpth9ha3.md new file mode 100644 index 00000000..85932a22 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-keep-a-local-incremental-shader-build-on-each-ag--5zr06bg4kpth9ha3.md @@ -0,0 +1,12 @@ +--- +id: dec-keep-a-local-incremental-shader-build-on-each-ag--5zr06bg4kpth9ha3 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Keep a local incremental shader build on each agent +state: rejected +created_at: '2025-09-16T11:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-how-should-the-farm-stop-recompiling-unchanged-s--b2kcgasfccnydkjp +rejected_by: dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh +--- +Each agent keeps its own build directory and recompiles only what changed since its last job. Cheap to try, but jobs land on different agents each time, so Tomasz Brandt measured only a 19% local hit rate on a two-day trial. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-keep-clustered-forward-and-tune-light-culling--18zwcwr0cb3tpmpt.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-keep-clustered-forward-and-tune-light-culling--18zwcwr0cb3tpmpt.md new file mode 100644 index 00000000..7b4c4756 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-keep-clustered-forward-and-tune-light-culling--18zwcwr0cb3tpmpt.md @@ -0,0 +1,13 @@ +--- +id: dec-keep-clustered-forward-and-tune-light-culling--18zwcwr0cb3tpmpt +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Keep clustered forward+ and tune light culling +state: rejected +created_at: '2025-09-27T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-forward-overdraw-on-saltglass-cliffs--q9n76frhz7a7ssnp + - iss-should-lantern-replace-clustered-forward-with-a--7c8zxrdsj59q8hmd +rejected_by: dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4 +--- +Keep forward+, add a depth-only prepass for the cliffs and tighten cluster bounds. The material system stays as it is, so the risk is low. Tomasz Brandt estimates 1.5 ms back on the cliffs benchmark, against the 4.4 ms the visibility buffer prototype saves. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-keep-cpu-frustum-culling-with-software-occlusion--02qna664kkar8fva.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-keep-cpu-frustum-culling-with-software-occlusion--02qna664kkar8fva.md new file mode 100644 index 00000000..89d4f13e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-keep-cpu-frustum-culling-with-software-occlusion--02qna664kkar8fva.md @@ -0,0 +1,12 @@ +--- +id: dec-keep-cpu-frustum-culling-with-software-occlusion--02qna664kkar8fva +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Keep CPU frustum culling with software occlusion +state: rejected +created_at: '2025-10-27T11:00:00Z' +created_by: Rhea Valdés +derives_from: + - iss-how-should-lantern-cull-geometry--jnrp9qd2fywqvqgw +rejected_by: dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee +--- +Keep culling on the CPU and add a software occlusion rasterizer on two worker threads. Kestrel gameplay already knows which objects exist, so this keeps one source of truth. Rhea Valdés expects 1.4 ms back. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-keep-gull-on-the-tree-walking-interpreter--br1kgzfmw57xmm9m.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-keep-gull-on-the-tree-walking-interpreter--br1kgzfmw57xmm9m.md new file mode 100644 index 00000000..f4d44dd4 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-keep-gull-on-the-tree-walking-interpreter--br1kgzfmw57xmm9m.md @@ -0,0 +1,14 @@ +--- +id: dec-keep-gull-on-the-tree-walking-interpreter--br1kgzfmw57xmm9m +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Keep Gull on the tree-walking interpreter +state: superseded +created_at: '2025-10-16T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - fnd-gull-s-tree-walking-interpreter-spends-1-8-ms-on--bj1ge76d3wy5aqq3 + - iss-should-gull-run-on-a-tree-walking-interpreter-or--dkfsjk9enx1myhff +superseded_by: + - dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3 +--- +Keep the interpreter through pre-production. 1.8 ms fits the slice, and designers keep instant hot reload. Revisit when alpha content lands. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-key-the-shader-cache-on-file-modification-times--0ckga1dkdtc81k9g.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-key-the-shader-cache-on-file-modification-times--0ckga1dkdtc81k9g.md new file mode 100644 index 00000000..636f1ea1 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-key-the-shader-cache-on-file-modification-times--0ckga1dkdtc81k9g.md @@ -0,0 +1,12 @@ +--- +id: dec-key-the-shader-cache-on-file-modification-times--0ckga1dkdtc81k9g +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Key the shader cache on file modification times +state: rejected +created_at: '2025-09-22T11:30:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-what-should-the-shader-compile-cache-key-hash--y1ja5t3r75r63s28 +rejected_by: dec-key-the-shader-cache-on-raw-source-text-and-comp--hp6awmx3gq5rn9nc +--- +Use the newest modification time of the shader and its includes. Nearly free to compute, but Git checkouts reset modification times, so every fresh agent would see a cold cache. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-key-the-shader-cache-on-preprocessed-source-defi--3a05ff0r954vxh30.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-key-the-shader-cache-on-preprocessed-source-defi--3a05ff0r954vxh30.md new file mode 100644 index 00000000..24e91a9d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-key-the-shader-cache-on-preprocessed-source-defi--3a05ff0r954vxh30.md @@ -0,0 +1,29 @@ +--- +id: dec-key-the-shader-cache-on-preprocessed-source-defi--3a05ff0r954vxh30 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: >- + Key the shader cache on preprocessed source, defines, target and compiler + binary hash +state: accepted +created_at: '2026-01-15T10:00:00Z' +created_by: Liam O'Connell +derives_from: + - con-a-cache-hit-must-give-the-same-bytes-as-a-fresh--3gmcswztxzpmpz83 + - fnd-two-compiler-builds-with-the-same-version-string--gmgr4ha0ndxqmcn9 + - iss-what-should-the-shader-compile-cache-key-hash--y1ja5t3r75r63s28 +supersedes: + - dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp +--- +This replaces the version-string key. The key is now the SHA-256 of these inputs, in this order: + +1. The preprocessed shader source, so every included header counts. +2. The sorted define set for the permutation. +3. The target platform: PC, Meridian or Skiff. +4. The SHA-256 of the shader compiler binary and its optimizer library, not the version string. +5. The compile flags after normalization (flag order no longer matters). + +Hashing the compiler binary costs nothing per permutation: each agent hashes its install once at startup and caches the result. +Rolling the key forward invalidates the whole cache once, so the first build after the change runs cold, about 14 minutes with remote execution. +Liam O'Connell considered keeping the old entries as a fallback and decided against it, since the old key is exactly what let mismatched bytecode through. + +One input is left out on purpose: the shader debug name. Lantern embeds debug names in the bytecode only in development builds, and including the name split identical permutations into 3,100 extra entries in a trial. Debug names are stripped before hashing and re-added after a fetch. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp.md new file mode 100644 index 00000000..63bc9f53 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp.md @@ -0,0 +1,18 @@ +--- +id: dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: >- + Key the shader cache on preprocessed source, defines, compiler version and + target +state: superseded +created_at: '2025-10-16T10:00:00Z' +created_by: Liam O'Connell +derives_from: + - fnd-raw-source-cache-keys-served-stale-shaders-after--f32vyjth0qtmr6wb + - iss-what-should-the-shader-compile-cache-key-hash--y1ja5t3r75r63s28 +supersedes: + - dec-key-the-shader-cache-on-raw-source-text-and-comp--hp6awmx3gq5rn9nc +superseded_by: + - dec-key-the-shader-cache-on-preprocessed-source-defi--3a05ff0r954vxh30 +--- +Run the preprocessor first and hash its output, so every included header is part of the key. Add the full define set and the target platform (PC, Meridian or Skiff) to the hash. Preprocessing costs 70 seconds per clean build, which is a fair price for never shipping stale includes again. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-key-the-shader-cache-on-raw-source-text-and-comp--hp6awmx3gq5rn9nc.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-key-the-shader-cache-on-raw-source-text-and-comp--hp6awmx3gq5rn9nc.md new file mode 100644 index 00000000..bca21060 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-key-the-shader-cache-on-raw-source-text-and-comp--hp6awmx3gq5rn9nc.md @@ -0,0 +1,13 @@ +--- +id: dec-key-the-shader-cache-on-raw-source-text-and-comp--hp6awmx3gq5rn9nc +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Key the shader cache on raw source text and compiler version +state: superseded +created_at: '2025-09-22T11:00:00Z' +created_by: Liam O'Connell +derives_from: + - iss-what-should-the-shader-compile-cache-key-hash--y1ja5t3r75r63s28 +superseded_by: + - dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp +--- +Key = SHA-256 of the shader file text plus the compiler version string. Simple and fast: hashing all 38,000 permutations takes 9 seconds. Liam O'Connell flagged a doubt: included headers are not part of the hash yet. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-load-skiff-fast-travel-without-a-loading-screen--v4qft5znysjv5f24.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-load-skiff-fast-travel-without-a-loading-screen--v4qft5znysjv5f24.md new file mode 100644 index 00000000..b581c8e8 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-load-skiff-fast-travel-without-a-loading-screen--v4qft5znysjv5f24.md @@ -0,0 +1,14 @@ +--- +id: dec-load-skiff-fast-travel-without-a-loading-screen--v4qft5znysjv5f24 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Load Skiff fast travel without a loading screen +state: accepted +created_at: '2026-03-06T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-skiff-microsd-sustains-92-mb-s--xr1fsyjd45y2tqcx + - iss-skiff-fast-travel-has-no-load-time-plan--8xqtfd6x0mfvbkts +invalidated_by: + - fnd-skiff-microsd-slows-sharply-on-full-warm-cards--p1rgh36hat2egpz3 +--- +At 92 MB/s a fast travel destination loads in 4.1 seconds on Skiff. That fits behind the same camera move Meridian uses, stretched to 4.5 seconds. No loading screen on Skiff. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-lock-caustic-photon-jitter-to-the-tide-phase--85x10k4h11t8nx7c.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-lock-caustic-photon-jitter-to-the-tide-phase--85x10k4h11t8nx7c.md new file mode 100644 index 00000000..3fbabae1 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-lock-caustic-photon-jitter-to-the-tide-phase--85x10k4h11t8nx7c.md @@ -0,0 +1,11 @@ +--- +id: dec-lock-caustic-photon-jitter-to-the-tide-phase--85x10k4h11t8nx7c +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Lock caustic photon jitter to the tide phase +state: proposed +created_at: '2026-03-03T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5 +--- +Seed the photon jitter from the tide phase instead of the frame number, so the pattern changes only as the water moves. Tern then sees a stable pattern between tide steps. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-lock-skiff-to-30-hz--qs42s8xraw7rkkv4.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-lock-skiff-to-30-hz--qs42s8xraw7rkkv4.md new file mode 100644 index 00000000..7a2bf9b3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-lock-skiff-to-30-hz--qs42s8xraw7rkkv4.md @@ -0,0 +1,13 @@ +--- +id: dec-lock-skiff-to-30-hz--qs42s8xraw7rkkv4 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Lock Skiff to 30 Hz +state: rejected +created_at: '2025-12-03T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - con-frame-budget--wt5rfqh5z444g2cg + - iss-should-skiff-offer-a-40-hz-mode--h83ktxc994y2gvx2 +rejected_by: dec-offer-a-40-hz-mode-on-skiff-alongside-30-hz--xhcgs101g1stnf05 +--- +Ship one mode. Every Skiff capture, every cert run, and every performance fix then targets one number, 33.3 ms. Priya Natarajan worries a second mode doubles the test matrix. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-lower-the-skiff-dynamic-resolution-floor-to-504p--15esnt90gcn29enn.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-lower-the-skiff-dynamic-resolution-floor-to-504p--15esnt90gcn29enn.md new file mode 100644 index 00000000..456831e2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-lower-the-skiff-dynamic-resolution-floor-to-504p--15esnt90gcn29enn.md @@ -0,0 +1,16 @@ +--- +id: dec-lower-the-skiff-dynamic-resolution-floor-to-504p--15esnt90gcn29enn +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Lower the Skiff dynamic resolution floor to 504p behind Tern +state: accepted +created_at: '2026-07-22T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - con-frame-budget--br0qszfg8fys908n + - dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3 + - fnd-the-576p-floor-misses-the-40-hz-budget-in-tide-s--gqnqc4vef424e5af + - iss-how-should-skiff-hold-its-frame-budget-when-the--1zdpg3npqmscp42d +supersedes: + - dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb +--- +Dynamic resolution on Skiff now ranges from 504p to 720p. The floor relies on Tern at the Performance preset to rebuild a clean 720p image; without Tern, 504p would shimmer worse than 540p did. The 30 Hz mode rarely drops below 600p. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-make-skiff-a-launch-platform--7fh37fbjmqpjgj0a.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-make-skiff-a-launch-platform--7fh37fbjmqpjgj0a.md new file mode 100644 index 00000000..554a2a2a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-make-skiff-a-launch-platform--7fh37fbjmqpjgj0a.md @@ -0,0 +1,14 @@ +--- +id: dec-make-skiff-a-launch-platform--7fh37fbjmqpjgj0a +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Make Skiff a launch platform +state: accepted +created_at: '2026-06-01T09:00:00Z' +created_by: Dara Whitlock +derives_from: + - con-frame-budget--br0qszfg8fys908n + - con-skiff-memory-budget--nf7qbhsnmcn6v479 + - fnd-kelp-high-ratio-textures-bring-the-skiff-harbor--rnzeng8fj363pr75 + - fnd-skiff-pipeline-cache-removes-second-visit-hitche--kzjtp9dpbpbmrb0x +--- +Skiff ships on launch day with PC and Meridian. The harbor fits in 7.7 GB, the pipeline cache works, and both cert failures are fixed. Dara Whitlock confirmed the date with the platform holder at the beta review. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-mark-tide-exposed-instances-visible-for-one-fram--157jf1cesjt3nkrc.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-mark-tide-exposed-instances-visible-for-one-fram--157jf1cesjt3nkrc.md new file mode 100644 index 00000000..4b5d7fd6 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-mark-tide-exposed-instances-visible-for-one-fram--157jf1cesjt3nkrc.md @@ -0,0 +1,11 @@ +--- +id: dec-mark-tide-exposed-instances-visible-for-one-fram--157jf1cesjt3nkrc +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Mark tide-exposed instances visible for one frame after a tide step +state: accepted +created_at: '2026-03-25T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-objects-pop-in-for-one-frame-when-the-tide-uncov--6165dkqm91r63ckf +--- +The world streaming system already knows which instances a tide step uncovers. Kenji Arakawa adds a flag for them, and the first culling phase treats flagged instances as visible for one frame. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-memory-map-packed-cell-archives-and-fault-data-i--ekwscq306qv3t7dq.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-memory-map-packed-cell-archives-and-fault-data-i--ekwscq306qv3t7dq.md new file mode 100644 index 00000000..e9b1d3b5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-memory-map-packed-cell-archives-and-fault-data-i--ekwscq306qv3t7dq.md @@ -0,0 +1,12 @@ +--- +id: dec-memory-map-packed-cell-archives-and-fault-data-i--ekwscq306qv3t7dq +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Memory-map packed cell archives and fault data in +state: rejected +created_at: '2025-09-29T14:30:00Z' +created_by: Rhea Valdés +derives_from: + - iss-which-read-path-should-streaming-use-on-each-pla--v9wd5sxvfjfsgx9r +rejected_by: dec-read-streamed-assets-through-one-async-request-q--rd5c8rxr5pwz50ds +--- +Map the packed archives and let the OS page data in on first touch. Least code, and the OS cache does the work. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq.md new file mode 100644 index 00000000..b622de70 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq.md @@ -0,0 +1,18 @@ +--- +id: dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Move engine jobs to fibers +state: superseded +created_at: '2025-11-26T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-fibers-hide-waits-but-need-custom-stacks-and-deb--0ynync38mj13w03k + - fnd-priority-lanes-still-leave-workers-28-idle-durin--fhswesk5c086dk1y +supersedes: + - dec-run-engine-jobs-on-a-work-stealing-thread-pool-w--8zpbcym92dkh87f1 +superseded_by: + - dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te +invalidated_by: + - fnd-the-gull-vm-reads-thread-local-registers-after-f--1qser43b9j8ac5pf +--- +Replace the thread pool with a fiber scheduler: 160 fibers with 64 KB stacks, run by one worker thread per hardware thread. A wait yields the fiber and the worker picks up other work. This is the model Kenji Arakawa proposed in September; the lane split showed that blocking waits cannot be scheduled away. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-move-to-a-deferred-g-buffer--16yh63n8kwqevakc.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-move-to-a-deferred-g-buffer--16yh63n8kwqevakc.md new file mode 100644 index 00000000..0192aafd --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-move-to-a-deferred-g-buffer--16yh63n8kwqevakc.md @@ -0,0 +1,12 @@ +--- +id: dec-move-to-a-deferred-g-buffer--16yh63n8kwqevakc +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Move to a deferred G-buffer +state: rejected +created_at: '2025-09-27T11:00:00Z' +created_by: Yusuf Demir +derives_from: + - iss-should-lantern-replace-clustered-forward-with-a--7c8zxrdsj59q8hmd +rejected_by: dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4 +--- +A classic G-buffer: four render targets at 1440p cost 118 MB and about 2.8 ms of bandwidth on Meridian. Artists and tools already understand it. It does not fix overdraw on dense meshes as well as a visibility buffer, because the G-buffer pass still writes every covered quad. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee.md new file mode 100644 index 00000000..b650f70f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee.md @@ -0,0 +1,12 @@ +--- +id: dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Move to GPU-driven two-phase occlusion culling +state: accepted +created_at: '2025-10-27T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-cpu-culling-and-draw-submission-cost-3-2-ms-on-t--1y0j1b9p0zjh0n1g + - iss-how-should-lantern-cull-geometry--jnrp9qd2fywqvqgw +--- +Cull instances on the GPU against last frame's depth pyramid, draw the survivors, rebuild the pyramid, then test the rejected ones again. The CPU only uploads instance data. Submission drops from 3.2 ms to 0.6 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-offer-a-40-hz-mode-on-skiff-alongside-30-hz--xhcgs101g1stnf05.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-offer-a-40-hz-mode-on-skiff-alongside-30-hz--xhcgs101g1stnf05.md new file mode 100644 index 00000000..ef2f8d9b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-offer-a-40-hz-mode-on-skiff-alongside-30-hz--xhcgs101g1stnf05.md @@ -0,0 +1,11 @@ +--- +id: dec-offer-a-40-hz-mode-on-skiff-alongside-30-hz--xhcgs101g1stnf05 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Offer a 40 Hz mode on Skiff alongside 30 Hz +state: accepted +created_at: '2025-12-03T10:15:00Z' +created_by: Dara Whitlock +derives_from: + - iss-should-skiff-offer-a-40-hz-mode--h83ktxc994y2gvx2 +--- +Add a 40 Hz option in the Skiff display menu, off by default. 30 Hz stays the default and the cert target. The 40 Hz mode leans on dynamic resolution to fit its shorter frame. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw.md new file mode 100644 index 00000000..dae65a7a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw.md @@ -0,0 +1,16 @@ +--- +id: dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Partition the world into 128 m cells +state: superseded +created_at: '2025-11-20T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-128-m-cells-should-add-only-40-mb-of-per-cell-ov--ape0tgv597x77p6z + - fnd-a-falling-tide-reloads-18-cells-at-410-mb-s-peak--tjz5vscfrdtazcms +supersedes: + - dec-partition-the-world-into-256-m-cells--j002wj4g6pgxg4d3 +superseded_by: + - dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc +--- +Halve the cell size to 128 m. A tide change then reloads only the narrow coastal cells it touches, and the replayed Skiff trace peaks at 190 MB/s instead of 410 MB/s. Per-cell overhead is estimated at 40 MB in total. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc.md new file mode 100644 index 00000000..9a593a6a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc.md @@ -0,0 +1,14 @@ +--- +id: dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Partition the world into 192 m cells +state: accepted +created_at: '2026-04-02T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-128-m-cells-cost-216-mb-of-per-cell-overhead-on--05dnx4k8a0wjtzdw + - fnd-a-falling-tide-reloads-18-cells-at-410-mb-s-peak--tjz5vscfrdtazcms +supersedes: + - dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw +--- +Move to 192 m cells. About 88 cells are resident on Skiff, so overhead falls to roughly 97 MB, and a falling tide reloads 9 cells with a replayed peak of 240 MB/s. That is above the 128 m peak but well under the 410 MB/s of 256 m cells, and the file count drops by half. 192 m is also three 64 m tiles wide. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-192-meter-cells--q62ddwdv2n8wxay6.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-192-meter-cells--q62ddwdv2n8wxay6.md new file mode 100644 index 00000000..1b39c7af --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-192-meter-cells--q62ddwdv2n8wxay6.md @@ -0,0 +1,14 @@ +--- +id: dec-partition-the-world-into-192-meter-cells--q62ddwdv2n8wxay6 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Partition the world into 192 meter cells +state: proposed +created_at: '2026-04-02T09:00:00Z' +created_by: Dara Whitlock +retracted: true +retracted_at: '2026-04-02T16:00:00.000Z' +retracted_reason: >- + Duplicate of Kenji Arakawa's proposal, written from the planning meeting + notes. +--- +From the planning meeting: move to 192 m cells. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-256-m-cells--j002wj4g6pgxg4d3.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-256-m-cells--j002wj4g6pgxg4d3.md new file mode 100644 index 00000000..048e04e6 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-256-m-cells--j002wj4g6pgxg4d3.md @@ -0,0 +1,14 @@ +--- +id: dec-partition-the-world-into-256-m-cells--j002wj4g6pgxg4d3 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Partition the world into 256 m cells +state: superseded +created_at: '2025-09-29T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-cell-size-sweep-for-the-768-m-streaming-radius--q3qfh6cp8a0k0f7g + - iss-what-cell-size-should-the-world-partition-use--k3bncp2dabkekydq +superseded_by: + - dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw +--- +Use 256 m cells. They fit the streaming pool with room to spare (1.18 GB of 2.0 GB) and keep the file count low. The tide is not yet modelled in streaming; Kenji Arakawa will revisit once tides change terrain in the build. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-512-m-cells--hgbn5yem7vx1hxtt.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-512-m-cells--hgbn5yem7vx1hxtt.md new file mode 100644 index 00000000..d41ec4f3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-partition-the-world-into-512-m-cells--hgbn5yem7vx1hxtt.md @@ -0,0 +1,13 @@ +--- +id: dec-partition-the-world-into-512-m-cells--hgbn5yem7vx1hxtt +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Partition the world into 512 m cells +state: rejected +created_at: '2025-09-29T11:00:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-cell-size-sweep-for-the-768-m-streaming-radius--q3qfh6cp8a0k0f7g + - iss-what-cell-size-should-the-world-partition-use--k3bncp2dabkekydq +rejected_by: dec-partition-the-world-into-256-m-cells--j002wj4g6pgxg4d3 +--- +Use 512 m cells and stream lower mips for the outer ring to fit the pool. Fewer, larger files suit the console storage APIs, which prefer big sequential reads. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-project-animated-caustic-textures-along-the-sun--xe80zje9085n84q6.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-project-animated-caustic-textures-along-the-sun--xe80zje9085n84q6.md new file mode 100644 index 00000000..4719b028 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-project-animated-caustic-textures-along-the-sun--xe80zje9085n84q6.md @@ -0,0 +1,14 @@ +--- +id: dec-project-animated-caustic-textures-along-the-sun--xe80zje9085n84q6 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Project animated caustic textures along the sun direction +state: rejected +created_at: '2025-10-15T14:00:00Z' +created_by: Yusuf Demir +derives_from: + - iss-how-should-lantern-draw-saltglass-caustics--a6wcxavrp4ky319s +invalidated_by: + - fnd-projected-caustic-textures-tile-visibly-past-600--dkyy65zqqh5gx04x +rejected_by: dec-splat-caustic-photons-from-a-sun-space-map--gz19gensacx2zh1w +--- +Project a tiling animated caustic texture along the sun direction under any saltglass. Costs 0.2 ms. Artists control the look directly. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4.md new file mode 100644 index 00000000..c6cf3b70 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4.md @@ -0,0 +1,15 @@ +--- +id: dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4 +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Prototype rollback netcode for co-op +state: superseded +created_at: '2025-11-07T10:00:00Z' +created_by: Sofia Marchetti +derives_from: + - con-co-op-must-stay-playable-at-150-ms-round-trip--q330d4g95q7jtt4q + - con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g + - iss-how-should-co-op-keep-up-to-four-players-in-sync--92t2zfsy3etfzr89 +superseded_by: + - dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b +--- +Each peer predicts remote inputs and simulates ahead. When a late input arrives, the peer restores a snapshot and re-simulates the frames since. Local input never waits on the network, which suits traversal and combat at 150 ms. The cost is re-simulation: everything in the snapshot must run again for every rolled-back frame. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6.md new file mode 100644 index 00000000..0ab07b9d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6.md @@ -0,0 +1,11 @@ +--- +id: dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Raise the shader cache fetch timeout from 5 seconds to 30 seconds +state: accepted +created_at: '2025-12-08T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-flaky-nightly-builds-trace-to-cache-server-fetch--v4wsxzj1x72zz8rs +--- +A longer fetch timeout should ride out the 02:00 network peak. A fetch that takes 30 seconds is still faster than recompiling most permutations. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb.md new file mode 100644 index 00000000..35a960f8 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb.md @@ -0,0 +1,16 @@ +--- +id: dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Raise the Skiff dynamic resolution floor to 576p +state: superseded +created_at: '2026-01-22T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q + - iss-how-should-skiff-hold-its-frame-budget-when-the--1zdpg3npqmscp42d +supersedes: + - dec-scale-skiff-resolution-dynamically-between-540p--jtytvgh2erd32x68 +superseded_by: + - dec-lower-the-skiff-dynamic-resolution-floor-to-504p--15esnt90gcn29enn +--- +Dynamic resolution on Skiff now ranges from 576p to 720p. The worst dune view at the 576p floor costs 27.3 ms, still inside 33.3 ms at 30 Hz. In 40 Hz mode the floor leaves little room. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ray-march-refraction-through-the-saltglass-dista--wjj9jrek6kkgy04m.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ray-march-refraction-through-the-saltglass-dista--wjj9jrek6kkgy04m.md new file mode 100644 index 00000000..a3a42fc9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ray-march-refraction-through-the-saltglass-dista--wjj9jrek6kkgy04m.md @@ -0,0 +1,12 @@ +--- +id: dec-ray-march-refraction-through-the-saltglass-dista--wjj9jrek6kkgy04m +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Ray-march refraction through the saltglass distance field +state: rejected +created_at: '2025-10-03T11:00:00Z' +created_by: Yusuf Demir +derives_from: + - iss-how-should-lantern-render-saltglass-refraction--brndmsn2n8jz6yyk +rejected_by: dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6 +--- +March the refracted ray through the distance field up to 64 steps and shade the hit. Correct even when the refracted point is off screen. Costs 3.4 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f.md new file mode 100644 index 00000000..75178c0e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f.md @@ -0,0 +1,12 @@ +--- +id: dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Re-simulate tides at quarter resolution during rollback +state: rejected +created_at: '2026-03-24T10:00:00Z' +created_by: Sofia Marchetti +derives_from: + - fnd-re-running-tides-every-rollback-frame-costs-4-8--tp4gxe8prh0bh9h4 +rejected_by: dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b +--- +Keep rollback, but re-run tides on a quarter-resolution grid for rolled-back frames and correct to full resolution afterwards. This would cut tide re-simulation to about 1.2 ms. Rhea Valdés doubts the correction step can stay bit-exact. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-read-paper-white-from-the-meridian-system-settin--7crbx73gqw1hn7xq.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-read-paper-white-from-the-meridian-system-settin--7crbx73gqw1hn7xq.md new file mode 100644 index 00000000..403d5756 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-read-paper-white-from-the-meridian-system-settin--7crbx73gqw1hn7xq.md @@ -0,0 +1,11 @@ +--- +id: dec-read-paper-white-from-the-meridian-system-settin--7crbx73gqw1hn7xq +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Read paper white from the Meridian system setting and scale the UI with it +state: proposed +created_at: '2026-07-20T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - iss-meridian-hdr-certification-fails-the-paper-white--bper6nwencgtgf7b +--- +On first boot, read paper white from the Meridian system setting. Composite the UI at that level instead of a fixed 203 nits. Smallest change that passes the system half of the test. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-read-streamed-assets-through-one-async-request-q--rd5c8rxr5pwz50ds.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-read-streamed-assets-through-one-async-request-q--rd5c8rxr5pwz50ds.md new file mode 100644 index 00000000..c10d6c78 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-read-streamed-assets-through-one-async-request-q--rd5c8rxr5pwz50ds.md @@ -0,0 +1,12 @@ +--- +id: dec-read-streamed-assets-through-one-async-request-q--rd5c8rxr5pwz50ds +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Read streamed assets through one async request queue per platform +state: accepted +created_at: '2025-09-29T14:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-skiff-s-file-system-cannot-memory-map-packed-arc--00ecsf304vk38ajb + - iss-which-read-path-should-streaming-use-on-each-pla--v9wd5sxvfjfsgx9r +--- +Every streamed read goes through an async request queue with a priority and a completion callback. Each platform backs the queue with its native async API. One code path, explicit priorities, and no page-fault stalls on the main thread. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-recompile-a-1-in-50-sample-of-cache-hits-and-com--9n176hnc9w0tax3s.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-recompile-a-1-in-50-sample-of-cache-hits-and-com--9n176hnc9w0tax3s.md new file mode 100644 index 00000000..2678b4bc --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-recompile-a-1-in-50-sample-of-cache-hits-and-com--9n176hnc9w0tax3s.md @@ -0,0 +1,12 @@ +--- +id: dec-recompile-a-1-in-50-sample-of-cache-hits-and-com--9n176hnc9w0tax3s +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Recompile a 1-in-50 sample of cache hits and compare bytes +state: accepted +created_at: '2025-11-11T10:00:00Z' +created_by: Liam O'Connell +derives_from: + - con-a-cache-hit-must-give-the-same-bytes-as-a-fresh--3gmcswztxzpmpz83 + - rsk-a-bad-cache-entry-could-ship-broken-bytecode-to--9w76xhyz9xy8g5k5 +--- +Each build recompiles 2% of its cache hits on an idle agent and compares bytes with the cached copy. A mismatch evicts the entry and fails the build loudly. This adds about 40 seconds to a build and should catch a poisoned entry within two or three builds. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-refract-into-local-cubemaps--1aek3p2p2hrfg5b6.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-refract-into-local-cubemaps--1aek3p2p2hrfg5b6.md new file mode 100644 index 00000000..17bbd646 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-refract-into-local-cubemaps--1aek3p2p2hrfg5b6.md @@ -0,0 +1,12 @@ +--- +id: dec-refract-into-local-cubemaps--1aek3p2p2hrfg5b6 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Refract into local cubemaps +state: rejected +created_at: '2025-10-03T12:00:00Z' +created_by: Ines Okafor +derives_from: + - iss-how-should-lantern-render-saltglass-refraction--brndmsn2n8jz6yyk +rejected_by: dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6 +--- +Capture cubemaps every 50 m along the coast and refract into the nearest one. Cheapest at 0.5 ms, but parallax is wrong and tides make the captures stale every 40 minutes. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-rejoin-the-co-op-session-after-meridian-resumes--gp2btfw62qm4khy9.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-rejoin-the-co-op-session-after-meridian-resumes--gp2btfw62qm4khy9.md new file mode 100644 index 00000000..bbb0fc55 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-rejoin-the-co-op-session-after-meridian-resumes--gp2btfw62qm4khy9.md @@ -0,0 +1,11 @@ +--- +id: dec-rejoin-the-co-op-session-after-meridian-resumes--gp2btfw62qm4khy9 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Rejoin the co-op session after Meridian resumes +state: accepted +created_at: '2026-05-27T10:00:00Z' +created_by: Sofia Marchetti +derives_from: + - fnd-meridian-drops-co-op-sessions-because-the-relay--73hf67080kkyf76j +--- +On the Meridian resume event the client drops its socket, reconnects to the relay, and rejoins the session if the host is still there. If not, the player lands in a solo copy of the world with a message. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-render-skiff-at-native-720p-without-upscaling--x1gdj55bvfn1f8z9.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-render-skiff-at-native-720p-without-upscaling--x1gdj55bvfn1f8z9.md new file mode 100644 index 00000000..d8bc2bb6 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-render-skiff-at-native-720p-without-upscaling--x1gdj55bvfn1f8z9.md @@ -0,0 +1,12 @@ +--- +id: dec-render-skiff-at-native-720p-without-upscaling--x1gdj55bvfn1f8z9 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Render Skiff at native 720p without upscaling +state: rejected +created_at: '2025-11-24T10:40:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-which-upscaler-should-skiff-use--jyp1hqdy0ahwfeej +rejected_by: dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3 +--- +Skip upscaling and render 720p always. Tomasz Brandt notes this only works if saltglass refraction drops to half resolution on Skiff, which the art team dislikes. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r.md new file mode 100644 index 00000000..88bc59d9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r.md @@ -0,0 +1,12 @@ +--- +id: dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Resolve materials with one uber shader over bindless material tables +state: accepted +created_at: '2025-12-02T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9 + - rsk-visibility-buffer-material-resolve-multiplies-sh--e0sam0jrjgsvx0gj +--- +Material resolve uses one uber shader per tile class that reads material parameters from bindless material tables, instead of one shader per material. The shader count for resolve drops from 1,860 to 6. Cost on the cliffs benchmark rises 0.2 ms because of branching, which Tomasz Brandt accepts. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h.md new file mode 100644 index 00000000..bf276ec9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h.md @@ -0,0 +1,23 @@ +--- +id: dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Return engine jobs to a thread pool with continuation waits +state: superseded +created_at: '2026-04-14T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m + - fnd-a-thread-pool-with-continuation-waits-keeps-work--3nryg6kq6w7236ae + - iss-crash-triage-stalls-because-fiber-stacks-are-unr--dyr12bpb18sav85g +supersedes: + - dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te +superseded_by: + - dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3 +--- +Retire the fiber scheduler. Engine jobs run on a work-stealing thread pool again, one worker per hardware thread minus one. A job that must wait registers a continuation, and the scheduler runs the continuation when the read, decompression, or job it waits on completes. + +Why now: 41% of alpha crash reports had no usable stack, crash triage is blocked for beta, and the continuation prototype keeps workers 93% busy during tide turns, close to the 95% fibers gave. Fibers bought two points of utilisation at the price of unreadable crashes and the Gull thread-local bug. + +Migration: Kenji Arakawa converts the streaming and decompression waits first, then simulation. Each system keeps a wait wrapper during the move so both models can run in one build. + +Gull keeps its two dedicated threads for now. Marta Lindqvist will measure whether Gull can rejoin the pool once no job ever changes threads mid-run. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-return-engine-jobs-to-the-thread-pool-with-conti--547qbweqvrp1j5g3.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-return-engine-jobs-to-the-thread-pool-with-conti--547qbweqvrp1j5g3.md new file mode 100644 index 00000000..cf565eb0 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-return-engine-jobs-to-the-thread-pool-with-conti--547qbweqvrp1j5g3.md @@ -0,0 +1,12 @@ +--- +id: dec-return-engine-jobs-to-the-thread-pool-with-conti--547qbweqvrp1j5g3 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Return engine jobs to the thread pool with continuation waits +state: proposed +created_at: '2026-04-13T16:00:00Z' +created_by: Kenji Arakawa +retracted: true +retracted_at: '2026-04-14T09:00:00.000Z' +retracted_reason: Kenji Arakawa's draft; Rhea Valdés wrote the version under review. +--- +Draft: go back to a thread pool, waits become continuations. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3.md new file mode 100644 index 00000000..a251b678 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3.md @@ -0,0 +1,13 @@ +--- +id: dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Run engine jobs and Gull scripts on one thread pool with continuation waits +state: accepted +created_at: '2026-06-24T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-gull-s-two-dedicated-threads-sit-idle-70-of-each--qekr5vjr9pand9rs +supersedes: + - dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h +--- +Fold Gull back into the job thread pool. Gull scripts become ordinary jobs; a script wait registers a continuation like any other job. The two dedicated Gull threads are removed. A Gull job is never moved between threads mid-run, which keeps the VM's thread-local state valid. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x.md new file mode 100644 index 00000000..376dbf7b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x.md @@ -0,0 +1,14 @@ +--- +id: dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Run engine jobs on a work-stealing thread pool +state: superseded +created_at: '2025-09-10T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-fibers-hide-waits-but-need-custom-stacks-and-deb--0ynync38mj13w03k + - iss-which-job-model-should-the-kestrel-scheduler-use--7ghtksxxrxcsxn3q +superseded_by: + - dec-run-engine-jobs-on-a-work-stealing-thread-pool-w--8zpbcym92dkh87f1 +--- +Run one worker per hardware thread, minus one for the main thread. Jobs must not block: a job that needs data schedules a follow-up job instead of waiting. This keeps the scheduler small and debuggable for pre-production. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-on-a-work-stealing-thread-pool-w--8zpbcym92dkh87f1.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-on-a-work-stealing-thread-pool-w--8zpbcym92dkh87f1.md new file mode 100644 index 00000000..f54ce4a6 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-on-a-work-stealing-thread-pool-w--8zpbcym92dkh87f1.md @@ -0,0 +1,15 @@ +--- +id: dec-run-engine-jobs-on-a-work-stealing-thread-pool-w--8zpbcym92dkh87f1 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Run engine jobs on a work-stealing thread pool with priority lanes +state: superseded +created_at: '2025-10-21T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-streaming-jobs-block-workers-while-waiting-on-re--sn2bmfdgjeqwkk3p +supersedes: + - dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x +superseded_by: + - dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq +--- +Keep the thread pool but split it into three lanes: frame-critical, streaming, and background. Waits are allowed only in the streaming lane, so a blocked read never delays a frame-critical job. Two workers serve the streaming lane on every platform. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te.md new file mode 100644 index 00000000..a47035d8 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te.md @@ -0,0 +1,16 @@ +--- +id: dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Run engine jobs on fibers and pin Gull scripts to two dedicated threads +state: superseded +created_at: '2026-02-10T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-the-gull-vm-reads-thread-local-registers-after-f--1qser43b9j8ac5pf + - iss-gull-scripts-crash-after-a-fiber-resumes-on-anot--n2hvwg59w0rem0te +supersedes: + - dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq +superseded_by: + - dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h +--- +Keep fibers for engine jobs, but take Gull out of the fiber pool. Gull scripts run on two dedicated threads that never migrate, so the VM's thread-local state stays valid. Engine code that calls into Gull posts a request to those threads. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-on-fibers-from-the-start--2vyf6raa3ntt2dsr.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-on-fibers-from-the-start--2vyf6raa3ntt2dsr.md new file mode 100644 index 00000000..ecf8633a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-engine-jobs-on-fibers-from-the-start--2vyf6raa3ntt2dsr.md @@ -0,0 +1,13 @@ +--- +id: dec-run-engine-jobs-on-fibers-from-the-start--2vyf6raa3ntt2dsr +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Run engine jobs on fibers from the start +state: rejected +created_at: '2025-09-10T10:30:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-fibers-hide-waits-but-need-custom-stacks-and-deb--0ynync38mj13w03k + - iss-which-job-model-should-the-kestrel-scheduler-use--7ghtksxxrxcsxn3q +rejected_by: dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x +--- +Kenji Arakawa proposes fibers from day one. Streaming code is full of waits on I/O and decompression, and rewriting those as follow-up jobs is error-prone. Fibers make a wait a yield. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3.md new file mode 100644 index 00000000..0ddade5a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3.md @@ -0,0 +1,14 @@ +--- +id: dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Run Tern on Skiff at the Performance preset +state: accepted +created_at: '2025-11-24T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0 + - iss-which-upscaler-should-skiff-use--jyp1hqdy0ahwfeej +--- +Skiff uses Tern, the temporal upscaler the render Effort owns. The render Decision "Ship Tern as Lantern's only upscaler" makes Tern the only upscaler Lantern supports, so Skiff cannot ship a second one without the render team taking it on. + +Skiff runs Tern at the Performance preset, a lower quality preset than other platforms use: 2.1 ms against 3.9 ms for Quality. The 1.8 ms saved pays for tide foam on Skiff. Yusuf Demir signed off on the extra foam ghosting after a side-by-side on the handheld screen, where it is hard to see. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e.md new file mode 100644 index 00000000..da8ebcd7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e.md @@ -0,0 +1,19 @@ +--- +id: dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Run the tide simulation in 32.32 fixed point +state: accepted +created_at: '2025-11-02T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - con-tide-state-must-be-bit-identical-on-every-peer--zrpnp8qjyxzkas7t + - fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss + - iss-how-do-we-make-the-tide-simulation-deterministic--48yc2jreapt0n7jf +--- +Run the whole tide simulation in 32.32 fixed-point arithmetic: 32 integer bits and 32 fraction bits in a signed 64-bit value. Integer adds and multiplies give the same bits on every CPU and compiler, so the drift that float tides show within 6 minutes cannot happen. + +Scope: tide phase, wave height field, and the walkability mask derived from it. Rendering reads the result and converts to float, so Lantern is unaffected. Physics reads the walkability mask only. + +Trigonometry uses a 4,096-entry sine table in fixed point with linear interpolation, generated at build time and checked into the repository, so no platform math library is involved. + +The tide simulation steps at 10 Hz and the renderer interpolates between steps. Co-op peers exchange only inputs; they never send tide heights. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-save-full-world-snapshots--296ytcmq2f4kpahk.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-save-full-world-snapshots--296ytcmq2f4kpahk.md new file mode 100644 index 00000000..0bef85e7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-save-full-world-snapshots--296ytcmq2f4kpahk.md @@ -0,0 +1,13 @@ +--- +id: dec-save-full-world-snapshots--296ytcmq2f4kpahk +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Save full world snapshots +state: rejected +created_at: '2025-12-05T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-a-full-world-snapshot-save-is-310-mb--2c7a78gjb54ygkj4 + - iss-how-should-save-games-store-the-changing-world--kpdhcdkax56a7b7d +rejected_by: dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw +--- +Write the whole world state into each save. Simple, and a load needs no baseline data. Size can be cut later with compression. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw.md new file mode 100644 index 00000000..f5ae16f7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw.md @@ -0,0 +1,16 @@ +--- +id: dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Save player changes as deltas against the tide-free baseline +state: superseded +created_at: '2025-12-05T11:00:00Z' +created_by: Marta Lindqvist +derives_from: + - fnd-a-full-world-snapshot-save-is-310-mb--2c7a78gjb54ygkj4 + - iss-how-should-save-games-store-the-changing-world--kpdhcdkax56a7b7d +superseded_by: + - dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8 +invalidated_by: + - fnd-deltas-saved-at-low-tide-replay-wrongly-at-high--25b4vwytarw8ej50 +--- +Save only what players changed, as deltas against the shipped world with the tide removed. Loading applies the deltas to the baseline, then runs the tide forward to the saved time. Saves shrink to a few hundred kilobytes. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8.md new file mode 100644 index 00000000..5ce44c9a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8.md @@ -0,0 +1,14 @@ +--- +id: dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Save player changes as deltas keyed to the tide phase +state: accepted +created_at: '2026-02-24T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e + - fnd-deltas-saved-at-low-tide-replay-wrongly-at-high--25b4vwytarw8ej50 +supersedes: + - dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw +--- +Store each delta together with the 32.32 tide phase at which it was made. On load, the tide runs to each delta's phase before that delta applies, so a dig made at low tide lands in low-tide sand. Because the tide is deterministic, replaying to a phase gives the same terrain every time. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-scale-skiff-resolution-dynamically-between-540p--jtytvgh2erd32x68.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-scale-skiff-resolution-dynamically-between-540p--jtytvgh2erd32x68.md new file mode 100644 index 00000000..a1f46f49 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-scale-skiff-resolution-dynamically-between-540p--jtytvgh2erd32x68.md @@ -0,0 +1,14 @@ +--- +id: dec-scale-skiff-resolution-dynamically-between-540p--jtytvgh2erd32x68 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Scale Skiff resolution dynamically between 540p and 720p +state: superseded +created_at: '2025-11-05T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - con-frame-budget--wt5rfqh5z444g2cg + - iss-how-should-skiff-hold-its-frame-budget-when-the--1zdpg3npqmscp42d +superseded_by: + - dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb +--- +Lantern already has a dynamic resolution path for PC. On Skiff it will drop the internal resolution from 720p to as low as 540p when the GPU frame runs over. The HUD stays at native 720p. Tomasz Brandt measured the 540p floor at 26 ms on the worst dune view, inside 33.3 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-scale-the-skiff-hud-to-125-percent--9gnbdvt72aq3n3vc.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-scale-the-skiff-hud-to-125-percent--9gnbdvt72aq3n3vc.md new file mode 100644 index 00000000..a87875f1 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-scale-the-skiff-hud-to-125-percent--9gnbdvt72aq3n3vc.md @@ -0,0 +1,12 @@ +--- +id: dec-scale-the-skiff-hud-to-125-percent--9gnbdvt72aq3n3vc +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Scale the Skiff HUD to 125 percent +state: accepted +created_at: '2026-05-22T10:30:00Z' +created_by: Yusuf Demir +derives_from: + - con-skiff-minimum-text-height--hhc7n09kx88203zh + - iss-skiff-cert-hud-text-below-minimum-height--va9m4gpjff2vxtrn +--- +Scale every HUD element by 125 percent on Skiff handheld. Plain scaling turns the 6 px labels into blurry 7.5 px ones, still under the minimum, so Yusuf Demir redrew the label font at 9 px for Skiff and the panels grow to fit. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-schedule-streaming-reads-by-deadline-instead-of--q2x5aknabgcssdj2.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-schedule-streaming-reads-by-deadline-instead-of--q2x5aknabgcssdj2.md new file mode 100644 index 00000000..c6dc01e3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-schedule-streaming-reads-by-deadline-instead-of--q2x5aknabgcssdj2.md @@ -0,0 +1,13 @@ +--- +id: dec-schedule-streaming-reads-by-deadline-instead-of--q2x5aknabgcssdj2 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Schedule streaming reads by deadline instead of fixed priority +state: proposed +created_at: '2026-08-14T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - con-cell-load-deadline--m20x64m5eh7q2bh6 + - fnd-tide-priority-reads-starve-player-proximity-load--by0d7b0bk39xz3rk + - iss-tide-turns-leave-inland-terrain-untextured-for-s--ccv6nhwk68kj732c +--- +Give every read a deadline: tide cells get exposure time minus 8 seconds, proximity cells get the time the player will reach them at current speed. The queue serves the earliest deadline first. Tide reads with slack then yield to the player. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r.md new file mode 100644 index 00000000..d381ed03 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r.md @@ -0,0 +1,18 @@ +--- +id: dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Screen-space refraction with a ray-marched fallback for off-screen rays +state: accepted +created_at: '2026-01-08T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-refraction-cost-screen-space-0-9-ms-ray-marched--pr6bzy3tvstaptdc + - fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy +supersedes: + - dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6 +--- +Refraction first tries the screen-space lookup. When the refracted ray leaves the screen, or the depth test from the halo fix rejects the sample, the pixel falls back to a ray march through the saltglass distance field. On the dunes at grazing angles about 40 percent of saltglass pixels take the fallback, and the total refraction cost is 1.8 ms on Meridian, against 0.9 ms for screen-space alone and 3.4 ms for marching everything. + +The halo fix stays in. Ray-marching every pixel, the option rejected in October, is still too expensive; this Decision uses the march only where screen space has nothing to show. Past 2 km the fallback samples the sky cubemap instead of marching. + +The fallback march is capped at 32 steps, half of the 64 steps the October cost Finding measured. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-four-tern-quality-presets--vjw18d82dx5gath8.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-four-tern-quality-presets--vjw18d82dx5gath8.md new file mode 100644 index 00000000..0585c21a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-four-tern-quality-presets--vjw18d82dx5gath8.md @@ -0,0 +1,12 @@ +--- +id: dec-ship-four-tern-quality-presets--vjw18d82dx5gath8 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Ship four Tern quality presets +state: rejected +created_at: '2026-02-25T11:00:00Z' +created_by: Yusuf Demir +derives_from: + - iss-which-tern-quality-presets-should-ship--7yanr9kzekkky53f +rejected_by: dec-ship-three-tern-quality-presets--jkdzxsd8wt3w91hb +--- +Ship Quality, Balanced, Performance and an Ultra Performance preset for players on low-end PCs. More choice for players, one more preset to tune. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-four-tern-quality-presets-adding-ultra-perf--3jg1wyq3bshv839c.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-four-tern-quality-presets-adding-ultra-perf--3jg1wyq3bshv839c.md new file mode 100644 index 00000000..50e41f8c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-four-tern-quality-presets-adding-ultra-perf--3jg1wyq3bshv839c.md @@ -0,0 +1,15 @@ +--- +id: dec-ship-four-tern-quality-presets-adding-ultra-perf--3jg1wyq3bshv839c +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Ship four Tern quality presets, adding Ultra Performance for 120 Hz mode' +state: accepted +created_at: '2026-06-10T10:00:00Z' +created_by: Ines Okafor +derives_from: + - con-meridian-120-hz-performance-mode-budget--khgjmq18bfr40tyj + - fnd-tern-preset-render-scales-and-costs--gjp3q966nngdd580 + - iss-which-tern-quality-presets-should-ship--7yanr9kzekkky53f +supersedes: + - dec-ship-three-tern-quality-presets--jkdzxsd8wt3w91hb +--- +The 120 Hz performance mode on Meridian needs a cheaper preset than Performance, so Tern ships four presets: Quality, Balanced, Performance and Ultra Performance. Ultra Performance is offered only in the 120 Hz mode, not as a general menu option, which keeps saltglass tuning to the one mode that needs it. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-halcyon-on-pc-and-meridian-and-tern-on-skif--9xaxpqsq997w087x.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-halcyon-on-pc-and-meridian-and-tern-on-skif--9xaxpqsq997w087x.md new file mode 100644 index 00000000..4bfd0834 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-halcyon-on-pc-and-meridian-and-tern-on-skif--9xaxpqsq997w087x.md @@ -0,0 +1,12 @@ +--- +id: dec-ship-halcyon-on-pc-and-meridian-and-tern-on-skif--9xaxpqsq997w087x +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Ship Halcyon on PC and Meridian and Tern on Skiff +state: rejected +created_at: '2025-10-28T15:00:00Z' +created_by: Yusuf Demir +derives_from: + - iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v +rejected_by: dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e +--- +Use each upscaler where it is strongest: Halcyon on PC and Meridian, Tern on Skiff. Two upscalers to tune for saltglass, but the best image on each platform. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn.md new file mode 100644 index 00000000..349bca80 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn.md @@ -0,0 +1,14 @@ +--- +id: dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Ship prebuilt pipeline blobs in the Skiff package +state: superseded +created_at: '2025-12-12T10:00:00Z' +created_by: Liam O'Connell +derives_from: + - fnd-prebuilt-pipeline-blobs-load-on-skiff-dev-firmwa--yzb10ygwr1q151e7 + - iss-how-should-skiff-avoid-first-use-pipeline-compil--5nvhn8xzyz2d7y7k +superseded_by: + - dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7 +--- +The build farm compiles every Skiff pipeline at package time and ships the blobs, about 140 MB. Players never compile. This adds 9 minutes to a Skiff package build. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e.md new file mode 100644 index 00000000..87961975 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e.md @@ -0,0 +1,18 @@ +--- +id: dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Ship Tern as Lantern's only upscaler +state: accepted +created_at: '2025-10-28T13:00:00Z' +created_by: Tomasz Brandt +derives_from: + - con-one-upscaler-path-on-every-platform--f91bgj6n66kwc5d3 + - fnd-halcyon-vendor-upscaler-quality-and-platform-cov--xz7hp3e1m1mh44v4 + - fnd-tern-cost-at-4k-output-on-meridian--wycx6ek6sfme73k9 + - iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v +--- +Tern is the only temporal upscaler Lantern ships, on PC, Meridian and Skiff. Halcyon has no Skiff build, and shipping it on two platforms would break the one-upscaler Constraint. Tern costs 0.7 ms more than Halcyon on Meridian today; Tomasz Brandt expects to recover most of that. + +Owning the code matters more for saltglass than raw quality. Refraction moves light independently of geometry motion vectors, and the caustics change every frame. Both need upscaler changes the team can make the same week, not vendor tickets. There is no license to negotiate. + +Other Efforts may pick a Tern preset per platform, but no Effort may add a second upscaler without reopening this Decision. Tern's history buffer is stored as 16-bit float per channel, and every preset shares it. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-tern-as-the-only-upscaler-in-lantern--a6gbj8djpd8p6w67.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-tern-as-the-only-upscaler-in-lantern--a6gbj8djpd8p6w67.md new file mode 100644 index 00000000..7ce2c72d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-tern-as-the-only-upscaler-in-lantern--a6gbj8djpd8p6w67.md @@ -0,0 +1,14 @@ +--- +id: dec-ship-tern-as-the-only-upscaler-in-lantern--a6gbj8djpd8p6w67 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Ship Tern as the only upscaler in Lantern +state: proposed +created_at: '2025-10-28T16:00:00Z' +created_by: Tomasz Brandt +retracted: true +retracted_at: '2025-11-10T10:00:00.000Z' +retracted_reason: >- + Draft of the upscaler Decision saved by mistake; the full Decision was written + three hours earlier. +--- +Tern is the only upscaler. Draft. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-the-halcyon-vendor-upscaler-on-pc-and-merid--bbbhavy3fj67x27p.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-the-halcyon-vendor-upscaler-on-pc-and-merid--bbbhavy3fj67x27p.md new file mode 100644 index 00000000..4a867a33 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-the-halcyon-vendor-upscaler-on-pc-and-merid--bbbhavy3fj67x27p.md @@ -0,0 +1,19 @@ +--- +id: dec-ship-the-halcyon-vendor-upscaler-on-pc-and-merid--bbbhavy3fj67x27p +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Ship the Halcyon vendor upscaler on PC and Meridian +state: rejected +created_at: '2025-10-28T14:00:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-halcyon-vendor-upscaler-quality-and-platform-cov--xz7hp3e1m1mh44v4 + - iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v +rejected_by: dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k +reopen_history: + - at: '2026-04-20T10:00:00.000Z' + reason: >- + Dara Whitlock asked to weigh Halcyon again after the saltglass ghosting + reports, since Halcyon ships its own reactive mask for transparency. + rejected_by: dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e +--- +Use Halcyon on PC and Meridian, where it is 0.7 ms cheaper than Tern and cleaner on disocclusions. Skiff would need something else. Priya Natarajan thinks platform holders will favor the vendor SDK. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-the-missing-meridian-activity-cards-in-the--g947vhgwr7smr8dq.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-the-missing-meridian-activity-cards-in-the--g947vhgwr7smr8dq.md new file mode 100644 index 00000000..b6a0e60b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-the-missing-meridian-activity-cards-in-the--g947vhgwr7smr8dq.md @@ -0,0 +1,11 @@ +--- +id: dec-ship-the-missing-meridian-activity-cards-in-the--g947vhgwr7smr8dq +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Ship the missing Meridian activity cards in the day-one patch +state: accepted +created_at: '2026-05-29T10:00:00Z' +created_by: Dara Whitlock +derives_from: + - iss-meridian-cert-activity-cards-missing-for-two-bio--k214cmfra7pyvvzq +--- +The two missing activity cards need new art and a localization pass. They go in the day-one patch, not the disc build. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-three-tern-quality-presets--jkdzxsd8wt3w91hb.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-three-tern-quality-presets--jkdzxsd8wt3w91hb.md new file mode 100644 index 00000000..1952610a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-ship-three-tern-quality-presets--jkdzxsd8wt3w91hb.md @@ -0,0 +1,14 @@ +--- +id: dec-ship-three-tern-quality-presets--jkdzxsd8wt3w91hb +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Ship three Tern quality presets +state: superseded +created_at: '2026-02-25T10:00:00Z' +created_by: Ines Okafor +derives_from: + - fnd-tern-preset-render-scales-and-costs--gjp3q966nngdd580 + - iss-which-tern-quality-presets-should-ship--7yanr9kzekkky53f +superseded_by: + - dec-ship-four-tern-quality-presets-adding-ultra-perf--3jg1wyq3bshv839c +--- +Ship Quality, Balanced and Performance. Three presets keep saltglass tuning manageable, and every one keeps refraction edges readable. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-show-a-tide-chart-loading-screen-for-skiff-fast--yq2k6tt7gw38wvnh.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-show-a-tide-chart-loading-screen-for-skiff-fast--yq2k6tt7gw38wvnh.md new file mode 100644 index 00000000..bdf10067 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-show-a-tide-chart-loading-screen-for-skiff-fast--yq2k6tt7gw38wvnh.md @@ -0,0 +1,12 @@ +--- +id: dec-show-a-tide-chart-loading-screen-for-skiff-fast--yq2k6tt7gw38wvnh +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Show a tide-chart loading screen for Skiff fast travel +state: accepted +created_at: '2026-04-24T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-skiff-microsd-slows-sharply-on-full-warm-cards--p1rgh36hat2egpz3 + - iss-skiff-fast-travel-has-no-load-time-plan--8xqtfd6x0mfvbkts +--- +Skiff fast travel shows a loading screen with the tide chart for the destination. The screen stays up until the destination tiles are in, up to 7 seconds on slow cards. It also gives the pipeline cache a chance to warm. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew.md new file mode 100644 index 00000000..d287b65b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew.md @@ -0,0 +1,12 @@ +--- +id: dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Shrink Kelp's dictionary to 1 MB for streamed assets +state: accepted +created_at: '2026-02-06T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m + - fnd-kelp-with-a-1-mb-dictionary-decodes-at-2-2-gb-s--vkt1dgk99x2xrmbs +--- +Keep Kelp and ship the 1 MB dictionary on every platform. Cold on Skiff it beats Zstandard by 1.7x. The reopened Zstandard option is closed again by this decision. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-splat-caustic-photons-from-a-sun-space-map--gz19gensacx2zh1w.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-splat-caustic-photons-from-a-sun-space-map--gz19gensacx2zh1w.md new file mode 100644 index 00000000..8480d8e2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-splat-caustic-photons-from-a-sun-space-map--gz19gensacx2zh1w.md @@ -0,0 +1,12 @@ +--- +id: dec-splat-caustic-photons-from-a-sun-space-map--gz19gensacx2zh1w +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Splat caustic photons from a sun-space map +state: accepted +created_at: '2025-10-15T15:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-photon-caustics-cost-1-1-ms-from-a-512-by-512-su--2rg1xq89re42cgaj + - iss-how-should-lantern-draw-saltglass-caustics--a6wcxavrp4ky319s +--- +Trace photons from a 512 by 512 sun-space map through the saltglass, jitter them each frame, and splat the hits into a caustic buffer that lighting reads. The pattern follows the real glass shape. Costs 1.1 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w.md new file mode 100644 index 00000000..def35e6e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w.md @@ -0,0 +1,19 @@ +--- +id: dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Stamp each save with a schema version and upgrade it step by step on load +state: accepted +created_at: '2026-03-12T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - con-saves-from-beta-onward-must-load-in-every-later--v6z856sxtgc5sb09 + - dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8 + - fnd-each-save-upgrade-step-costs-under-5-ms--qs1rweqqgj7kweem +--- +Every save header carries a schema version number. Each format change adds one upgrade step that converts version N to N+1. On load, the game runs every step from the save's version to the current one, in order, before applying deltas. + +Rules for steps: a step is a pure function of the old save; it never reads the current world data; and a step is never edited or deleted once a build that writes its input version has shipped to players. + +Tide state is part of the versioned format. A change to the tide simulation's state, such as a new phase value, needs its own upgrade step that fills the new value for old saves. + +The version counter starts at 1 with this decision. Each upgrade step must be covered by a golden save from the build that wrote its input version, kept in the save test corpus. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-start-the-second-harmonic-at-zero-phase-for-beta--vq8av7c58fmaq9jg.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-start-the-second-harmonic-at-zero-phase-for-beta--vq8av7c58fmaq9jg.md new file mode 100644 index 00000000..a2a9de43 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-start-the-second-harmonic-at-zero-phase-for-beta--vq8av7c58fmaq9jg.md @@ -0,0 +1,11 @@ +--- +id: dec-start-the-second-harmonic-at-zero-phase-for-beta--vq8av7c58fmaq9jg +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Start the second harmonic at zero phase for beta saves +state: proposed +created_at: '2026-07-17T11:00:00Z' +created_by: Rhea Valdés +derives_from: + - iss-beta-saves-lack-the-second-tide-harmonic-s-phase--gmhrjdy35pjfq651 +--- +Set the second harmonic's phase to zero for beta saves, so the harmonic adds nothing at load and grows in over the next cycle. Deltas replay against the tide they were made on. The tide in an upgraded save then differs from a fresh game's tide for up to seven cycles. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-store-all-components-in-archetype-tables--59zqp578hnw072z1.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-store-all-components-in-archetype-tables--59zqp578hnw072z1.md new file mode 100644 index 00000000..8b712065 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-store-all-components-in-archetype-tables--59zqp578hnw072z1.md @@ -0,0 +1,13 @@ +--- +id: dec-store-all-components-in-archetype-tables--59zqp578hnw072z1 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Store all components in archetype tables +state: rejected +created_at: '2025-09-17T09:00:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-archetype-tables-iterate-transforms-2-4x-faster--3xtpgtqs17zzq6v3 + - iss-how-should-kestrel-store-entity-components--aj37s7xz78dszyzp +rejected_by: dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9 +--- +Use archetype tables for every component. Iteration speed matters most for transforms, physics proxies, and render handles, and archetype tables win that by 2.4x. The tide spike would need batching of Submerged flips across several frames. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-store-all-components-in-sparse-sets--fywmr5yvt68xnrpx.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-store-all-components-in-sparse-sets--fywmr5yvt68xnrpx.md new file mode 100644 index 00000000..e66a8c45 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-store-all-components-in-sparse-sets--fywmr5yvt68xnrpx.md @@ -0,0 +1,13 @@ +--- +id: dec-store-all-components-in-sparse-sets--fywmr5yvt68xnrpx +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Store all components in sparse sets +state: rejected +created_at: '2025-09-17T09:30:00Z' +created_by: Marta Lindqvist +derives_from: + - fnd-tide-turns-toggle-the-submerged-tag-on-40-000-en--a95p39zkd5ckmg5y + - iss-how-should-kestrel-store-entity-components--aj37s7xz78dszyzp +rejected_by: dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9 +--- +Use sparse sets for every component. Structural changes cost 45 ns instead of 380 ns, which makes the tide spike disappear. Iteration is slower, but Marta Lindqvist argues that most gameplay queries touch few entities. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-store-components-in-archetype-tables-and-volatil--8679sjn071ycsbpv.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-store-components-in-archetype-tables-and-volatil--8679sjn071ycsbpv.md new file mode 100644 index 00000000..e12c4c78 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-store-components-in-archetype-tables-and-volatil--8679sjn071ycsbpv.md @@ -0,0 +1,12 @@ +--- +id: dec-store-components-in-archetype-tables-and-volatil--8679sjn071ycsbpv +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Store components in archetype tables and volatile tags in sparse set +state: proposed +created_at: '2025-09-18T10:20:00Z' +created_by: Marta Lindqvist +retracted: true +retracted_at: '2025-09-18T15:00:00.000Z' +retracted_reason: Duplicate submission of the hybrid proposal from the review form. +--- +Hybrid storage: archetype tables for stable components, a sparse set for tide tags. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9.md new file mode 100644 index 00000000..8e8506a2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9.md @@ -0,0 +1,13 @@ +--- +id: dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Store components in archetype tables and volatile tags in sparse sets +state: accepted +created_at: '2025-09-18T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-archetype-tables-iterate-transforms-2-4x-faster--3xtpgtqs17zzq6v3 + - fnd-tide-turns-toggle-the-submerged-tag-on-40-000-en--a95p39zkd5ckmg5y + - iss-how-should-kestrel-store-entity-components--aj37s7xz78dszyzp +--- +Keep hot, stable components (transforms, physics proxies, render handles) in archetype tables. Store volatile tags that flip often, starting with Submerged, Exposed, and Buried, in sparse sets beside the tables. A tide turn then flips sparse entries only, and bulk iteration keeps the archetype speed. Queries that mix the two pay a join. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw.md new file mode 100644 index 00000000..53e9812a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw.md @@ -0,0 +1,11 @@ +--- +id: dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Stream Skiff world tiles in 2 MB reads +state: accepted +created_at: '2026-03-06T10:30:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-skiff-microsd-sustains-92-mb-s--xr1fsyjd45y2tqcx +--- +Read world tiles from storage in 2 MB blocks on Skiff. At 92 MB/s a 2 MB read takes about 22 ms, so streaming keeps up with a sprint across the dunes. Smaller reads waste time on per-read overhead on microSD. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-trace-sdf-gi-at-quarter-resolution-in-performanc--06cqt3mqn3fg5h6e.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-trace-sdf-gi-at-quarter-resolution-in-performanc--06cqt3mqn3fg5h6e.md new file mode 100644 index 00000000..674a2548 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-trace-sdf-gi-at-quarter-resolution-in-performanc--06cqt3mqn3fg5h6e.md @@ -0,0 +1,11 @@ +--- +id: dec-trace-sdf-gi-at-quarter-resolution-in-performanc--06cqt3mqn3fg5h6e +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Trace SDF GI at quarter resolution in performance mode +state: proposed +created_at: '2026-04-10T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-gi-does-not-fit-the-120-hz-performance-mode-budg--get9cq6er1ac4vzx +--- +Keep SDF GI in performance mode but trace at quarter resolution and upsample with a depth-aware filter. Thin walls stay correct. Tomasz Brandt expects about 1.3 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-transpile-gull-to-c-at-build-time--ytm47gyt6x8j6xx7.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-transpile-gull-to-c-at-build-time--ytm47gyt6x8j6xx7.md new file mode 100644 index 00000000..262df5f7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-transpile-gull-to-c-at-build-time--ytm47gyt6x8j6xx7.md @@ -0,0 +1,12 @@ +--- +id: dec-transpile-gull-to-c-at-build-time--ytm47gyt6x8j6xx7 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Transpile Gull to C++ at build time +state: rejected +created_at: '2026-01-19T10:00:00Z' +created_by: Liam O'Connell +derives_from: + - fnd-alpha-content-needs-6-2-ms-of-gull-time-per-fram--4mekgdpsdv5nk085 +rejected_by: dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3 +--- +Liam O'Connell proposes translating Gull scripts to C++ during the build. Native speed, and no runtime code generation. The cost: every script edit needs a rebuild, so hot reload is gone, and build times grow by about 6 minutes. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-turn-the-shader-compile-cache-on-for-every-farm--4rr3b12b4sasdmaj.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-turn-the-shader-compile-cache-on-for-every-farm--4rr3b12b4sasdmaj.md new file mode 100644 index 00000000..c0f1c544 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-turn-the-shader-compile-cache-on-for-every-farm--4rr3b12b4sasdmaj.md @@ -0,0 +1,13 @@ +--- +id: dec-turn-the-shader-compile-cache-on-for-every-farm--4rr3b12b4sasdmaj +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Turn the shader compile cache on for every farm build +state: accepted +created_at: '2026-03-20T10:00:00Z' +created_by: Liam O'Connell +derives_from: + - dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh + - dec-cap-each-farm-agent-at-6-parallel-shader-compile--q5w4sfjm73tsj8x8 + - dec-key-the-shader-cache-on-preprocessed-source-defi--3a05ff0r954vxh30 +--- +Nightly, on-demand and release builds all read from and write to the cache from today. Release builds keep the 1-in-50 byte-compare sample. Fresh compiles remain available with a build flag. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-128-vertex-meshlets-with-up-to-256-triangles--2ta4nkmwjgrd29bh.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-128-vertex-meshlets-with-up-to-256-triangles--2ta4nkmwjgrd29bh.md new file mode 100644 index 00000000..a67529ce --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-128-vertex-meshlets-with-up-to-256-triangles--2ta4nkmwjgrd29bh.md @@ -0,0 +1,12 @@ +--- +id: dec-use-128-vertex-meshlets-with-up-to-256-triangles--2ta4nkmwjgrd29bh +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use 128-vertex meshlets with up to 256 triangles +state: rejected +created_at: '2025-11-21T11:00:00Z' +created_by: Rhea Valdés +derives_from: + - iss-what-meshlet-size-should-lantern-use--myg13k3gkk2b61nj +rejected_by: dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h +--- +Larger meshlets halve the meshlet count and the culling dispatch size, and match what Kestrel tools already export. Rhea Valdés prefers fewer, bigger units. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h.md new file mode 100644 index 00000000..1039b61d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h.md @@ -0,0 +1,12 @@ +--- +id: dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use 64-vertex meshlets with up to 124 triangles +state: accepted +created_at: '2025-11-21T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-meshlet-size-sweep-on-the-cliffs-benchmark--zeg5q7pn92jd42x3 + - iss-what-meshlet-size-should-lantern-use--myg13k3gkk2b61nj +--- +Build all saltglass and terrain meshes into meshlets of at most 64 vertices and 124 triangles. Fastest raster in the sweep, and fine enough for per-meshlet culling. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-4-frame-rollback-window--pqe4hvbgmbp0dmh9.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-4-frame-rollback-window--pqe4hvbgmbp0dmh9.md new file mode 100644 index 00000000..1fdc0831 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-4-frame-rollback-window--pqe4hvbgmbp0dmh9.md @@ -0,0 +1,14 @@ +--- +id: dec-use-a-4-frame-rollback-window--pqe4hvbgmbp0dmh9 +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Use a 4-frame rollback window +state: superseded +created_at: '2025-11-20T10:00:00Z' +created_by: Sofia Marchetti +derives_from: + - dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4 + - fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf +superseded_by: + - dec-use-a-7-frame-rollback-window--ewptan6y616adtfw +--- +Roll back at most 4 frames (67 ms at 60 Hz). Inputs later than that stall the peer. At 1.1 ms per full rollback this costs almost nothing, and covers same-region play. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk.md new file mode 100644 index 00000000..d8acf3bb --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk.md @@ -0,0 +1,15 @@ +--- +id: dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Use a 6-frame rollback window with 1 frame of input delay +state: accepted +created_at: '2026-02-02T10:00:00Z' +created_by: Sofia Marchetti +derives_from: + - fnd-one-frame-of-input-delay-is-invisible-in-playtes--azn8kxedq3pp1vq0 + - fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf + - fnd-skiff-co-op-sessions-over-wi-fi-see-180-ms-round--4ttevy0e2zfjqw18 +supersedes: + - dec-use-a-7-frame-rollback-window--ewptan6y616adtfw +--- +Add 1 frame of local input delay, which playtesters cannot see, and shrink the window to 6 frames. Together they still cover p95 Skiff Wi-Fi. Scaling the 1.1 ms measurement, a 6-frame rollback should cost under 2 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-7-frame-rollback-window--ewptan6y616adtfw.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-7-frame-rollback-window--ewptan6y616adtfw.md new file mode 100644 index 00000000..7c48110a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-7-frame-rollback-window--ewptan6y616adtfw.md @@ -0,0 +1,15 @@ +--- +id: dec-use-a-7-frame-rollback-window--ewptan6y616adtfw +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Use a 7-frame rollback window +state: superseded +created_at: '2026-01-12T10:00:00Z' +created_by: Sofia Marchetti +derives_from: + - fnd-skiff-co-op-sessions-over-wi-fi-see-180-ms-round--4ttevy0e2zfjqw18 +supersedes: + - dec-use-a-4-frame-rollback-window--pqe4hvbgmbp0dmh9 +superseded_by: + - dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk +--- +Grow the window to 7 frames (117 ms at 60 Hz) to cover p95 Skiff Wi-Fi. The snapshot ring grows to about 1 MB for four players. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j.md new file mode 100644 index 00000000..03a0f226 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j.md @@ -0,0 +1,11 @@ +--- +id: dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use a cached shadow atlas for local lights +state: accepted +created_at: '2025-11-12T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-which-shadow-technique-should-lantern-use-for-lo--90dy5vvmare2h2kz +--- +Local lights render cube or spot shadows into one 8k atlas, cached until something in range moves. The harbor with 40 shadowed lights costs 0.9 ms. Simple and predictable. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-neutral-curve-and-grade-everything-in-luts--g0p17ez0dk3p7sde.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-neutral-curve-and-grade-everything-in-luts--g0p17ez0dk3p7sde.md new file mode 100644 index 00000000..7a1d6b77 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-neutral-curve-and-grade-everything-in-luts--g0p17ez0dk3p7sde.md @@ -0,0 +1,12 @@ +--- +id: dec-use-a-neutral-curve-and-grade-everything-in-luts--g0p17ez0dk3p7sde +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use a neutral curve and grade everything in LUTs +state: rejected +created_at: '2025-10-09T15:00:00Z' +created_by: Yusuf Demir +derives_from: + - iss-which-tonemapping-curve-should-lantern-use--4y8z3rv7fq2j2a2t +rejected_by: dec-use-the-stock-filmic-tonemapping-curve--wefzd9091kztq0wb +--- +Use a near-linear neutral curve and put all of the look into per-biome grading LUTs. Most control for art, most work for art. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-probe-grid-for-the-far-field-and-sdf-traci--sk8asp26gxtq5tdd.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-probe-grid-for-the-far-field-and-sdf-traci--sk8asp26gxtq5tdd.md new file mode 100644 index 00000000..eb66252a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-probe-grid-for-the-far-field-and-sdf-traci--sk8asp26gxtq5tdd.md @@ -0,0 +1,12 @@ +--- +id: dec-use-a-probe-grid-for-the-far-field-and-sdf-traci--sk8asp26gxtq5tdd +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use a probe grid for the far field and SDF tracing near the camera +state: rejected +created_at: '2025-10-20T15:00:00Z' +created_by: Ines Okafor +derives_from: + - iss-how-should-lantern-do-global-illumination--3hs82xftkrdhk3f7 +rejected_by: dec-use-signed-distance-field-gi--yn366zmp3k7snd9w +--- +Trace the distance field within 64 m of the camera and fall back to the relit probe grid beyond it. More code than either option alone, but each half does what it is good at. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-relit-probe-grid-for-global-illumination--yvz1bpyrnm75wc5p.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-relit-probe-grid-for-global-illumination--yvz1bpyrnm75wc5p.md new file mode 100644 index 00000000..4e69920f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-relit-probe-grid-for-global-illumination--yvz1bpyrnm75wc5p.md @@ -0,0 +1,12 @@ +--- +id: dec-use-a-relit-probe-grid-for-global-illumination--yvz1bpyrnm75wc5p +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use a relit probe grid for global illumination +state: rejected +created_at: '2025-10-20T13:00:00Z' +created_by: Yusuf Demir +derives_from: + - iss-how-should-lantern-do-global-illumination--3hs82xftkrdhk3f7 +rejected_by: dec-use-signed-distance-field-gi--yn366zmp3k7snd9w +--- +Place probes on a 1 m grid near the player and 4 m further out, and relight them each frame from the sun and sky. Cheap at about 0.6 ms. Leaks through thin saltglass walls are the known weakness. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-spatial-upscaler-with-sharpening-on-skiff--cynznx2wg9hswzgb.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-spatial-upscaler-with-sharpening-on-skiff--cynznx2wg9hswzgb.md new file mode 100644 index 00000000..c7a4f0fb --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-a-spatial-upscaler-with-sharpening-on-skiff--cynznx2wg9hswzgb.md @@ -0,0 +1,12 @@ +--- +id: dec-use-a-spatial-upscaler-with-sharpening-on-skiff--cynznx2wg9hswzgb +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Use a spatial upscaler with sharpening on Skiff +state: rejected +created_at: '2025-11-24T10:30:00Z' +created_by: Yusuf Demir +derives_from: + - iss-which-upscaler-should-skiff-use--jyp1hqdy0ahwfeej +rejected_by: dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3 +--- +Bilinear upscale plus a sharpening pass. It costs 0.4 ms and needs no motion vectors. Yusuf Demir raised it as the cheap fallback. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr.md new file mode 100644 index 00000000..0fc1c374 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr.md @@ -0,0 +1,14 @@ +--- +id: dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use cascaded shadow maps with four cascades +state: superseded +created_at: '2025-09-30T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-virtual-shadow-maps-cost-3-1-ms-on-meridian--r6x0sdfecms7j1yg + - iss-which-shadow-technique-should-lantern-use-for-su--y4k75xvbgb2fhj85 +superseded_by: + - dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4 +--- +Sun shadows use four cascaded shadow maps out to 2 km, with the last cascade updated every fourth frame. Cost is 1.6 ms on the dunes benchmark against 3.1 ms for virtual shadow maps. The technique is well understood and needs no new page management. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-deterministic-lockstep-for-co-op--h0agvr5m0d8ndj72.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-deterministic-lockstep-for-co-op--h0agvr5m0d8ndj72.md new file mode 100644 index 00000000..b215ac49 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-deterministic-lockstep-for-co-op--h0agvr5m0d8ndj72.md @@ -0,0 +1,13 @@ +--- +id: dec-use-deterministic-lockstep-for-co-op--h0agvr5m0d8ndj72 +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Use deterministic lockstep for co-op +state: rejected +created_at: '2025-11-07T11:00:00Z' +created_by: Sofia Marchetti +derives_from: + - con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g + - iss-how-should-co-op-keep-up-to-four-players-in-sync--92t2zfsy3etfzr89 +rejected_by: dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4 +--- +Every peer waits for every other peer's input for a frame before simulating it. Simple and cheap on CPU, and determinism is already required for tides. The cost is input delay equal to half the round trip, and the slowest peer gates everyone. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-host-authoritative-sync-for-co-op--17hqrmtja7pn98d6.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-host-authoritative-sync-for-co-op--17hqrmtja7pn98d6.md new file mode 100644 index 00000000..c0d4394a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-host-authoritative-sync-for-co-op--17hqrmtja7pn98d6.md @@ -0,0 +1,14 @@ +--- +id: dec-use-host-authoritative-sync-for-co-op--17hqrmtja7pn98d6 +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Use host-authoritative sync for co-op +state: accepted +created_at: '2026-04-02T10:00:00Z' +created_by: Sofia Marchetti +derives_from: + - con-co-op-must-stay-playable-at-150-ms-round-trip--q330d4g95q7jtt4q + - dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b + - fnd-host-authoritative-spike-keeps-tides-off-the-cli--dp9vx6afks514js6 + - iss-how-should-co-op-keep-up-to-four-players-in-sync--92t2zfsy3etfzr89 +--- +The host runs the only tide simulation and the only physics for shared objects. Clients send inputs and render the host's state with local prediction for their own player. Nothing re-runs tides, so the 4.8 ms cost disappears. Clients see corrections on tide edges at their round trip; Marta Lindqvist will tune how those corrections blend. The snapshot send rate is not chosen yet. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-kelp-s-high-ratio-mode-for-skiff-textures--ztsejzpkp6nn13s5.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-kelp-s-high-ratio-mode-for-skiff-textures--ztsejzpkp6nn13s5.md new file mode 100644 index 00000000..69be8cf3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-kelp-s-high-ratio-mode-for-skiff-textures--ztsejzpkp6nn13s5.md @@ -0,0 +1,12 @@ +--- +id: dec-use-kelp-s-high-ratio-mode-for-skiff-textures--ztsejzpkp6nn13s5 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Use Kelp's high-ratio mode for Skiff textures +state: accepted +created_at: '2026-02-20T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - con-skiff-memory-budget--nf7qbhsnmcn6v479 + - rsk-skiff-runs-out-of-memory-in-dense-districts--p5pv42sgezzjhpfz +--- +Encode Skiff textures with Kelp's high-ratio mode instead of the default mode. Priya Natarajan expects it to save about 900 MB on the harbor route. Decode costs 0.3 ms more per streamed tile on Skiff's CPU, and Yusuf Demir sees slight banding on saltglass gradients at handheld size only. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-ray-traced-sun-shadows--9xpd0kwe2v1rwefd.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-ray-traced-sun-shadows--9xpd0kwe2v1rwefd.md new file mode 100644 index 00000000..a1eaddcc --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-ray-traced-sun-shadows--9xpd0kwe2v1rwefd.md @@ -0,0 +1,17 @@ +--- +id: dec-use-ray-traced-sun-shadows--9xpd0kwe2v1rwefd +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use ray-traced sun shadows +state: proposed +created_at: '2025-09-30T12:00:00Z' +created_by: Yusuf Demir +derives_from: + - iss-which-shadow-technique-should-lantern-use-for-su--y4k75xvbgb2fhj85 +reopen_history: + - at: '2026-05-12T10:00:00.000Z' + reason: >- + Yusuf Demir wants ray-traced sun shadows considered again as a PC ultra + option now that PC has GPU time to spare. + rejected_by: dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr +--- +Trace one shadow ray per pixel against the hardware acceleration structure, with denoising. Soft penumbrae through saltglass come for free. Skiff has no ray-tracing hardware, so Skiff would need a second technique anyway. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6.md new file mode 100644 index 00000000..297aeffe --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6.md @@ -0,0 +1,16 @@ +--- +id: dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use screen-space refraction for saltglass +state: superseded +created_at: '2025-10-03T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-refraction-cost-screen-space-0-9-ms-ray-marched--pr6bzy3tvstaptdc + - iss-how-should-lantern-render-saltglass-refraction--brndmsn2n8jz6yyk +superseded_by: + - dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r +invalidated_by: + - fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy +--- +Offset the scene-color lookup by the refracted view ray, in screen space. At 0.9 ms it is the cheapest option that shows the right thing behind the glass most of the time. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-signed-distance-field-gi--yn366zmp3k7snd9w.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-signed-distance-field-gi--yn366zmp3k7snd9w.md new file mode 100644 index 00000000..6f209ed7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-signed-distance-field-gi--yn366zmp3k7snd9w.md @@ -0,0 +1,13 @@ +--- +id: dec-use-signed-distance-field-gi--yn366zmp3k7snd9w +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use signed-distance-field GI +state: accepted +created_at: '2025-10-20T14:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-probe-grid-leaks-light-through-thin-saltglass-wa--h2hdqdfj92mnmkbj + - fnd-sdf-gi-costs-2-2-ms-on-meridian--r7t7zy97nwxxxctd + - iss-how-should-lantern-do-global-illumination--3hs82xftkrdhk3f7 +--- +Trace short cones against a signed-distance-field clipmap of the scene, four cascades of 64 cubed. Thin saltglass walls block light correctly because the distance field knows they are there. At 2.2 ms on Meridian it fits the Frame budget. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86.md new file mode 100644 index 00000000..175ea3e5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86.md @@ -0,0 +1,15 @@ +--- +id: dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use the custom Brine curve for tonemapping +state: superseded +created_at: '2026-01-30T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - fnd-stock-filmic-curve-clips-38-percent-of-caustic-h--7n6g1tssnkwqqwm6 +supersedes: + - dec-use-the-stock-filmic-tonemapping-curve--wefzd9091kztq0wb +superseded_by: + - dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e +--- +Replace the stock filmic curve with the Brine curve: a custom curve with a long, slow shoulder that keeps caustic detail up to 40 times scene mid-grey. Yusuf Demir tuned it on the dunes at noon and at dusk. The SDR and HDR outputs share the curve below the shoulder. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-the-probe-grid-alone-in-120-hz-performance-m--6dzm1nt40pjfpyae.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-the-probe-grid-alone-in-120-hz-performance-m--6dzm1nt40pjfpyae.md new file mode 100644 index 00000000..658b30b5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-the-probe-grid-alone-in-120-hz-performance-m--6dzm1nt40pjfpyae.md @@ -0,0 +1,12 @@ +--- +id: dec-use-the-probe-grid-alone-in-120-hz-performance-m--6dzm1nt40pjfpyae +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use the probe grid alone in 120 Hz performance mode +state: proposed +created_at: '2026-03-26T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - fnd-probe-grid-leaks-light-through-thin-saltglass-wa--h2hdqdfj92mnmkbj + - iss-gi-does-not-fit-the-120-hz-performance-mode-budg--get9cq6er1ac4vzx +--- +In performance mode only, replace SDF GI with the relit probe grid at 2 m spacing. It costs about 0.6 ms. The leak through thin saltglass walls comes back, and Yusuf Demir would hide the worst ruins with authored blockers. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-the-stock-filmic-tonemapping-curve--wefzd9091kztq0wb.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-the-stock-filmic-tonemapping-curve--wefzd9091kztq0wb.md new file mode 100644 index 00000000..7cf0f790 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-the-stock-filmic-tonemapping-curve--wefzd9091kztq0wb.md @@ -0,0 +1,15 @@ +--- +id: dec-use-the-stock-filmic-tonemapping-curve--wefzd9091kztq0wb +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use the stock filmic tonemapping curve +state: superseded +created_at: '2025-10-09T14:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-which-tonemapping-curve-should-lantern-use--4y8z3rv7fq2j2a2t +superseded_by: + - dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86 +invalidated_by: + - fnd-stock-filmic-curve-clips-38-percent-of-caustic-h--7n6g1tssnkwqqwm6 +--- +Use the stock filmic curve that Kestrel already ships. Artists know it, and it rolls off highlights softly in SDR. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-ubershaders-while-skiff-pipelines-compile--bab5rkqkvq647966.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-ubershaders-while-skiff-pipelines-compile--bab5rkqkvq647966.md new file mode 100644 index 00000000..5fe666a0 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-ubershaders-while-skiff-pipelines-compile--bab5rkqkvq647966.md @@ -0,0 +1,12 @@ +--- +id: dec-use-ubershaders-while-skiff-pipelines-compile--bab5rkqkvq647966 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Use ubershaders while Skiff pipelines compile +state: rejected +created_at: '2025-12-12T10:40:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-how-should-skiff-avoid-first-use-pipeline-compil--5nvhn8xzyz2d7y7k +rejected_by: dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn +--- +Draw with a slow general shader until the specialized pipeline finishes compiling on a worker thread. Tomasz Brandt measured the ubershader at 2.4 times the GPU cost of the specialized saltglass shader, which Skiff cannot afford at 33.3 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-virtual-shadow-maps-for-local-lights--619ngez1rrf39xa1.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-virtual-shadow-maps-for-local-lights--619ngez1rrf39xa1.md new file mode 100644 index 00000000..81d893d2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-virtual-shadow-maps-for-local-lights--619ngez1rrf39xa1.md @@ -0,0 +1,12 @@ +--- +id: dec-use-virtual-shadow-maps-for-local-lights--619ngez1rrf39xa1 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use virtual shadow maps for local lights +state: rejected +created_at: '2025-11-12T11:00:00Z' +created_by: Ines Okafor +derives_from: + - iss-which-shadow-technique-should-lantern-use-for-lo--90dy5vvmare2h2kz +rejected_by: dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j +--- +Give each local light its own virtual shadow map sharing the sun page pool. One system for every light. The harbor would need about 1,500 extra pages. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4.md new file mode 100644 index 00000000..030bc4ef --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4.md @@ -0,0 +1,24 @@ +--- +id: dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Use virtual shadow maps for the sun +state: accepted +created_at: '2025-09-30T11:00:00Z' +created_by: Ines Okafor +derives_from: + - iss-which-shadow-technique-should-lantern-use-for-su--y4k75xvbgb2fhj85 +supersedes: + - dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr +reopen_history: + - at: '2026-01-12T10:00:00.000Z' + reason: >- + The cost Finding that sank virtual shadow maps was a capture error; with + cached pages VSM costs 1.4 ms, less than four cascades. Cascade seams + through saltglass remain unsolved under CSM. + rejected_by: dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr +--- +Sun shadows use one 16k virtual shadow map split into 128-texel pages, allocated where the camera needs detail and cached between frames. Resolution follows the screen, so there are no cascade boundaries to show through saltglass. Pages for static geometry stay valid until the sun moves far enough or a tide step changes the terrain. + +Page caching is the whole point: a static scene should redraw only a few hundred pages a frame. The page pool holds 4,096 pages, which is 256 MB inside the render-target memory budget. Moving objects use a small separate page set that is redrawn every frame. Tomasz Brandt will own page management; Ines Okafor owns the sampling side. + +Beyond 1.2 km, VSM pages are not allocated at all; a distance-field shadow covers 1.2 km to 2 km. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9.md new file mode 100644 index 00000000..36aecd6a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9.md @@ -0,0 +1,15 @@ +--- +id: dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Visibility buffer for opaque geometry; foliage and saltglass stay forward +state: superseded +created_at: '2025-11-14T10:00:00Z' +created_by: Ines Okafor +derives_from: + - fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb +supersedes: + - dec-adopt-a-visibility-buffer-with-64-bit-instance-a--zwmywxyvnqzvw5xq +superseded_by: + - dec-visibility-buffer-with-compute-material-resolve--5s2z9mqmv8vnszed +--- +A partial step back. Opaque geometry stays in the 64-bit visibility buffer, but alpha-tested foliage and refractive saltglass render in a forward pass after the resolve. That keeps foliage at 0.8 ms and gives saltglass the resolved scene to refract. Ines Okafor accepts carrying two shading paths until foliage has a better answer. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1.md new file mode 100644 index 00000000..0cc03900 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1.md @@ -0,0 +1,17 @@ +--- +id: dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Visibility buffer on all platforms; Skiff resolves materials at half rate +state: accepted +created_at: '2026-07-08T10:00:00Z' +created_by: Ines Okafor +derives_from: + - fnd-visibility-buffer-costs-7-4-ms-on-skiff-in-a-rel--fs86h16tm5hgempd +supersedes: + - dec-visibility-buffer-on-pc-and-meridian-forward-fal--khvgysnhmnkjqe9k +--- +Skiff returns to the visibility buffer. The release-build capture puts it at 7.4 ms against 8.1 ms for forward+, and at 6.3 ms with material resolve at half rate, so the forward+ fallback is no longer worth keeping. + +On Skiff, material resolve shades every other pixel in a checkerboard and Tern fills the gaps from history. PC and Meridian resolve at full rate. Saltglass still renders in a forward pass after the resolve on every platform, because refraction needs the resolved scene behind it. The ports team has signed off on the half-rate look on the handheld screen; Yusuf Demir saw no difference on foliage and a slight softening on cliff detail. + +Keeping two opaque paths cost one engineer-week a month in fixes. The Skiff forward+ path will be deleted from the codebase on 2026-07-24, after one week of nightly captures confirm the half-rate numbers. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-visibility-buffer-on-pc-and-meridian-forward-fal--khvgysnhmnkjqe9k.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-visibility-buffer-on-pc-and-meridian-forward-fal--khvgysnhmnkjqe9k.md new file mode 100644 index 00000000..394fe4b7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-visibility-buffer-on-pc-and-meridian-forward-fal--khvgysnhmnkjqe9k.md @@ -0,0 +1,16 @@ +--- +id: dec-visibility-buffer-on-pc-and-meridian-forward-fal--khvgysnhmnkjqe9k +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Visibility buffer on PC and Meridian; forward+ fallback on Skiff +state: superseded +created_at: '2026-04-15T10:00:00Z' +created_by: Ines Okafor +derives_from: + - con-skiff-has-no-mesh-shader-support--zz4xpaqy1n0zzrj7 + - fnd-visibility-buffer-costs-11-2-ms-on-skiff--s3vphdwnhbh4650s +supersedes: + - dec-visibility-buffer-with-compute-material-resolve--5s2z9mqmv8vnszed +superseded_by: + - dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1 +--- +PC and Meridian keep the visibility buffer as before. Skiff goes back to clustered forward+ for opaque geometry, because the visibility buffer costs 11.2 ms there against 8.9 ms. This reverses part of the original move and means two opaque paths to maintain until release. Dara Whitlock agreed to the extra maintenance. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-visibility-buffer-with-compute-material-resolve--5s2z9mqmv8vnszed.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-visibility-buffer-with-compute-material-resolve--5s2z9mqmv8vnszed.md new file mode 100644 index 00000000..85dc0dc9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-visibility-buffer-with-compute-material-resolve--5s2z9mqmv8vnszed.md @@ -0,0 +1,16 @@ +--- +id: dec-visibility-buffer-with-compute-material-resolve--5s2z9mqmv8vnszed +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Visibility buffer with compute material resolve; foliage back in the buffer +state: superseded +created_at: '2026-01-20T10:00:00Z' +created_by: Ines Okafor +derives_from: + - dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r + - fnd-meshlet-alpha-masks-bring-foliage-back-into-the--672xvn788702zkn6 +supersedes: + - dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9 +superseded_by: + - dec-visibility-buffer-on-pc-and-meridian-forward-fal--khvgysnhmnkjqe9k +--- +Foliage moves back into the visibility buffer using meshlet alpha masks, so only saltglass renders forward. Material resolve runs in compute over the bindless material tables. This removes the second shading path for foliage that the previous version carried. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-wrap-the-tide-phase-accumulator-at-each-40-minut--hx88m4hbg27n0xwy.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-wrap-the-tide-phase-accumulator-at-each-40-minut--hx88m4hbg27n0xwy.md new file mode 100644 index 00000000..3db38ab3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-wrap-the-tide-phase-accumulator-at-each-40-minut--hx88m4hbg27n0xwy.md @@ -0,0 +1,12 @@ +--- +id: dec-wrap-the-tide-phase-accumulator-at-each-40-minut--hx88m4hbg27n0xwy +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Wrap the tide phase accumulator at each 40-minute cycle +state: accepted +created_at: '2025-11-12T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e + - rsk-the-fixed-point-tide-phase-may-overflow-in-long--wvaysxbvtnehxfka +--- +Store the tide phase as a fraction of the 40-minute cycle and wrap it to zero at each cycle boundary. The accumulator then never holds more than one cycle and cannot overflow. diff --git a/benchmarks/proof-recall/.flatbread-proof/decisions/dec-write-delta-saves-on-skiff--a0g7x2bvk59t82jw.md b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-write-delta-saves-on-skiff--a0g7x2bvk59t82jw.md new file mode 100644 index 00000000..7ceda909 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/decisions/dec-write-delta-saves-on-skiff--a0g7x2bvk59t82jw.md @@ -0,0 +1,12 @@ +--- +id: dec-write-delta-saves-on-skiff--a0g7x2bvk59t82jw +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Write delta saves on Skiff +state: accepted +created_at: '2026-05-22T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - con-skiff-storage-write-limit--39sn09p505a1s8j7 + - iss-skiff-cert-autosave-writes-11-mb-per-minute--z8qh0wed0sga93tw +--- +Autosave on Skiff writes only the tide cells and inventory slots that changed since the last save, plus a full save every 10 minutes. Expected volume: 2.6 MB a minute, including the pipeline cache. diff --git a/benchmarks/proof-recall/.flatbread-proof/efforts/eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49.md b/benchmarks/proof-recall/.flatbread-proof/efforts/eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49.md new file mode 100644 index 00000000..f51d2c49 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/efforts/eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49.md @@ -0,0 +1,7 @@ +--- +id: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Co-op rollback netcode prototype +status: abandoned +created_at: '2025-11-03T09:00:00Z' +--- +Sofia Marchetti owns this Effort. It prototypes rollback netcode for Saltglass Reach co-op (one to four players) and decides whether rollback can ship. The tide simulation reshapes walkable terrain, so every sync model must keep tide state identical on all peers. diff --git a/benchmarks/proof-recall/.flatbread-proof/efforts/eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4.md b/benchmarks/proof-recall/.flatbread-proof/efforts/eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4.md new file mode 100644 index 00000000..e13f1108 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/efforts/eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4.md @@ -0,0 +1,7 @@ +--- +id: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Kestrel world streaming and simulation core +status: active +created_at: '2025-09-01T09:00:00Z' +--- +Kestrel's engine core for Saltglass Reach: entity storage, the job system, world partition and streaming, the tide simulation, asset compression, save games, the Gull scripting VM, and memory budgets. Rhea Valdés leads; Kenji Arakawa owns streaming and Marta Lindqvist owns gameplay systems. diff --git a/benchmarks/proof-recall/.flatbread-proof/efforts/eff-lantern-renderer-overhaul--qwgke408pte4k0ar.md b/benchmarks/proof-recall/.flatbread-proof/efforts/eff-lantern-renderer-overhaul--qwgke408pte4k0ar.md new file mode 100644 index 00000000..eb115dd6 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/efforts/eff-lantern-renderer-overhaul--qwgke408pte4k0ar.md @@ -0,0 +1,7 @@ +--- +id: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Lantern renderer overhaul +status: active +created_at: '2025-09-01T09:00:00Z' +--- +Lantern is Kestrel's renderer. This Effort covers its overhaul for Saltglass Reach: the move to a visibility buffer, sun and local shadows, global illumination, saltglass refraction and caustics, the Tern upscaler, HDR and tonemapping, GPU-driven culling, and the Meridian frame budgets including the 120 Hz performance mode. Ines Okafor leads it. diff --git a/benchmarks/proof-recall/.flatbread-proof/efforts/eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx.md b/benchmarks/proof-recall/.flatbread-proof/efforts/eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx.md new file mode 100644 index 00000000..fc6a3290 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/efforts/eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx.md @@ -0,0 +1,9 @@ +--- +id: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Meridian and Skiff ports +status: active +created_at: '2025-10-15T09:00:00Z' +--- +Bring Saltglass Reach to the Meridian home console and the Skiff handheld. Meridian targets 60 Hz; Skiff targets 30 Hz with a 40 Hz mode. + +This Effort owns the Skiff numbers: memory, frame budget, the on-device pipeline cache, the Tern preset on Skiff, dynamic resolution, storage, and certification on both consoles. Priya Natarajan leads it. diff --git a/benchmarks/proof-recall/.flatbread-proof/efforts/eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn.md b/benchmarks/proof-recall/.flatbread-proof/efforts/eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn.md new file mode 100644 index 00000000..95584779 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/efforts/eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn.md @@ -0,0 +1,7 @@ +--- +id: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Shader compile cache and build farm +status: completed +created_at: '2025-09-08T09:00:00Z' +--- +Liam O'Connell owns this Effort. It covers the build farm's shader compile cache, the cache key, remote execution of shader compiles, and the flaky nightly builds that came with them. In this Effort "shader cache" means the farm-side compile cache that stores compiled Lantern bytecode. It is not the on-device pipeline cache on Skiff, which the ports Effort owns. The Effort ends when every farm build reads from the cache. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-128-m-cells-cost-216-mb-of-per-cell-overhead-on--05dnx4k8a0wjtzdw.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-128-m-cells-cost-216-mb-of-per-cell-overhead-on--05dnx4k8a0wjtzdw.md new file mode 100644 index 00000000..27a04a7f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-128-m-cells-cost-216-mb-of-per-cell-overhead-on--05dnx4k8a0wjtzdw.md @@ -0,0 +1,20 @@ +--- +id: fnd-128-m-cells-cost-216-mb-of-per-cell-overhead-on--05dnx4k8a0wjtzdw +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 128 m cells cost 216 MB of per-cell overhead on Skiff +kind: measurement +created_at: '2026-03-20T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw + - fnd-128-m-cells-should-add-only-40-mb-of-per-cell-ov--ape0tgv597x77p6z +invalidates: + - fnd-128-m-cells-should-add-only-40-mb-of-per-cell-ov--ape0tgv597x77p6z +--- +Kenji Arakawa measured per-cell overhead on the alpha build instead of estimating it from headers. The November estimate counted only the 0.25 MB cell header. Each resident cell also owns a physics broadphase grid of about 0.5 MB and navigation tile metadata of about 0.35 MB, so the real overhead is 1.1 MB per cell. + +The alpha build keeps 196 cells resident on Skiff, because the streaming radius grew to cover tide pools. At 1.1 MB each that is 216 MB of overhead, more than five times the estimate and over a tenth of the streaming pool. + +File handling is the second cost. Small cells mean many small files. Skiff's storage queue holds 32 requests, and a falling tide now issues so many small reads that the queue stays full and the scheduler cannot slip in urgent reads. + +Over one tide turn the 128 m layout performs 4,100 file opens, against 600 for the old 256 m layout. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-128-m-cells-should-add-only-40-mb-of-per-cell-ov--ape0tgv597x77p6z.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-128-m-cells-should-add-only-40-mb-of-per-cell-ov--ape0tgv597x77p6z.md new file mode 100644 index 00000000..3d7af7a2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-128-m-cells-should-add-only-40-mb-of-per-cell-ov--ape0tgv597x77p6z.md @@ -0,0 +1,14 @@ +--- +id: fnd-128-m-cells-should-add-only-40-mb-of-per-cell-ov--ape0tgv597x77p6z +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 128 m cells should add only 40 MB of per-cell overhead +kind: estimate +created_at: '2025-11-14T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-a-falling-tide-reloads-18-cells-at-410-mb-s-peak--tjz5vscfrdtazcms + - fnd-cell-size-sweep-for-the-768-m-streaming-radius--q3qfh6cp8a0k0f7g +invalidated_by: + - fnd-128-m-cells-cost-216-mb-of-per-cell-overhead-on--05dnx4k8a0wjtzdw +--- +Each cell carries a 0.25 MB header (bounds, index, dependency list). At 169 resident 128 m cells the headers cost about 40 MB, a fair price for reloading only the cells the tide touches. This is an estimate from header sizes alone. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-3-of-200-saves-taken-mid-turn-fail-to-load--4j1kafsdeq0wedhf.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-3-of-200-saves-taken-mid-turn-fail-to-load--4j1kafsdeq0wedhf.md new file mode 100644 index 00000000..e0f94eb8 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-3-of-200-saves-taken-mid-turn-fail-to-load--4j1kafsdeq0wedhf.md @@ -0,0 +1,11 @@ +--- +id: fnd-3-of-200-saves-taken-mid-turn-fail-to-load--4j1kafsdeq0wedhf +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 3 of 200 saves taken mid-turn fail to load +kind: measurement +created_at: '2026-05-05T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - rsk-saving-during-a-tide-turn-may-record-a-half-appl--zezc1pxx8zp5b82m +--- +QA forced 200 autosaves during tide turns. Three fail to load: the terrain solver rejects a delta whose height lies between the old and new tide surfaces. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-32-bit-visibility-ids-overflow-on-the-dunes-benc--eyjs4sekprhhtddp.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-32-bit-visibility-ids-overflow-on-the-dunes-benc--eyjs4sekprhhtddp.md new file mode 100644 index 00000000..e29d7fe9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-32-bit-visibility-ids-overflow-on-the-dunes-benc--eyjs4sekprhhtddp.md @@ -0,0 +1,11 @@ +--- +id: fnd-32-bit-visibility-ids-overflow-on-the-dunes-benc--eyjs4sekprhhtddp +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 32-bit visibility ids overflow on the dunes benchmark +kind: measurement +created_at: '2025-10-14T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4 +--- +The prototype's 32-bit id gives 20 bits to the instance and 12 to the triangle. The dunes benchmark draws 1.6 million instances when the tide is out, past the 1,048,576 limit, and the far flats shade with the wrong materials. A 64-bit target fixes it and costs 28 MB more at 1440p. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m.md new file mode 100644 index 00000000..05536d9f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m.md @@ -0,0 +1,11 @@ +--- +id: fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 41% of alpha crash reports have no usable stack +kind: measurement +created_at: '2026-03-16T10:00:00Z' +created_by: Liam O'Connell +derives_from: + - rsk-fiber-stacks-may-make-crash-dumps-unreadable--b7c1mkn9ygvmsy57 +--- +Liam O'Connell sampled 600 crash reports from the alpha build. In 246 of them (41%) the crashing thread was a fiber worker and the dump shows only scheduler frames. The vendor fiber plug-in recovers stacks on Meridian but still crashes the dump tool on Skiff. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-40-hour-save-takes-1-9-s-to-upgrade-through-si--gw6ahjtssbrm2jwx.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-40-hour-save-takes-1-9-s-to-upgrade-through-si--gw6ahjtssbrm2jwx.md new file mode 100644 index 00000000..80964297 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-40-hour-save-takes-1-9-s-to-upgrade-through-si--gw6ahjtssbrm2jwx.md @@ -0,0 +1,14 @@ +--- +id: fnd-a-40-hour-save-takes-1-9-s-to-upgrade-through-si--gw6ahjtssbrm2jwx +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: A 40-hour save takes 1.9 s to upgrade through six steps +kind: measurement +created_at: '2026-07-20T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w + - fnd-each-save-upgrade-step-costs-under-5-ms--qs1rweqqgj7kweem +invalidates: + - fnd-each-save-upgrade-step-costs-under-5-ms--qs1rweqqgj7kweem +--- +The 5 ms estimate came from a 2-hour save with a field rename. Real steps rewrite every delta, and a 40-hour save holds 35,400 of them. Upgrading such a save through the six steps written so far takes 1.9 s on Skiff, on top of the 2.9 s load. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-falling-tide-reloads-18-cells-at-410-mb-s-peak--tjz5vscfrdtazcms.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-falling-tide-reloads-18-cells-at-410-mb-s-peak--tjz5vscfrdtazcms.md new file mode 100644 index 00000000..547632c9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-falling-tide-reloads-18-cells-at-410-mb-s-peak--tjz5vscfrdtazcms.md @@ -0,0 +1,13 @@ +--- +id: fnd-a-falling-tide-reloads-18-cells-at-410-mb-s-peak--tjz5vscfrdtazcms +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: A falling tide reloads 18 cells at 410 MB/s peak +kind: measurement +created_at: '2025-11-11T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - dec-partition-the-world-into-256-m-cells--j002wj4g6pgxg4d3 +cites: + - cit-skiff-streaming-trace-stream-trace-1110--fn7z3ms8hsz2tw9c +--- +When the tide falls, about 30% of a coastal 256 m cell changes: sand paths appear and glass ridges surface. Today the whole cell reloads. In the Skiff trace, one falling tide reloads 18 cells over 40 seconds with a 410 MB/s peak read rate, and the game drops frames while it does. The trace breaks the reads down by asset type. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-full-world-snapshot-save-is-310-mb--2c7a78gjb54ygkj4.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-full-world-snapshot-save-is-310-mb--2c7a78gjb54ygkj4.md new file mode 100644 index 00000000..1973c153 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-full-world-snapshot-save-is-310-mb--2c7a78gjb54ygkj4.md @@ -0,0 +1,11 @@ +--- +id: fnd-a-full-world-snapshot-save-is-310-mb--2c7a78gjb54ygkj4 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: A full world snapshot save is 310 MB +kind: measurement +created_at: '2025-12-04T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - iss-how-should-save-games-store-the-changing-world--kpdhcdkax56a7b7d +--- +Serializing every entity and the terrain height field of the slice map produces a 310 MB save that takes 4.2 s to write on Skiff. Players changed less than 1% of that data. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-rollback-snapshot-is-38-kb-per-player-per-fram--wa18f2emyakt0tgx.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-rollback-snapshot-is-38-kb-per-player-per-fram--wa18f2emyakt0tgx.md new file mode 100644 index 00000000..5284aaa0 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-rollback-snapshot-is-38-kb-per-player-per-fram--wa18f2emyakt0tgx.md @@ -0,0 +1,13 @@ +--- +id: fnd-a-rollback-snapshot-is-38-kb-per-player-per-fram--wa18f2emyakt0tgx +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: A rollback snapshot is 38 KB per player per frame +kind: measurement +created_at: '2025-12-09T11:00:00Z' +created_by: Sofia Marchetti +derives_from: + - dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4 +cites: + - cit-studio-wiki-primer-on-rollback-netcode--mktyz3g3cwfc7xa7 +--- +With player physics, Gull script state and the local tide cells included, one player's rollback snapshot is 38 KB per frame. A 4-frame ring for four players needs about 600 KB, which is fine on every platform. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-saltglass-reactive-mask-removes-90-percent-of--p2mmqg2yj8nz43st.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-saltglass-reactive-mask-removes-90-percent-of--p2mmqg2yj8nz43st.md new file mode 100644 index 00000000..020cf083 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-saltglass-reactive-mask-removes-90-percent-of--p2mmqg2yj8nz43st.md @@ -0,0 +1,13 @@ +--- +id: fnd-a-saltglass-reactive-mask-removes-90-percent-of--p2mmqg2yj8nz43st +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: A saltglass reactive mask removes 90 percent of Tern ghosting +kind: measurement +created_at: '2026-05-14T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-tern-ghosting-on-moving-saltglass--2yr3q6zf476wajqp +invalidated_by: + - fnd-reactive-mask-removes-61-percent-of-saltglass-gh--csg97ges3067ehrp +--- +Saltglass writes a reactive mask that tells Tern to trust the current frame where refraction moves. In the glass-cliff orbit test the trail length drops from 14 frames to one or two, a 90 percent cut in ghosting energy. Cost: 0.2 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-thread-pool-with-continuation-waits-keeps-work--3nryg6kq6w7236ae.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-thread-pool-with-continuation-waits-keeps-work--3nryg6kq6w7236ae.md new file mode 100644 index 00000000..0c34ad1e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-a-thread-pool-with-continuation-waits-keeps-work--3nryg6kq6w7236ae.md @@ -0,0 +1,12 @@ +--- +id: fnd-a-thread-pool-with-continuation-waits-keeps-work--3nryg6kq6w7236ae +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: A thread pool with continuation waits keeps workers 93% busy +kind: measurement +created_at: '2026-04-02T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-priority-lanes-still-leave-workers-28-idle-durin--fhswesk5c086dk1y + - iss-crash-triage-stalls-because-fiber-stacks-are-unr--dyr12bpb18sav85g +--- +Kenji Arakawa prototyped a thread pool where a wait registers a continuation job instead of blocking. The read API now has completion callbacks, which it lacked in October. During a tide turn, workers are idle 7% of the time, against 28% for the lane pool and 5% for fibers. Every stack in a crash dump is a normal thread stack. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-alpha-content-needs-6-2-ms-of-gull-time-per-fram--4mekgdpsdv5nk085.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-alpha-content-needs-6-2-ms-of-gull-time-per-fram--4mekgdpsdv5nk085.md new file mode 100644 index 00000000..a16f1ea7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-alpha-content-needs-6-2-ms-of-gull-time-per-fram--4mekgdpsdv5nk085.md @@ -0,0 +1,12 @@ +--- +id: fnd-alpha-content-needs-6-2-ms-of-gull-time-per-fram--4mekgdpsdv5nk085 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Alpha content needs 6.2 ms of Gull time per frame +kind: measurement +created_at: '2026-01-14T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - con-gull-script-tick-budget--4p9jp4dj1njf7q9m + - dec-keep-gull-on-the-tree-walking-interpreter--br1kgzfmw57xmm9m +--- +Alpha content has 1,200 crabs, tide-pool creatures, and 40 quest scripts. On Meridian the interpreter needs 6.2 ms per frame, three times the 2.0 ms budget. Time-slicing makes crabs visibly stutter. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb.md new file mode 100644 index 00000000..8299240c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb.md @@ -0,0 +1,11 @@ +--- +id: fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Alpha-tested foliage costs 2.1 ms in the visibility buffer +kind: measurement +created_at: '2025-11-04T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - dec-adopt-a-visibility-buffer-with-64-bit-instance-a--zwmywxyvnqzvw5xq +--- +Dune grass and kelp are alpha-tested. In the visibility buffer the alpha test runs in the raster pass with a texture fetch per pixel, and foliage on the coast benchmark goes from 0.8 ms in forward+ to 2.1 ms. Saltglass cannot live in the buffer at all, because it refracts what is behind it and needs that image first. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-archetype-iteration-takes-3-4-ms-in-the-alpha-wo--dawb9m0pa999mhpe.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-archetype-iteration-takes-3-4-ms-in-the-alpha-wo--dawb9m0pa999mhpe.md new file mode 100644 index 00000000..e9bcd396 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-archetype-iteration-takes-3-4-ms-in-the-alpha-wo--dawb9m0pa999mhpe.md @@ -0,0 +1,17 @@ +--- +id: fnd-archetype-iteration-takes-3-4-ms-in-the-alpha-wo--dawb9m0pa999mhpe +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'Archetype iteration takes 3.4 ms in the alpha world, not 1.9 ms' +kind: measurement +created_at: '2026-01-19T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-archetype-tables-iterate-transforms-2-4x-faster--3xtpgtqs17zzq6v3 +invalidates: + - fnd-archetype-tables-iterate-transforms-2-4x-faster--3xtpgtqs17zzq6v3 +--- +Rhea Valdés repeated the transform iteration test on a capture of the alpha world instead of the synthetic ecs-bench world. The September benchmark spawned every entity from a single template, so nearly all entities shared one table and the iteration was one long linear walk. That is not what a real coast looks like. + +The alpha world has 912 archetypes. Most tables hold fewer than 2,000 rows, so the iterator jumps between tables constantly and the hardware prefetcher never settles. Iterating one million transforms takes 3.4 ms on the PC dev box, not 1.9 ms. Sparse sets on the same capture take 4.9 ms, so archetype tables still win, but by 1.4x and not 2.4x. + +The join between archetype tables and sparse tags is the bigger surprise. On Skiff the join of transforms with the Submerged tag across the crab herd takes 5.1 ms, which is most of a 30 Hz frame's simulation share. The September numbers should not be quoted again. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-archetype-tables-iterate-transforms-2-4x-faster--3xtpgtqs17zzq6v3.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-archetype-tables-iterate-transforms-2-4x-faster--3xtpgtqs17zzq6v3.md new file mode 100644 index 00000000..31d80171 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-archetype-tables-iterate-transforms-2-4x-faster--3xtpgtqs17zzq6v3.md @@ -0,0 +1,15 @@ +--- +id: fnd-archetype-tables-iterate-transforms-2-4x-faster--3xtpgtqs17zzq6v3 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Archetype tables iterate transforms 2.4x faster than sparse sets +kind: measurement +created_at: '2025-09-10T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - iss-how-should-kestrel-store-entity-components--aj37s7xz78dszyzp +invalidated_by: + - fnd-archetype-iteration-takes-3-4-ms-in-the-alpha-wo--dawb9m0pa999mhpe +cites: + - cit-ecs-bench-profile-run-0909--m0zy2gppwwgsv5zh +--- +Rhea Valdés ran ecs-bench with one million entities on the PC dev box. Iterating every transform takes 1.9 ms with archetype tables and 4.6 ms with sparse sets. The cost runs the other way for structural changes: adding or removing one component costs 380 ns with archetype tables, because the row moves to a new table, and 45 ns with sparse sets. The hybrid layout sits close to the best of both. The full profile, including memory per layout, is in the attached capture. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-beta-retrospective-for-the-skiff-port--hwdfe7e67ja5r2h6.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-beta-retrospective-for-the-skiff-port--hwdfe7e67ja5r2h6.md new file mode 100644 index 00000000..9062e10a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-beta-retrospective-for-the-skiff-port--hwdfe7e67ja5r2h6.md @@ -0,0 +1,19 @@ +--- +id: fnd-beta-retrospective-for-the-skiff-port--hwdfe7e67ja5r2h6 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Beta retrospective for the Skiff port +kind: retrospective +created_at: '2026-06-22T15:00:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-kelp-high-ratio-textures-bring-the-skiff-harbor--rnzeng8fj363pr75 + - fnd-skiff-firmware-1-2-rejects-pipeline-blobs-built--pernvgb2he7m3z3y + - fnd-skiff-microsd-slows-sharply-on-full-warm-cards--p1rgh36hat2egpz3 +--- +What went well: the Kelp high-ratio switch took one week end to end and saved 900 MB, just as predicted. The 40 Hz mode cost less than feared because dynamic resolution already existed. The cert pre-check caught both failures early enough to fix them before beta. + +What went badly: twice we trusted a test that ran on a better setup than players have. The December pipeline blob test ran on the same firmware the blobs were built for. The March storage test ran on new, empty cards on a cold Skiff. Both looked fine and both were wrong. + +We also sized memory against the 9 GB figure for four months after the platform holder had hinted at a bigger system reserve. Priya Natarajan now checks the SDK release notes every Monday. + +Cost: the wrong pipeline choice cost 6 weeks of schedule: the beta slipped 6 weeks past its planned date while the team rebuilt pipelines as an on-device cache. Rule from here: run every platform test on retail firmware and on the worst hardware a player can buy. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-brine-hdr-shoulder-clips-caustics-on-800-nit-pan--xe75a0mm3sqmtk4r.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-brine-hdr-shoulder-clips-caustics-on-800-nit-pan--xe75a0mm3sqmtk4r.md new file mode 100644 index 00000000..488d1f46 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-brine-hdr-shoulder-clips-caustics-on-800-nit-pan--xe75a0mm3sqmtk4r.md @@ -0,0 +1,12 @@ +--- +id: fnd-brine-hdr-shoulder-clips-caustics-on-800-nit-pan--xe75a0mm3sqmtk4r +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Brine HDR shoulder clips caustics on 800-nit panels +kind: measurement +created_at: '2026-09-07T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - con-meridian-hdr-certification-requirements--nx9pmkwjjvxy1smf + - dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e +--- +On panels calibrated to 800 nits, the HDR shoulder starting at 1,000 nits never begins before the panel peak, so caustics clip hard at 800. The certification lab uses an 800-nit panel for the ramp test. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-bytecode-swap-at-frame-boundaries-reloads-94-of--rqrk03vvef5jgv2x.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-bytecode-swap-at-frame-boundaries-reloads-94-of--rqrk03vvef5jgv2x.md new file mode 100644 index 00000000..de46dc4b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-bytecode-swap-at-frame-boundaries-reloads-94-of--rqrk03vvef5jgv2x.md @@ -0,0 +1,14 @@ +--- +id: fnd-bytecode-swap-at-frame-boundaries-reloads-94-of--rqrk03vvef5jgv2x +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Bytecode swap at frame boundaries reloads 94% of edits +kind: measurement +created_at: '2026-02-20T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3 + - iss-gull-hot-reload-rejects-struct-layout-changes--3v2w2f9hg2gwy6aj +invalidated_by: + - fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws +--- +Marta Lindqvist replayed 500 script edits from the design team's history against a reload prototype that swaps function bytecode between frames. 94% applied cleanly; the rest changed struct layouts. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-caustics-flicker-at-3-to-6-hz-under-tern--9je5rqt89es3rcz4.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-caustics-flicker-at-3-to-6-hz-under-tern--9je5rqt89es3rcz4.md new file mode 100644 index 00000000..857365bb --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-caustics-flicker-at-3-to-6-hz-under-tern--9je5rqt89es3rcz4.md @@ -0,0 +1,14 @@ +--- +id: fnd-caustics-flicker-at-3-to-6-hz-under-tern--9je5rqt89es3rcz4 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Caustics flicker at 3 to 6 Hz under Tern +kind: measurement +created_at: '2026-01-23T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e + - dec-splat-caustic-photons-from-a-sun-space-map--gz19gensacx2zh1w +cites: + - cit-trace-caustic-luminance-under-tern--55mm8xmemz44s5ah +--- +Photon jitter changes the caustic pattern every frame. At 720p internal resolution Tern cannot tell new caustic detail from noise, clamps it away on some frames and keeps it on others, and the sand under the dunes flickers at 3 to 6 Hz. Full trace attached. At native resolution there is no visible flicker. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-cell-size-sweep-for-the-768-m-streaming-radius--q3qfh6cp8a0k0f7g.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-cell-size-sweep-for-the-768-m-streaming-radius--q3qfh6cp8a0k0f7g.md new file mode 100644 index 00000000..5ab8569f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-cell-size-sweep-for-the-768-m-streaming-radius--q3qfh6cp8a0k0f7g.md @@ -0,0 +1,12 @@ +--- +id: fnd-cell-size-sweep-for-the-768-m-streaming-radius--q3qfh6cp8a0k0f7g +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Cell size sweep for the 768 m streaming radius +kind: measurement +created_at: '2025-09-25T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - con-streaming-pool-budget--632bkbs79bwj4cr5 + - iss-what-cell-size-should-the-world-partition-use--k3bncp2dabkekydq +--- +Kenji Arakawa swept three cell sizes over the coast test map. With 512 m cells, 25 cells are resident at about 96 MB each, 2.4 GB in total, which breaks the 2.0 GB streaming pool. With 256 m cells, 49 cells are resident at about 24 MB each, 1.18 GB. With 128 m cells, 169 cells are resident; content per cell is small, but per-cell overhead was not measured yet. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-clamp-exclusion-removes-caustic-flicker-but-ghos--2m4pgjzbz7ze93j5.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-clamp-exclusion-removes-caustic-flicker-but-ghos--2m4pgjzbz7ze93j5.md new file mode 100644 index 00000000..50ce4018 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-clamp-exclusion-removes-caustic-flicker-but-ghos--2m4pgjzbz7ze93j5.md @@ -0,0 +1,11 @@ +--- +id: fnd-clamp-exclusion-removes-caustic-flicker-but-ghos--2m4pgjzbz7ze93j5 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Clamp exclusion removes caustic flicker but ghosts caustics for 9 frames +kind: measurement +created_at: '2026-08-12T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4 +--- +With caustic light outside the history clamp, the 3 to 6 Hz flicker is gone in the dunes noon trace. But when a cliff shadow or the player crosses the caustics, the old pattern lingers for 9 frames. Tomasz Brandt thinks a reactive mask could fix it, as it did for refraction; nobody has tried yet. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-co-op-netcode-where-things-stand-in-february--8b4mdjfnrqfw5d9d.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-co-op-netcode-where-things-stand-in-february--8b4mdjfnrqfw5d9d.md new file mode 100644 index 00000000..7ffd1d6c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-co-op-netcode-where-things-stand-in-february--8b4mdjfnrqfw5d9d.md @@ -0,0 +1,36 @@ +--- +id: fnd-co-op-netcode-where-things-stand-in-february--8b4mdjfnrqfw5d9d +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: 'Co-op netcode: where things stand in February' +kind: compaction +created_at: '2026-02-18T16:00:00Z' +created_by: Sofia Marchetti +derives_from: + - dec-hash-tide-physics-and-gull-state-every-30-frames--yqf2m6hqbjhwvkzq + - dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4 + - dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk + - fnd-a-rollback-snapshot-is-38-kb-per-player-per-fram--wa18f2emyakt0tgx + - fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf + - fnd-two-player-rollback-co-op-ran-the-vertical-slice--p51cfe0dn47vfkya + - iss-late-join-during-a-tide-surge-desyncs-the-joinin--mya93va0n7s8g7cj + - rsk-re-simulation-cost-could-blow-the-skiff-frame-bu--sk2njsp170a3qwyf +covers: + - con-co-op-must-stay-playable-at-150-ms-round-trip--q330d4g95q7jtt4q@live + - con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g@live + - >- + dec-hash-tide-physics-and-gull-state-every-30-frames--yqf2m6hqbjhwvkzq@accepted + - dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4@accepted + - >- + dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk@accepted + - fnd-a-rollback-snapshot-is-38-kb-per-player-per-fram--wa18f2emyakt0tgx@live + - fnd-lockstep-playtest-at-150-ms-round-trip--hjp498j88mtdbnhs@live + - fnd-one-frame-of-input-delay-is-invisible-in-playtes--azn8kxedq3pp1vq0@live + - fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf@live + - fnd-skiff-co-op-sessions-over-wi-fi-see-180-ms-round--4ttevy0e2zfjqw18@live + - fnd-the-first-checksum-mismatch-came-from-gull-rando--wrrrkwvq1d0pc35p@live + - fnd-two-player-rollback-co-op-ran-the-vertical-slice--p51cfe0dn47vfkya@live + - iss-how-should-co-op-keep-up-to-four-players-in-sync--92t2zfsy3etfzr89@open + - iss-late-join-during-a-tide-surge-desyncs-the-joinin--mya93va0n7s8g7cj@open + - rsk-re-simulation-cost-could-blow-the-skiff-frame-bu--sk2njsp170a3qwyf@open +--- +Rollback is the chosen co-op sync model; lockstep was rejected after the 150 ms playtest. The window is 6 frames with 1 frame of input delay, which covers p95 Skiff Wi-Fi. Measured rollback cost is 1.1 ms for 4 frames on PC, so a 6-frame rollback should stay under 2 ms. Desync checksums work. Open: late join during a tide surge, and the Risk that tide re-simulation costs more once tides join the snapshot. Next: profile on Skiff with tides running, then plan for alpha. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-concept-match-review-11-of-14-key-shots-pass-und--1sv3grvmm4hbtyf5.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-concept-match-review-11-of-14-key-shots-pass-und--1sv3grvmm4hbtyf5.md new file mode 100644 index 00000000..8b7b1c5a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-concept-match-review-11-of-14-key-shots-pass-und--1sv3grvmm4hbtyf5.md @@ -0,0 +1,11 @@ +--- +id: fnd-concept-match-review-11-of-14-key-shots-pass-und--1sv3grvmm4hbtyf5 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Concept match review: 11 of 14 key shots pass under the Brine curve' +kind: survey +created_at: '2026-03-31T10:00:00Z' +created_by: Dara Whitlock +derives_from: + - rsk-artists-cannot-match-concept-paintings-under-the--6cfh9vkamn0kbtcx +--- +The art review compared 14 key shots against the concept paintings. 11 pass. The three that fail are night harbor shots, and art direction chose to repaint the concepts rather than bend the curve. Dara Whitlock accepted the remaining gap. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-cpu-culling-and-draw-submission-cost-3-2-ms-on-t--1y0j1b9p0zjh0n1g.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-cpu-culling-and-draw-submission-cost-3-2-ms-on-t--1y0j1b9p0zjh0n1g.md new file mode 100644 index 00000000..c0a8c739 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-cpu-culling-and-draw-submission-cost-3-2-ms-on-t--1y0j1b9p0zjh0n1g.md @@ -0,0 +1,11 @@ +--- +id: fnd-cpu-culling-and-draw-submission-cost-3-2-ms-on-t--1y0j1b9p0zjh0n1g +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: CPU culling and draw submission cost 3.2 ms on the dunes benchmark +kind: measurement +created_at: '2025-10-13T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-how-should-lantern-cull-geometry--jnrp9qd2fywqvqgw +--- +Frustum culling, LOD selection and draw submission for the dunes benchmark take 3.2 ms of render-thread time on Meridian. A GPU-driven prototype brings submission to 0.6 ms with two-phase occlusion. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-cross-platform-cloud-saves-need-platform-agreeme--4qgfc1a4nq4padvz.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-cross-platform-cloud-saves-need-platform-agreeme--4qgfc1a4nq4padvz.md new file mode 100644 index 00000000..10fac585 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-cross-platform-cloud-saves-need-platform-agreeme--4qgfc1a4nq4padvz.md @@ -0,0 +1,11 @@ +--- +id: fnd-cross-platform-cloud-saves-need-platform-agreeme--4qgfc1a4nq4padvz +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Cross-platform cloud saves need platform agreements we do not have +kind: survey +created_at: '2026-06-02T10:00:00Z' +created_by: Dara Whitlock +derives_from: + - iss-cross-platform-cloud-saves-are-unplanned--5bk0k4wrgj42ztfy +--- +Each platform holder must approve cross-platform save transfer, and none of the three agreements is in place. Dara Whitlock moves cloud saves to a post-launch patch. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-delta-saves-reach-6-2-mb-after-40-hours--8g1j04z0vhjwrkyn.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-delta-saves-reach-6-2-mb-after-40-hours--8g1j04z0vhjwrkyn.md new file mode 100644 index 00000000..a5939c10 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-delta-saves-reach-6-2-mb-after-40-hours--8g1j04z0vhjwrkyn.md @@ -0,0 +1,13 @@ +--- +id: fnd-delta-saves-reach-6-2-mb-after-40-hours--8g1j04z0vhjwrkyn +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Delta saves reach 6.2 MB after 40 hours +kind: measurement +created_at: '2026-05-20T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - rsk-delta-saves-may-outgrow-console-save-slots--8re48mgme427hzds +cites: + - cit-save-size-sweep-from-the-playtest-save-corpus--5d385vtvgmy4qtmz +--- +Across the playtest save corpus, delta saves grow linearly, about 0.15 MB per hour. A 40-hour save is 6.2 MB. Every platform's save slot allows far more than that, so size is not a problem for any realistic playthrough. The sweep also lists load times on Skiff. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-deltas-saved-at-low-tide-replay-wrongly-at-high--25b4vwytarw8ej50.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-deltas-saved-at-low-tide-replay-wrongly-at-high--25b4vwytarw8ej50.md new file mode 100644 index 00000000..d16d8c7c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-deltas-saved-at-low-tide-replay-wrongly-at-high--25b4vwytarw8ej50.md @@ -0,0 +1,19 @@ +--- +id: fnd-deltas-saved-at-low-tide-replay-wrongly-at-high--25b4vwytarw8ej50 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Deltas saved at low tide replay wrongly at high tide +kind: measurement +created_at: '2026-02-18T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw +invalidates: + - dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw +--- +The delta format assumes that a player change means the same thing at any tide. It does not. A player who digs out a salvage chest at low tide changes sand that only exists at low tide. The delta stores the dig against the tide-free baseline, where that sand has a different height. + +On load, the game applies the delta to the baseline and then runs the tide forward to the saved time. The tide rebuilds the sand on top of the dig, and the chest is buried again or pushed sideways by the terrain solver. + +QA reproduced this in 31 of 50 saves taken at low tide and 4 of 50 taken at high tide. Saves taken mid-turn were not tested. + +In the worst case the terrain solver pushed a salvage chest 11 m inland, onto a ridge the player could not reach. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-each-save-upgrade-step-costs-under-5-ms--qs1rweqqgj7kweem.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-each-save-upgrade-step-costs-under-5-ms--qs1rweqqgj7kweem.md new file mode 100644 index 00000000..fbdb67f3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-each-save-upgrade-step-costs-under-5-ms--qs1rweqqgj7kweem.md @@ -0,0 +1,13 @@ +--- +id: fnd-each-save-upgrade-step-costs-under-5-ms--qs1rweqqgj7kweem +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Each save upgrade step costs under 5 ms +kind: measurement +created_at: '2026-03-11T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8 +invalidated_by: + - fnd-a-40-hour-save-takes-1-9-s-to-upgrade-through-si--gw6ahjtssbrm2jwx +--- +A prototype upgrade step that renames one delta field runs in 3 ms on a 2-hour test save. Marta Lindqvist expects every step to cost under 5 ms, so a chain of upgrades is free at load time. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-fibers-hide-waits-but-need-custom-stacks-and-deb--0ynync38mj13w03k.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-fibers-hide-waits-but-need-custom-stacks-and-deb--0ynync38mj13w03k.md new file mode 100644 index 00000000..c782e0bb --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-fibers-hide-waits-but-need-custom-stacks-and-deb--0ynync38mj13w03k.md @@ -0,0 +1,11 @@ +--- +id: fnd-fibers-hide-waits-but-need-custom-stacks-and-deb--0ynync38mj13w03k +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Fibers hide waits but need custom stacks and debugger support +kind: survey +created_at: '2025-09-08T15:00:00Z' +created_by: Rhea Valdés +derives_from: + - iss-which-job-model-should-the-kestrel-scheduler-use--7ghtksxxrxcsxn3q +--- +Rhea Valdés surveyed two models. A work-stealing thread pool is simple and every debugger understands it, but a job that waits blocks its worker. Fibers let a job yield on a wait and resume later on any worker, but they need custom stack allocation, and the Meridian and Skiff debuggers show fiber stacks only through a vendor plug-in that is still in beta. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-field-captures-show-forecast-eviction-cuts-reloa--ee6m7fwv4798jdmv.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-field-captures-show-forecast-eviction-cuts-reloa--ee6m7fwv4798jdmv.md new file mode 100644 index 00000000..af87077f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-field-captures-show-forecast-eviction-cuts-reloa--ee6m7fwv4798jdmv.md @@ -0,0 +1,22 @@ +--- +id: fnd-field-captures-show-forecast-eviction-cuts-reloa--ee6m7fwv4798jdmv +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'Field captures show forecast eviction cuts reloads by 22%, not 63%' +kind: measurement +created_at: '2026-03-04T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg + - fnd-simulated-forecast-eviction-cuts-reloads-by-63--7c086ee2h8dw247k +invalidates: + - fnd-simulated-forecast-eviction-cuts-reloads-by-63--7c086ee2h8dw247k +cites: + - cit-pool-occupancy-capture-pool-occupancy-0303--5k8w8xj2a4g21wtm +--- +Kenji Arakawa captured pool behaviour across twelve alpha playtest sessions and replayed the same sessions under LRU for comparison. Forecast eviction is better, but nowhere near the simulation's figure: it cuts reloads by 22%, not 63%. + +The tide half of the score works as designed. No cell the tide exposed had to reload during a turn. The distance half is the problem. Each resident cell is scored by straight-line distance from the nearest player, and players do not move like that. + +The simulation assumed players walk in straight lines toward a goal. Real players double back to pick up salvage, look at caustics, or wait for a friend, so a cell evicted for being behind the player is often needed again a minute later. In the field captures, players reversed direction 3.4 times per minute on average. + +The decision stands, because 22% is still a gain and the tide protection matters most. The 63% figure should not be quoted. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-firmware-1-2-skiff-dev-kits-arrived--7dzaq12qessxaasd.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-firmware-1-2-skiff-dev-kits-arrived--7dzaq12qessxaasd.md new file mode 100644 index 00000000..39300e83 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-firmware-1-2-skiff-dev-kits-arrived--7dzaq12qessxaasd.md @@ -0,0 +1,11 @@ +--- +id: fnd-firmware-1-2-skiff-dev-kits-arrived--7dzaq12qessxaasd +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Firmware 1.2 Skiff dev kits arrived +kind: survey +created_at: '2026-03-16T14:00:00Z' +created_by: Dara Whitlock +derives_from: + - iss-no-skiff-dev-kits-on-firmware-1-2--3qkawq17a60504j7 +--- +Four dev kits on firmware 1.2 arrived on 2026-03-16. Two go to ports, one to render, one to QA. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-fixed-point-tide-step-costs-0-3-ms-on-meridian--jzxe4pa936rxawns.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-fixed-point-tide-step-costs-0-3-ms-on-meridian--jzxe4pa936rxawns.md new file mode 100644 index 00000000..47d6c429 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-fixed-point-tide-step-costs-0-3-ms-on-meridian--jzxe4pa936rxawns.md @@ -0,0 +1,11 @@ +--- +id: fnd-fixed-point-tide-step-costs-0-3-ms-on-meridian--jzxe4pa936rxawns +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Fixed-point tide step costs 0.3 ms on Meridian +kind: measurement +created_at: '2025-12-02T11:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e +--- +One fixed-point tide step costs 0.3 ms on Meridian, against 0.2 ms for the float step. Meridian's wider multiplier hides most of the cost. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-fixed-point-tide-step-costs-0-9-ms-on-skiff--mfc73bg9wwaxtfra.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-fixed-point-tide-step-costs-0-9-ms-on-skiff--mfc73bg9wwaxtfra.md new file mode 100644 index 00000000..a2e32a53 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-fixed-point-tide-step-costs-0-9-ms-on-skiff--mfc73bg9wwaxtfra.md @@ -0,0 +1,11 @@ +--- +id: fnd-fixed-point-tide-step-costs-0-9-ms-on-skiff--mfc73bg9wwaxtfra +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Fixed-point tide step costs 0.9 ms on Skiff +kind: measurement +created_at: '2025-12-02T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e +--- +One fixed-point tide step costs 0.9 ms on Skiff, against 0.4 ms for the old float step. Most of the extra time is 64-bit multiplies in the wave height field. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-fixed-point-tides-match-bit-for-bit-across-all-p--kb3ssw5190e93r4m.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-fixed-point-tides-match-bit-for-bit-across-all-p--kb3ssw5190e93r4m.md new file mode 100644 index 00000000..44e90d90 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-fixed-point-tides-match-bit-for-bit-across-all-p--kb3ssw5190e93r4m.md @@ -0,0 +1,12 @@ +--- +id: fnd-fixed-point-tides-match-bit-for-bit-across-all-p--kb3ssw5190e93r4m +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Fixed-point tides match bit for bit across all platforms for 4 hours +kind: measurement +created_at: '2025-12-03T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e + - iss-tide-heights-differ-between-co-op-peers--gqmq087dr478v1px +--- +A soak test ran the fixed-point tide simulation on PC, Meridian, and Skiff side by side for 4 hours, almost three full days of game time. Every tide state hash matched on every step. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-flaky-nightly-builds-are-compiler-processes-runn--1sabnpb1s7004jkb.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-flaky-nightly-builds-are-compiler-processes-runn--1sabnpb1s7004jkb.md new file mode 100644 index 00000000..5e88e848 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-flaky-nightly-builds-are-compiler-processes-runn--1sabnpb1s7004jkb.md @@ -0,0 +1,16 @@ +--- +id: fnd-flaky-nightly-builds-are-compiler-processes-runn--1sabnpb1s7004jkb +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: >- + Flaky nightly builds are compiler processes running out of memory on agents 7 + and 11 +kind: diagnosis +created_at: '2026-02-24T09:00:00Z' +created_by: Liam O'Connell +derives_from: + - dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6 + - iss-nightly-builds-fail-about-1-in-9-runs-with-shade--ka2xgkfgaepemgbh +invalidates: + - fnd-flaky-nightly-builds-trace-to-cache-server-fetch--v4wsxzj1x72zz8rs +--- +The 30-second fetch timeout did not help: 4 of the next 31 nightly builds still failed. Every failed job since December ran on agent 7 or agent 11, the two agents with 32 GB of RAM instead of 64 GB. During the 02:00 burst those agents run 16 parallel compiles, the compiler hits the memory limit, and the job hangs until it times out. The slow cache fetches were a symptom of swapping, not the cause. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-flaky-nightly-builds-trace-to-cache-server-fetch--v4wsxzj1x72zz8rs.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-flaky-nightly-builds-trace-to-cache-server-fetch--v4wsxzj1x72zz8rs.md new file mode 100644 index 00000000..f993a44d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-flaky-nightly-builds-trace-to-cache-server-fetch--v4wsxzj1x72zz8rs.md @@ -0,0 +1,13 @@ +--- +id: fnd-flaky-nightly-builds-trace-to-cache-server-fetch--v4wsxzj1x72zz8rs +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Flaky nightly builds trace to cache server fetch timeouts +kind: diagnosis +created_at: '2025-12-05T11:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-nightly-builds-fail-about-1-in-9-runs-with-shade--ka2xgkfgaepemgbh +invalidated_by: + - fnd-flaky-nightly-builds-are-compiler-processes-runn--1sabnpb1s7004jkb +--- +The failed jobs all logged a cache fetch that took longer than the 5-second fetch timeout. The cache server's network card peaks at 94% during the 02:00 burst. Tomasz Brandt thinks the slow fetches cascade into job timeouts. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-float-tide-heights-drift-apart-between-pc-and-me--7jb0fg4b5xzr7q5e.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-float-tide-heights-drift-apart-between-pc-and-me--7jb0fg4b5xzr7q5e.md new file mode 100644 index 00000000..39eebb7b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-float-tide-heights-drift-apart-between-pc-and-me--7jb0fg4b5xzr7q5e.md @@ -0,0 +1,15 @@ +--- +id: fnd-float-tide-heights-drift-apart-between-pc-and-me--7jb0fg4b5xzr7q5e +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Float tide heights drift apart between PC and Meridian within 9 minutes +kind: measurement +created_at: '2025-10-20T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - iss-tide-heights-differ-between-co-op-peers--gqmq087dr478v1px +supersedes: + - fnd-float-tide-heights-drift-apart-between-pcs-after--emk2nb56tej8t2jx +superseded_by: + - fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss +--- +Across platforms the drift comes sooner. PC against Meridian passes 1 cm within 9 minutes. The Meridian compiler contracts multiply-adds into fused instructions, which round differently from the PC build. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-float-tide-heights-drift-apart-between-pcs-after--emk2nb56tej8t2jx.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-float-tide-heights-drift-apart-between-pcs-after--emk2nb56tej8t2jx.md new file mode 100644 index 00000000..d359959d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-float-tide-heights-drift-apart-between-pcs-after--emk2nb56tej8t2jx.md @@ -0,0 +1,13 @@ +--- +id: fnd-float-tide-heights-drift-apart-between-pcs-after--emk2nb56tej8t2jx +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Float tide heights drift apart between PCs after 18 minutes +kind: measurement +created_at: '2025-10-10T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - iss-tide-heights-differ-between-co-op-peers--gqmq087dr478v1px +superseded_by: + - fnd-float-tide-heights-drift-apart-between-pc-and-me--7jb0fg4b5xzr7q5e +--- +Marta Lindqvist ran the same tide simulation on two PCs with different CPUs and the same binary. Heights match to the bit for the first minutes, then drift: the difference passes 1 cm, enough to flip a walkable tile, after 18 minutes. The likely cause is differing vector code paths in the math library. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-float-tides-drift-apart-between-machines-within--43a3rsxjp296ns6b.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-float-tides-drift-apart-between-machines-within--43a3rsxjp296ns6b.md new file mode 100644 index 00000000..4bc0d77e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-float-tides-drift-apart-between-machines-within--43a3rsxjp296ns6b.md @@ -0,0 +1,12 @@ +--- +id: fnd-float-tides-drift-apart-between-machines-within--43a3rsxjp296ns6b +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Float tides drift apart between machines within six minutes +kind: measurement +created_at: '2025-10-29T14:00:00Z' +created_by: Sofia Marchetti +retracted: true +retracted_at: '2025-10-30T09:00:00.000Z' +retracted_reason: 'Duplicate of Marta Lindqvist''s measurement, copied from the netcode channel.' +--- +Copied from the netcode channel: tides drift within six minutes across machines. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss.md new file mode 100644 index 00000000..910638a7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss.md @@ -0,0 +1,15 @@ +--- +id: fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Float tides drift apart between machines within 6 minutes +kind: measurement +created_at: '2025-10-29T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - iss-tide-heights-differ-between-co-op-peers--gqmq087dr478v1px +supersedes: + - fnd-float-tide-heights-drift-apart-between-pc-and-me--7jb0fg4b5xzr7q5e +cites: + - cit-tide-drift-log-tide-drift-1028--3dpqqgs1ep6qm1wc +--- +With Skiff in the mix, float tides drift apart between machines within 6 minutes. The worst pair is PC against Skiff, which passes the 1 cm threshold first. Two causes stack: fused multiply-add contraction, and a Skiff sin() that differs by one ulp. Any co-op session longer than 6 minutes will disagree about walkable ground. The per-pair numbers and the first tile to flip are in the drift log. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-forward-overdraw-on-saltglass-cliffs--q9n76frhz7a7ssnp.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-forward-overdraw-on-saltglass-cliffs--q9n76frhz7a7ssnp.md new file mode 100644 index 00000000..3e0d4f24 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-forward-overdraw-on-saltglass-cliffs--q9n76frhz7a7ssnp.md @@ -0,0 +1,13 @@ +--- +id: fnd-forward-overdraw-on-saltglass-cliffs--q9n76frhz7a7ssnp +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Forward+ overdraw on saltglass cliffs +kind: measurement +created_at: '2025-09-10T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-should-lantern-replace-clustered-forward-with-a--7c8zxrdsj59q8hmd +cites: + - cit-capture-forward-cliffs-benchmark--2ykf7yxr2qmwjz23 +--- +On the cliffs benchmark, forward+ opaque shading takes 7.9 ms of the 16.6 ms Meridian frame. Quad overdraw averages 3.4x because the cliff meshes are dense with sub-pixel triangles. Light culling itself is cheap at 0.6 ms; the cost is shading quads that never reach the screen. The full capture is attached. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-gi-takes-13-percent-of-the-quality-mode-frame--afshqnfm209zrae9.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-gi-takes-13-percent-of-the-quality-mode-frame--afshqnfm209zrae9.md new file mode 100644 index 00000000..ca036932 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-gi-takes-13-percent-of-the-quality-mode-frame--afshqnfm209zrae9.md @@ -0,0 +1,12 @@ +--- +id: fnd-gi-takes-13-percent-of-the-quality-mode-frame--afshqnfm209zrae9 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: GI takes 13 percent of the quality-mode frame +kind: analysis +created_at: '2025-11-05T10:00:00Z' +created_by: Ines Okafor +derives_from: + - con-frame-budget--f5qxxq5572878wrp + - fnd-sdf-gi-costs-2-2-ms-on-meridian--r7t7zy97nwxxxctd +--- +At 2.2 ms, SDF GI is 13 percent of the 16.6 ms Meridian frame. Ines Okafor uses this share to plan the other passes: shadows, refraction and Tern together may take 5 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-gull-s-tree-walking-interpreter-spends-1-8-ms-on--bj1ge76d3wy5aqq3.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-gull-s-tree-walking-interpreter-spends-1-8-ms-on--bj1ge76d3wy5aqq3.md new file mode 100644 index 00000000..e7de25ea --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-gull-s-tree-walking-interpreter-spends-1-8-ms-on--bj1ge76d3wy5aqq3.md @@ -0,0 +1,11 @@ +--- +id: fnd-gull-s-tree-walking-interpreter-spends-1-8-ms-on--bj1ge76d3wy5aqq3 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Gull's tree-walking interpreter spends 1.8 ms on 300 crabs +kind: measurement +created_at: '2025-10-15T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - iss-should-gull-run-on-a-tree-walking-interpreter-or--dkfsjk9enx1myhff +--- +The slice map's 300 crabs run their AI in Gull. The tree-walking interpreter spends 1.8 ms per frame on them on Meridian, about 11 times what the same logic costs in C++. Hot reload is trivial: the interpreter just reparses the edited file. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-gull-s-two-dedicated-threads-sit-idle-70-of-each--qekr5vjr9pand9rs.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-gull-s-two-dedicated-threads-sit-idle-70-of-each--qekr5vjr9pand9rs.md new file mode 100644 index 00000000..d2e85b81 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-gull-s-two-dedicated-threads-sit-idle-70-of-each--qekr5vjr9pand9rs.md @@ -0,0 +1,11 @@ +--- +id: fnd-gull-s-two-dedicated-threads-sit-idle-70-of-each--qekr5vjr9pand9rs +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Gull's two dedicated threads sit idle 70% of each frame +kind: measurement +created_at: '2026-06-18T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h +--- +On the beta build the two Gull threads are busy only 30% of the frame on Meridian and 34% on Skiff, while the job pool is saturated during tide turns. With fibers gone, a Gull job never resumes on another thread, so the thread-local problem no longer applies. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-halcyon-vendor-upscaler-quality-and-platform-cov--xz7hp3e1m1mh44v4.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-halcyon-vendor-upscaler-quality-and-platform-cov--xz7hp3e1m1mh44v4.md new file mode 100644 index 00000000..2ce639a3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-halcyon-vendor-upscaler-quality-and-platform-cov--xz7hp3e1m1mh44v4.md @@ -0,0 +1,11 @@ +--- +id: fnd-halcyon-vendor-upscaler-quality-and-platform-cov--xz7hp3e1m1mh44v4 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Halcyon vendor upscaler: quality and platform coverage' +kind: survey +created_at: '2025-10-16T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v +--- +Halcyon gives cleaner disocclusions than Tern on PC and costs 1.2 ms at 4K output on Meridian. The SDK ships for PC and Meridian only; there is no Skiff build and the vendor gives no date for one. The license is per title and needs legal review. Halcyon is a closed binary, so saltglass fixes would mean filing vendor tickets. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-harbor-district-needs-1-460-pipelines-on-skiff--dwd5ry1wqaeacmpn.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-harbor-district-needs-1-460-pipelines-on-skiff--dwd5ry1wqaeacmpn.md new file mode 100644 index 00000000..6c9e0f1b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-harbor-district-needs-1-460-pipelines-on-skiff--dwd5ry1wqaeacmpn.md @@ -0,0 +1,13 @@ +--- +id: fnd-harbor-district-needs-1-460-pipelines-on-skiff--dwd5ry1wqaeacmpn +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Harbor district needs 1,460 pipelines on Skiff' +kind: measurement +created_at: '2025-12-09T10:30:00Z' +created_by: Priya Natarajan +derives_from: + - iss-first-visit-hitches-of-45-to-190-ms-on-skiff--jcraqy468yw51kpf +cites: + - cit-skiff-pipeline-compile-capture-build-3810--2ybmweekyepbf8s4 +--- +The harbor district draws 1,460 unique graphics pipelines. Each first compile on Skiff takes 45 to 190 ms, median 72 ms. The capture covers the harbor, the dunes, and the ruins. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-harbor-district-peaks-at-8-6-gb-on-skiff--vccxye8jy3mkba2v.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-harbor-district-peaks-at-8-6-gb-on-skiff--vccxye8jy3mkba2v.md new file mode 100644 index 00000000..391461fb --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-harbor-district-peaks-at-8-6-gb-on-skiff--vccxye8jy3mkba2v.md @@ -0,0 +1,22 @@ +--- +id: fnd-harbor-district-peaks-at-8-6-gb-on-skiff--vccxye8jy3mkba2v +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Harbor district peaks at 8.6 GB on Skiff +kind: measurement +created_at: '2026-02-18T15:00:00Z' +created_by: Kenji Arakawa +derives_from: + - con-skiff-memory-budget--nf7qbhsnmcn6v479 + - rsk-skiff-runs-out-of-memory-in-dense-districts--p5pv42sgezzjhpfz +invalidates: + - fnd-skiff-slice-build-peaks-at-6-9-gb--5hqgdkdbk2tsn8cj +cites: + - cit-skiff-harbor-memory-capture-build-4127--20svcfra9jy1hd1d +--- +Kenji Arakawa and Priya Natarajan captured build 4127 on the harbor route with firmware 1.2 memory limits emulated. Peak use was 8.6 GB, 614 MB over the 8 GB Skiff memory budget, before counting the 300 MB safety margin. + +Most of the growth since the vertical slice came from audio banks, which grew by 388 MB when the harbor ambience was split per tide state, and from the tide simulation, which now double buffers two tide cells while the tide turns. The slice capture missed that second tide cell entirely because it ran with one cell loaded at a time. + +The peak lasts about 4 seconds, during the tide turn. Outside it the harbor sits near 7.9 GB, which is still too close to the budget to ship. + +Next step: the largest single category is the place to cut, not the fastest-growing one. The full per-category numbers are in the attached capture. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-host-authoritative-spike-keeps-tides-off-the-cli--dp9vx6afks514js6.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-host-authoritative-spike-keeps-tides-off-the-cli--dp9vx6afks514js6.md new file mode 100644 index 00000000..41627949 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-host-authoritative-spike-keeps-tides-off-the-cli--dp9vx6afks514js6.md @@ -0,0 +1,12 @@ +--- +id: fnd-host-authoritative-spike-keeps-tides-off-the-cli--dp9vx6afks514js6 +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Host-authoritative spike keeps tides off the client CPU +kind: measurement +created_at: '2026-03-31T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g + - fnd-re-running-tides-every-rollback-frame-costs-4-8--tp4gxe8prh0bh9h4 +--- +Marta Lindqvist built a two-day host-authoritative spike on Shoal-01 with one PC host and one Skiff client. The Skiff client never runs the tide step, so its simulation cost fell from 7.7 ms to 1.4 ms per frame. At 150 ms round trip the client sees tide edges correct by up to half a cell; Marta Lindqvist thinks blending can hide it. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws.md new file mode 100644 index 00000000..6416e6a1 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws.md @@ -0,0 +1,15 @@ +--- +id: fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Hot reload drops suspended Gull coroutines +kind: measurement +created_at: '2026-05-18T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42 + - fnd-bytecode-swap-at-frame-boundaries-reloads-94-of--rqrk03vvef5jgv2x +invalidates: + - fnd-bytecode-swap-at-frame-boundaries-reloads-94-of--rqrk03vvef5jgv2x + - fnd-world-core-state-at-alpha--tkbsm4867h65jqq8 +--- +The 94% figure replayed edits on idle scripts. In real sessions most creature scripts are suspended coroutines waiting on a timer or a tide event. A suspended coroutine holds a return address into the old bytecode; after a swap it resumes into the new bytecode at a wrong offset, so the runtime kills it. Logged over two weeks of design sessions, only 71% of reloads kept every script running. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-decodes-at-1-1-gb-s-on-skiff-with-a-cold-ca--vef244qjn2mjf07x.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-decodes-at-1-1-gb-s-on-skiff-with-a-cold-ca--vef244qjn2mjf07x.md new file mode 100644 index 00000000..c4536a3e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-decodes-at-1-1-gb-s-on-skiff-with-a-cold-ca--vef244qjn2mjf07x.md @@ -0,0 +1,22 @@ +--- +id: fnd-kelp-decodes-at-1-1-gb-s-on-skiff-with-a-cold-ca--vef244qjn2mjf07x +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Kelp decodes at 1.1 GB/s on Skiff with a cold cache +kind: measurement +created_at: '2026-01-12T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-kelp-decodes-streamed-assets-at-2-9-gb-s-per-cor--32tjx83v8ky28sz4 + - rsk-kelp-s-4-mb-dictionary-may-thrash-the-skiff-cach--rv7ac1hedneqkp0v +invalidates: + - fnd-kelp-decodes-streamed-assets-at-2-9-gb-s-per-cor--32tjx83v8ky28sz4 +cites: + - cit-codec-benchmark-table-january-2026-skiff-cold-ca--sztretts5cxatw6c +--- +The October benchmark that put Kelp at 2.9 GB/s was wrong for our use. It ran on the PC dev box, it loaded Kelp's 4 MB dictionary once before the run, and it decoded every asset class back to back. The dictionary stayed hot in the PC's cache for the whole run. + +Streaming never looks like that. Cells arrive in bursts between simulation jobs, and by the time a decode job runs, simulation has evicted the dictionary. Kenji Arakawa reran the benchmark on Skiff retail units with caches flushed before each asset. + +Cold, Kelp decodes at 1.1 GB/s and Zstandard at 1.3 GB/s. Zstandard's working set is small enough that a cold start costs it little. Kelp loses on every asset class. The full table is attached. + +Kenji Arakawa repeated the cold run on three retail Skiff units, and the spread between units was under 4 percent. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-decodes-streamed-assets-at-2-9-gb-s-per-cor--32tjx83v8ky28sz4.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-decodes-streamed-assets-at-2-9-gb-s-per-cor--32tjx83v8ky28sz4.md new file mode 100644 index 00000000..1016f8ae --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-decodes-streamed-assets-at-2-9-gb-s-per-cor--32tjx83v8ky28sz4.md @@ -0,0 +1,15 @@ +--- +id: fnd-kelp-decodes-streamed-assets-at-2-9-gb-s-per-cor--32tjx83v8ky28sz4 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Kelp decodes streamed assets at 2.9 GB/s per core +kind: measurement +created_at: '2025-10-14T11:00:00Z' +created_by: Kenji Arakawa +derives_from: + - iss-which-codec-should-compress-streamed-assets--9gnh870e1qwzd28r +invalidated_by: + - fnd-kelp-decodes-at-1-1-gb-s-on-skiff-with-a-cold-ca--vef244qjn2mjf07x +cites: + - cit-codec-benchmark-table-october-2025--wg58ryzjhtpaca3x +--- +On the PC dev box, Kelp decodes streamed assets at 2.9 GB/s per core with a 3.1:1 ratio. Zstandard at level 9 decodes at 1.4 GB/s with 2.8:1. LZ4 decodes fastest, 3.8 GB/s, but its 2.1:1 ratio would grow the install by a third. The per-class table is attached. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-decodes-streamed-assets-at-29-gb-s-per-core--9wkngsymce4v33pf.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-decodes-streamed-assets-at-29-gb-s-per-core--9wkngsymce4v33pf.md new file mode 100644 index 00000000..cd444b77 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-decodes-streamed-assets-at-29-gb-s-per-core--9wkngsymce4v33pf.md @@ -0,0 +1,12 @@ +--- +id: fnd-kelp-decodes-streamed-assets-at-29-gb-s-per-core--9wkngsymce4v33pf +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Kelp decodes streamed assets at 29 GB/s per core +kind: measurement +created_at: '2025-10-14T10:00:00Z' +created_by: Kenji Arakawa +retracted: true +retracted_at: '2025-10-14T11:05:00.000Z' +retracted_reason: 'Unit typo: 29 GB/s should read 2.9 GB/s; the corrected finding replaces it.' +--- +Kelp decodes streamed assets at 29 GB/s per core on the PC dev box. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-high-ratio-textures-bring-the-skiff-harbor--rnzeng8fj363pr75.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-high-ratio-textures-bring-the-skiff-harbor--rnzeng8fj363pr75.md new file mode 100644 index 00000000..449ce94b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-high-ratio-textures-bring-the-skiff-harbor--rnzeng8fj363pr75.md @@ -0,0 +1,11 @@ +--- +id: fnd-kelp-high-ratio-textures-bring-the-skiff-harbor--rnzeng8fj363pr75 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Kelp high-ratio textures bring the Skiff harbor peak to 7.7 GB +kind: measurement +created_at: '2026-02-27T16:00:00Z' +created_by: Kenji Arakawa +derives_from: + - dec-use-kelp-s-high-ratio-mode-for-skiff-textures--ztsejzpkp6nn13s5 +--- +With Kelp high-ratio textures the harbor peak falls from 8.6 GB to 7.7 GB on build 4211. That leaves 300 MB, exactly the safety margin. Any new harbor content now needs a matching cut. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-with-a-1-mb-dictionary-decodes-at-1-5-gb-s--y9v8jrxgbv6abrx5.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-with-a-1-mb-dictionary-decodes-at-1-5-gb-s--y9v8jrxgbv6abrx5.md new file mode 100644 index 00000000..c78ed009 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-with-a-1-mb-dictionary-decodes-at-1-5-gb-s--y9v8jrxgbv6abrx5.md @@ -0,0 +1,15 @@ +--- +id: fnd-kelp-with-a-1-mb-dictionary-decodes-at-1-5-gb-s--y9v8jrxgbv6abrx5 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: >- + Kelp with a 1 MB dictionary decodes at 1.5 GB/s cold on Skiff after firmware + 3.2 +kind: measurement +created_at: '2026-09-02T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew +supersedes: + - fnd-kelp-with-a-1-mb-dictionary-decodes-at-2-2-gb-s--vkt1dgk99x2xrmbs +--- +Skiff firmware 3.2 shrank the cache share given to game cores. Cold on Skiff, Kelp with the 1 MB dictionary now decodes at 1.5 GB/s, down from 2.2 GB/s. Zstandard dropped from 1.3 to 1.2 GB/s. Kelp still wins, by 1.25x instead of 1.7x. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-with-a-1-mb-dictionary-decodes-at-2-2-gb-s--vkt1dgk99x2xrmbs.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-with-a-1-mb-dictionary-decodes-at-2-2-gb-s--vkt1dgk99x2xrmbs.md new file mode 100644 index 00000000..2825955c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-kelp-with-a-1-mb-dictionary-decodes-at-2-2-gb-s--vkt1dgk99x2xrmbs.md @@ -0,0 +1,13 @@ +--- +id: fnd-kelp-with-a-1-mb-dictionary-decodes-at-2-2-gb-s--vkt1dgk99x2xrmbs +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Kelp with a 1 MB dictionary decodes at 2.2 GB/s cold on Skiff +kind: measurement +created_at: '2026-02-03T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-kelp-decodes-at-1-1-gb-s-on-skiff-with-a-cold-ca--vef244qjn2mjf07x +superseded_by: + - fnd-kelp-with-a-1-mb-dictionary-decodes-at-1-5-gb-s--y9v8jrxgbv6abrx5 +--- +Kenji Arakawa retrained Kelp's dictionary at 1 MB, which fits Skiff's cache next to the decode job. Cold on Skiff, Kelp now decodes at 2.2 GB/s, against 1.3 GB/s for Zstandard. The ratio drops from 3.1:1 to 2.9:1, which grows the install by about 7%. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c.md new file mode 100644 index 00000000..21a52df5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c.md @@ -0,0 +1,92 @@ +--- +id: fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Lantern at alpha +kind: compaction +created_at: '2026-03-05T10:00:00Z' +created_by: Ines Okafor +derives_from: + - con-frame-budget--j6vneva1g2ywj86m + - dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r + - dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e + - dec-ship-three-tern-quality-presets--jkdzxsd8wt3w91hb + - dec-use-signed-distance-field-gi--yn366zmp3k7snd9w + - dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86 + - dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4 + - dec-visibility-buffer-with-compute-material-resolve--5s2z9mqmv8vnszed + - fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr + - iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5 +supersedes: + - fnd-lantern-at-the-vertical-slice--10g62g9rfaw438qf +superseded_by: + - fnd-lantern-at-beta--53jwv4ngqk0wf9aw +covers: + - con-frame-budget--j6vneva1g2ywj86m@live + - con-meridian-hdr-certification-requirements--nx9pmkwjjvxy1smf@live + - con-one-upscaler-path-on-every-platform--f91bgj6n66kwc5d3@live + - con-render-target-memory-on-meridian--q4szajxse9c1csdv@live + - con-saltglass-must-read-at-2-km--65a67jbwhr7r73qw@live + - con-skiff-has-no-mesh-shader-support--zz4xpaqy1n0zzrj7@live + - con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s@live + - >- + dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676@accepted + - >- + dec-drop-the-far-sdf-gi-cascade-for-the-vertical-sli--0af6sjseeftc621j@accepted + - dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2@accepted + - >- + dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4@proposed + - >- + dec-expand-meshlets-to-index-buffers-in-compute-on-s--bpbtr54dgzgsjgme@accepted + - >- + dec-hard-code-hdr-paper-white-at-200-nits-on-meridia--k481dkkr69gf77rr@accepted + - dec-lock-caustic-photon-jitter-to-the-tide-phase--85x10k4h11t8nx7c@proposed + - >- + dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee@accepted + - >- + dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r@accepted + - >- + dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r@accepted + - dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e@accepted + - dec-ship-three-tern-quality-presets--jkdzxsd8wt3w91hb@accepted + - dec-splat-caustic-photons-from-a-sun-space-map--gz19gensacx2zh1w@accepted + - >- + dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h@accepted + - dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j@accepted + - dec-use-signed-distance-field-gi--yn366zmp3k7snd9w@accepted + - dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86@accepted + - dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4@accepted + - >- + dec-visibility-buffer-with-compute-material-resolve--5s2z9mqmv8vnszed@accepted + - fnd-32-bit-visibility-ids-overflow-on-the-dunes-benc--eyjs4sekprhhtddp@live + - fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb@live + - fnd-caustics-flicker-at-3-to-6-hz-under-tern--9je5rqt89es3rcz4@live + - fnd-cpu-culling-and-draw-submission-cost-3-2-ms-on-t--1y0j1b9p0zjh0n1g@live + - fnd-forward-overdraw-on-saltglass-cliffs--q9n76frhz7a7ssnp@live + - fnd-gi-takes-13-percent-of-the-quality-mode-frame--afshqnfm209zrae9@live + - fnd-halcyon-vendor-upscaler-quality-and-platform-cov--xz7hp3e1m1mh44v4@live + - fnd-meshlet-alpha-masks-bring-foliage-back-into-the--672xvn788702zkn6@live + - fnd-meshlet-cone-culling-rejects-31-percent-of-trian--7qqt9dr77xyptb85@live + - fnd-meshlet-size-sweep-on-the-cliffs-benchmark--zeg5q7pn92jd42x3@live + - fnd-photon-caustics-cost-1-1-ms-from-a-512-by-512-su--2rg1xq89re42cgaj@live + - fnd-probe-grid-leaks-light-through-thin-saltglass-wa--h2hdqdfj92mnmkbj@live + - fnd-projected-caustic-textures-tile-visibly-past-600--dkyy65zqqh5gx04x@live + - fnd-refraction-cost-screen-space-0-9-ms-ray-marched--pr6bzy3tvstaptdc@live + - fnd-screen-space-refraction-halos-around-the-player--6ytj9mvh0v1bfsdf@live + - fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy@live + - fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr@live + - fnd-skiff-devkits-reach-the-render-team-in-april--bx6zmw2s52vr2t1z@live + - fnd-stock-filmic-curve-clips-38-percent-of-caustic-h--7n6g1tssnkwqqwm6@live + - fnd-tern-cost-at-4k-output-on-meridian-after-fp16-pa--p4gcmzw2a4bvzjev@live + - fnd-tern-preset-render-scales-and-costs--gjp3q966nngdd580@live + - fnd-virtual-shadow-maps-cost-1-4-ms-on-meridian-with--mwpybda1vh0ac55e@live + - fnd-visibility-buffer-prototype-timings--qcfzqvyxbxkf2spw@live + - iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5@open + - rsk-artists-cannot-match-concept-paintings-under-the--6cfh9vkamn0kbtcx@open + - rsk-caustic-flicker-fails-photosensitivity-review--vrpf3390abxh1q4d@open + - rsk-compute-meshlet-expansion-is-too-slow-on-skiff--b1915sgdsr1bpwda@open + - rsk-sdf-volumes-outgrow-the-render-target-memory-bud--xfd2pfztvskdcd2c@open + - rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty@open +--- +Alpha landed on 2026-03-02. The visibility buffer now resolves materials in compute, and foliage is back in the buffer thanks to meshlet alpha masks; saltglass still renders forward. + +Virtual shadow maps replaced cascaded shadow maps on 2026-02-16 after the 3.1 ms cost Finding turned out to be a capture error. SDF GI remains the accepted GI Decision, but the recapture on a Meridian devkit measured 4.7 ms, not 2.2 ms, and nobody has re-weighed the GI Decision. Refraction is screen-space with a ray-marched fallback. Caustics flicker under Tern; the blocker is open with two proposed fixes. Tonemapping moved to the Brine curve. Tern ships three presets. The Frame budget gives GPU passes 15.2 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lantern-at-beta--53jwv4ngqk0wf9aw.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lantern-at-beta--53jwv4ngqk0wf9aw.md new file mode 100644 index 00000000..fdcac25f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lantern-at-beta--53jwv4ngqk0wf9aw.md @@ -0,0 +1,108 @@ +--- +id: fnd-lantern-at-beta--53jwv4ngqk0wf9aw +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Lantern at beta +kind: compaction +created_at: '2026-06-04T10:00:00Z' +created_by: Ines Okafor +derives_from: + - con-frame-budget--fzdrbxns6dmrrmy3 + - con-meridian-120-hz-performance-mode-budget--khgjmq18bfr40tyj + - dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e + - dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k + - dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4 + - dec-visibility-buffer-on-pc-and-meridian-forward-fal--khvgysnhmnkjqe9k + - fnd-tern-cost-at-4k-output-on-meridian-with-the-reac--81tcpzvhwzcy6wyn + - iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5 + - iss-gi-does-not-fit-the-120-hz-performance-mode-budg--get9cq6er1ac4vzx + - rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty +supersedes: + - fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c +superseded_by: + - fnd-lantern-at-content-lock--npcagtz7rj6gkasn +covers: + - con-frame-budget--fzdrbxns6dmrrmy3@live + - con-meridian-120-hz-performance-mode-budget--khgjmq18bfr40tyj@live + - con-meridian-hdr-certification-requirements--nx9pmkwjjvxy1smf@live + - con-one-upscaler-path-on-every-platform--f91bgj6n66kwc5d3@live + - con-render-target-memory-on-meridian--q4szajxse9c1csdv@live + - con-saltglass-must-read-at-2-km--65a67jbwhr7r73qw@live + - con-skiff-has-no-mesh-shader-support--zz4xpaqy1n0zzrj7@live + - con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s@live + - >- + dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e@accepted + - >- + dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676@accepted + - >- + dec-drop-the-far-sdf-gi-cascade-for-the-vertical-sli--0af6sjseeftc621j@accepted + - dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2@accepted + - >- + dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4@proposed + - >- + dec-expand-meshlets-to-index-buffers-in-compute-on-s--bpbtr54dgzgsjgme@accepted + - dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k@accepted + - >- + dec-hard-code-hdr-paper-white-at-200-nits-on-meridia--k481dkkr69gf77rr@accepted + - dec-lock-caustic-photon-jitter-to-the-tide-phase--85x10k4h11t8nx7c@proposed + - >- + dec-mark-tide-exposed-instances-visible-for-one-fram--157jf1cesjt3nkrc@accepted + - >- + dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee@accepted + - >- + dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r@accepted + - >- + dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r@accepted + - dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e@accepted + - dec-ship-three-tern-quality-presets--jkdzxsd8wt3w91hb@accepted + - dec-splat-caustic-photons-from-a-sun-space-map--gz19gensacx2zh1w@accepted + - >- + dec-trace-sdf-gi-at-quarter-resolution-in-performanc--06cqt3mqn3fg5h6e@proposed + - >- + dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h@accepted + - dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j@accepted + - dec-use-ray-traced-sun-shadows--9xpd0kwe2v1rwefd@proposed + - dec-use-signed-distance-field-gi--yn366zmp3k7snd9w@accepted + - >- + dec-use-the-probe-grid-alone-in-120-hz-performance-m--6dzm1nt40pjfpyae@proposed + - dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4@accepted + - >- + dec-visibility-buffer-on-pc-and-meridian-forward-fal--khvgysnhmnkjqe9k@accepted + - fnd-32-bit-visibility-ids-overflow-on-the-dunes-benc--eyjs4sekprhhtddp@live + - fnd-a-saltglass-reactive-mask-removes-90-percent-of--p2mmqg2yj8nz43st@live + - fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb@live + - fnd-caustics-flicker-at-3-to-6-hz-under-tern--9je5rqt89es3rcz4@live + - fnd-concept-match-review-11-of-14-key-shots-pass-und--1sv3grvmm4hbtyf5@live + - fnd-cpu-culling-and-draw-submission-cost-3-2-ms-on-t--1y0j1b9p0zjh0n1g@live + - fnd-forward-overdraw-on-saltglass-cliffs--q9n76frhz7a7ssnp@live + - fnd-gi-takes-13-percent-of-the-quality-mode-frame--afshqnfm209zrae9@live + - fnd-halcyon-vendor-upscaler-quality-and-platform-cov--xz7hp3e1m1mh44v4@live + - fnd-meshlet-alpha-masks-bring-foliage-back-into-the--672xvn788702zkn6@live + - fnd-meshlet-cone-culling-rejects-9-percent-of-triang--t6e5x7trzedex105@live + - fnd-meshlet-size-sweep-on-the-cliffs-benchmark--zeg5q7pn92jd42x3@live + - fnd-photon-caustics-cost-1-1-ms-from-a-512-by-512-su--2rg1xq89re42cgaj@live + - fnd-probe-grid-leaks-light-through-thin-saltglass-wa--h2hdqdfj92mnmkbj@live + - fnd-projected-caustic-textures-tile-visibly-past-600--dkyy65zqqh5gx04x@live + - fnd-refraction-cost-screen-space-0-9-ms-ray-marched--pr6bzy3tvstaptdc@live + - fnd-screen-space-refraction-halos-around-the-player--6ytj9mvh0v1bfsdf@live + - fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy@live + - fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr@live + - fnd-sdf-volumes-use-410-mb-of-render-target-memory--y8bm788y240rqq7d@live + - fnd-skiff-devkits-reach-the-render-team-in-april--bx6zmw2s52vr2t1z@live + - fnd-stock-filmic-curve-clips-38-percent-of-caustic-h--7n6g1tssnkwqqwm6@live + - fnd-tern-cost-at-4k-output-on-meridian-with-the-reac--81tcpzvhwzcy6wyn@live + - fnd-tern-ghosts-behind-moving-saltglass--j48ss757xfxmw31q@live + - fnd-tern-preset-render-scales-and-costs--gjp3q966nngdd580@live + - fnd-tide-locked-jitter-halves-caustic-flicker-but-st--nck1ftqr38v01cq1@live + - fnd-virtual-shadow-maps-cost-1-4-ms-on-meridian-with--mwpybda1vh0ac55e@live + - fnd-visibility-buffer-costs-11-2-ms-on-skiff--s3vphdwnhbh4650s@live + - fnd-visibility-buffer-prototype-timings--qcfzqvyxbxkf2spw@live + - iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5@open + - iss-gi-does-not-fit-the-120-hz-performance-mode-budg--get9cq6er1ac4vzx@open + - rsk-caustic-flicker-fails-photosensitivity-review--vrpf3390abxh1q4d@open + - rsk-compute-meshlet-expansion-is-too-slow-on-skiff--b1915sgdsr1bpwda@open + - rsk-gi-cannot-fit-the-120-hz-performance-mode--tqt3fj839dqfq5s7@open + - rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty@open +--- +Beta landed on 2026-06-01 with Skiff as a launch platform. The visibility buffer runs on PC and Meridian; Skiff falls back to forward+ because the April Skiff capture put the buffer at 11.2 ms. + +Virtual shadow maps are in, and the page-pool overflow Risk is open. Tern gets a saltglass reactive mask, which removes 90 percent of the ghosting, and the Halcyon vendor upscaler was rejected a second time. Tern costs 1.6 ms at 4K output. The Brine curve has a separate HDR shoulder. The 120 Hz performance mode is now a hard launch commitment at 8.3 ms; GI does not fit it yet and that blocker is open. Caustic flicker is still open with two proposed fixes. Quality mode keeps 15.0 ms of GPU time. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lantern-at-content-lock--npcagtz7rj6gkasn.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lantern-at-content-lock--npcagtz7rj6gkasn.md new file mode 100644 index 00000000..d1254421 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lantern-at-content-lock--npcagtz7rj6gkasn.md @@ -0,0 +1,117 @@ +--- +id: fnd-lantern-at-content-lock--npcagtz7rj6gkasn +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Lantern at content lock +kind: compaction +created_at: '2026-08-26T10:00:00Z' +created_by: Ines Okafor +derives_from: + - con-meridian-120-hz-performance-mode-budget--khgjmq18bfr40tyj + - dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e + - dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k + - dec-ship-four-tern-quality-presets-adding-ultra-perf--3jg1wyq3bshv839c + - dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e + - dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4 + - dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1 + - iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5 + - iss-meridian-hdr-certification-fails-the-paper-white--bper6nwencgtgf7b + - rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4 +supersedes: + - fnd-lantern-at-beta--53jwv4ngqk0wf9aw +covers: + - con-frame-budget--fzdrbxns6dmrrmy3@live + - con-meridian-120-hz-performance-mode-budget--khgjmq18bfr40tyj@live + - con-meridian-hdr-certification-requirements--nx9pmkwjjvxy1smf@live + - con-one-upscaler-path-on-every-platform--f91bgj6n66kwc5d3@live + - con-render-target-memory-on-meridian--q4szajxse9c1csdv@live + - con-saltglass-must-read-at-2-km--65a67jbwhr7r73qw@live + - con-skiff-has-no-mesh-shader-support--zz4xpaqy1n0zzrj7@live + - con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s@live + - >- + dec-add-an-in-game-paper-white-slider-from-80-to-400--1phfvxby983z8tjf@proposed + - >- + dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e@accepted + - >- + dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676@accepted + - >- + dec-drop-the-far-sdf-gi-cascade-for-the-vertical-sli--0af6sjseeftc621j@accepted + - dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2@accepted + - >- + dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4@proposed + - >- + dec-expand-meshlets-to-index-buffers-in-compute-on-s--bpbtr54dgzgsjgme@accepted + - dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k@accepted + - dec-lock-caustic-photon-jitter-to-the-tide-phase--85x10k4h11t8nx7c@proposed + - >- + dec-mark-tide-exposed-instances-visible-for-one-fram--157jf1cesjt3nkrc@accepted + - >- + dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee@accepted + - >- + dec-read-paper-white-from-the-meridian-system-settin--7crbx73gqw1hn7xq@proposed + - >- + dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r@accepted + - >- + dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r@accepted + - >- + dec-ship-four-tern-quality-presets-adding-ultra-perf--3jg1wyq3bshv839c@accepted + - dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e@accepted + - dec-splat-caustic-photons-from-a-sun-space-map--gz19gensacx2zh1w@accepted + - >- + dec-trace-sdf-gi-at-quarter-resolution-in-performanc--06cqt3mqn3fg5h6e@proposed + - >- + dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h@accepted + - dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j@accepted + - dec-use-ray-traced-sun-shadows--9xpd0kwe2v1rwefd@proposed + - dec-use-signed-distance-field-gi--yn366zmp3k7snd9w@accepted + - >- + dec-use-the-probe-grid-alone-in-120-hz-performance-m--6dzm1nt40pjfpyae@proposed + - dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4@accepted + - >- + dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1@accepted + - fnd-32-bit-visibility-ids-overflow-on-the-dunes-benc--eyjs4sekprhhtddp@live + - fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb@live + - fnd-caustics-flicker-at-3-to-6-hz-under-tern--9je5rqt89es3rcz4@live + - fnd-clamp-exclusion-removes-caustic-flicker-but-ghos--2m4pgjzbz7ze93j5@live + - fnd-concept-match-review-11-of-14-key-shots-pass-und--1sv3grvmm4hbtyf5@live + - fnd-cpu-culling-and-draw-submission-cost-3-2-ms-on-t--1y0j1b9p0zjh0n1g@live + - fnd-forward-overdraw-on-saltglass-cliffs--q9n76frhz7a7ssnp@live + - fnd-gi-takes-13-percent-of-the-quality-mode-frame--afshqnfm209zrae9@live + - fnd-halcyon-vendor-upscaler-quality-and-platform-cov--xz7hp3e1m1mh44v4@live + - fnd-meridian-hdr-certification-pre-check-failed-on-p--qz0rr1cqqmcr6kh9@live + - fnd-meshlet-alpha-masks-bring-foliage-back-into-the--672xvn788702zkn6@live + - fnd-meshlet-cone-culling-rejects-9-percent-of-triang--t6e5x7trzedex105@live + - fnd-meshlet-size-sweep-on-the-cliffs-benchmark--zeg5q7pn92jd42x3@live + - fnd-photon-caustics-cost-1-1-ms-from-a-512-by-512-su--2rg1xq89re42cgaj@live + - fnd-probe-grid-leaks-light-through-thin-saltglass-wa--h2hdqdfj92mnmkbj@live + - fnd-projected-caustic-textures-tile-visibly-past-600--dkyy65zqqh5gx04x@live + - fnd-quarter-resolution-sdf-gi-costs-1-9-ms-in-perfor--md9qdmtne78wv7mf@live + - fnd-reactive-mask-removes-61-percent-of-saltglass-gh--csg97ges3067ehrp@live + - fnd-refraction-cost-screen-space-0-9-ms-ray-marched--pr6bzy3tvstaptdc@live + - fnd-screen-space-refraction-halos-around-the-player--6ytj9mvh0v1bfsdf@live + - fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy@live + - fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr@live + - fnd-sdf-volumes-use-410-mb-of-render-target-memory--y8bm788y240rqq7d@live + - fnd-skiff-devkits-reach-the-render-team-in-april--bx6zmw2s52vr2t1z@live + - fnd-stock-filmic-curve-clips-38-percent-of-caustic-h--7n6g1tssnkwqqwm6@live + - fnd-tern-cost-at-4k-output-on-meridian-with-the-reac--81tcpzvhwzcy6wyn@live + - fnd-tern-ghosts-behind-moving-saltglass--j48ss757xfxmw31q@live + - fnd-tern-preset-render-scales-and-costs--gjp3q966nngdd580@live + - fnd-tide-locked-jitter-halves-caustic-flicker-but-st--nck1ftqr38v01cq1@live + - fnd-virtual-shadow-maps-cost-1-4-ms-on-meridian-with--mwpybda1vh0ac55e@live + - fnd-visibility-buffer-costs-7-4-ms-on-skiff-in-a-rel--fs86h16tm5hgempd@live + - fnd-visibility-buffer-prototype-timings--qcfzqvyxbxkf2spw@live + - fnd-vsm-page-pool-overflows-during-spring-tides--m2p8e89hhdmh0z8a@live + - iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5@open + - iss-gi-does-not-fit-the-120-hz-performance-mode-budg--get9cq6er1ac4vzx@open + - iss-meridian-hdr-certification-fails-the-paper-white--bper6nwencgtgf7b@open + - iss-shadow-pages-run-out-at-spring-low-tide--f4fgy6b44jbkrsmh@open + - rsk-caustic-flicker-fails-photosensitivity-review--vrpf3390abxh1q4d@open + - rsk-compute-meshlet-expansion-is-too-slow-on-skiff--b1915sgdsr1bpwda@open + - rsk-gi-cannot-fit-the-120-hz-performance-mode--tqt3fj839dqfq5s7@realized + - rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4@open + - >- + rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty@realized +--- +Content locked on 2026-08-24. The visibility buffer runs on every platform; Skiff resolves materials at half rate and the Skiff forward+ path is gone. + +Virtual shadow maps cover sun shadows, but shadow pages still run out at spring low tide. Tern is the only upscaler, with four presets including Ultra Performance for the 120 Hz mode, and a saltglass reactive mask against ghosting. The Brine curve's HDR shoulder starts at 1,000 nits. HDR certification failed its first pre-check on paper white; two fixes are proposed, and Priya Natarajan expects the resubmission on 2026-09-12 to pass. Caustic flicker under Tern is still an open blocker after seven months, and neither proposed fix has been accepted. The 120 Hz mode holds 8.3 ms per frame. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lantern-at-the-vertical-slice--10g62g9rfaw438qf.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lantern-at-the-vertical-slice--10g62g9rfaw438qf.md new file mode 100644 index 00000000..8a99e02a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lantern-at-the-vertical-slice--10g62g9rfaw438qf.md @@ -0,0 +1,76 @@ +--- +id: fnd-lantern-at-the-vertical-slice--10g62g9rfaw438qf +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Lantern at the vertical slice +kind: compaction +created_at: '2025-12-18T10:00:00Z' +created_by: Ines Okafor +derives_from: + - dec-drop-the-far-sdf-gi-cascade-for-the-vertical-sli--0af6sjseeftc621j + - dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee + - dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e + - dec-splat-caustic-photons-from-a-sun-space-map--gz19gensacx2zh1w + - dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h + - dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr + - dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6 + - dec-use-signed-distance-field-gi--yn366zmp3k7snd9w + - dec-use-the-stock-filmic-tonemapping-curve--wefzd9091kztq0wb + - dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9 +superseded_by: + - fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c +covers: + - con-frame-budget--f5qxxq5572878wrp@live + - con-meridian-hdr-certification-requirements--nx9pmkwjjvxy1smf@live + - con-one-upscaler-path-on-every-platform--f91bgj6n66kwc5d3@live + - con-render-target-memory-on-meridian--q4szajxse9c1csdv@live + - con-saltglass-must-read-at-2-km--65a67jbwhr7r73qw@live + - con-skiff-has-no-mesh-shader-support--zz4xpaqy1n0zzrj7@live + - con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s@live + - >- + dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676@accepted + - >- + dec-drop-the-far-sdf-gi-cascade-for-the-vertical-sli--0af6sjseeftc621j@accepted + - >- + dec-expand-meshlets-to-index-buffers-in-compute-on-s--bpbtr54dgzgsjgme@accepted + - >- + dec-hard-code-hdr-paper-white-at-200-nits-on-meridia--k481dkkr69gf77rr@accepted + - >- + dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee@accepted + - >- + dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r@accepted + - dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e@accepted + - dec-splat-caustic-photons-from-a-sun-space-map--gz19gensacx2zh1w@accepted + - >- + dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h@accepted + - dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j@accepted + - dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr@accepted + - dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6@invalidated + - dec-use-signed-distance-field-gi--yn366zmp3k7snd9w@accepted + - dec-use-the-stock-filmic-tonemapping-curve--wefzd9091kztq0wb@accepted + - >- + dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9@accepted + - fnd-32-bit-visibility-ids-overflow-on-the-dunes-benc--eyjs4sekprhhtddp@live + - fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb@live + - fnd-cpu-culling-and-draw-submission-cost-3-2-ms-on-t--1y0j1b9p0zjh0n1g@live + - fnd-forward-overdraw-on-saltglass-cliffs--q9n76frhz7a7ssnp@live + - fnd-gi-takes-13-percent-of-the-quality-mode-frame--afshqnfm209zrae9@live + - fnd-halcyon-vendor-upscaler-quality-and-platform-cov--xz7hp3e1m1mh44v4@live + - fnd-meshlet-size-sweep-on-the-cliffs-benchmark--zeg5q7pn92jd42x3@live + - fnd-photon-caustics-cost-1-1-ms-from-a-512-by-512-su--2rg1xq89re42cgaj@live + - fnd-probe-grid-leaks-light-through-thin-saltglass-wa--h2hdqdfj92mnmkbj@live + - fnd-projected-caustic-textures-tile-visibly-past-600--dkyy65zqqh5gx04x@live + - fnd-refraction-cost-screen-space-0-9-ms-ray-marched--pr6bzy3tvstaptdc@live + - fnd-screen-space-refraction-halos-around-the-player--6ytj9mvh0v1bfsdf@live + - fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy@live + - fnd-sdf-gi-costs-2-2-ms-on-meridian--r7t7zy97nwxxxctd@live + - fnd-tern-cost-at-4k-output-on-meridian-after-fp16-pa--p4gcmzw2a4bvzjev@live + - fnd-virtual-shadow-maps-cost-1-4-ms-on-meridian-with--mwpybda1vh0ac55e@live + - fnd-visibility-buffer-prototype-timings--qcfzqvyxbxkf2spw@live + - iss-cascade-seams-visible-through-saltglass-at-300-t--3590ssrc8xxa4ae6@open + - iss-no-ray-traced-reflections-on-saltglass--pdcbm94d32f55fa0@open + - rsk-compute-meshlet-expansion-is-too-slow-on-skiff--b1915sgdsr1bpwda@open + - rsk-sdf-volumes-outgrow-the-render-target-memory-bud--xfd2pfztvskdcd2c@open +--- +The vertical slice shipped on 2025-12-15. The dunes flyover ran at 16.1 ms on Meridian after the far SDF GI cascade was dropped for the slice build, so the 16.6 ms Frame budget held. + +Opaque geometry renders through a visibility buffer, with foliage and saltglass in a forward pass after the resolve. Sun shadows use four cascaded shadow maps; virtual shadow maps were rejected on a 3.1 ms cost. GI is signed-distance-field GI at 2.2 ms. Saltglass refraction is screen-space, although a Finding has shown it loses off-screen content at grazing angles and a replacement is due in January. Caustics are photon splats. Tern is the only upscaler. Tonemapping uses the stock filmic curve. Culling is GPU-driven with 64-vertex meshlets. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lockstep-playtest-at-150-ms-round-trip--hjp498j88mtdbnhs.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lockstep-playtest-at-150-ms-round-trip--hjp498j88mtdbnhs.md new file mode 100644 index 00000000..b37c8909 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lockstep-playtest-at-150-ms-round-trip--hjp498j88mtdbnhs.md @@ -0,0 +1,24 @@ +--- +id: fnd-lockstep-playtest-at-150-ms-round-trip--hjp498j88mtdbnhs +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Lockstep playtest at 150 ms round trip +kind: measurement +created_at: '2025-11-12T15:00:00Z' +created_by: Sofia Marchetti +derives_from: + - con-co-op-must-stay-playable-at-150-ms-round-trip--q330d4g95q7jtt4q + - dec-use-deterministic-lockstep-for-co-op--h0agvr5m0d8ndj72 +--- +Sofia Marchetti and Marta Lindqvist ran a four-player lockstep build on the Shoal-01 test map with 150 ms of injected round trip. + +Setup: +- Two PC peers at 60 Hz, one Meridian devkit at 60 Hz, one Skiff devkit at 30 Hz. +- Ten minutes of traversal and one tide surge. +- Input delay fixed at 5 frames (75 ms at 60 Hz), the minimum that kept every peer fed. + +What we saw: +- Marta Lindqvist rated traversal "mushy" from the first minute. Jumps across saltglass gaps landed late. +- Every peer ran at the speed of the slowest one. The Skiff devkit dropped frames during the tide surge and the whole session waited for it. +- Network traffic was tiny: 1.2 KB/s per peer. + +The Skiff devkit stalled the whole session 41 times in 10 minutes. With a handheld in the group, lockstep would feel broken for all four players. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lru-eviction-thrashes-during-tide-turns--0tvj4hmg42jy5d3f.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lru-eviction-thrashes-during-tide-turns--0tvj4hmg42jy5d3f.md new file mode 100644 index 00000000..24a5f149 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-lru-eviction-thrashes-during-tide-turns--0tvj4hmg42jy5d3f.md @@ -0,0 +1,13 @@ +--- +id: fnd-lru-eviction-thrashes-during-tide-turns--0tvj4hmg42jy5d3f +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: LRU eviction thrashes during tide turns +kind: measurement +created_at: '2026-01-05T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - dec-evict-the-least-recently-used-cells-first--4eap3mr9tkafxy2p +invalidates: + - dec-evict-the-least-recently-used-cells-first--4eap3mr9tkafxy2p +--- +Cells the tide is about to expose have not been touched for a whole cycle, so LRU evicts them first, just before they are needed. In a slice playtest, 38% of tide-turn reloads were cells evicted in the previous 60 seconds. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meridian-drops-co-op-sessions-because-the-relay--73hf67080kkyf76j.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meridian-drops-co-op-sessions-because-the-relay--73hf67080kkyf76j.md new file mode 100644 index 00000000..a64bf9c1 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meridian-drops-co-op-sessions-because-the-relay--73hf67080kkyf76j.md @@ -0,0 +1,11 @@ +--- +id: fnd-meridian-drops-co-op-sessions-because-the-relay--73hf67080kkyf76j +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Meridian drops co-op sessions because the relay socket times out +kind: measurement +created_at: '2026-05-26T14:00:00Z' +created_by: Sofia Marchetti +derives_from: + - iss-meridian-cert-resume-from-suspend-drops-the-co-o--jbqz6wqm1w747bbx +--- +Sofia Marchetti traced the suspend defect: the co-op relay closes an idle socket after 30 seconds, and Meridian suspends the network stack with the game. On resume the client still thinks the socket is open and waits forever. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meridian-hdr-certification-pre-check-failed-agai--w4q6pdtqc7akayt0.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meridian-hdr-certification-pre-check-failed-agai--w4q6pdtqc7akayt0.md new file mode 100644 index 00000000..3eeaa553 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meridian-hdr-certification-pre-check-failed-agai--w4q6pdtqc7akayt0.md @@ -0,0 +1,11 @@ +--- +id: fnd-meridian-hdr-certification-pre-check-failed-agai--w4q6pdtqc7akayt0 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Meridian HDR certification pre-check failed again on paper white +kind: measurement +created_at: '2026-09-14T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - iss-meridian-hdr-certification-fails-the-paper-white--bper6nwencgtgf7b +--- +The second pre-check, on 2026-09-12, failed the paper-white test again. Neither proposed fix was merged in time, so the build still used a fixed paper white. The next submission window opens on 2026-09-24. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meridian-hdr-certification-pre-check-failed-on-p--qz0rr1cqqmcr6kh9.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meridian-hdr-certification-pre-check-failed-on-p--qz0rr1cqqmcr6kh9.md new file mode 100644 index 00000000..961cbd7d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meridian-hdr-certification-pre-check-failed-on-p--qz0rr1cqqmcr6kh9.md @@ -0,0 +1,13 @@ +--- +id: fnd-meridian-hdr-certification-pre-check-failed-on-p--qz0rr1cqqmcr6kh9 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Meridian HDR certification pre-check failed on paper white +kind: measurement +created_at: '2026-07-15T10:00:00Z' +created_by: Priya Natarajan +invalidates: + - dec-hard-code-hdr-paper-white-at-200-nits-on-meridia--k481dkkr69gf77rr +cites: + - cit-report-meridian-hdr-pre-check-july--mqw9w3jm6srcm3x0 +--- +The July pre-check failed one test: paper white ignores the system setting and offers no user range. The hard-coded 200 nits was never allowed by the certification requirements. Every other HDR test passed. The report is attached. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meshlet-alpha-masks-bring-foliage-back-into-the--672xvn788702zkn6.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meshlet-alpha-masks-bring-foliage-back-into-the--672xvn788702zkn6.md new file mode 100644 index 00000000..2a64af02 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meshlet-alpha-masks-bring-foliage-back-into-the--672xvn788702zkn6.md @@ -0,0 +1,12 @@ +--- +id: fnd-meshlet-alpha-masks-bring-foliage-back-into-the--672xvn788702zkn6 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Meshlet alpha masks bring foliage back into the visibility buffer at 0.7 ms +kind: measurement +created_at: '2026-01-16T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h + - fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb +--- +With 64-vertex meshlets each carrying a coarse alpha-coverage mask, the raster pass skips fully transparent meshlets, and the per-pixel alpha test runs on 22 percent of the pixels it ran on before. Coast benchmark foliage costs 0.7 ms in the buffer against 0.8 ms in the forward pass. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meshlet-cone-culling-rejects-31-percent-of-trian--7qqt9dr77xyptb85.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meshlet-cone-culling-rejects-31-percent-of-trian--7qqt9dr77xyptb85.md new file mode 100644 index 00000000..4c4ee49f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meshlet-cone-culling-rejects-31-percent-of-trian--7qqt9dr77xyptb85.md @@ -0,0 +1,13 @@ +--- +id: fnd-meshlet-cone-culling-rejects-31-percent-of-trian--7qqt9dr77xyptb85 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Meshlet cone culling rejects 31 percent of triangles +kind: measurement +created_at: '2026-01-28T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h +invalidated_by: + - fnd-meshlet-cone-culling-rejects-9-percent-of-triang--t6e5x7trzedex105 +--- +Testing each meshlet against a normal cone before rasterizing rejects 31 percent of triangles on the cliffs benchmark, for 0.1 ms of culling work. Cliff faces turned away from the camera are the bulk of it. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meshlet-cone-culling-rejects-9-percent-of-triang--t6e5x7trzedex105.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meshlet-cone-culling-rejects-9-percent-of-triang--t6e5x7trzedex105.md new file mode 100644 index 00000000..408fceb9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meshlet-cone-culling-rejects-9-percent-of-triang--t6e5x7trzedex105.md @@ -0,0 +1,11 @@ +--- +id: fnd-meshlet-cone-culling-rejects-9-percent-of-triang--t6e5x7trzedex105 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Meshlet cone culling rejects 9 percent of triangles +kind: measurement +created_at: '2026-05-26T10:00:00Z' +created_by: Rhea Valdés +invalidates: + - fnd-meshlet-cone-culling-rejects-31-percent-of-trian--7qqt9dr77xyptb85 +--- +Rhea Valdés recounted the cone-culling numbers. The January count included triangles that back-face culling already removed, so they were counted twice. Cone culling on its own rejects 9 percent of triangles on the cliffs benchmark. It still pays for its 0.1 ms on PC and Meridian; on Skiff it is close to break-even. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meshlet-size-sweep-on-the-cliffs-benchmark--zeg5q7pn92jd42x3.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meshlet-size-sweep-on-the-cliffs-benchmark--zeg5q7pn92jd42x3.md new file mode 100644 index 00000000..e67e573e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-meshlet-size-sweep-on-the-cliffs-benchmark--zeg5q7pn92jd42x3.md @@ -0,0 +1,13 @@ +--- +id: fnd-meshlet-size-sweep-on-the-cliffs-benchmark--zeg5q7pn92jd42x3 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Meshlet size sweep on the cliffs benchmark +kind: measurement +created_at: '2025-11-20T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-what-meshlet-size-should-lantern-use--myg13k3gkk2b61nj +cites: + - cit-table-meshlet-size-sweep--gw92j9g9071gj8v8 +--- +Tomasz Brandt swept three meshlet sizes on the cliffs benchmark. The middle size rasterizes fastest; the largest culls noticeably fewer triangles. The table is attached. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-most-shader-compile-time-on-the-farm-repeats-ide--n7mr2yxxxtzpak35.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-most-shader-compile-time-on-the-farm-repeats-ide--n7mr2yxxxtzpak35.md new file mode 100644 index 00000000..0d70f97f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-most-shader-compile-time-on-the-farm-repeats-ide--n7mr2yxxxtzpak35.md @@ -0,0 +1,11 @@ +--- +id: fnd-most-shader-compile-time-on-the-farm-repeats-ide--n7mr2yxxxtzpak35 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Most shader compile time on the farm repeats identical work +kind: measurement +created_at: '2025-09-12T14:00:00Z' +created_by: Liam O'Connell +derives_from: + - iss-full-shader-rebuilds-take-47-minutes-on-the-buil--4bnh1e17snf5y3h6 +--- +Liam O'Connell hashed the compiled output of every permutation over five days of nightly and on-demand builds (61 builds). 61% of permutation compiles produced bytecode identical to the previous build of the same permutation. Another 22% changed only because an unrelated define moved in a shared header. A cache keyed on the right inputs could have skipped roughly 29 of the 47 minutes on an average build. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-one-frame-of-input-delay-is-invisible-in-playtes--azn8kxedq3pp1vq0.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-one-frame-of-input-delay-is-invisible-in-playtes--azn8kxedq3pp1vq0.md new file mode 100644 index 00000000..64866641 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-one-frame-of-input-delay-is-invisible-in-playtes--azn8kxedq3pp1vq0.md @@ -0,0 +1,9 @@ +--- +id: fnd-one-frame-of-input-delay-is-invisible-in-playtes--azn8kxedq3pp1vq0 +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: One frame of input delay is invisible in playtests +kind: playtest +created_at: '2026-01-28T10:00:00Z' +created_by: Marta Lindqvist +--- +Marta Lindqvist ran blind tests with 0, 1 and 2 frames of local input delay. Nobody of eight testers noticed 1 frame; five of eight noticed 2 frames. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-photon-caustics-cost-1-1-ms-from-a-512-by-512-su--2rg1xq89re42cgaj.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-photon-caustics-cost-1-1-ms-from-a-512-by-512-su--2rg1xq89re42cgaj.md new file mode 100644 index 00000000..0dfbb2f4 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-photon-caustics-cost-1-1-ms-from-a-512-by-512-su--2rg1xq89re42cgaj.md @@ -0,0 +1,11 @@ +--- +id: fnd-photon-caustics-cost-1-1-ms-from-a-512-by-512-su--2rg1xq89re42cgaj +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Photon caustics cost 1.1 ms from a 512 by 512 sun-space map +kind: measurement +created_at: '2025-10-14T15:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-how-should-lantern-draw-saltglass-caustics--a6wcxavrp4ky319s +--- +Tracing one photon per texel of a 512 by 512 sun-space map through the saltglass and splatting the hits costs 1.1 ms on Meridian. Projected textures cost 0.2 ms but do not follow the shape of the glass. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-platform-holder-waived-the-docked-30-hz-judder-a--7qckhx7c2vfyemqd.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-platform-holder-waived-the-docked-30-hz-judder-a--7qckhx7c2vfyemqd.md new file mode 100644 index 00000000..74cdffa1 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-platform-holder-waived-the-docked-30-hz-judder-a--7qckhx7c2vfyemqd.md @@ -0,0 +1,11 @@ +--- +id: fnd-platform-holder-waived-the-docked-30-hz-judder-a--7qckhx7c2vfyemqd +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Platform holder waived the docked 30 Hz judder advisory +kind: survey +created_at: '2026-05-28T09:00:00Z' +created_by: Dara Whitlock +derives_from: + - iss-skiff-cert-docked-30-hz-judder-on-some-tvs--9nq2xg9mzash474g +--- +Dara Whitlock asked the Skiff platform holder to waive the docked judder advisory. The waiver came back the same day: it affects TVs that cannot accept 60 Hz input, under 1 percent of the installed base. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-player-snapshot-is-14-kb-per-player--z10z27xaqg1bp451.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-player-snapshot-is-14-kb-per-player--z10z27xaqg1bp451.md new file mode 100644 index 00000000..d56091ec --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-player-snapshot-is-14-kb-per-player--z10z27xaqg1bp451.md @@ -0,0 +1,14 @@ +--- +id: fnd-player-snapshot-is-14-kb-per-player--z10z27xaqg1bp451 +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Player snapshot is 14 KB per player +kind: measurement +created_at: '2025-12-10T09:00:00Z' +created_by: Marta Lindqvist +retracted: true +retracted_at: '2025-12-12T09:00:00.000Z' +retracted_reason: >- + Filed here by mistake. This measures save-game snapshots for the world Effort, + not rollback snapshots. +--- +Serialized player state, including Gull script variables and inventory, comes to 14 KB per player. Measured on the coast save slot. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-ports-cut-the-skiff-memory-total-and-streaming-m--1p8b10ttb07jkznx.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-ports-cut-the-skiff-memory-total-and-streaming-m--1p8b10ttb07jkznx.md new file mode 100644 index 00000000..7cd3fe19 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-ports-cut-the-skiff-memory-total-and-streaming-m--1p8b10ttb07jkznx.md @@ -0,0 +1,11 @@ +--- +id: fnd-ports-cut-the-skiff-memory-total-and-streaming-m--1p8b10ttb07jkznx +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'Ports cut the Skiff memory total, and streaming must give back 400 MB' +kind: survey +created_at: '2026-06-02T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - rsk-ports-may-need-to-shrink-the-streaming-pool-for--1gtjkygrtkb5kgww +--- +Priya Natarajan reports that Skiff is now a launch platform, so the world must fit the ports Constraint "Skiff memory budget", which fell from 9 GB to 8 GB in February. The ports team split the 1 GB cut across systems, and streaming's share is 400 MB. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-ports-status-after-alpha--yaqm024j41anp4vn.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-ports-status-after-alpha--yaqm024j41anp4vn.md new file mode 100644 index 00000000..85047688 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-ports-status-after-alpha--yaqm024j41anp4vn.md @@ -0,0 +1,57 @@ +--- +id: fnd-ports-status-after-alpha--yaqm024j41anp4vn +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Ports status after alpha +kind: compaction +created_at: '2026-03-10T17:00:00Z' +created_by: Priya Natarajan +derives_from: + - con-frame-budget--br0qszfg8fys908n + - con-skiff-memory-budget--nf7qbhsnmcn6v479 + - dec-load-skiff-fast-travel-without-a-loading-screen--v4qft5znysjv5f24 + - dec-offer-a-40-hz-mode-on-skiff-alongside-30-hz--xhcgs101g1stnf05 + - dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb + - dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3 + - dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn + - dec-use-kelp-s-high-ratio-mode-for-skiff-textures--ztsejzpkp6nn13s5 + - iss-no-skiff-dev-kits-on-firmware-1-2--3qkawq17a60504j7 + - rsk-skiff-runs-out-of-memory-in-dense-districts--p5pv42sgezzjhpfz +superseded_by: + - fnd-ports-status-after-beta--g265shcdqe263c44 +covers: + - con-frame-budget--br0qszfg8fys908n@live + - con-meridian-memory-budget--99q6099e423wdtqn@live + - con-skiff-memory-budget--nf7qbhsnmcn6v479@live + - >- + dec-load-skiff-fast-travel-without-a-loading-screen--v4qft5znysjv5f24@accepted + - dec-offer-a-40-hz-mode-on-skiff-alongside-30-hz--xhcgs101g1stnf05@accepted + - >- + dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb@accepted + - dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3@accepted + - >- + dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn@accepted + - dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw@accepted + - dec-use-kelp-s-high-ratio-mode-for-skiff-textures--ztsejzpkp6nn13s5@accepted + - fnd-harbor-district-needs-1-460-pipelines-on-skiff--dwd5ry1wqaeacmpn@live + - fnd-harbor-district-peaks-at-8-6-gb-on-skiff--vccxye8jy3mkba2v@live + - fnd-kelp-high-ratio-textures-bring-the-skiff-harbor--rnzeng8fj363pr75@live + - fnd-prebuilt-pipeline-blobs-load-on-skiff-dev-firmwa--yzb10ygwr1q151e7@live + - fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q@live + - fnd-skiff-40-hz-playtest-9-of-12-testers-preferred-4--8jbe1vyf06rzdcek@live + - fnd-skiff-dev-kit-gives-the-game-9-gb--e6h71skfna4ttpd0@live + - fnd-skiff-microsd-sustains-92-mb-s--xr1fsyjd45y2tqcx@live + - fnd-skiff-sdk-1-2-takes-1-gb-back-from-games--a0ybdgjzw64hwfqa@live + - fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0@live + - iss-first-visit-hitches-of-45-to-190-ms-on-skiff--jcraqy468yw51kpf@open + - iss-no-skiff-dev-kits-on-firmware-1-2--3qkawq17a60504j7@open + - iss-skiff-fast-travel-has-no-load-time-plan--8xqtfd6x0mfvbkts@open + - rsk-pipeline-compiles-hitch-skiff-on-first-visits--6sq225m8dx36aefs@open + - rsk-skiff-runs-out-of-memory-in-dense-districts--p5pv42sgezzjhpfz@realized + - rsk-skiff-throttles-the-gpu-in-long-handheld-session--1nwtqw8gyc9x4h1b@open + - rsk-tide-streaming-outruns-skiff-storage--6q8s3b383z2tyeyb@open +--- +Skiff memory budget is 8 GB from firmware 1.2. The harbor district overran it at 8.6 GB; Kelp high-ratio textures brought it to 7.7 GB. The out-of-memory risk is marked realized. + +Frame budget: Skiff 30 Hz at 33.3 ms, plus an optional 40 Hz mode at 25 ms. Dynamic resolution floor is 576p. Tern runs at the Performance preset on Skiff. + +Pipeline compiles are handled by shipping prebuilt blobs in the package. Fast travel on Skiff loads with no loading screen. Waiting on firmware 1.2 dev kits. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-ports-status-after-beta--g265shcdqe263c44.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-ports-status-after-beta--g265shcdqe263c44.md new file mode 100644 index 00000000..59be364b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-ports-status-after-beta--g265shcdqe263c44.md @@ -0,0 +1,70 @@ +--- +id: fnd-ports-status-after-beta--g265shcdqe263c44 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Ports status after beta +kind: compaction +created_at: '2026-07-10T17:00:00Z' +created_by: Priya Natarajan +derives_from: + - con-frame-budget--br0qszfg8fys908n + - con-skiff-memory-budget--nf7qbhsnmcn6v479 + - dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7 + - dec-make-skiff-a-launch-platform--7fh37fbjmqpjgj0a + - dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb + - dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3 + - dec-show-a-tide-chart-loading-screen-for-skiff-fast--yq2k6tt7gw38wvnh + - dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw + - rsk-skiff-certification-slips-past-the-release-candi--3xe2z6qf5ncxf87h + - rsk-tide-streaming-outruns-skiff-storage--6q8s3b383z2tyeyb +supersedes: + - fnd-ports-status-after-alpha--yaqm024j41anp4vn +covers: + - con-frame-budget--br0qszfg8fys908n@live + - con-meridian-memory-budget--99q6099e423wdtqn@live + - con-skiff-memory-budget--nf7qbhsnmcn6v479@live + - con-skiff-minimum-text-height--hhc7n09kx88203zh@live + - con-skiff-storage-write-limit--39sn09p505a1s8j7@live + - dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7@accepted + - dec-make-skiff-a-launch-platform--7fh37fbjmqpjgj0a@accepted + - dec-offer-a-40-hz-mode-on-skiff-alongside-30-hz--xhcgs101g1stnf05@accepted + - >- + dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb@accepted + - >- + dec-rejoin-the-co-op-session-after-meridian-resumes--gp2btfw62qm4khy9@accepted + - dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3@accepted + - dec-scale-the-skiff-hud-to-125-percent--9gnbdvt72aq3n3vc@accepted + - >- + dec-ship-the-missing-meridian-activity-cards-in-the--g947vhgwr7smr8dq@accepted + - >- + dec-show-a-tide-chart-loading-screen-for-skiff-fast--yq2k6tt7gw38wvnh@accepted + - dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw@accepted + - dec-use-kelp-s-high-ratio-mode-for-skiff-textures--ztsejzpkp6nn13s5@accepted + - dec-write-delta-saves-on-skiff--a0g7x2bvk59t82jw@accepted + - fnd-beta-retrospective-for-the-skiff-port--hwdfe7e67ja5r2h6@live + - fnd-firmware-1-2-skiff-dev-kits-arrived--7dzaq12qessxaasd@live + - fnd-harbor-district-needs-1-460-pipelines-on-skiff--dwd5ry1wqaeacmpn@live + - fnd-harbor-district-peaks-at-8-6-gb-on-skiff--vccxye8jy3mkba2v@live + - fnd-kelp-high-ratio-textures-bring-the-skiff-harbor--rnzeng8fj363pr75@live + - fnd-meridian-drops-co-op-sessions-because-the-relay--73hf67080kkyf76j@live + - fnd-platform-holder-waived-the-docked-30-hz-judder-a--7qckhx7c2vfyemqd@live + - fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q@live + - fnd-skiff-40-hz-playtest-9-of-12-testers-preferred-4--8jbe1vyf06rzdcek@live + - fnd-skiff-dev-kit-gives-the-game-9-gb--e6h71skfna4ttpd0@live + - fnd-skiff-firmware-1-2-rejects-pipeline-blobs-built--pernvgb2he7m3z3y@live + - fnd-skiff-gpu-clock-drops-8-percent-after-20-minutes--5st35qqh8nwzabb4@live + - fnd-skiff-microsd-slows-sharply-on-full-warm-cards--p1rgh36hat2egpz3@live + - fnd-skiff-pipeline-cache-removes-second-visit-hitche--kzjtp9dpbpbmrb0x@live + - fnd-skiff-pre-certification-found-two-failures-and-o--ehe0e727vmd0d1jj@live + - fnd-skiff-sdk-1-2-takes-1-gb-back-from-games--a0ybdgjzw64hwfqa@live + - fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0@live + - rsk-skiff-certification-slips-past-the-release-candi--3xe2z6qf5ncxf87h@open + - rsk-skiff-runs-out-of-memory-in-dense-districts--p5pv42sgezzjhpfz@realized + - rsk-tide-streaming-outruns-skiff-storage--6q8s3b383z2tyeyb@open +--- +Skiff is a launch platform. Skiff memory budget is 8 GB; the harbor peak is 7.7 GB with Kelp high-ratio textures. + +Frame budget: Skiff 30 Hz at 33.3 ms, 40 Hz mode at 25 ms. Dynamic resolution floor on Skiff is 576p. Tern runs at the Performance preset on Skiff. + +Pipeline compiles: the on-device pipeline cache replaced prebuilt blobs; second visits hit the cache 99.6 percent of the time. Fast travel on Skiff shows a tide-chart loading screen. World tiles stream in 2 MB reads. + +Open risks: tide streaming on slow storage, and Skiff certification slipping past the release candidate. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-prebuilt-pipeline-blobs-load-on-skiff-dev-firmwa--yzb10ygwr1q151e7.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-prebuilt-pipeline-blobs-load-on-skiff-dev-firmwa--yzb10ygwr1q151e7.md new file mode 100644 index 00000000..bc06da4a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-prebuilt-pipeline-blobs-load-on-skiff-dev-firmwa--yzb10ygwr1q151e7.md @@ -0,0 +1,13 @@ +--- +id: fnd-prebuilt-pipeline-blobs-load-on-skiff-dev-firmwa--yzb10ygwr1q151e7 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Prebuilt pipeline blobs load on Skiff dev firmware +kind: measurement +created_at: '2025-12-11T15:00:00Z' +created_by: Liam O'Connell +derives_from: + - iss-how-should-skiff-avoid-first-use-pipeline-compil--5nvhn8xzyz2d7y7k +invalidated_by: + - fnd-skiff-firmware-1-2-rejects-pipeline-blobs-built--pernvgb2he7m3z3y +--- +Liam O'Connell built pipeline blobs on the build farm and loaded them on a Skiff dev kit running firmware 1.0. All 1,460 harbor pipelines loaded with no compile and no hitch. Only one firmware version was tested. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-priority-lanes-still-leave-workers-28-idle-durin--fhswesk5c086dk1y.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-priority-lanes-still-leave-workers-28-idle-durin--fhswesk5c086dk1y.md new file mode 100644 index 00000000..10e5e376 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-priority-lanes-still-leave-workers-28-idle-durin--fhswesk5c086dk1y.md @@ -0,0 +1,12 @@ +--- +id: fnd-priority-lanes-still-leave-workers-28-idle-durin--fhswesk5c086dk1y +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Priority lanes still leave workers 28% idle during tide turns +kind: measurement +created_at: '2025-11-18T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - dec-run-engine-jobs-on-a-work-stealing-thread-pool-w--8zpbcym92dkh87f1 + - fnd-streaming-jobs-block-workers-while-waiting-on-re--sn2bmfdgjeqwkk3p +--- +During a tide turn the streaming lane gets 18 cell reloads at once. Both streaming workers block on reads, the lane backs up, and across the pool workers are idle 28% of the time while work waits. Adding streaming workers only moves the problem, because each new worker also blocks. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-probe-grid-leaks-light-through-thin-saltglass-wa--h2hdqdfj92mnmkbj.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-probe-grid-leaks-light-through-thin-saltglass-wa--h2hdqdfj92mnmkbj.md new file mode 100644 index 00000000..5e3a5c9e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-probe-grid-leaks-light-through-thin-saltglass-wa--h2hdqdfj92mnmkbj.md @@ -0,0 +1,11 @@ +--- +id: fnd-probe-grid-leaks-light-through-thin-saltglass-wa--h2hdqdfj92mnmkbj +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Probe grid leaks light through thin saltglass walls +kind: measurement +created_at: '2025-10-17T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - iss-how-should-lantern-do-global-illumination--3hs82xftkrdhk3f7 +--- +With 1 m probe spacing, probes behind 20 cm saltglass walls in the ruins see the sunlit side, and the dark side glows. Halving the spacing to 0.5 m cuts the leak by about half and costs eight times the probes. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-projected-caustic-textures-tile-visibly-past-600--dkyy65zqqh5gx04x.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-projected-caustic-textures-tile-visibly-past-600--dkyy65zqqh5gx04x.md new file mode 100644 index 00000000..68dccd69 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-projected-caustic-textures-tile-visibly-past-600--dkyy65zqqh5gx04x.md @@ -0,0 +1,11 @@ +--- +id: fnd-projected-caustic-textures-tile-visibly-past-600--dkyy65zqqh5gx04x +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Projected caustic textures tile visibly past 600 m +kind: measurement +created_at: '2025-12-09T10:00:00Z' +created_by: Yusuf Demir +invalidates: + - dec-project-animated-caustic-textures-along-the-sun--xe80zje9085n84q6 +--- +Yusuf Demir kept the projected caustic textures alive as a possible Skiff fallback and tested them on the far dunes. Past 600 m the texture repeat is obvious on every dune face. The projected option is wrong for saltglass at any distance the game shows. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-prototype-storm-particle-cap-saves-3-5-ms-on-the--p4evjsy9qfaehhg8.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-prototype-storm-particle-cap-saves-3-5-ms-on-the--p4evjsy9qfaehhg8.md new file mode 100644 index 00000000..72eb1cea --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-prototype-storm-particle-cap-saves-3-5-ms-on-the--p4evjsy9qfaehhg8.md @@ -0,0 +1,11 @@ +--- +id: fnd-prototype-storm-particle-cap-saves-3-5-ms-on-the--p4evjsy9qfaehhg8 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Prototype storm particle cap saves 3.5 ms on the Skiff CPU +kind: measurement +created_at: '2026-09-08T16:00:00Z' +created_by: Yusuf Demir +derives_from: + - dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1 +--- +Yusuf Demir built the 6,000 particle cap behind a debug flag. On the storm sequence the CPU frame fell from 28.4 ms to 24.9 ms in the 40 Hz mode, 0.1 ms inside budget. Art has not signed off on the thinner storm, and nobody has chosen between the cap and the 30 Hz fallback yet. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-quarter-resolution-sdf-gi-costs-1-9-ms-in-perfor--md9qdmtne78wv7mf.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-quarter-resolution-sdf-gi-costs-1-9-ms-in-perfor--md9qdmtne78wv7mf.md new file mode 100644 index 00000000..d0e31ad9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-quarter-resolution-sdf-gi-costs-1-9-ms-in-perfor--md9qdmtne78wv7mf.md @@ -0,0 +1,12 @@ +--- +id: fnd-quarter-resolution-sdf-gi-costs-1-9-ms-in-perfor--md9qdmtne78wv7mf +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Quarter-resolution SDF GI costs 1.9 ms in performance mode +kind: measurement +created_at: '2026-06-24T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - con-meridian-120-hz-performance-mode-budget--khgjmq18bfr40tyj + - dec-trace-sdf-gi-at-quarter-resolution-in-performanc--06cqt3mqn3fg5h6e +--- +Quarter-resolution tracing measured 1.9 ms on the dunes benchmark in performance mode, not the 1.3 ms hoped for; the upsample filter costs 0.5 ms by itself. Performance mode allows GI at most 1.0 ms. Neither proposal fits as written. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-quarter-resolution-tide-re-simulation-desyncs-pe--064cvn1d3t35bnra.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-quarter-resolution-tide-re-simulation-desyncs-pe--064cvn1d3t35bnra.md new file mode 100644 index 00000000..daff4004 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-quarter-resolution-tide-re-simulation-desyncs-pe--064cvn1d3t35bnra.md @@ -0,0 +1,12 @@ +--- +id: fnd-quarter-resolution-tide-re-simulation-desyncs-pe--064cvn1d3t35bnra +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Quarter-resolution tide re-simulation desyncs peers within 90 seconds +kind: measurement +created_at: '2026-03-27T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g + - dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f +--- +In the quarter-resolution prototype the tide checksum diverged between peers within 90 seconds in all 10 runs. The correction step rounds differently depending on how many frames were rolled back. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-raw-source-cache-keys-served-stale-shaders-after--f32vyjth0qtmr6wb.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-raw-source-cache-keys-served-stale-shaders-after--f32vyjth0qtmr6wb.md new file mode 100644 index 00000000..9c024cfb --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-raw-source-cache-keys-served-stale-shaders-after--f32vyjth0qtmr6wb.md @@ -0,0 +1,11 @@ +--- +id: fnd-raw-source-cache-keys-served-stale-shaders-after--f32vyjth0qtmr6wb +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Raw-source cache keys served stale shaders after header edits +kind: defect +created_at: '2025-10-14T08:30:00Z' +created_by: Yusuf Demir +derives_from: + - dec-key-the-shader-cache-on-raw-source-text-and-comp--hp6awmx3gq5rn9nc +--- +Three nightly builds between 2025-10-09 and 2025-10-13 shipped refraction shaders compiled against an old lighting header. The raw-source key did not change when only an included header changed, so agents fetched stale bytecode. Yusuf Demir caught it when saltglass caustics rendered with last week's falloff curve. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-re-running-tides-every-rollback-frame-costs-4-8--tp4gxe8prh0bh9h4.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-re-running-tides-every-rollback-frame-costs-4-8--tp4gxe8prh0bh9h4.md new file mode 100644 index 00000000..d2fb2ce3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-re-running-tides-every-rollback-frame-costs-4-8--tp4gxe8prh0bh9h4.md @@ -0,0 +1,16 @@ +--- +id: fnd-re-running-tides-every-rollback-frame-costs-4-8--tp4gxe8prh0bh9h4 +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Re-running tides every rollback frame costs 4.8 ms on Skiff +kind: measurement +created_at: '2026-03-19T10:00:00Z' +created_by: Sofia Marchetti +derives_from: + - iss-rollback-has-not-been-profiled-on-skiff-with-tid--34pra8d0kj2x92dg + - rsk-re-simulation-cost-could-blow-the-skiff-frame-bu--sk2njsp170a3qwyf +invalidates: + - fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf +cites: + - cit-skiff-rollback-profile-capture--qhbe4rs9ax0h3z3d +--- +With tides in the snapshot, every rolled-back frame must re-run the tide step. One 32.32 fixed-point tide step costs 0.8 ms on Skiff, so a full 6-frame rollback re-runs tides for 4.8 ms, before physics and Gull. Rollbacks happen on most frames at Wi-Fi latency. Against the 25 ms Skiff frame at 40 Hz that is far too much. The 1.1 ms PC figure was measured with tides frozen and does not describe the real cost. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-reactive-mask-removes-61-percent-of-saltglass-gh--csg97ges3067ehrp.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-reactive-mask-removes-61-percent-of-saltglass-gh--csg97ges3067ehrp.md new file mode 100644 index 00000000..ca77abfb --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-reactive-mask-removes-61-percent-of-saltglass-gh--csg97ges3067ehrp.md @@ -0,0 +1,13 @@ +--- +id: fnd-reactive-mask-removes-61-percent-of-saltglass-gh--csg97ges3067ehrp +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Reactive mask removes 61 percent of saltglass ghosting with a moving camera +kind: measurement +created_at: '2026-06-08T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k +invalidates: + - fnd-a-saltglass-reactive-mask-removes-90-percent-of--p2mmqg2yj8nz43st +--- +The 90 percent figure came from the orbit test with a fixed orbit speed, which the mask was tuned on. On the free-camera dunes route the mask removes 61 percent of ghosting energy, and trails of five or six frames remain behind fast glass. The mask helps but the earlier number overstated it. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-refraction-cost-screen-space-0-9-ms-ray-marched--pr6bzy3tvstaptdc.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-refraction-cost-screen-space-0-9-ms-ray-marched--pr6bzy3tvstaptdc.md new file mode 100644 index 00000000..20578b95 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-refraction-cost-screen-space-0-9-ms-ray-marched--pr6bzy3tvstaptdc.md @@ -0,0 +1,11 @@ +--- +id: fnd-refraction-cost-screen-space-0-9-ms-ray-marched--pr6bzy3tvstaptdc +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Refraction cost: screen-space 0.9 ms, ray-marched 3.4 ms' +kind: measurement +created_at: '2025-10-02T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-how-should-lantern-render-saltglass-refraction--brndmsn2n8jz6yyk +--- +On the cliffs benchmark with saltglass covering 40 percent of the screen, screen-space refraction costs 0.9 ms and a 64-step ray march through the distance field costs 3.4 ms. Local cubemaps cost 0.5 ms but show the wrong place behind the glass whenever the camera moves away from the capture point. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-register-vm-prototype-runs-the-crab-herd-4-1x-fa--1eb9hfat7611jksr.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-register-vm-prototype-runs-the-crab-herd-4-1x-fa--1eb9hfat7611jksr.md new file mode 100644 index 00000000..a6c5f42a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-register-vm-prototype-runs-the-crab-herd-4-1x-fa--1eb9hfat7611jksr.md @@ -0,0 +1,12 @@ +--- +id: fnd-register-vm-prototype-runs-the-crab-herd-4-1x-fa--1eb9hfat7611jksr +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Register VM prototype runs the crab herd 4.1x faster +kind: measurement +created_at: '2026-01-23T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3 + - fnd-alpha-content-needs-6-2-ms-of-gull-time-per-fram--4mekgdpsdv5nk085 +--- +Rhea Valdés's register VM prototype runs the 1,200-crab herd in 1.5 ms per frame on Meridian, against 6.2 ms on the interpreter: 4.1x faster. Bytecode for all alpha scripts is 2.3 MB. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-release-candidate-capture-quality-mode-14-6-ms-p--rc0kswjvgrwcp8te.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-release-candidate-capture-quality-mode-14-6-ms-p--rc0kswjvgrwcp8te.md new file mode 100644 index 00000000..ea91bf5a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-release-candidate-capture-quality-mode-14-6-ms-p--rc0kswjvgrwcp8te.md @@ -0,0 +1,12 @@ +--- +id: fnd-release-candidate-capture-quality-mode-14-6-ms-p--rc0kswjvgrwcp8te +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: 'Release-candidate capture: quality mode 14.6 ms, performance mode 7.3 ms' +kind: measurement +created_at: '2026-09-25T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - con-frame-budget--fzdrbxns6dmrrmy3 + - con-meridian-120-hz-performance-mode-budget--khgjmq18bfr40tyj +--- +Nightly capture of the release-candidate build on a Meridian devkit, dunes flyover. Quality mode GPU time is 14.6 ms against the 15.0 ms allowance. Performance mode GPU time is 7.3 ms against 7.4 ms, with 0.1 ms to spare. Spring low tide was not part of this run. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-remote-execution-spreads-cache-misses-across-all--120mx6z98n6qfmwh.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-remote-execution-spreads-cache-misses-across-all--120mx6z98n6qfmwh.md new file mode 100644 index 00000000..a6492138 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-remote-execution-spreads-cache-misses-across-all--120mx6z98n6qfmwh.md @@ -0,0 +1,11 @@ +--- +id: fnd-remote-execution-spreads-cache-misses-across-all--120mx6z98n6qfmwh +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Remote execution spreads cache misses across all 12 agents +kind: measurement +created_at: '2025-11-03T13:00:00Z' +created_by: Liam O'Connell +derives_from: + - dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh +--- +With the cache warm, a typical build still misses about 2,400 permutations. Compiled on the agent that started the job, those misses take 11 minutes. Fanned out to all 12 agents through remote execution, they take 1 minute 50 seconds, plus 25 seconds of scheduling overhead. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-retail-skiff-units-sustain-only-190-mb-s-of-stre--485sdcmm3gweevvn.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-retail-skiff-units-sustain-only-190-mb-s-of-stre--485sdcmm3gweevvn.md new file mode 100644 index 00000000..8708a04e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-retail-skiff-units-sustain-only-190-mb-s-of-stre--485sdcmm3gweevvn.md @@ -0,0 +1,15 @@ +--- +id: fnd-retail-skiff-units-sustain-only-190-mb-s-of-stre--485sdcmm3gweevvn +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Retail Skiff units sustain only 190 MB/s of streaming reads +kind: measurement +created_at: '2026-02-20T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-skiff-streaming-reads-sustain-260-mb-s--s1gkt975grre2ewr +invalidates: + - fnd-skiff-streaming-reads-sustain-260-mb-s--s1gkt975grre2ewr +cites: + - cit-retail-skiff-streaming-trace-stream-trace-0217--gsdd04w1pck5s0am +--- +The December figure came from a dev kit, which has faster storage than retail units. On two retail Skiff units the same coast loop sustains about 190 MB/s, and tail latency is nearly three times worse. The trace lists each unit. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-retrospective-on-the-shader-compile-cache--9rpv2a60ach04cx6.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-retrospective-on-the-shader-compile-cache--9rpv2a60ach04cx6.md new file mode 100644 index 00000000..70b52db7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-retrospective-on-the-shader-compile-cache--9rpv2a60ach04cx6.md @@ -0,0 +1,29 @@ +--- +id: fnd-retrospective-on-the-shader-compile-cache--9rpv2a60ach04cx6 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Retrospective on the shader compile cache +kind: retrospective +created_at: '2026-04-28T15:00:00Z' +created_by: Liam O'Connell +derives_from: + - dec-turn-the-shader-compile-cache-on-for-every-farm--4rr3b12b4sasdmaj + - fnd-shader-cache-hit-rate-climbs-steadily-after-the--2d268h587na645rx + - iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj + - rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd +--- +The cache has run on every farm build for five weeks. What went well and what did not: + +- The content-addressed design held up. Two key changes were needed before the cache could be trusted: the first after stale headers, the second after the compiler hotfix build. +- Remote execution made cold builds tolerable inside the 12-agent limit. +- We lost about three weeks blaming the network for the flaky nightly builds. The real cause was memory on agents 7 and 11. +- The byte-compare sample caught real problems twice and never fired falsely. + +Numbers at the end of the Effort: + +- Steady-state hit rate: 94%. +- Storage used: 1.9 TB of the 4 TB volume, growing about 210 GB a month, which leaves roughly ten months of headroom. + +Dara Whitlock and Liam O'Connell agreed not to build cache eviction before release; storage growth is accepted as it stands. +Workstation access to the cache is deferred until after release; it needs a VPN change nobody has time for. + +Final clean rebuild time with a warm cache: 6 min 40 s, down from 47 minutes. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf.md new file mode 100644 index 00000000..61308a98 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf.md @@ -0,0 +1,13 @@ +--- +id: fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Rollback re-simulates a 4-frame window in 1.1 ms on PC +kind: measurement +created_at: '2025-11-18T14:00:00Z' +created_by: Sofia Marchetti +derives_from: + - dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4 +invalidated_by: + - fnd-re-running-tides-every-rollback-frame-costs-4-8--tp4gxe8prh0bh9h4 +--- +First rollback prototype on Shoal-01, PC, four players. Restoring a snapshot and re-simulating 4 frames takes 1.1 ms in total. Sofia Marchetti calls this cheap enough to grow the window later. Caveat: the tide simulation was frozen for this run, because it was not yet in the snapshot. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q.md new file mode 100644 index 00000000..7e6a47a5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q.md @@ -0,0 +1,11 @@ +--- +id: fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Saltglass caustics shimmer at the 540p floor +kind: measurement +created_at: '2026-01-20T14:00:00Z' +created_by: Yusuf Demir +derives_from: + - dec-scale-skiff-resolution-dynamically-between-540p--jtytvgh2erd32x68 +--- +At 540p internal resolution the caustic patterns under saltglass shimmer badly in motion, even after Tern. Yusuf Demir counted visible shimmer in 7 of 10 dune views. At 576p it drops to 2 of 10. The 576p floor costs 1.3 ms more on the worst view. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-screen-space-refraction-halos-around-the-player--6ytj9mvh0v1bfsdf.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-screen-space-refraction-halos-around-the-player--6ytj9mvh0v1bfsdf.md new file mode 100644 index 00000000..9d076753 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-screen-space-refraction-halos-around-the-player--6ytj9mvh0v1bfsdf.md @@ -0,0 +1,11 @@ +--- +id: fnd-screen-space-refraction-halos-around-the-player--6ytj9mvh0v1bfsdf +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Screen-space refraction halos around the player +kind: measurement +created_at: '2025-11-26T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6 +--- +When the player stands in front of saltglass, the refraction samples the player instead of what is behind the glass, leaving a bright halo two to six pixels wide around the silhouette. A depth test on the offset sample removes most of it. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy.md new file mode 100644 index 00000000..8fd129f7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy.md @@ -0,0 +1,11 @@ +--- +id: fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Screen-space refraction loses off-screen content at grazing angles +kind: measurement +created_at: '2025-12-04T14:00:00Z' +created_by: Yusuf Demir +invalidates: + - dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6 +--- +Looking along the dunes at grazing angles, 30 to 45 percent of refracted rays leave the screen, and those pixels show smeared edge color. This is the common view in the game, not a corner case. Screen-space refraction cannot be the answer for saltglass on its own; the vertical slice will ship with the artifact. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-sdf-gi-costs-2-2-ms-on-meridian--r7t7zy97nwxxxctd.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-sdf-gi-costs-2-2-ms-on-meridian--r7t7zy97nwxxxctd.md new file mode 100644 index 00000000..3ffb307d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-sdf-gi-costs-2-2-ms-on-meridian--r7t7zy97nwxxxctd.md @@ -0,0 +1,15 @@ +--- +id: fnd-sdf-gi-costs-2-2-ms-on-meridian--r7t7zy97nwxxxctd +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: SDF GI costs 2.2 ms on Meridian +kind: measurement +created_at: '2025-10-15T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-how-should-lantern-do-global-illumination--3hs82xftkrdhk3f7 +invalidated_by: + - fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr +cites: + - cit-capture-sdf-gi-dunes-benchmark--3q4n5ewn42faqaeb +--- +SDF GI with four clipmap cascades of 64 cubed costs 2.2 ms per frame at 1440p on the dunes benchmark, with tracing the largest part at 1.3 ms. That is affordable inside the Frame budget. The capture is attached. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-sdf-gi-costs-2-4-ms-on-meridian--2w6c2pc5zmcsyjre.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-sdf-gi-costs-2-4-ms-on-meridian--2w6c2pc5zmcsyjre.md new file mode 100644 index 00000000..fc4fd3e8 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-sdf-gi-costs-2-4-ms-on-meridian--2w6c2pc5zmcsyjre.md @@ -0,0 +1,14 @@ +--- +id: fnd-sdf-gi-costs-2-4-ms-on-meridian--2w6c2pc5zmcsyjre +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: SDF GI costs 2.4 ms on Meridian +kind: measurement +created_at: '2025-10-15T10:05:00Z' +created_by: Tomasz Brandt +retracted: true +retracted_at: '2025-10-16T10:00:00.000Z' +retracted_reason: >- + Draft written before the capture finished; the 2.4 ms figure included the + debug overlay. The 2.2 ms Finding is the one to use. +--- +SDF GI costs 2.4 ms per frame at 1440p on the dunes benchmark. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr.md new file mode 100644 index 00000000..6a3085c9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr.md @@ -0,0 +1,17 @@ +--- +id: fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: SDF GI costs 4.7 ms on Meridian +kind: measurement +created_at: '2026-02-05T10:00:00Z' +created_by: Tomasz Brandt +invalidates: + - fnd-sdf-gi-costs-2-2-ms-on-meridian--r7t7zy97nwxxxctd +cites: + - cit-capture-sdf-gi-on-a-meridian-devkit--1hjqjkb1e7z7tryy +--- +The October SDF GI number was not a Meridian number. The first nightly devkit capture of the dunes benchmark puts SDF GI at 4.7 ms, more than twice the 2.2 ms the GI Decision was accepted on. Tracing went from 1.3 ms to 3.2 ms; the distance-field update and the filter grew a little too. The October capture predates the nightly capture job and was taken by hand; its attached capture names the machine it ran on. + +Why the gap is so large: SDF tracing is bound by cache misses. Each cone step reads a different part of the clipmap, so the trace pass lives or dies on the L2 cache. The Decision 'Use signed-distance-field GI' still stands on the 2.2 ms figure and nobody has re-weighed it against the probe grid. Tomasz Brandt does not propose reversing it yet, because the probe grid still leaks through thin walls. + +The L2 hit rate in the trace pass fell from 81 percent in the October capture to 52 percent on the devkit. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-sdf-volumes-use-410-mb-of-render-target-memory--y8bm788y240rqq7d.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-sdf-volumes-use-410-mb-of-render-target-memory--y8bm788y240rqq7d.md new file mode 100644 index 00000000..465551ea --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-sdf-volumes-use-410-mb-of-render-target-memory--y8bm788y240rqq7d.md @@ -0,0 +1,11 @@ +--- +id: fnd-sdf-volumes-use-410-mb-of-render-target-memory--y8bm788y240rqq7d +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: SDF volumes use 410 MB of render-target memory +kind: measurement +created_at: '2026-03-09T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - rsk-sdf-volumes-outgrow-the-render-target-memory-bud--xfd2pfztvskdcd2c +--- +With every ruin in the alpha build loaded, the clipmaps and per-mesh distance fields use 410 MB of the 1.8 GB render-target budget. That fits today, but leaves about 90 MB of slack for new ruins before the 500 MB line the Risk named. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shader-cache-hit-rate-climbs-steadily-after-the--2d268h587na645rx.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shader-cache-hit-rate-climbs-steadily-after-the--2d268h587na645rx.md new file mode 100644 index 00000000..96464b55 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shader-cache-hit-rate-climbs-steadily-after-the--2d268h587na645rx.md @@ -0,0 +1,13 @@ +--- +id: fnd-shader-cache-hit-rate-climbs-steadily-after-the--2d268h587na645rx +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Shader cache hit rate climbs steadily after the key change +kind: measurement +created_at: '2026-01-26T11:00:00Z' +created_by: Liam O'Connell +derives_from: + - dec-key-the-shader-cache-on-preprocessed-source-defi--3a05ff0r954vxh30 +cites: + - cit-weekly-shader-cache-hit-rate-report--821p29gvf3dtcssg +--- +The first week on the binary-hash key started cold and hit 71% of permutations. The rate climbed every week after that; the weekly figures are in the attached report. Median build time is now well under the 47 minutes we started from. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shader-cache-hit-rate-reaches-97-percent--hv1e342tgdw7fs79.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shader-cache-hit-rate-reaches-97-percent--hv1e342tgdw7fs79.md new file mode 100644 index 00000000..674ca082 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shader-cache-hit-rate-reaches-97-percent--hv1e342tgdw7fs79.md @@ -0,0 +1,14 @@ +--- +id: fnd-shader-cache-hit-rate-reaches-97-percent--hv1e342tgdw7fs79 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Shader cache hit rate reaches 97 percent +kind: measurement +created_at: '2026-06-08T11:00:00Z' +created_by: Liam O'Connell +retracted: true +retracted_at: '2026-06-08T11:30:00.000Z' +retracted_reason: >- + Build farm compile cache numbers posted to the wrong Effort. They say nothing + about the Skiff on-device pipeline cache. +--- +Shader cache hit rate is 97 percent across the last 50 builds. Cold compiles fell from 41 minutes to 6. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shader-cache-warms-in-40-seconds-on-first-boot--eadc6xjwgfhmbg86.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shader-cache-warms-in-40-seconds-on-first-boot--eadc6xjwgfhmbg86.md new file mode 100644 index 00000000..ce88e4d7 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shader-cache-warms-in-40-seconds-on-first-boot--eadc6xjwgfhmbg86.md @@ -0,0 +1,14 @@ +--- +id: fnd-shader-cache-warms-in-40-seconds-on-first-boot--eadc6xjwgfhmbg86 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Shader cache warms in 40 seconds on first boot +kind: measurement +created_at: '2025-12-10T16:00:00Z' +created_by: Priya Natarajan +retracted: true +retracted_at: '2025-12-11T09:00:00.000Z' +retracted_reason: >- + Filed in the wrong Effort. This measures the on-device pipeline cache on + Skiff, which the ports Effort owns, not the build farm shader compile cache. +--- +On a Skiff devkit, the pipeline cache took 40 seconds to warm on first boot of the coast level, with hitches of up to 120 ms while it filled. Second boot showed no hitches. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shader-compile-cache-where-things-stand-in-febru--xnwv3jqqg71tb370.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shader-compile-cache-where-things-stand-in-febru--xnwv3jqqg71tb370.md new file mode 100644 index 00000000..1a29f990 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shader-compile-cache-where-things-stand-in-febru--xnwv3jqqg71tb370.md @@ -0,0 +1,41 @@ +--- +id: fnd-shader-compile-cache-where-things-stand-in-febru--xnwv3jqqg71tb370 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: 'Shader compile cache: where things stand in February' +kind: compaction +created_at: '2026-02-10T16:00:00Z' +created_by: Liam O'Connell +derives_from: + - dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh + - dec-fan-shader-cache-misses-out-to-every-farm-agent--pwrf9w720rf4hd27 + - dec-key-the-shader-cache-on-preprocessed-source-defi--3a05ff0r954vxh30 + - dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6 + - fnd-flaky-nightly-builds-trace-to-cache-server-fetch--v4wsxzj1x72zz8rs + - fnd-shader-cache-hit-rate-climbs-steadily-after-the--2d268h587na645rx + - iss-full-shader-rebuilds-take-47-minutes-on-the-buil--4bnh1e17snf5y3h6 + - iss-nightly-builds-fail-about-1-in-9-runs-with-shade--ka2xgkfgaepemgbh + - rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd +covers: + - con-a-cache-hit-must-give-the-same-bytes-as-a-fresh--3gmcswztxzpmpz83@live + - con-the-build-farm-stays-at-12-agents-until-alpha--w7e1xfex9z2ycpx1@live + - >- + dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh@accepted + - >- + dec-fan-shader-cache-misses-out-to-every-farm-agent--pwrf9w720rf4hd27@accepted + - >- + dec-key-the-shader-cache-on-preprocessed-source-defi--3a05ff0r954vxh30@accepted + - >- + dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6@accepted + - >- + dec-recompile-a-1-in-50-sample-of-cache-hits-and-com--9n176hnc9w0tax3s@accepted + - fnd-flaky-nightly-builds-trace-to-cache-server-fetch--v4wsxzj1x72zz8rs@live + - fnd-most-shader-compile-time-on-the-farm-repeats-ide--n7mr2yxxxtzpak35@live + - fnd-raw-source-cache-keys-served-stale-shaders-after--f32vyjth0qtmr6wb@live + - fnd-remote-execution-spreads-cache-misses-across-all--120mx6z98n6qfmwh@live + - fnd-shader-cache-hit-rate-climbs-steadily-after-the--2d268h587na645rx@live + - fnd-two-compiler-builds-with-the-same-version-string--gmgr4ha0ndxqmcn9@live + - iss-full-shader-rebuilds-take-47-minutes-on-the-buil--4bnh1e17snf5y3h6@open + - iss-nightly-builds-fail-about-1-in-9-runs-with-shade--ka2xgkfgaepemgbh@open + - rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd@open +--- +The farm shader compile cache is live on nightly builds. Remote execution spreads cache misses across all 12 agents. The current key hashes preprocessed source, defines, target and the compiler binary; hit rate reached the low 90s. Flaky nightly builds are still open. The working diagnosis is cache server fetch timeouts during the 02:00 burst, and the fix in place is the 30-second fetch timeout. Storage growth is an open Risk. Next: turn the cache on for every build, then close the Effort before alpha. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shipping-entity-names-costs-57-mb-at-full-popula--6w7gjvy7wdmdx9qx.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shipping-entity-names-costs-57-mb-at-full-popula--6w7gjvy7wdmdx9qx.md new file mode 100644 index 00000000..510021ad --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-shipping-entity-names-costs-57-mb-at-full-popula--6w7gjvy7wdmdx9qx.md @@ -0,0 +1,11 @@ +--- +id: fnd-shipping-entity-names-costs-57-mb-at-full-popula--6w7gjvy7wdmdx9qx +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Shipping entity names costs 57 MB at full population +kind: measurement +created_at: '2025-11-06T11:00:00Z' +created_by: Rhea Valdés +derives_from: + - iss-entity-debug-names-are-missing-in-release-builds--e00p8nba80n2ykb8 +--- +A Name component averages 48 bytes. At the 1.2 million entities of a fully populated coast that is 57 MB, which no console budget can spare. The crash pipeline can map entity numbers back to names from the build's symbol file instead. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-simulated-forecast-eviction-cuts-reloads-by-63--7c086ee2h8dw247k.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-simulated-forecast-eviction-cuts-reloads-by-63--7c086ee2h8dw247k.md new file mode 100644 index 00000000..ca1c511a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-simulated-forecast-eviction-cuts-reloads-by-63--7c086ee2h8dw247k.md @@ -0,0 +1,13 @@ +--- +id: fnd-simulated-forecast-eviction-cuts-reloads-by-63--7c086ee2h8dw247k +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Simulated forecast eviction cuts reloads by 63% +kind: simulation +created_at: '2026-01-08T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-lru-eviction-thrashes-during-tide-turns--0tvj4hmg42jy5d3f +invalidated_by: + - fnd-field-captures-show-forecast-eviction-cuts-reloa--ee6m7fwv4798jdmv +--- +Kenji Arakawa simulated an eviction policy that scores cells by distance from the player and by the tide forecast. Over 50 simulated tide cycles, it cuts reloads by 63% against LRU. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-40-hz-playtest-9-of-12-testers-preferred-4--8jbe1vyf06rzdcek.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-40-hz-playtest-9-of-12-testers-preferred-4--8jbe1vyf06rzdcek.md new file mode 100644 index 00000000..0687b334 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-40-hz-playtest-9-of-12-testers-preferred-4--8jbe1vyf06rzdcek.md @@ -0,0 +1,11 @@ +--- +id: fnd-skiff-40-hz-playtest-9-of-12-testers-preferred-4--8jbe1vyf06rzdcek +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Skiff 40 Hz playtest: 9 of 12 testers preferred 40 Hz' +kind: survey +created_at: '2026-01-12T16:00:00Z' +created_by: Dara Whitlock +derives_from: + - iss-should-skiff-offer-a-40-hz-mode--h83ktxc994y2gvx2 +--- +Dara Whitlock ran 12 testers through the dune route on Skiff at 30 Hz and at 40 Hz, in random order. 9 preferred 40 Hz, 2 saw no difference, 1 preferred 30 Hz for battery life. Battery drain rose from 11 to 13 percent an hour. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-co-op-sessions-over-wi-fi-see-180-ms-round--4ttevy0e2zfjqw18.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-co-op-sessions-over-wi-fi-see-180-ms-round--4ttevy0e2zfjqw18.md new file mode 100644 index 00000000..133c328b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-co-op-sessions-over-wi-fi-see-180-ms-round--4ttevy0e2zfjqw18.md @@ -0,0 +1,11 @@ +--- +id: fnd-skiff-co-op-sessions-over-wi-fi-see-180-ms-round--4ttevy0e2zfjqw18 +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Skiff co-op sessions over Wi-Fi see 180 ms round trips at p95 +kind: measurement +created_at: '2026-01-08T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - dec-use-a-4-frame-rollback-window--pqe4hvbgmbp0dmh9 +--- +Priya Natarajan logged 340 Skiff sessions on home Wi-Fi. Median round trip was 95 ms; p95 was 180 ms. A 4-frame window covers only about half of those sessions without stalls. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-dev-kit-firmware-blocks-the-gull-debugger--hjkc0v1fjd4qfxj4.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-dev-kit-firmware-blocks-the-gull-debugger--hjkc0v1fjd4qfxj4.md new file mode 100644 index 00000000..8092aa7c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-dev-kit-firmware-blocks-the-gull-debugger--hjkc0v1fjd4qfxj4.md @@ -0,0 +1,11 @@ +--- +id: fnd-skiff-dev-kit-firmware-blocks-the-gull-debugger--hjkc0v1fjd4qfxj4 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Skiff dev kit firmware blocks the Gull debugger port +kind: measurement +created_at: '2026-09-10T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - iss-the-gull-debugger-cannot-attach-on-skiff-dev-kit--84pppnx1wzwf33bz +--- +The new Skiff dev kit firmware closes every inbound port except the platform's own debug service. The Gull debugger listens on its own port, so the attach never connects. Tunnelling through the platform debug service would work, but nobody has built it. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-dev-kit-gives-the-game-9-gb--e6h71skfna4ttpd0.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-dev-kit-gives-the-game-9-gb--e6h71skfna4ttpd0.md new file mode 100644 index 00000000..d5def9b5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-dev-kit-gives-the-game-9-gb--e6h71skfna4ttpd0.md @@ -0,0 +1,13 @@ +--- +id: fnd-skiff-dev-kit-gives-the-game-9-gb--e6h71skfna4ttpd0 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff dev kit gives the game 9 GB +kind: measurement +created_at: '2025-10-20T14:00:00Z' +created_by: Priya Natarajan +derives_from: + - iss-skiff-memory-limits-for-the-game-are-unknown--3109v2v4p9x931cz +cites: + - cit-skiff-sdk-0-9-memory-map--nk82yq60vqfa2g4b +--- +The SDK 0.9 memory map on dev kit 0412 reserves 3 GB of the 12 GB for the system and hands 9 GB to the title. A test app allocated 9.0 GB and was killed at 9.02 GB. The figure holds in handheld and docked mode. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-devkits-reach-the-render-team-in-april--bx6zmw2s52vr2t1z.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-devkits-reach-the-render-team-in-april--bx6zmw2s52vr2t1z.md new file mode 100644 index 00000000..ac727208 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-devkits-reach-the-render-team-in-april--bx6zmw2s52vr2t1z.md @@ -0,0 +1,11 @@ +--- +id: fnd-skiff-devkits-reach-the-render-team-in-april--bx6zmw2s52vr2t1z +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Skiff devkits reach the render team in April +kind: survey +created_at: '2026-02-11T10:00:00Z' +created_by: Dara Whitlock +derives_from: + - iss-no-skiff-gpu-timings-for-lantern-passes--mve09m4aktb7tya1 +--- +Dara Whitlock checked with the platform holder: the render team gets two Skiff devkits in the first week of April 2026. Until then only the ports team has hardware, and it is booked for memory work. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-firmware-1-2-rejects-pipeline-blobs-built--pernvgb2he7m3z3y.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-firmware-1-2-rejects-pipeline-blobs-built--pernvgb2he7m3z3y.md new file mode 100644 index 00000000..710dff9b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-firmware-1-2-rejects-pipeline-blobs-built--pernvgb2he7m3z3y.md @@ -0,0 +1,13 @@ +--- +id: fnd-skiff-firmware-1-2-rejects-pipeline-blobs-built--pernvgb2he7m3z3y +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff firmware 1.2 rejects pipeline blobs built for firmware 1.0 +kind: measurement +created_at: '2026-03-20T11:00:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-firmware-1-2-skiff-dev-kits-arrived--7dzaq12qessxaasd +invalidates: + - fnd-prebuilt-pipeline-blobs-load-on-skiff-dev-firmwa--yzb10ygwr1q151e7 +--- +On the new firmware 1.2 kits, all 1,460 prebuilt harbor pipelines failed to load and recompiled on the device. Skiff checks a driver hash in every blob and rejects any blob built for another driver. The platform holder plans driver updates every two to three months, so shipped blobs would go stale after the first update. The December test passed only because it used the same firmware the blobs were built for. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-gpu-clock-drops-8-percent-after-20-minutes--5st35qqh8nwzabb4.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-gpu-clock-drops-8-percent-after-20-minutes--5st35qqh8nwzabb4.md new file mode 100644 index 00000000..ed5e1bb3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-gpu-clock-drops-8-percent-after-20-minutes--5st35qqh8nwzabb4.md @@ -0,0 +1,11 @@ +--- +id: fnd-skiff-gpu-clock-drops-8-percent-after-20-minutes--5st35qqh8nwzabb4 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff GPU clock drops 8 percent after 20 minutes handheld +kind: measurement +created_at: '2026-05-04T13:00:00Z' +created_by: Priya Natarajan +derives_from: + - rsk-skiff-throttles-the-gpu-in-long-handheld-session--1nwtqw8gyc9x4h1b +--- +In a 2 hour handheld session at 30 Hz, the Skiff GPU clock fell 8 percent after 20 minutes and stayed there. Dynamic resolution absorbed it; average internal resolution fell from 662p to 640p. No frame went past 33.3 ms. Docked play never throttled. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-microsd-slows-sharply-on-full-warm-cards--p1rgh36hat2egpz3.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-microsd-slows-sharply-on-full-warm-cards--p1rgh36hat2egpz3.md new file mode 100644 index 00000000..40254487 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-microsd-slows-sharply-on-full-warm-cards--p1rgh36hat2egpz3.md @@ -0,0 +1,22 @@ +--- +id: fnd-skiff-microsd-slows-sharply-on-full-warm-cards--p1rgh36hat2egpz3 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Skiff microSD slows sharply on full, warm cards' +kind: measurement +created_at: '2026-04-20T16:00:00Z' +created_by: Kenji Arakawa +derives_from: + - iss-skiff-fast-travel-has-no-load-time-plan--8xqtfd6x0mfvbkts +invalidates: + - dec-load-skiff-fast-travel-without-a-loading-screen--v4qft5znysjv5f24 + - fnd-skiff-microsd-sustains-92-mb-s--xr1fsyjd45y2tqcx +cites: + - cit-skiff-storage-benchmark-sheet--rszq3fw5c7eps8a2 +--- +Kenji Arakawa repeated the March storage benchmark under player conditions: cards filled past 80 percent, a Skiff that had run the game for 40 minutes, and the cheapest cards on sale in our three launch regions. The March test used three new, empty cards on a cold Skiff, which no player will have after a week. + +Results by card: the two premium cards held close to their March numbers. The four budget cards slowed as they filled, and all of them slowed further once the Skiff warmed up. The card controller throttles writes and reads together when it gets hot, and a full card spends more time on wear levelling. + +Fast travel to the harbor took 6.8 seconds on the worst card, far past the 4.5 second camera move. + +Worst sustained read across the budget cards, full and warm: 61 MB/s. Plan Skiff loading and streaming against that number, not 92 MB/s. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-microsd-sustains-92-mb-s--xr1fsyjd45y2tqcx.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-microsd-sustains-92-mb-s--xr1fsyjd45y2tqcx.md new file mode 100644 index 00000000..f05af498 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-microsd-sustains-92-mb-s--xr1fsyjd45y2tqcx.md @@ -0,0 +1,13 @@ +--- +id: fnd-skiff-microsd-sustains-92-mb-s--xr1fsyjd45y2tqcx +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff microSD sustains 92 MB/s +kind: measurement +created_at: '2026-03-04T10:30:00Z' +created_by: Kenji Arakawa +invalidated_by: + - fnd-skiff-microsd-slows-sharply-on-full-warm-cards--p1rgh36hat2egpz3 +cites: + - cit-skiff-storage-benchmark-sheet--rszq3fw5c7eps8a2 +--- +Kenji Arakawa read 4 GB of packed world tiles from three new microSD cards on a cold Skiff. Sustained read was 92 MB/s on all three. Internal storage reads at about 200 MB/s, but most players will install to microSD. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-pipeline-cache-removes-second-visit-hitche--kzjtp9dpbpbmrb0x.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-pipeline-cache-removes-second-visit-hitche--kzjtp9dpbpbmrb0x.md new file mode 100644 index 00000000..15a5f344 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-pipeline-cache-removes-second-visit-hitche--kzjtp9dpbpbmrb0x.md @@ -0,0 +1,11 @@ +--- +id: fnd-skiff-pipeline-cache-removes-second-visit-hitche--kzjtp9dpbpbmrb0x +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff pipeline cache removes second-visit hitches +kind: measurement +created_at: '2026-04-14T15:00:00Z' +created_by: Priya Natarajan +derives_from: + - dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7 +--- +With the on-device pipeline cache, second visits to the harbor compiled nothing: 99.6 percent of pipeline lookups hit the cache, and the misses were all photo-mode filters. First visits after load-screen warming still hitched 6 times on the harbor route, down from 212. After a full playthrough the cache held 212 MB. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-pre-certification-found-two-failures-and-o--ehe0e727vmd0d1jj.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-pre-certification-found-two-failures-and-o--ehe0e727vmd0d1jj.md new file mode 100644 index 00000000..fd2e8c88 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-pre-certification-found-two-failures-and-o--ehe0e727vmd0d1jj.md @@ -0,0 +1,11 @@ +--- +id: fnd-skiff-pre-certification-found-two-failures-and-o--ehe0e727vmd0d1jj +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff pre-certification found two failures and one advisory +kind: survey +created_at: '2026-05-18T09:30:00Z' +created_by: Dara Whitlock +cites: + - cit-skiff-pre-certification-report-build-5530--caakwntpfm63vy97 +--- +The platform holder pre-checked build 5530. Two failures must be fixed before full submission: autosave write volume and HUD text size. One advisory covers docked 30 Hz judder on some TVs. Codes and details are in the attached report. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-s-file-system-cannot-memory-map-packed-arc--00ecsf304vk38ajb.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-s-file-system-cannot-memory-map-packed-arc--00ecsf304vk38ajb.md new file mode 100644 index 00000000..509c638a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-s-file-system-cannot-memory-map-packed-arc--00ecsf304vk38ajb.md @@ -0,0 +1,11 @@ +--- +id: fnd-skiff-s-file-system-cannot-memory-map-packed-arc--00ecsf304vk38ajb +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Skiff's file system cannot memory-map packed archives +kind: survey +created_at: '2025-09-26T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - iss-which-read-path-should-streaming-use-on-each-pla--v9wd5sxvfjfsgx9r +--- +Priya Natarajan checked the platform SDKs. PC and Meridian can memory-map files. Skiff's file system maps only loose files under 64 MB, and the packed cell archives are several gigabytes. A mapped design would need a second read path for Skiff anyway. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-sdk-1-2-takes-1-gb-back-from-games--a0ybdgjzw64hwfqa.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-sdk-1-2-takes-1-gb-back-from-games--a0ybdgjzw64hwfqa.md new file mode 100644 index 00000000..16c992b6 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-sdk-1-2-takes-1-gb-back-from-games--a0ybdgjzw64hwfqa.md @@ -0,0 +1,13 @@ +--- +id: fnd-skiff-sdk-1-2-takes-1-gb-back-from-games--a0ybdgjzw64hwfqa +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff SDK 1.2 takes 1 GB back from games +kind: survey +created_at: '2026-02-10T11:30:00Z' +created_by: Priya Natarajan +derives_from: + - con-skiff-memory-budget--8ngr8fep3gxdfy80 +cites: + - cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe +--- +The SDK 1.2 release notes move the system overlay and the new voice chat service into title memory. Games now get 8 GB, down from 9 GB. The change applies to every title from firmware 1.2, with no opt-out. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-slice-build-peaks-at-6-9-gb--5hqgdkdbk2tsn8cj.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-slice-build-peaks-at-6-9-gb--5hqgdkdbk2tsn8cj.md new file mode 100644 index 00000000..195ab567 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-slice-build-peaks-at-6-9-gb--5hqgdkdbk2tsn8cj.md @@ -0,0 +1,11 @@ +--- +id: fnd-skiff-slice-build-peaks-at-6-9-gb--5hqgdkdbk2tsn8cj +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff slice build peaks at 6.9 GB +kind: measurement +created_at: '2025-11-12T16:00:00Z' +created_by: Kenji Arakawa +invalidated_by: + - fnd-harbor-district-peaks-at-8-6-gb-on-skiff--vccxye8jy3mkba2v +--- +Kenji Arakawa captured the vertical slice build on Skiff: peak 6.9 GB on the harbor route, 2.1 GB under the 9 GB budget. The capture ran with one tide cell loaded at a time. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-streaming-reads-sustain-260-mb-s--s1gkt975grre2ewr.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-streaming-reads-sustain-260-mb-s--s1gkt975grre2ewr.md new file mode 100644 index 00000000..8c5f1639 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-skiff-streaming-reads-sustain-260-mb-s--s1gkt975grre2ewr.md @@ -0,0 +1,13 @@ +--- +id: fnd-skiff-streaming-reads-sustain-260-mb-s--s1gkt975grre2ewr +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Skiff streaming reads sustain 260 MB/s +kind: measurement +created_at: '2025-12-08T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - dec-read-streamed-assets-through-one-async-request-q--rd5c8rxr5pwz50ds +invalidated_by: + - fnd-retail-skiff-units-sustain-only-190-mb-s-of-stre--485sdcmm3gweevvn +--- +On a Skiff dev kit, the async queue sustains 260 MB/s of streaming reads over a 10-minute run along the coast. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-stock-filmic-curve-clips-38-percent-of-caustic-h--7n6g1tssnkwqqwm6.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-stock-filmic-curve-clips-38-percent-of-caustic-h--7n6g1tssnkwqqwm6.md new file mode 100644 index 00000000..b704d323 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-stock-filmic-curve-clips-38-percent-of-caustic-h--7n6g1tssnkwqqwm6.md @@ -0,0 +1,13 @@ +--- +id: fnd-stock-filmic-curve-clips-38-percent-of-caustic-h--7n6g1tssnkwqqwm6 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Stock filmic curve clips 38 percent of caustic highlights +kind: measurement +created_at: '2026-01-16T10:00:00Z' +created_by: Yusuf Demir +invalidates: + - dec-use-the-stock-filmic-tonemapping-curve--wefzd9091kztq0wb +cites: + - cit-histogram-caustic-highlights-under-filmic--rr06d7k5s8c05gdw +--- +On the dunes at noon, 38 percent of caustic pixels hit the top of the stock filmic curve and turn flat white. The caustic pattern, which is the whole point of the effect, disappears where it is brightest. The curve was the wrong choice for saltglass from the start; its shoulder was tuned for skies, not for small, very bright sources. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-streaming-jobs-block-workers-while-waiting-on-re--sn2bmfdgjeqwkk3p.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-streaming-jobs-block-workers-while-waiting-on-re--sn2bmfdgjeqwkk3p.md new file mode 100644 index 00000000..ca187102 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-streaming-jobs-block-workers-while-waiting-on-re--sn2bmfdgjeqwkk3p.md @@ -0,0 +1,11 @@ +--- +id: fnd-streaming-jobs-block-workers-while-waiting-on-re--sn2bmfdgjeqwkk3p +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Streaming jobs block workers while waiting on reads +kind: measurement +created_at: '2025-10-14T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x +--- +The no-blocking rule is not holding. Decompression jobs wait for their reads instead of chaining, because the read API has no completion callback yet. On Meridian, workers sit idle for 3.1 ms per frame, and frame-critical jobs queue behind blocked streaming jobs. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-streaming-tide-heights-costs-46-kb-s-per-peer--knxqtyqh6xcz1tp9.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-streaming-tide-heights-costs-46-kb-s-per-peer--knxqtyqh6xcz1tp9.md new file mode 100644 index 00000000..608e1aa5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-streaming-tide-heights-costs-46-kb-s-per-peer--knxqtyqh6xcz1tp9.md @@ -0,0 +1,11 @@ +--- +id: fnd-streaming-tide-heights-costs-46-kb-s-per-peer--knxqtyqh6xcz1tp9 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Streaming tide heights costs 46 KB/s per peer +kind: measurement +created_at: '2025-11-04T14:00:00Z' +created_by: Sofia Marchetti +derives_from: + - dec-have-the-host-stream-tide-heights-to-every-peer--a3rb1seedn2bj7k8 +--- +A compressed tide height field for the area around each player costs 46 KB/s per peer at 10 updates a second. The co-op bandwidth target is 16 KB/s per peer for everything, so host streaming is out by a factor of three before any gameplay traffic. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-strict-float-mode-still-diverges-because-skiff-s--z811r28v0a1wzb13.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-strict-float-mode-still-diverges-because-skiff-s--z811r28v0a1wzb13.md new file mode 100644 index 00000000..bf7f6022 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-strict-float-mode-still-diverges-because-skiff-s--z811r28v0a1wzb13.md @@ -0,0 +1,11 @@ +--- +id: fnd-strict-float-mode-still-diverges-because-skiff-s--z811r28v0a1wzb13 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Strict float mode still diverges because Skiff's sin() differs by one ulp +kind: measurement +created_at: '2025-11-04T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-force-strict-ieee-float-mode-for-the-tide-simula--ecwmqt7ncjngysqw +--- +With strict flags on every platform, PC against Meridian now matches for 2 hours. PC against Skiff still drifts past 1 cm at minute 11, because Skiff's math library returns a sin() that differs by one ulp for some inputs. Strict mode fixes the compiler, not the library. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-cost-at-4k-output-on-meridian--wycx6ek6sfme73k9.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-cost-at-4k-output-on-meridian--wycx6ek6sfme73k9.md new file mode 100644 index 00000000..f22961a1 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-cost-at-4k-output-on-meridian--wycx6ek6sfme73k9.md @@ -0,0 +1,13 @@ +--- +id: fnd-tern-cost-at-4k-output-on-meridian--wycx6ek6sfme73k9 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Tern cost at 4K output on Meridian +kind: measurement +created_at: '2025-10-16T11:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v +superseded_by: + - fnd-tern-cost-at-4k-output-on-meridian-after-fp16-pa--p4gcmzw2a4bvzjev +--- +Tern upscaling 1440p to 4K on Meridian costs 1.9 ms on the dunes benchmark, with history reprojection the largest part. That is 0.7 ms more than Halcyon on the same view. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-cost-at-4k-output-on-meridian-after-fp16-pa--p4gcmzw2a4bvzjev.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-cost-at-4k-output-on-meridian-after-fp16-pa--p4gcmzw2a4bvzjev.md new file mode 100644 index 00000000..dd39cc6d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-cost-at-4k-output-on-meridian-after-fp16-pa--p4gcmzw2a4bvzjev.md @@ -0,0 +1,13 @@ +--- +id: fnd-tern-cost-at-4k-output-on-meridian-after-fp16-pa--p4gcmzw2a4bvzjev +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Tern cost at 4K output on Meridian after FP16 packing +kind: measurement +created_at: '2025-12-10T10:00:00Z' +created_by: Tomasz Brandt +supersedes: + - fnd-tern-cost-at-4k-output-on-meridian--wycx6ek6sfme73k9 +superseded_by: + - fnd-tern-cost-at-4k-output-on-meridian-with-the-reac--81tcpzvhwzcy6wyn +--- +Packing the reprojection inputs as FP16 and merging two passes brings Tern at 4K output on Meridian to 1.4 ms on the dunes benchmark, down from 1.9 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-cost-at-4k-output-on-meridian-with-the-reac--81tcpzvhwzcy6wyn.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-cost-at-4k-output-on-meridian-with-the-reac--81tcpzvhwzcy6wyn.md new file mode 100644 index 00000000..7756b178 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-cost-at-4k-output-on-meridian-with-the-reac--81tcpzvhwzcy6wyn.md @@ -0,0 +1,11 @@ +--- +id: fnd-tern-cost-at-4k-output-on-meridian-with-the-reac--81tcpzvhwzcy6wyn +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Tern cost at 4K output on Meridian with the reactive mask +kind: measurement +created_at: '2026-05-22T10:00:00Z' +created_by: Tomasz Brandt +supersedes: + - fnd-tern-cost-at-4k-output-on-meridian-after-fp16-pa--p4gcmzw2a4bvzjev +--- +With the saltglass reactive mask, Tern at 4K output on Meridian costs 1.6 ms on the dunes benchmark, up from 1.4 ms. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0.md new file mode 100644 index 00000000..1feeeee5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0.md @@ -0,0 +1,11 @@ +--- +id: fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Tern costs 3.9 ms at Quality and 2.1 ms at Performance on Skiff +kind: measurement +created_at: '2025-11-20T13:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-which-upscaler-should-skiff-use--jyp1hqdy0ahwfeej +--- +Tomasz Brandt profiled Tern on the Skiff dev kit, 540p in, 720p out, harbor route. Quality preset: 3.9 ms of GPU time. Performance preset: 2.1 ms. Performance shows a little more ghosting on foam but keeps saltglass edges stable. A bilinear upscale with sharpening costs 0.4 ms and crawls on every glass edge. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-ghosts-behind-moving-saltglass--j48ss757xfxmw31q.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-ghosts-behind-moving-saltglass--j48ss757xfxmw31q.md new file mode 100644 index 00000000..ecf3853d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-ghosts-behind-moving-saltglass--j48ss757xfxmw31q.md @@ -0,0 +1,11 @@ +--- +id: fnd-tern-ghosts-behind-moving-saltglass--j48ss757xfxmw31q +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Tern ghosts behind moving saltglass +kind: measurement +created_at: '2026-04-02T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e +--- +When saltglass moves across the background, or the camera orbits a glass cliff, the refracted image carries no motion vectors of its own. Tern reprojects the old refracted image and leaves trails up to 14 frames long. Press previews have already shown it. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-preset-render-scales-and-costs--gjp3q966nngdd580.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-preset-render-scales-and-costs--gjp3q966nngdd580.md new file mode 100644 index 00000000..473df5e8 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tern-preset-render-scales-and-costs--gjp3q966nngdd580.md @@ -0,0 +1,14 @@ +--- +id: fnd-tern-preset-render-scales-and-costs--gjp3q966nngdd580 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Tern preset render scales and costs +kind: measurement +created_at: '2026-02-24T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e + - iss-which-tern-quality-presets-should-ship--7yanr9kzekkky53f +cites: + - cit-tern-preset-table--6bbg3evqt1zz6smb +--- +Tomasz Brandt measured four candidate Tern presets on Meridian and Skiff. Cost falls slowly with render scale because reprojection runs at output resolution. Saltglass edges hold up to Performance; below that, refraction detail turns to mush. The table is attached. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-the-576p-floor-misses-the-40-hz-budget-in-tide-s--gqnqc4vef424e5af.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-the-576p-floor-misses-the-40-hz-budget-in-tide-s--gqnqc4vef424e5af.md new file mode 100644 index 00000000..04d6909b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-the-576p-floor-misses-the-40-hz-budget-in-tide-s--gqnqc4vef424e5af.md @@ -0,0 +1,12 @@ +--- +id: fnd-the-576p-floor-misses-the-40-hz-budget-in-tide-s--gqnqc4vef424e5af +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: The 576p floor misses the 40 Hz budget in tide storms +kind: measurement +created_at: '2026-07-20T14:00:00Z' +created_by: Tomasz Brandt +derives_from: + - con-frame-budget--br0qszfg8fys908n + - dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb +--- +Tomasz Brandt captured the 40 Hz mode during a tide storm on the dunes. At the 576p floor the GPU frame reached 26.9 ms, over the 25 ms budget, for 14 seconds. At 504p it fell to 23.8 ms. Side by side, Tern Performance from 504p looked better than the old 540p image because Tern now reuses saltglass history, and caustic shimmer stayed at 2 of 10 views. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-the-first-checksum-mismatch-came-from-gull-rando--wrrrkwvq1d0pc35p.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-the-first-checksum-mismatch-came-from-gull-rando--wrrrkwvq1d0pc35p.md new file mode 100644 index 00000000..7829a7d3 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-the-first-checksum-mismatch-came-from-gull-rando--wrrrkwvq1d0pc35p.md @@ -0,0 +1,11 @@ +--- +id: fnd-the-first-checksum-mismatch-came-from-gull-rando--wrrrkwvq1d0pc35p +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: The first checksum mismatch came from Gull random number calls +kind: diagnosis +created_at: '2026-02-16T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-hash-tide-physics-and-gull-state-every-30-frames--yqf2m6hqbjhwvkzq +--- +The checksums caught a Gull script that seeded its random generator from wall-clock time. Fixed in a day. Tide and physics hashes have matched in every session since. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-the-gull-vm-reads-thread-local-registers-after-f--1qser43b9j8ac5pf.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-the-gull-vm-reads-thread-local-registers-after-f--1qser43b9j8ac5pf.md new file mode 100644 index 00000000..94c1c23f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-the-gull-vm-reads-thread-local-registers-after-f--1qser43b9j8ac5pf.md @@ -0,0 +1,20 @@ +--- +id: fnd-the-gull-vm-reads-thread-local-registers-after-f--1qser43b9j8ac5pf +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: The Gull VM reads thread-local registers after fiber migration +kind: measurement +created_at: '2026-02-04T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq + - iss-gull-scripts-crash-after-a-fiber-resumes-on-anot--n2hvwg59w0rem0te +invalidates: + - dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq +--- +Marta Lindqvist traced the Gull crashes to thread-local storage. The Gull VM keeps its register file and its current-script pointer in thread-local variables, which was safe on a thread pool because a job never changed threads mid-run. + +Under fibers, a Gull script that waits yields its fiber. When the fiber resumes, the scheduler may run it on a different worker thread. The VM then reads the new thread's register file, which belongs to some other script, and either corrupts that script or dereferences a stale pointer. + +Moving the VM state out of thread-local storage means touching every native binding, about 1,400 functions. The debugger has the same problem in reverse: it shows the worker's stack, so a script breakpoint lands in scheduler code. + +Measured on the alpha build, the failure rate is one crash per 900 script waits, which works out to a crash every four minutes in a four-player session. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-band-cells-need-320-mb-resident-during-a-sp--0erj5eqw3ved35t0.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-band-cells-need-320-mb-resident-during-a-sp--0erj5eqw3ved35t0.md new file mode 100644 index 00000000..de311dff --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-band-cells-need-320-mb-resident-during-a-sp--0erj5eqw3ved35t0.md @@ -0,0 +1,12 @@ +--- +id: fnd-tide-band-cells-need-320-mb-resident-during-a-sp--0erj5eqw3ved35t0 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Tide-band cells need 320 MB resident during a spring tide turn +kind: measurement +created_at: '2026-07-10T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - con-streaming-pool-budget--kca88sgh2j6sxvd5 + - dec-add-a-second-tide-harmonic-for-spring-and-neap-t--1c3s7dtyxvj70gvw +--- +With the second harmonic, a spring tide exposes up to 11 coastal cells at once. Keeping them resident through the turn needs 320 MB of the pool. Without a reservation, forecast eviction pushes out cells near the player to make room. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-band-chunks-cut-the-skiff-crab-join-to-3-2--v7q7jytpsd3zf06x.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-band-chunks-cut-the-skiff-crab-join-to-3-2--v7q7jytpsd3zf06x.md new file mode 100644 index 00000000..4a332bbf --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-band-chunks-cut-the-skiff-crab-join-to-3-2--v7q7jytpsd3zf06x.md @@ -0,0 +1,11 @@ +--- +id: fnd-tide-band-chunks-cut-the-skiff-crab-join-to-3-2--v7q7jytpsd3zf06x +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Tide-band chunks cut the Skiff crab join to 3.2 ms +kind: measurement +created_at: '2026-09-16T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - dec-group-archetype-chunks-by-tide-band-to-cut-fragm--qxnkv5bxqz1r7afv +--- +With chunks grouped by tide band, the Skiff join of transforms with the Submerged tag across the crab herd takes 3.2 ms, down from the figure measured on the alpha world. The gain comes from fewer chunk switches: 140 per query instead of 610. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-locked-jitter-halves-caustic-flicker-but-st--nck1ftqr38v01cq1.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-locked-jitter-halves-caustic-flicker-but-st--nck1ftqr38v01cq1.md new file mode 100644 index 00000000..87984cd4 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-locked-jitter-halves-caustic-flicker-but-st--nck1ftqr38v01cq1.md @@ -0,0 +1,15 @@ +--- +id: fnd-tide-locked-jitter-halves-caustic-flicker-but-st--nck1ftqr38v01cq1 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Tide-locked jitter halves caustic flicker but stalls caustic motion +kind: measurement +created_at: '2026-05-20T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - dec-lock-caustic-photon-jitter-to-the-tide-phase--85x10k4h11t8nx7c +--- +Yusuf Demir built the tide-locked seed on the r6600 branch and ran the dunes noon trace again. Peak flicker energy in the 3 to 6 Hz band drops by about half. It does not go away, because Tern still sees sub-pixel photon positions change between tide steps. + +The bigger problem is motion. Caustics are supposed to crawl with the water, and the tide only moves the pattern when the phase advances. Around slack water the phase barely moves, so the caustics stand still while the water surface keeps rippling. Reviewers in the art meeting called it frozen. Yusuf Demir tried adding a slow drift on top of the tide seed, and the flicker came straight back. + +Around slack tide the caustic pattern freezes for about 4 minutes of each 40-minute cycle. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-priority-reads-starve-player-proximity-load--by0d7b0bk39xz3rk.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-priority-reads-starve-player-proximity-load--by0d7b0bk39xz3rk.md new file mode 100644 index 00000000..0023fc06 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-priority-reads-starve-player-proximity-load--by0d7b0bk39xz3rk.md @@ -0,0 +1,21 @@ +--- +id: fnd-tide-priority-reads-starve-player-proximity-load--by0d7b0bk39xz3rk +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Tide-priority reads starve player-proximity loads +kind: measurement +created_at: '2026-08-10T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - dec-give-reads-for-tide-exposed-cells-top-priority--8ftkvqhawbdf5djh +invalidates: + - dec-give-reads-for-tide-exposed-cells-top-priority--8ftkvqhawbdf5djh +cites: + - cit-skiff-streaming-trace-stream-trace-0807--e4vdxvga0amqyzjb +--- +Giving tide-exposed cells absolute priority was a mistake. On a falling spring tide, the second harmonic exposes far more coast than a normal tide, and the queue fills with tide-cell reads for minutes at a time. + +A player who sprints inland during that window outruns streaming. Proximity reads for the cells ahead of the player wait behind every queued tide read, because nothing outranks the tide lane. The ground arrives as untextured glass and fills in seconds later. + +The tide deadline itself is met with time to spare: tide cells finish 20 seconds before exposure on average, against an 8-second deadline. The priority rule protects a deadline that had slack while it starves the reads that had none. + +In the worst capture, at the Glassreef inlet, inland terrain stayed untextured for 6.8 seconds. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-storms-push-skiff-40-hz-frames-to-28-4-ms-o--28gemvtznv4zztdc.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-storms-push-skiff-40-hz-frames-to-28-4-ms-o--28gemvtznv4zztdc.md new file mode 100644 index 00000000..9b6317a2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-storms-push-skiff-40-hz-frames-to-28-4-ms-o--28gemvtznv4zztdc.md @@ -0,0 +1,11 @@ +--- +id: fnd-tide-storms-push-skiff-40-hz-frames-to-28-4-ms-o--28gemvtznv4zztdc +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Tide storms push Skiff 40 Hz frames to 28.4 ms on the CPU +kind: measurement +created_at: '2026-08-10T15:00:00Z' +created_by: Priya Natarajan +derives_from: + - dec-lower-the-skiff-dynamic-resolution-floor-to-504p--15esnt90gcn29enn +--- +Priya Natarajan captured the full storm sequence on a retail-firmware Skiff. Even at the 504p floor, the CPU frame reached 28.4 ms in the 40 Hz mode, over the 25 ms budget. Storm particles and their tide collision cost 6.1 ms of it. The GPU stayed inside budget. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-turns-toggle-the-submerged-tag-on-40-000-en--a95p39zkd5ckmg5y.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-turns-toggle-the-submerged-tag-on-40-000-en--a95p39zkd5ckmg5y.md new file mode 100644 index 00000000..7a59fd08 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-tide-turns-toggle-the-submerged-tag-on-40-000-en--a95p39zkd5ckmg5y.md @@ -0,0 +1,11 @@ +--- +id: fnd-tide-turns-toggle-the-submerged-tag-on-40-000-en--a95p39zkd5ckmg5y +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 'Tide turns toggle the Submerged tag on 40,000 entities' +kind: measurement +created_at: '2025-09-15T11:00:00Z' +created_by: Marta Lindqvist +derives_from: + - iss-how-should-kestrel-store-entity-components--aj37s7xz78dszyzp +--- +The tide turns every 20 minutes, twice per 40-minute cycle. In the coast test map, 40,000 entities gain or lose the Submerged tag on each turn. With archetype tables every flip moves a row: 40,000 x 380 ns is 15.2 ms on the main thread in one frame. With sparse sets the same flips cost 1.8 ms. Marta Lindqvist expects the count to double once the full coast is populated. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-two-compiler-builds-with-the-same-version-string--gmgr4ha0ndxqmcn9.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-two-compiler-builds-with-the-same-version-string--gmgr4ha0ndxqmcn9.md new file mode 100644 index 00000000..c649dcfa --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-two-compiler-builds-with-the-same-version-string--gmgr4ha0ndxqmcn9.md @@ -0,0 +1,13 @@ +--- +id: fnd-two-compiler-builds-with-the-same-version-string--gmgr4ha0ndxqmcn9 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Two compiler builds with the same version string emit different bytecode +kind: defect +created_at: '2026-01-12T11:00:00Z' +created_by: Liam O'Connell +derives_from: + - dec-recompile-a-1-in-50-sample-of-cache-hits-and-com--9n176hnc9w0tax3s +cites: + - cit-shader-compiler-release-notes-for-build-1-8-2407--j9egrx9rnpp9ne9x +--- +Agents 3 and 8 both report shader compiler version 1.8.2407, but agent 8 runs a hotfix build with a different optimizer. The byte-compare check from the sampling Decision flagged 14 mismatched water shader permutations in one week. Hashing the version string is not enough: the key must hash the compiler binary itself. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-two-player-rollback-co-op-ran-the-vertical-slice--p51cfe0dn47vfkya.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-two-player-rollback-co-op-ran-the-vertical-slice--p51cfe0dn47vfkya.md new file mode 100644 index 00000000..0d0a18e9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-two-player-rollback-co-op-ran-the-vertical-slice--p51cfe0dn47vfkya.md @@ -0,0 +1,11 @@ +--- +id: fnd-two-player-rollback-co-op-ran-the-vertical-slice--p51cfe0dn47vfkya +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Two-player rollback co-op ran the vertical slice demo without a visible desync +kind: playtest +created_at: '2025-12-16T10:00:00Z' +created_by: Sofia Marchetti +derives_from: + - dec-use-a-4-frame-rollback-window--pqe4hvbgmbp0dmh9 +--- +The vertical slice demo on 2025-12-15 ran two-player co-op on PC with rollback for 25 minutes. No visible desync and no stalls. Tides were still frozen in co-op builds. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-virtual-shadow-maps-cost-1-4-ms-on-meridian-with--mwpybda1vh0ac55e.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-virtual-shadow-maps-cost-1-4-ms-on-meridian-with--mwpybda1vh0ac55e.md new file mode 100644 index 00000000..df77a38d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-virtual-shadow-maps-cost-1-4-ms-on-meridian-with--mwpybda1vh0ac55e.md @@ -0,0 +1,13 @@ +--- +id: fnd-virtual-shadow-maps-cost-1-4-ms-on-meridian-with--mwpybda1vh0ac55e +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Virtual shadow maps cost 1.4 ms on Meridian with cached pages +kind: measurement +created_at: '2025-11-24T10:00:00Z' +created_by: Tomasz Brandt +invalidates: + - fnd-virtual-shadow-maps-cost-3-1-ms-on-meridian--r6x0sdfecms7j1yg +cites: + - cit-capture-virtual-shadow-maps-with-page-caching--xjxn0ftjsfe4dhcq +--- +The September capture had the prototype's debug flag on, which threw away cached pages and redrew the whole pool each frame. With caching as designed, only pages touched by moving objects or by the slow sun drift redraw. Dunes benchmark: 1.4 ms, against 1.6 ms for four cascades. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-virtual-shadow-maps-cost-3-1-ms-on-meridian--r6x0sdfecms7j1yg.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-virtual-shadow-maps-cost-3-1-ms-on-meridian--r6x0sdfecms7j1yg.md new file mode 100644 index 00000000..07730d86 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-virtual-shadow-maps-cost-3-1-ms-on-meridian--r6x0sdfecms7j1yg.md @@ -0,0 +1,15 @@ +--- +id: fnd-virtual-shadow-maps-cost-3-1-ms-on-meridian--r6x0sdfecms7j1yg +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Virtual shadow maps cost 3.1 ms on Meridian +kind: measurement +created_at: '2025-09-29T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - iss-which-shadow-technique-should-lantern-use-for-su--y4k75xvbgb2fhj85 +invalidated_by: + - fnd-virtual-shadow-maps-cost-1-4-ms-on-meridian-with--mwpybda1vh0ac55e +cites: + - cit-capture-virtual-shadow-map-prototype--4122x7gedhmg5v15 +--- +The virtual shadow map prototype, at 16k virtual resolution with 128-texel pages, costs 3.1 ms on the dunes benchmark. Four cascaded shadow maps cost 1.6 ms on the same view. Most of the VSM time is page rasterization. On these numbers VSM is twice the price of CSM. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-visibility-buffer-costs-11-2-ms-on-skiff--s3vphdwnhbh4650s.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-visibility-buffer-costs-11-2-ms-on-skiff--s3vphdwnhbh4650s.md new file mode 100644 index 00000000..4635bdad --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-visibility-buffer-costs-11-2-ms-on-skiff--s3vphdwnhbh4650s.md @@ -0,0 +1,15 @@ +--- +id: fnd-visibility-buffer-costs-11-2-ms-on-skiff--s3vphdwnhbh4650s +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Visibility buffer costs 11.2 ms on Skiff +kind: measurement +created_at: '2026-04-08T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - dec-visibility-buffer-with-compute-material-resolve--5s2z9mqmv8vnszed +invalidated_by: + - fnd-visibility-buffer-costs-7-4-ms-on-skiff-in-a-rel--fs86h16tm5hgempd +cites: + - cit-capture-visibility-buffer-on-skiff--ymeda5m6p45hba8f +--- +First Skiff devkit capture of the cliffs benchmark at 720p: the visibility buffer path costs 11.2 ms, against forward+'s 8.9 ms. Material resolve alone is 5.0 ms. Skiff's memory bandwidth looks like the limit, since every resolve fetch goes through the bindless material tables. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-visibility-buffer-costs-7-4-ms-on-skiff-in-a-rel--fs86h16tm5hgempd.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-visibility-buffer-costs-7-4-ms-on-skiff-in-a-rel--fs86h16tm5hgempd.md new file mode 100644 index 00000000..9f0e7799 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-visibility-buffer-costs-7-4-ms-on-skiff-in-a-rel--fs86h16tm5hgempd.md @@ -0,0 +1,11 @@ +--- +id: fnd-visibility-buffer-costs-7-4-ms-on-skiff-in-a-rel--fs86h16tm5hgempd +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Visibility buffer costs 7.4 ms on Skiff in a release build +kind: measurement +created_at: '2026-06-22T10:00:00Z' +created_by: Tomasz Brandt +invalidates: + - fnd-visibility-buffer-costs-11-2-ms-on-skiff--s3vphdwnhbh4650s +--- +The April Skiff capture ran with GPU validation on, which roughly doubles the cost of every bindless fetch. In a release build the cliffs benchmark visibility buffer path costs 7.4 ms against forward+ at 8.1 ms, at 720p. With material resolve at half rate the visibility buffer path is 6.3 ms. The April number should not have driven a Decision. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-visibility-buffer-prototype-timings--qcfzqvyxbxkf2spw.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-visibility-buffer-prototype-timings--qcfzqvyxbxkf2spw.md new file mode 100644 index 00000000..e104d8d4 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-visibility-buffer-prototype-timings--qcfzqvyxbxkf2spw.md @@ -0,0 +1,13 @@ +--- +id: fnd-visibility-buffer-prototype-timings--qcfzqvyxbxkf2spw +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Visibility buffer prototype timings +kind: measurement +created_at: '2025-09-24T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-forward-overdraw-on-saltglass-cliffs--q9n76frhz7a7ssnp +cites: + - cit-timing-table-visibility-buffer-prototype--njktyg0k8aej7kpf +--- +The visibility buffer prototype draws the cliffs benchmark opaque work in 4.6 ms against forward+'s 9.0 ms on Meridian. The win comes from shading each pixel once. The prototype packs instance and triangle into 32 bits, which may not be enough for the dunes. Pass-by-pass numbers are in the attached table. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-vsm-page-pool-overflows-during-spring-tides--m2p8e89hhdmh0z8a.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-vsm-page-pool-overflows-during-spring-tides--m2p8e89hhdmh0z8a.md new file mode 100644 index 00000000..7d56027d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-vsm-page-pool-overflows-during-spring-tides--m2p8e89hhdmh0z8a.md @@ -0,0 +1,17 @@ +--- +id: fnd-vsm-page-pool-overflows-during-spring-tides--m2p8e89hhdmh0z8a +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: VSM page pool overflows during spring tides +kind: measurement +created_at: '2026-06-15T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty +cites: + - cit-trace-vsm-page-pool-across-a-spring-tide--mhwdj0xh0k2wrnpq +--- +A full spring-tide cycle on the flats asks for far more shadow pages at low water than the pool holds. Shadows on the far flats drop to the fallback resolution and visibly pop as pages come back. The trace is attached. Neap tides stay inside the pool; only the two spring tides of each in-game month overflow. + +Tomasz Brandt checked three cheaper ideas before writing this up. Dropping the page size to 64 texels makes the overflow worse, because the page table grows. Skipping pages for wet sand that is darker than a threshold saves about 600 pages, not enough. Freezing pages on the far flats for a whole tide step hides the popping but leaves shadows pointing the wrong way at sunset. + +Raising the pool from 4,096 to 6,144 pages would end the overflow and cost another 128 MB, which the render-target memory budget does not have. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-world-core-state-after-beta--v9mfhngtx7m2bdkk.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-world-core-state-after-beta--v9mfhngtx7m2bdkk.md new file mode 100644 index 00000000..73c6e79f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-world-core-state-after-beta--v9mfhngtx7m2bdkk.md @@ -0,0 +1,107 @@ +--- +id: fnd-world-core-state-after-beta--v9mfhngtx7m2bdkk +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: World core state after beta +kind: compaction +created_at: '2026-06-10T16:00:00Z' +created_by: Rhea Valdés +derives_from: + - con-streaming-pool-budget--kca88sgh2j6sxvd5 + - dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3 + - dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg + - dec-give-reads-for-tide-exposed-cells-top-priority--8ftkvqhawbdf5djh + - dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc + - dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e + - dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8 + - dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew + - dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w +supersedes: + - fnd-world-core-state-at-alpha--tkbsm4867h65jqq8 +superseded_by: + - fnd-world-core-state-before-content-lock--15jbzxzr0wj9gsd2 +covers: + - con-archetype-changes-happen-only-at-frame-sync-poin--kcsrz5g8g8yndwnx@live + - con-cell-load-deadline--m20x64m5eh7q2bh6@live + - con-gull-script-tick-budget--4p9jp4dj1njf7q9m@live + - con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73@live + - con-saves-from-beta-onward-must-load-in-every-later--v6z856sxtgc5sb09@live + - con-streaming-i-o-budget--vhc7mrmpqv9qcfdc@live + - con-streaming-pool-budget--kca88sgh2j6sxvd5@live + - con-tide-state-must-be-bit-identical-on-every-peer--zrpnp8qjyxzkas7t@live + - dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3@accepted + - dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m@accepted + - >- + dec-cut-navigation-tiles-to-64-m-so-three-fit-along--snvepk8ygeb3qsjs@accepted + - dec-delay-autosaves-until-the-tide-turn-finishes--4agcgjjj70djdv6b@accepted + - dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg@accepted + - >- + dec-give-reads-for-tide-exposed-cells-top-priority--8ftkvqhawbdf5djh@accepted + - >- + dec-group-archetype-chunks-by-tide-band-to-cut-fragm--qxnkv5bxqz1r7afv@accepted + - >- + dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42@accepted + - dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc@accepted + - >- + dec-read-streamed-assets-through-one-async-request-q--rd5c8rxr5pwz50ds@accepted + - >- + dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h@accepted + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e@accepted + - >- + dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8@accepted + - >- + dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew@accepted + - >- + dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w@accepted + - >- + dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9@accepted + - >- + dec-wrap-the-tide-phase-accumulator-at-each-40-minut--hx88m4hbg27n0xwy@accepted + - fnd-128-m-cells-cost-216-mb-of-per-cell-overhead-on--05dnx4k8a0wjtzdw@live + - fnd-3-of-200-saves-taken-mid-turn-fail-to-load--4j1kafsdeq0wedhf@live + - fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m@live + - fnd-a-falling-tide-reloads-18-cells-at-410-mb-s-peak--tjz5vscfrdtazcms@live + - fnd-a-full-world-snapshot-save-is-310-mb--2c7a78gjb54ygkj4@live + - fnd-a-thread-pool-with-continuation-waits-keeps-work--3nryg6kq6w7236ae@live + - fnd-alpha-content-needs-6-2-ms-of-gull-time-per-fram--4mekgdpsdv5nk085@live + - fnd-archetype-iteration-takes-3-4-ms-in-the-alpha-wo--dawb9m0pa999mhpe@live + - fnd-cell-size-sweep-for-the-768-m-streaming-radius--q3qfh6cp8a0k0f7g@live + - fnd-cross-platform-cloud-saves-need-platform-agreeme--4qgfc1a4nq4padvz@live + - fnd-delta-saves-reach-6-2-mb-after-40-hours--8g1j04z0vhjwrkyn@live + - fnd-deltas-saved-at-low-tide-replay-wrongly-at-high--25b4vwytarw8ej50@live + - fnd-each-save-upgrade-step-costs-under-5-ms--qs1rweqqgj7kweem@live + - fnd-fibers-hide-waits-but-need-custom-stacks-and-deb--0ynync38mj13w03k@live + - fnd-field-captures-show-forecast-eviction-cuts-reloa--ee6m7fwv4798jdmv@live + - fnd-fixed-point-tide-step-costs-0-3-ms-on-meridian--jzxe4pa936rxawns@live + - fnd-fixed-point-tide-step-costs-0-9-ms-on-skiff--mfc73bg9wwaxtfra@live + - fnd-fixed-point-tides-match-bit-for-bit-across-all-p--kb3ssw5190e93r4m@live + - fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss@live + - fnd-gull-s-tree-walking-interpreter-spends-1-8-ms-on--bj1ge76d3wy5aqq3@live + - fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws@live + - fnd-kelp-decodes-at-1-1-gb-s-on-skiff-with-a-cold-ca--vef244qjn2mjf07x@live + - fnd-kelp-with-a-1-mb-dictionary-decodes-at-2-2-gb-s--vkt1dgk99x2xrmbs@live + - fnd-lru-eviction-thrashes-during-tide-turns--0tvj4hmg42jy5d3f@live + - fnd-ports-cut-the-skiff-memory-total-and-streaming-m--1p8b10ttb07jkznx@live + - fnd-priority-lanes-still-leave-workers-28-idle-durin--fhswesk5c086dk1y@live + - fnd-register-vm-prototype-runs-the-crab-herd-4-1x-fa--1eb9hfat7611jksr@live + - fnd-retail-skiff-units-sustain-only-190-mb-s-of-stre--485sdcmm3gweevvn@live + - fnd-shipping-entity-names-costs-57-mb-at-full-popula--6w7gjvy7wdmdx9qx@live + - fnd-skiff-s-file-system-cannot-memory-map-packed-arc--00ecsf304vk38ajb@live + - fnd-streaming-jobs-block-workers-while-waiting-on-re--sn2bmfdgjeqwkk3p@live + - fnd-streaming-tide-heights-costs-46-kb-s-per-peer--knxqtyqh6xcz1tp9@live + - fnd-strict-float-mode-still-diverges-because-skiff-s--z811r28v0a1wzb13@live + - fnd-the-gull-vm-reads-thread-local-registers-after-f--1qser43b9j8ac5pf@live + - fnd-tide-turns-toggle-the-submerged-tag-on-40-000-en--a95p39zkd5ckmg5y@live + - iss-gull-hot-reload-drops-suspended-coroutines--z7j2gmyny6gdxd07@open + - rsk-fiber-stacks-may-make-crash-dumps-unreadable--b7c1mkn9ygvmsy57@realized + - rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew@open + - >- + rsk-kelp-s-4-mb-dictionary-may-thrash-the-skiff-cach--rv7ac1hedneqkp0v@realized + - >- + rsk-ports-may-need-to-shrink-the-streaming-pool-for--1gtjkygrtkb5kgww@realized + - >- + rsk-queries-that-join-tables-with-sparse-tags-may-lo--2h5br5crhfn1nb8c@realized + - >- + rsk-saving-during-a-tide-turn-may-record-a-half-appl--zezc1pxx8zp5b82m@realized +--- +Engine jobs are back on a thread pool with continuation waits; fibers are gone, and Gull keeps two dedicated threads. Cells are 192 m, with 64 m navigation tiles. The streaming pool is 1.6 GB, cut from 2.0 GB to fit the Skiff memory budget. Reads for tide-exposed cells take top priority. Saves carry a schema version and upgrade step by step on load; beta saves must load in every later build. Hot reload drops suspended coroutines, so its real success rate is about 71%. The tide stays in 32.32 fixed point. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-world-core-state-at-alpha--tkbsm4867h65jqq8.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-world-core-state-at-alpha--tkbsm4867h65jqq8.md new file mode 100644 index 00000000..f5bad1e9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-world-core-state-at-alpha--tkbsm4867h65jqq8.md @@ -0,0 +1,90 @@ +--- +id: fnd-world-core-state-at-alpha--tkbsm4867h65jqq8 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: World core state at alpha +kind: compaction +created_at: '2026-03-06T16:00:00Z' +created_by: Rhea Valdés +derives_from: + - con-streaming-pool-budget--632bkbs79bwj4cr5 + - dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3 + - dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg + - dec-group-archetype-chunks-by-tide-band-to-cut-fragm--qxnkv5bxqz1r7afv + - dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42 + - dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw + - dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e + - dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8 + - dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew +supersedes: + - fnd-world-core-state-before-the-vertical-slice--rbpesp345hf8mesp +superseded_by: + - fnd-world-core-state-after-beta--v9mfhngtx7m2bdkk +invalidated_by: + - fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws +covers: + - con-archetype-changes-happen-only-at-frame-sync-poin--kcsrz5g8g8yndwnx@live + - con-cell-load-deadline--m20x64m5eh7q2bh6@live + - con-gull-script-tick-budget--4p9jp4dj1njf7q9m@live + - con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73@live + - con-streaming-i-o-budget--vhc7mrmpqv9qcfdc@live + - con-streaming-pool-budget--632bkbs79bwj4cr5@live + - con-tide-state-must-be-bit-identical-on-every-peer--zrpnp8qjyxzkas7t@live + - dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3@accepted + - dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m@accepted + - dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg@accepted + - >- + dec-group-archetype-chunks-by-tide-band-to-cut-fragm--qxnkv5bxqz1r7afv@accepted + - >- + dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42@accepted + - dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw@accepted + - >- + dec-read-streamed-assets-through-one-async-request-q--rd5c8rxr5pwz50ds@accepted + - >- + dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te@accepted + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e@accepted + - >- + dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8@accepted + - >- + dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew@accepted + - >- + dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9@accepted + - >- + dec-wrap-the-tide-phase-accumulator-at-each-40-minut--hx88m4hbg27n0xwy@accepted + - fnd-128-m-cells-should-add-only-40-mb-of-per-cell-ov--ape0tgv597x77p6z@live + - fnd-a-falling-tide-reloads-18-cells-at-410-mb-s-peak--tjz5vscfrdtazcms@live + - fnd-a-full-world-snapshot-save-is-310-mb--2c7a78gjb54ygkj4@live + - fnd-alpha-content-needs-6-2-ms-of-gull-time-per-fram--4mekgdpsdv5nk085@live + - fnd-archetype-iteration-takes-3-4-ms-in-the-alpha-wo--dawb9m0pa999mhpe@live + - fnd-bytecode-swap-at-frame-boundaries-reloads-94-of--rqrk03vvef5jgv2x@live + - fnd-cell-size-sweep-for-the-768-m-streaming-radius--q3qfh6cp8a0k0f7g@live + - fnd-deltas-saved-at-low-tide-replay-wrongly-at-high--25b4vwytarw8ej50@live + - fnd-fibers-hide-waits-but-need-custom-stacks-and-deb--0ynync38mj13w03k@live + - fnd-field-captures-show-forecast-eviction-cuts-reloa--ee6m7fwv4798jdmv@live + - fnd-fixed-point-tide-step-costs-0-3-ms-on-meridian--jzxe4pa936rxawns@live + - fnd-fixed-point-tide-step-costs-0-9-ms-on-skiff--mfc73bg9wwaxtfra@live + - fnd-fixed-point-tides-match-bit-for-bit-across-all-p--kb3ssw5190e93r4m@live + - fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss@live + - fnd-gull-s-tree-walking-interpreter-spends-1-8-ms-on--bj1ge76d3wy5aqq3@live + - fnd-kelp-decodes-at-1-1-gb-s-on-skiff-with-a-cold-ca--vef244qjn2mjf07x@live + - fnd-kelp-with-a-1-mb-dictionary-decodes-at-2-2-gb-s--vkt1dgk99x2xrmbs@live + - fnd-lru-eviction-thrashes-during-tide-turns--0tvj4hmg42jy5d3f@live + - fnd-priority-lanes-still-leave-workers-28-idle-durin--fhswesk5c086dk1y@live + - fnd-register-vm-prototype-runs-the-crab-herd-4-1x-fa--1eb9hfat7611jksr@live + - fnd-retail-skiff-units-sustain-only-190-mb-s-of-stre--485sdcmm3gweevvn@live + - fnd-shipping-entity-names-costs-57-mb-at-full-popula--6w7gjvy7wdmdx9qx@live + - fnd-skiff-s-file-system-cannot-memory-map-packed-arc--00ecsf304vk38ajb@live + - fnd-streaming-jobs-block-workers-while-waiting-on-re--sn2bmfdgjeqwkk3p@live + - fnd-streaming-tide-heights-costs-46-kb-s-per-peer--knxqtyqh6xcz1tp9@live + - fnd-strict-float-mode-still-diverges-because-skiff-s--z811r28v0a1wzb13@live + - fnd-the-gull-vm-reads-thread-local-registers-after-f--1qser43b9j8ac5pf@live + - fnd-tide-turns-toggle-the-submerged-tag-on-40-000-en--a95p39zkd5ckmg5y@live + - rsk-fiber-stacks-may-make-crash-dumps-unreadable--b7c1mkn9ygvmsy57@open + - rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew@open + - >- + rsk-kelp-s-4-mb-dictionary-may-thrash-the-skiff-cach--rv7ac1hedneqkp0v@realized + - rsk-ports-may-need-to-shrink-the-streaming-pool-for--1gtjkygrtkb5kgww@open + - >- + rsk-queries-that-join-tables-with-sparse-tags-may-lo--2h5br5crhfn1nb8c@realized +--- +Engine jobs run on fibers, and Gull scripts are pinned to two dedicated threads after fiber migration broke the VM's thread-local state. Cells stay 128 m. Kelp keeps streaming with a 1 MB dictionary, after a cold-cache rerun showed the 4 MB dictionary losing to Zstandard on Skiff. Gull now compiles to bytecode for a register VM, 4.1x faster than the interpreter, and hot reload swaps bytecode at frame boundaries, which applies 94% of edits. Saves key each delta to the tide phase. The 2.0 GB pool evicts by distance and tide forecast. ECS chunks are grouped by tide band. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-world-core-state-before-content-lock--15jbzxzr0wj9gsd2.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-world-core-state-before-content-lock--15jbzxzr0wj9gsd2.md new file mode 100644 index 00000000..36fb28ea --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-world-core-state-before-content-lock--15jbzxzr0wj9gsd2.md @@ -0,0 +1,118 @@ +--- +id: fnd-world-core-state-before-content-lock--15jbzxzr0wj9gsd2 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: World core state before content lock +kind: compaction +created_at: '2026-08-20T16:00:00Z' +created_by: Rhea Valdés +derives_from: + - con-streaming-pool-budget--8czwb4fjr5p5vpy7 + - dec-add-a-second-tide-harmonic-for-spring-and-neap-t--1c3s7dtyxvj70gvw + - dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3 + - dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc + - dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3 + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e + - dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew + - dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w + - iss-beta-saves-lack-the-second-tide-harmonic-s-phase--gmhrjdy35pjfq651 + - iss-tide-turns-leave-inland-terrain-untextured-for-s--ccv6nhwk68kj732c +supersedes: + - fnd-world-core-state-after-beta--v9mfhngtx7m2bdkk +covers: + - con-archetype-changes-happen-only-at-frame-sync-poin--kcsrz5g8g8yndwnx@live + - con-cell-load-deadline--m20x64m5eh7q2bh6@live + - con-gull-script-tick-budget--4p9jp4dj1njf7q9m@live + - con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73@live + - con-saves-from-beta-onward-must-load-in-every-later--v6z856sxtgc5sb09@live + - con-streaming-i-o-budget--vhc7mrmpqv9qcfdc@live + - con-streaming-pool-budget--8czwb4fjr5p5vpy7@live + - con-tide-state-must-be-bit-identical-on-every-peer--zrpnp8qjyxzkas7t@live + - >- + dec-add-a-second-tide-harmonic-for-spring-and-neap-t--1c3s7dtyxvj70gvw@accepted + - dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3@accepted + - dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m@accepted + - >- + dec-cut-navigation-tiles-to-64-m-so-three-fit-along--snvepk8ygeb3qsjs@accepted + - dec-delay-autosaves-until-the-tide-turn-finishes--4agcgjjj70djdv6b@accepted + - >- + dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw@proposed + - dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg@accepted + - >- + dec-group-archetype-chunks-by-tide-band-to-cut-fragm--qxnkv5bxqz1r7afv@accepted + - >- + dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42@accepted + - dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc@accepted + - >- + dec-read-streamed-assets-through-one-async-request-q--rd5c8rxr5pwz50ds@accepted + - >- + dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3@accepted + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e@accepted + - >- + dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8@accepted + - >- + dec-schedule-streaming-reads-by-deadline-instead-of--q2x5aknabgcssdj2@proposed + - >- + dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew@accepted + - >- + dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w@accepted + - >- + dec-start-the-second-harmonic-at-zero-phase-for-beta--vq8av7c58fmaq9jg@proposed + - >- + dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9@accepted + - >- + dec-wrap-the-tide-phase-accumulator-at-each-40-minut--hx88m4hbg27n0xwy@accepted + - fnd-128-m-cells-cost-216-mb-of-per-cell-overhead-on--05dnx4k8a0wjtzdw@live + - fnd-3-of-200-saves-taken-mid-turn-fail-to-load--4j1kafsdeq0wedhf@live + - fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m@live + - fnd-a-40-hour-save-takes-1-9-s-to-upgrade-through-si--gw6ahjtssbrm2jwx@live + - fnd-a-falling-tide-reloads-18-cells-at-410-mb-s-peak--tjz5vscfrdtazcms@live + - fnd-a-full-world-snapshot-save-is-310-mb--2c7a78gjb54ygkj4@live + - fnd-a-thread-pool-with-continuation-waits-keeps-work--3nryg6kq6w7236ae@live + - fnd-alpha-content-needs-6-2-ms-of-gull-time-per-fram--4mekgdpsdv5nk085@live + - fnd-archetype-iteration-takes-3-4-ms-in-the-alpha-wo--dawb9m0pa999mhpe@live + - fnd-cell-size-sweep-for-the-768-m-streaming-radius--q3qfh6cp8a0k0f7g@live + - fnd-cross-platform-cloud-saves-need-platform-agreeme--4qgfc1a4nq4padvz@live + - fnd-delta-saves-reach-6-2-mb-after-40-hours--8g1j04z0vhjwrkyn@live + - fnd-deltas-saved-at-low-tide-replay-wrongly-at-high--25b4vwytarw8ej50@live + - fnd-fibers-hide-waits-but-need-custom-stacks-and-deb--0ynync38mj13w03k@live + - fnd-field-captures-show-forecast-eviction-cuts-reloa--ee6m7fwv4798jdmv@live + - fnd-fixed-point-tide-step-costs-0-3-ms-on-meridian--jzxe4pa936rxawns@live + - fnd-fixed-point-tide-step-costs-0-9-ms-on-skiff--mfc73bg9wwaxtfra@live + - fnd-fixed-point-tides-match-bit-for-bit-across-all-p--kb3ssw5190e93r4m@live + - fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss@live + - fnd-gull-s-tree-walking-interpreter-spends-1-8-ms-on--bj1ge76d3wy5aqq3@live + - fnd-gull-s-two-dedicated-threads-sit-idle-70-of-each--qekr5vjr9pand9rs@live + - fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws@live + - fnd-kelp-decodes-at-1-1-gb-s-on-skiff-with-a-cold-ca--vef244qjn2mjf07x@live + - fnd-kelp-with-a-1-mb-dictionary-decodes-at-2-2-gb-s--vkt1dgk99x2xrmbs@live + - fnd-lru-eviction-thrashes-during-tide-turns--0tvj4hmg42jy5d3f@live + - fnd-ports-cut-the-skiff-memory-total-and-streaming-m--1p8b10ttb07jkznx@live + - fnd-priority-lanes-still-leave-workers-28-idle-durin--fhswesk5c086dk1y@live + - fnd-register-vm-prototype-runs-the-crab-herd-4-1x-fa--1eb9hfat7611jksr@live + - fnd-retail-skiff-units-sustain-only-190-mb-s-of-stre--485sdcmm3gweevvn@live + - fnd-shipping-entity-names-costs-57-mb-at-full-popula--6w7gjvy7wdmdx9qx@live + - fnd-skiff-s-file-system-cannot-memory-map-packed-arc--00ecsf304vk38ajb@live + - fnd-streaming-jobs-block-workers-while-waiting-on-re--sn2bmfdgjeqwkk3p@live + - fnd-streaming-tide-heights-costs-46-kb-s-per-peer--knxqtyqh6xcz1tp9@live + - fnd-strict-float-mode-still-diverges-because-skiff-s--z811r28v0a1wzb13@live + - fnd-the-gull-vm-reads-thread-local-registers-after-f--1qser43b9j8ac5pf@live + - fnd-tide-band-cells-need-320-mb-resident-during-a-sp--0erj5eqw3ved35t0@live + - fnd-tide-priority-reads-starve-player-proximity-load--by0d7b0bk39xz3rk@live + - fnd-tide-turns-toggle-the-submerged-tag-on-40-000-en--a95p39zkd5ckmg5y@live + - iss-beta-saves-lack-the-second-tide-harmonic-s-phase--gmhrjdy35pjfq651@open + - iss-gull-hot-reload-drops-suspended-coroutines--z7j2gmyny6gdxd07@open + - iss-tide-turns-leave-inland-terrain-untextured-for-s--ccv6nhwk68kj732c@open + - rsk-fiber-stacks-may-make-crash-dumps-unreadable--b7c1mkn9ygvmsy57@realized + - rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew@open + - >- + rsk-kelp-s-4-mb-dictionary-may-thrash-the-skiff-cach--rv7ac1hedneqkp0v@realized + - >- + rsk-ports-may-need-to-shrink-the-streaming-pool-for--1gtjkygrtkb5kgww@realized + - >- + rsk-queries-that-join-tables-with-sparse-tags-may-lo--2h5br5crhfn1nb8c@realized + - >- + rsk-saving-during-a-tide-turn-may-record-a-half-appl--zezc1pxx8zp5b82m@realized +--- +Engine jobs and Gull scripts share one thread pool with continuation waits; the dedicated Gull threads are gone. The world uses 192 m cells. The streaming pool is 1.6 GB, with 320 MB reserved for tide-band cells during a turn. The tide runs in 32.32 fixed point and now has a second harmonic for spring and neap tides. Kelp with a 1 MB dictionary decodes at 2.2 GB/s cold on Skiff, so decode has headroom. Saves are versioned and upgraded on load. + +Two blockers are open. Beta saves lack the second harmonic's phase, with two proposed fixes. Tide-priority reads starve player-proximity loads, and a deadline scheduler is proposed. Gull hot reload still drops suspended coroutines. diff --git a/benchmarks/proof-recall/.flatbread-proof/findings/fnd-world-core-state-before-the-vertical-slice--rbpesp345hf8mesp.md b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-world-core-state-before-the-vertical-slice--rbpesp345hf8mesp.md new file mode 100644 index 00000000..8bd2a571 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/findings/fnd-world-core-state-before-the-vertical-slice--rbpesp345hf8mesp.md @@ -0,0 +1,67 @@ +--- +id: fnd-world-core-state-before-the-vertical-slice--rbpesp345hf8mesp +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: World core state before the vertical slice +kind: compaction +created_at: '2025-12-12T16:00:00Z' +created_by: Rhea Valdés +derives_from: + - con-streaming-pool-budget--632bkbs79bwj4cr5 + - dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m + - dec-evict-the-least-recently-used-cells-first--4eap3mr9tkafxy2p + - dec-keep-gull-on-the-tree-walking-interpreter--br1kgzfmw57xmm9m + - dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq + - dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw + - dec-read-streamed-assets-through-one-async-request-q--rd5c8rxr5pwz50ds + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e + - dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw + - dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9 +superseded_by: + - fnd-world-core-state-at-alpha--tkbsm4867h65jqq8 +covers: + - con-archetype-changes-happen-only-at-frame-sync-poin--kcsrz5g8g8yndwnx@live + - con-cell-load-deadline--m20x64m5eh7q2bh6@live + - con-gull-script-tick-budget--4p9jp4dj1njf7q9m@live + - con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73@live + - con-streaming-i-o-budget--a99y4h0e7xmhp5qk@live + - con-streaming-pool-budget--632bkbs79bwj4cr5@live + - con-tide-state-must-be-bit-identical-on-every-peer--zrpnp8qjyxzkas7t@live + - dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m@accepted + - dec-evict-the-least-recently-used-cells-first--4eap3mr9tkafxy2p@accepted + - dec-keep-gull-on-the-tree-walking-interpreter--br1kgzfmw57xmm9m@accepted + - dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq@accepted + - dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw@accepted + - >- + dec-read-streamed-assets-through-one-async-request-q--rd5c8rxr5pwz50ds@accepted + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e@accepted + - >- + dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw@accepted + - >- + dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9@accepted + - >- + dec-wrap-the-tide-phase-accumulator-at-each-40-minut--hx88m4hbg27n0xwy@accepted + - fnd-128-m-cells-should-add-only-40-mb-of-per-cell-ov--ape0tgv597x77p6z@live + - fnd-a-falling-tide-reloads-18-cells-at-410-mb-s-peak--tjz5vscfrdtazcms@live + - fnd-a-full-world-snapshot-save-is-310-mb--2c7a78gjb54ygkj4@live + - fnd-archetype-tables-iterate-transforms-2-4x-faster--3xtpgtqs17zzq6v3@live + - fnd-cell-size-sweep-for-the-768-m-streaming-radius--q3qfh6cp8a0k0f7g@live + - fnd-fibers-hide-waits-but-need-custom-stacks-and-deb--0ynync38mj13w03k@live + - fnd-fixed-point-tide-step-costs-0-3-ms-on-meridian--jzxe4pa936rxawns@live + - fnd-fixed-point-tide-step-costs-0-9-ms-on-skiff--mfc73bg9wwaxtfra@live + - fnd-fixed-point-tides-match-bit-for-bit-across-all-p--kb3ssw5190e93r4m@live + - fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss@live + - fnd-gull-s-tree-walking-interpreter-spends-1-8-ms-on--bj1ge76d3wy5aqq3@live + - fnd-kelp-decodes-streamed-assets-at-2-9-gb-s-per-cor--32tjx83v8ky28sz4@live + - fnd-priority-lanes-still-leave-workers-28-idle-durin--fhswesk5c086dk1y@live + - fnd-shipping-entity-names-costs-57-mb-at-full-popula--6w7gjvy7wdmdx9qx@live + - fnd-skiff-s-file-system-cannot-memory-map-packed-arc--00ecsf304vk38ajb@live + - fnd-skiff-streaming-reads-sustain-260-mb-s--s1gkt975grre2ewr@live + - fnd-streaming-jobs-block-workers-while-waiting-on-re--sn2bmfdgjeqwkk3p@live + - fnd-streaming-tide-heights-costs-46-kb-s-per-peer--knxqtyqh6xcz1tp9@live + - fnd-strict-float-mode-still-diverges-because-skiff-s--z811r28v0a1wzb13@live + - fnd-tide-turns-toggle-the-submerged-tag-on-40-000-en--a95p39zkd5ckmg5y@live + - rsk-fiber-stacks-may-make-crash-dumps-unreadable--b7c1mkn9ygvmsy57@open + - rsk-kelp-s-4-mb-dictionary-may-thrash-the-skiff-cach--rv7ac1hedneqkp0v@open + - rsk-queries-that-join-tables-with-sparse-tags-may-lo--2h5br5crhfn1nb8c@open +--- +Components live in archetype tables, with volatile tide tags in sparse sets. Engine jobs run on fibers (160 fibers, 64 KB stacks) after two thread-pool versions left workers idle on waits. The world is partitioned into 128 m cells, halved from 256 m because falling tides forced whole-cell reloads. The tide simulation runs in 32.32 fixed point and matches bit for bit across platforms. Streamed assets use Kelp, read through one async request queue per platform, inside a 2.0 GB streaming pool with LRU eviction. Gull stays on its tree-walking interpreter until alpha content lands. Saves store player deltas against the tide-free baseline. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-banding-in-the-dusk-sky-with-the-brine-curve-on--qyfqbggg14ckxvc9.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-banding-in-the-dusk-sky-with-the-brine-curve-on--qyfqbggg14ckxvc9.md new file mode 100644 index 00000000..3e44a6ab --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-banding-in-the-dusk-sky-with-the-brine-curve-on--qyfqbggg14ckxvc9.md @@ -0,0 +1,14 @@ +--- +id: iss-banding-in-the-dusk-sky-with-the-brine-curve-on--qyfqbggg14ckxvc9 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Banding in the dusk sky with the Brine curve on 10-bit output +kind: defect +status: resolved +created_at: '2026-03-18T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86 +resolved_by: + - dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e +--- +In HDR on 10-bit output, the dusk sky shows visible bands where the Brine curve's shoulder is steepest. SDR is fine. Dithering hides some of it. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-beta-saves-lack-the-second-tide-harmonic-s-phase--gmhrjdy35pjfq651.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-beta-saves-lack-the-second-tide-harmonic-s-phase--gmhrjdy35pjfq651.md new file mode 100644 index 00000000..b035b814 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-beta-saves-lack-the-second-tide-harmonic-s-phase--gmhrjdy35pjfq651.md @@ -0,0 +1,13 @@ +--- +id: iss-beta-saves-lack-the-second-tide-harmonic-s-phase--gmhrjdy35pjfq651 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Beta saves lack the second tide harmonic's phase +kind: blocker +status: open +created_at: '2026-07-14T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - con-saves-from-beta-onward-must-load-in-every-later--v6z856sxtgc5sb09 + - dec-add-a-second-tide-harmonic-for-spring-and-neap-t--1c3s7dtyxvj70gvw +--- +The second tide harmonic adds a phase value to the tide state. Beta saves do not have it, and every tide-keyed delta in them was made against a one-harmonic tide. Loading a beta save in the current build replays the deltas against different terrain. Beta saves must load, so this blocks the release candidate. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-cascade-seams-visible-through-saltglass-at-300-t--3590ssrc8xxa4ae6.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-cascade-seams-visible-through-saltglass-at-300-t--3590ssrc8xxa4ae6.md new file mode 100644 index 00000000..95e4cd4c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-cascade-seams-visible-through-saltglass-at-300-t--3590ssrc8xxa4ae6.md @@ -0,0 +1,14 @@ +--- +id: iss-cascade-seams-visible-through-saltglass-at-300-t--3590ssrc8xxa4ae6 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Cascade seams visible through saltglass at 300 to 800 m +kind: defect +status: resolved +created_at: '2025-11-03T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr +resolved_by: + - dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4 +--- +Refraction through saltglass bends view rays across cascade boundaries, so a shadow sampled from cascade 2 sits next to one from cascade 3. The seam reads as a hard line in the glass at 300 to 800 m. Blending cascades hides it on sand but not inside the glass. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-caustics-flicker-under-tern-at-low-internal-reso--gbtcjdby6eyhnjca.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-caustics-flicker-under-tern-at-low-internal-reso--gbtcjdby6eyhnjca.md new file mode 100644 index 00000000..8337e4f0 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-caustics-flicker-under-tern-at-low-internal-reso--gbtcjdby6eyhnjca.md @@ -0,0 +1,13 @@ +--- +id: iss-caustics-flicker-under-tern-at-low-internal-reso--gbtcjdby6eyhnjca +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Caustics flicker under Tern at low internal resolutions +kind: blocker +status: open +created_at: '2026-01-26T10:02:00Z' +created_by: Ines Okafor +retracted: true +retracted_at: '2026-01-27T10:00:00.000Z' +retracted_reason: Duplicate of the blocker filed two minutes earlier. +--- +Caustics flicker under Tern at low internal resolution. Blocker for release. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5.md new file mode 100644 index 00000000..1a8e3b63 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5.md @@ -0,0 +1,12 @@ +--- +id: iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Caustics flicker under Tern at low internal resolution +kind: blocker +status: open +created_at: '2026-01-26T10:00:00Z' +created_by: Ines Okafor +derives_from: + - fnd-caustics-flicker-at-3-to-6-hz-under-tern--9je5rqt89es3rcz4 +--- +Flicker in the 3 to 6 Hz band is a photosensitivity problem as well as an ugly one. Release cannot happen with it. Any fix must keep the caustics moving with the tide and must work at the internal resolutions Tern uses on every platform. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-crash-triage-stalls-because-fiber-stacks-are-unr--dyr12bpb18sav85g.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-crash-triage-stalls-because-fiber-stacks-are-unr--dyr12bpb18sav85g.md new file mode 100644 index 00000000..376d8890 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-crash-triage-stalls-because-fiber-stacks-are-unr--dyr12bpb18sav85g.md @@ -0,0 +1,14 @@ +--- +id: iss-crash-triage-stalls-because-fiber-stacks-are-unr--dyr12bpb18sav85g +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Crash triage stalls because fiber stacks are unreadable +kind: blocker +status: resolved +created_at: '2026-03-25T10:00:00Z' +created_by: Dara Whitlock +derives_from: + - fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m +resolved_by: + - dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h +--- +QA cannot route 41% of crashes to an owner. Dara Whitlock marks this as a blocker for the beta certification pass, which needs a crash rate per system. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-cross-platform-cloud-saves-are-unplanned--5bk0k4wrgj42ztfy.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-cross-platform-cloud-saves-are-unplanned--5bk0k4wrgj42ztfy.md new file mode 100644 index 00000000..87819056 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-cross-platform-cloud-saves-are-unplanned--5bk0k4wrgj42ztfy.md @@ -0,0 +1,12 @@ +--- +id: iss-cross-platform-cloud-saves-are-unplanned--5bk0k4wrgj42ztfy +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Cross-platform cloud saves are unplanned +kind: gap +status: deferred +created_at: '2026-05-25T10:00:00Z' +created_by: Dara Whitlock +resolved_by: + - fnd-cross-platform-cloud-saves-need-platform-agreeme--4qgfc1a4nq4padvz +--- +Players will ask to continue a PC save on Skiff. Nothing in the save design covers cloud sync or conflict handling between platforms. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj.md new file mode 100644 index 00000000..2ebe96d5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj.md @@ -0,0 +1,14 @@ +--- +id: iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Developer workstations cannot read the farm shader cache +kind: gap +status: deferred +created_at: '2026-03-09T09:00:00Z' +created_by: Yusuf Demir +derives_from: + - dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh +resolved_by: + - fnd-retrospective-on-the-shader-compile-cache--9rpv2a60ach04cx6 +--- +Only farm agents can reach the cache volume. A developer workstation still compiles every shader locally, about 22 minutes after a fresh sync. Opening read access needs a VPN change and a cache proxy. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-entity-debug-names-are-missing-in-release-builds--e00p8nba80n2ykb8.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-entity-debug-names-are-missing-in-release-builds--e00p8nba80n2ykb8.md new file mode 100644 index 00000000..4780589a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-entity-debug-names-are-missing-in-release-builds--e00p8nba80n2ykb8.md @@ -0,0 +1,12 @@ +--- +id: iss-entity-debug-names-are-missing-in-release-builds--e00p8nba80n2ykb8 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Entity debug names are missing in release builds +kind: gap +status: wontfix +created_at: '2025-11-03T10:00:00Z' +created_by: Marta Lindqvist +resolved_by: + - fnd-shipping-entity-names-costs-57-mb-at-full-popula--6w7gjvy7wdmdx9qx +--- +Crash reports from release builds show entities as bare numbers. Marta Lindqvist asks whether the Name component can ship in release so the crash reports are readable. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-first-visit-hitches-of-45-to-190-ms-on-skiff--jcraqy468yw51kpf.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-first-visit-hitches-of-45-to-190-ms-on-skiff--jcraqy468yw51kpf.md new file mode 100644 index 00000000..5f8c1447 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-first-visit-hitches-of-45-to-190-ms-on-skiff--jcraqy468yw51kpf.md @@ -0,0 +1,13 @@ +--- +id: iss-first-visit-hitches-of-45-to-190-ms-on-skiff--jcraqy468yw51kpf +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: First-visit hitches of 45 to 190 ms on Skiff +kind: defect +status: resolved +created_at: '2025-12-08T11:00:00Z' +created_by: Priya Natarajan +resolved_by: + - dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7 + - fnd-skiff-pipeline-cache-removes-second-visit-hitche--kzjtp9dpbpbmrb0x +--- +Walking into a district for the first time on Skiff stalls the game for 45 to 190 ms at a time. The stalls vanish on a second visit in the same session and come back after a restart. Skiff compiles each graphics pipeline the first time it is drawn. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-full-shader-rebuilds-take-47-minutes-on-the-buil--4bnh1e17snf5y3h6.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-full-shader-rebuilds-take-47-minutes-on-the-buil--4bnh1e17snf5y3h6.md new file mode 100644 index 00000000..b30a87bb --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-full-shader-rebuilds-take-47-minutes-on-the-buil--4bnh1e17snf5y3h6.md @@ -0,0 +1,12 @@ +--- +id: iss-full-shader-rebuilds-take-47-minutes-on-the-buil--4bnh1e17snf5y3h6 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Full shader rebuilds take 47 minutes on the build farm +kind: gap +status: resolved +created_at: '2025-09-09T10:00:00Z' +created_by: Liam O'Connell +resolved_by: + - dec-turn-the-shader-compile-cache-on-for-every-farm--4rr3b12b4sasdmaj +--- +A clean rebuild of every Lantern shader permutation takes 47 minutes on the 12-agent farm. There are about 38,000 permutations today and Ines Okafor expects 50,000 by alpha. Yusuf Demir reports that a one-line change to the saltglass refraction shader blocks art iteration for most of an hour, because the farm recompiles every permutation that includes the shared lighting header. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-gi-does-not-fit-the-120-hz-performance-mode-budg--get9cq6er1ac4vzx.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-gi-does-not-fit-the-120-hz-performance-mode-budg--get9cq6er1ac4vzx.md new file mode 100644 index 00000000..c9822fa4 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-gi-does-not-fit-the-120-hz-performance-mode-budg--get9cq6er1ac4vzx.md @@ -0,0 +1,13 @@ +--- +id: iss-gi-does-not-fit-the-120-hz-performance-mode-budg--get9cq6er1ac4vzx +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: GI does not fit the 120 Hz performance-mode budget +kind: blocker +status: open +created_at: '2026-03-24T10:00:00Z' +created_by: Ines Okafor +derives_from: + - con-meridian-120-hz-performance-mode-budget--h9zg6vmd70sr78by + - fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr +--- +At 4.7 ms SDF GI alone takes more than half of an 8.3 ms performance-mode frame. The 120 Hz mode cannot ship with GI as it is. Some cheaper GI path for performance mode is needed. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-gull-hot-reload-drops-suspended-coroutines--26y5hmqf24s1kwjx.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-gull-hot-reload-drops-suspended-coroutines--26y5hmqf24s1kwjx.md new file mode 100644 index 00000000..7cee0d58 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-gull-hot-reload-drops-suspended-coroutines--26y5hmqf24s1kwjx.md @@ -0,0 +1,13 @@ +--- +id: iss-gull-hot-reload-drops-suspended-coroutines--26y5hmqf24s1kwjx +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Gull hot-reload drops suspended coroutines +kind: defect +status: open +created_at: '2026-05-19T10:10:00Z' +created_by: Yusuf Demir +retracted: true +retracted_at: '2026-05-19T14:00:00.000Z' +retracted_reason: Filed twice from the editor's bug button. +--- +Creatures freeze after reload. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-gull-hot-reload-drops-suspended-coroutines--z7j2gmyny6gdxd07.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-gull-hot-reload-drops-suspended-coroutines--z7j2gmyny6gdxd07.md new file mode 100644 index 00000000..89070b4f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-gull-hot-reload-drops-suspended-coroutines--z7j2gmyny6gdxd07.md @@ -0,0 +1,14 @@ +--- +id: iss-gull-hot-reload-drops-suspended-coroutines--z7j2gmyny6gdxd07 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Gull hot reload drops suspended coroutines +kind: defect +status: deferred +created_at: '2026-05-19T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws +resolved_by: + - fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws +--- +Yusuf Demir loses tide-pool creature behaviour after almost every reload: the creatures freeze until the level restarts. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-gull-hot-reload-rejects-struct-layout-changes--3v2w2f9hg2gwy6aj.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-gull-hot-reload-rejects-struct-layout-changes--3v2w2f9hg2gwy6aj.md new file mode 100644 index 00000000..88f684f9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-gull-hot-reload-rejects-struct-layout-changes--3v2w2f9hg2gwy6aj.md @@ -0,0 +1,14 @@ +--- +id: iss-gull-hot-reload-rejects-struct-layout-changes--3v2w2f9hg2gwy6aj +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Gull hot reload rejects struct layout changes +kind: gap +status: deferred +created_at: '2026-02-16T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3 +resolved_by: + - dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42 +--- +With bytecode, live objects have a fixed layout. An edit that adds or removes a field in a Gull struct cannot be applied to objects that already exist, so the editor refuses the reload. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-gull-scripts-crash-after-a-fiber-resumes-on-anot--n2hvwg59w0rem0te.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-gull-scripts-crash-after-a-fiber-resumes-on-anot--n2hvwg59w0rem0te.md new file mode 100644 index 00000000..c40f734f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-gull-scripts-crash-after-a-fiber-resumes-on-anot--n2hvwg59w0rem0te.md @@ -0,0 +1,12 @@ +--- +id: iss-gull-scripts-crash-after-a-fiber-resumes-on-anot--n2hvwg59w0rem0te +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Gull scripts crash after a fiber resumes on another worker +kind: defect +status: resolved +created_at: '2026-01-30T10:00:00Z' +created_by: Marta Lindqvist +resolved_by: + - dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te +--- +Gull scripts that wait (for an animation, a timer, or a tide event) crash at random after resuming. The crash is always inside the Gull VM's register access. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-do-we-make-the-tide-simulation-deterministic--48yc2jreapt0n7jf.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-do-we-make-the-tide-simulation-deterministic--48yc2jreapt0n7jf.md new file mode 100644 index 00000000..cf8ccac1 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-do-we-make-the-tide-simulation-deterministic--48yc2jreapt0n7jf.md @@ -0,0 +1,14 @@ +--- +id: iss-how-do-we-make-the-tide-simulation-deterministic--48yc2jreapt0n7jf +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: How do we make the tide simulation deterministic across machines? +kind: question +status: resolved +created_at: '2025-10-30T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss +resolved_by: + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e +--- +Peers must agree on every tide height for the whole 90-minute day. Pick the approach before co-op work builds on the tide state. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-co-op-keep-up-to-four-players-in-sync--92t2zfsy3etfzr89.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-co-op-keep-up-to-four-players-in-sync--92t2zfsy3etfzr89.md new file mode 100644 index 00000000..c764f91c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-co-op-keep-up-to-four-players-in-sync--92t2zfsy3etfzr89.md @@ -0,0 +1,12 @@ +--- +id: iss-how-should-co-op-keep-up-to-four-players-in-sync--92t2zfsy3etfzr89 +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: How should co-op keep up to four players in sync? +kind: question +status: resolved +created_at: '2025-11-04T10:00:00Z' +created_by: Sofia Marchetti +resolved_by: + - dec-use-host-authoritative-sync-for-co-op--17hqrmtja7pn98d6 +--- +Co-op needs a sync model before the vertical slice. Players fight, climb and ride the same tide surges, so any lag in shared state is visible. Candidates: rollback, deterministic lockstep, or a host-authoritative model. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-kestrel-store-entity-components--aj37s7xz78dszyzp.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-kestrel-store-entity-components--aj37s7xz78dszyzp.md new file mode 100644 index 00000000..064e2ee4 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-kestrel-store-entity-components--aj37s7xz78dszyzp.md @@ -0,0 +1,12 @@ +--- +id: iss-how-should-kestrel-store-entity-components--aj37s7xz78dszyzp +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: How should Kestrel store entity components? +kind: question +status: resolved +created_at: '2025-09-03T09:00:00Z' +created_by: Rhea Valdés +resolved_by: + - dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9 +--- +Kestrel needs one component storage model before gameplay code piles up on it. The candidates are archetype tables (dense columns per component set), sparse sets (one packed array per component type), or a mix of the two. The hard case is the tide: every tide turn flips state on tens of thousands of shoreline entities at once, and whichever layout we pick has to survive that spike. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-lantern-cull-geometry--jnrp9qd2fywqvqgw.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-lantern-cull-geometry--jnrp9qd2fywqvqgw.md new file mode 100644 index 00000000..8ae80108 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-lantern-cull-geometry--jnrp9qd2fywqvqgw.md @@ -0,0 +1,12 @@ +--- +id: iss-how-should-lantern-cull-geometry--jnrp9qd2fywqvqgw +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: How should Lantern cull geometry? +kind: question +status: resolved +created_at: '2025-10-09T10:00:00Z' +created_by: Tomasz Brandt +resolved_by: + - dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee +--- +The dunes benchmark submits 38,000 draws when the tide is out. The CPU spends more time deciding what to draw than the GPU spends drawing it. Options: GPU-driven culling, or keep CPU culling and add software occlusion. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-lantern-do-global-illumination--3hs82xftkrdhk3f7.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-lantern-do-global-illumination--3hs82xftkrdhk3f7.md new file mode 100644 index 00000000..5e9d804d --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-lantern-do-global-illumination--3hs82xftkrdhk3f7.md @@ -0,0 +1,12 @@ +--- +id: iss-how-should-lantern-do-global-illumination--3hs82xftkrdhk3f7 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: How should Lantern do global illumination? +kind: question +status: resolved +created_at: '2025-09-15T10:00:00Z' +created_by: Ines Okafor +resolved_by: + - dec-use-signed-distance-field-gi--yn366zmp3k7snd9w +--- +Tides move every 40 minutes and the sun crosses the sky in 90, so baked lighting is out. Candidates: a relit probe grid, signed-distance-field GI, or a hybrid of the two. Light must bounce through saltglass and must not leak through thin glass walls. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-lantern-draw-saltglass-caustics--a6wcxavrp4ky319s.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-lantern-draw-saltglass-caustics--a6wcxavrp4ky319s.md new file mode 100644 index 00000000..55bbb086 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-lantern-draw-saltglass-caustics--a6wcxavrp4ky319s.md @@ -0,0 +1,12 @@ +--- +id: iss-how-should-lantern-draw-saltglass-caustics--a6wcxavrp4ky319s +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: How should Lantern draw saltglass caustics? +kind: question +status: resolved +created_at: '2025-10-06T11:00:00Z' +created_by: Yusuf Demir +resolved_by: + - dec-splat-caustic-photons-from-a-sun-space-map--gz19gensacx2zh1w +--- +Sunlight through saltglass dunes should throw moving caustic patterns on the sand below. Options: project animated caustic textures along the sun, or splat photons traced through the glass. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-lantern-render-saltglass-refraction--brndmsn2n8jz6yyk.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-lantern-render-saltglass-refraction--brndmsn2n8jz6yyk.md new file mode 100644 index 00000000..591aea2a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-lantern-render-saltglass-refraction--brndmsn2n8jz6yyk.md @@ -0,0 +1,12 @@ +--- +id: iss-how-should-lantern-render-saltglass-refraction--brndmsn2n8jz6yyk +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: How should Lantern render saltglass refraction? +kind: question +status: resolved +created_at: '2025-09-18T10:00:00Z' +created_by: Yusuf Demir +resolved_by: + - dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6 +--- +Saltglass is the signature look of Saltglass Reach. Dunes, cliffs and ruins bend whatever is behind them, out to 2 km. Options: screen-space refraction, ray-marching through the saltglass distance field, or refracting into local cubemaps. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-save-games-store-the-changing-world--kpdhcdkax56a7b7d.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-save-games-store-the-changing-world--kpdhcdkax56a7b7d.md new file mode 100644 index 00000000..233e82d4 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-save-games-store-the-changing-world--kpdhcdkax56a7b7d.md @@ -0,0 +1,12 @@ +--- +id: iss-how-should-save-games-store-the-changing-world--kpdhcdkax56a7b7d +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: How should save games store the changing world? +kind: question +status: resolved +created_at: '2025-12-01T10:00:00Z' +created_by: Marta Lindqvist +resolved_by: + - dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw +--- +A save must restore everything players changed: dug sand, moved salvage, opened ruins, and the tide itself. The world is large and the tide reshapes it, so the save format decides both save size and what a reload looks like. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-skiff-avoid-first-use-pipeline-compil--5nvhn8xzyz2d7y7k.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-skiff-avoid-first-use-pipeline-compil--5nvhn8xzyz2d7y7k.md new file mode 100644 index 00000000..0e8c16de --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-skiff-avoid-first-use-pipeline-compil--5nvhn8xzyz2d7y7k.md @@ -0,0 +1,14 @@ +--- +id: iss-how-should-skiff-avoid-first-use-pipeline-compil--5nvhn8xzyz2d7y7k +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: How should Skiff avoid first-use pipeline compiles? +kind: question +status: resolved +created_at: '2025-12-11T09:00:00Z' +created_by: Priya Natarajan +derives_from: + - iss-first-visit-hitches-of-45-to-190-ms-on-skiff--jcraqy468yw51kpf +resolved_by: + - dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn +--- +Three options: ship pipelines prebuilt in the package, build and keep them on the device, or draw with ubershaders until the real pipelines compile in the background. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-skiff-hold-its-frame-budget-when-the--1zdpg3npqmscp42d.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-skiff-hold-its-frame-budget-when-the--1zdpg3npqmscp42d.md new file mode 100644 index 00000000..baa82911 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-skiff-hold-its-frame-budget-when-the--1zdpg3npqmscp42d.md @@ -0,0 +1,14 @@ +--- +id: iss-how-should-skiff-hold-its-frame-budget-when-the--1zdpg3npqmscp42d +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: How should Skiff hold its frame budget when the GPU is overloaded? +kind: question +status: resolved +created_at: '2025-11-03T09:30:00Z' +created_by: Priya Natarajan +derives_from: + - con-frame-budget--wt5rfqh5z444g2cg +resolved_by: + - dec-scale-skiff-resolution-dynamically-between-540p--jtytvgh2erd32x68 +--- +Saltglass refraction spikes GPU time when a dune ridge fills the screen. On Skiff the spike reaches 38 ms on the dune route. We need one standing answer for what gives way: resolution or effects. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-the-farm-stop-recompiling-unchanged-s--b2kcgasfccnydkjp.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-the-farm-stop-recompiling-unchanged-s--b2kcgasfccnydkjp.md new file mode 100644 index 00000000..bae161f6 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-the-farm-stop-recompiling-unchanged-s--b2kcgasfccnydkjp.md @@ -0,0 +1,15 @@ +--- +id: iss-how-should-the-farm-stop-recompiling-unchanged-s--b2kcgasfccnydkjp +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: How should the farm stop recompiling unchanged shaders? +kind: question +status: resolved +created_at: '2025-09-15T09:30:00Z' +created_by: Liam O'Connell +derives_from: + - con-the-build-farm-stays-at-12-agents-until-alpha--w7e1xfex9z2ycpx1 + - fnd-most-shader-compile-time-on-the-farm-repeats-ide--n7mr2yxxxtzpak35 +resolved_by: + - dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh +--- +The baseline says most of the farm's shader work repeats. We need one approach to stop doing it. Options on the table: a shared content-addressed cache, more agents, or per-agent incremental builds. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-the-streaming-pool-choose-cells-to-ev--4j47zrsgtxncn9dk.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-the-streaming-pool-choose-cells-to-ev--4j47zrsgtxncn9dk.md new file mode 100644 index 00000000..bfca8674 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-how-should-the-streaming-pool-choose-cells-to-ev--4j47zrsgtxncn9dk.md @@ -0,0 +1,14 @@ +--- +id: iss-how-should-the-streaming-pool-choose-cells-to-ev--4j47zrsgtxncn9dk +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: How should the streaming pool choose cells to evict? +kind: question +status: resolved +created_at: '2025-10-24T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - con-streaming-pool-budget--632bkbs79bwj4cr5 +resolved_by: + - dec-evict-the-least-recently-used-cells-first--4eap3mr9tkafxy2p +--- +When the pool is full and a new cell must load, streaming evicts resident cells. The policy decides how often we reload a cell we just threw away. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-late-join-during-a-tide-surge-desyncs-the-joinin--mya93va0n7s8g7cj.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-late-join-during-a-tide-surge-desyncs-the-joinin--mya93va0n7s8g7cj.md new file mode 100644 index 00000000..5ea64525 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-late-join-during-a-tide-surge-desyncs-the-joinin--mya93va0n7s8g7cj.md @@ -0,0 +1,13 @@ +--- +id: iss-late-join-during-a-tide-surge-desyncs-the-joinin--mya93va0n7s8g7cj +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Late join during a tide surge desyncs the joining player +kind: defect +status: open +created_at: '2026-01-26T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g + - dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4 +--- +A player who joins while a surge is rising receives tide cells from a snapshot that is up to 7 frames old. In 6 of 20 tries the joiner saw a dry path the others saw flooded. Kenji Arakawa suspects the join snapshot skips cells that are still streaming in. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-loaded-saves-misplace-objects-the-tide-moved--4jy763bv4xn9j5eh.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-loaded-saves-misplace-objects-the-tide-moved--4jy763bv4xn9j5eh.md new file mode 100644 index 00000000..f41052b6 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-loaded-saves-misplace-objects-the-tide-moved--4jy763bv4xn9j5eh.md @@ -0,0 +1,14 @@ +--- +id: iss-loaded-saves-misplace-objects-the-tide-moved--4jy763bv4xn9j5eh +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Loaded saves misplace objects the tide moved +kind: defect +status: resolved +created_at: '2026-02-19T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - fnd-deltas-saved-at-low-tide-replay-wrongly-at-high--25b4vwytarw8ej50 +resolved_by: + - dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8 +--- +Objects players moved in tide-dependent terrain reappear buried or shifted after a reload. Repro rate is 62% for saves taken at low tide. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-meridian-cert-activity-cards-missing-for-two-bio--k214cmfra7pyvvzq.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-meridian-cert-activity-cards-missing-for-two-bio--k214cmfra7pyvvzq.md new file mode 100644 index 00000000..f0991847 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-meridian-cert-activity-cards-missing-for-two-bio--k214cmfra7pyvvzq.md @@ -0,0 +1,14 @@ +--- +id: iss-meridian-cert-activity-cards-missing-for-two-bio--k214cmfra7pyvvzq +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Meridian cert: activity cards missing for two biomes' +kind: defect +status: deferred +created_at: '2026-05-20T11:20:00Z' +created_by: Dara Whitlock +resolved_by: + - dec-ship-the-missing-meridian-activity-cards-in-the--g947vhgwr7smr8dq +cites: + - cit-meridian-technical-requirements-checklist-2-4--xv7xnma0egx0119s +--- +Meridian shows an activity card for each biome on the console home screen. The glass forest and the drowned quarry have none. The checklist marks this as should-fix, not must-fix. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-meridian-cert-resume-from-suspend-drops-the-co-o--jbqz6wqm1w747bbx.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-meridian-cert-resume-from-suspend-drops-the-co-o--jbqz6wqm1w747bbx.md new file mode 100644 index 00000000..79720e81 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-meridian-cert-resume-from-suspend-drops-the-co-o--jbqz6wqm1w747bbx.md @@ -0,0 +1,14 @@ +--- +id: iss-meridian-cert-resume-from-suspend-drops-the-co-o--jbqz6wqm1w747bbx +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Meridian cert: resume from suspend drops the co-op session' +kind: defect +status: resolved +created_at: '2026-05-20T11:00:00Z' +created_by: Sofia Marchetti +resolved_by: + - dec-rejoin-the-co-op-session-after-meridian-resumes--gp2btfw62qm4khy9 +cites: + - cit-meridian-technical-requirements-checklist-2-4--xv7xnma0egx0119s +--- +Meridian pre-check: after a suspend of 8 hours, resuming the game leaves the player alone in an empty world. The checklist requires a clean return or a clear message. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-meridian-hdr-certification-fails-the-paper-white--bper6nwencgtgf7b.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-meridian-hdr-certification-fails-the-paper-white--bper6nwencgtgf7b.md new file mode 100644 index 00000000..8292f254 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-meridian-hdr-certification-fails-the-paper-white--bper6nwencgtgf7b.md @@ -0,0 +1,13 @@ +--- +id: iss-meridian-hdr-certification-fails-the-paper-white--bper6nwencgtgf7b +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Meridian HDR certification fails the paper-white test +kind: blocker +status: open +created_at: '2026-07-16T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - con-meridian-hdr-certification-requirements--nx9pmkwjjvxy1smf + - fnd-meridian-hdr-certification-pre-check-failed-on-p--qz0rr1cqqmcr6kh9 +--- +Release on Meridian is blocked until paper white follows the system and offers the required range. The UI pass assumes a fixed level, so the fix touches UI compositing as well as tonemapping. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-nightly-builds-fail-about-1-in-9-runs-with-shade--ka2xgkfgaepemgbh.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-nightly-builds-fail-about-1-in-9-runs-with-shade--ka2xgkfgaepemgbh.md new file mode 100644 index 00000000..f60ba02a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-nightly-builds-fail-about-1-in-9-runs-with-shade--ka2xgkfgaepemgbh.md @@ -0,0 +1,14 @@ +--- +id: iss-nightly-builds-fail-about-1-in-9-runs-with-shade--ka2xgkfgaepemgbh +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Nightly builds fail about 1 in 9 runs with shader compile timeouts +kind: defect +status: resolved +created_at: '2025-12-01T09:00:00Z' +created_by: Liam O'Connell +derives_from: + - dec-fan-shader-cache-misses-out-to-every-farm-agent--pwrf9w720rf4hd27 +resolved_by: + - dec-cap-each-farm-agent-at-6-parallel-shader-compile--q5w4sfjm73tsj8x8 +--- +Since remote execution went live, 7 of the last 63 nightly builds failed with "shader job timed out". A rerun always passes. The failures cluster after 02:00 UTC, when every platform builds at once. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-no-automated-gpu-captures-on-nightly-builds--k3vncp4qwzdwc2m6.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-no-automated-gpu-captures-on-nightly-builds--k3vncp4qwzdwc2m6.md new file mode 100644 index 00000000..87bdd745 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-no-automated-gpu-captures-on-nightly-builds--k3vncp4qwzdwc2m6.md @@ -0,0 +1,12 @@ +--- +id: iss-no-automated-gpu-captures-on-nightly-builds--k3vncp4qwzdwc2m6 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: No automated GPU captures on nightly builds +kind: gap +status: resolved +created_at: '2025-09-12T10:00:00Z' +created_by: Ines Okafor +resolved_by: + - dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676 +--- +Every timing in this Effort so far comes from a capture someone took by hand, on whatever machine was free. Nothing records which build or which hardware produced a number. We need captures taken the same way every night. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-no-ray-traced-reflections-on-saltglass--pdcbm94d32f55fa0.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-no-ray-traced-reflections-on-saltglass--pdcbm94d32f55fa0.md new file mode 100644 index 00000000..15374a12 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-no-ray-traced-reflections-on-saltglass--pdcbm94d32f55fa0.md @@ -0,0 +1,12 @@ +--- +id: iss-no-ray-traced-reflections-on-saltglass--pdcbm94d32f55fa0 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: No ray-traced reflections on saltglass +kind: gap +status: wontfix +created_at: '2025-11-25T10:00:00Z' +created_by: Yusuf Demir +resolved_by: + - con-frame-budget--j6vneva1g2ywj86m +--- +Saltglass reflects the sky and nearby cliffs with screen-space reflections only. Anything off screen vanishes from the reflection. Yusuf Demir asks whether ray-traced reflections on PC and Meridian are in scope. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-no-skiff-dev-kits-on-firmware-1-2--3qkawq17a60504j7.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-no-skiff-dev-kits-on-firmware-1-2--3qkawq17a60504j7.md new file mode 100644 index 00000000..e097e004 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-no-skiff-dev-kits-on-firmware-1-2--3qkawq17a60504j7.md @@ -0,0 +1,12 @@ +--- +id: iss-no-skiff-dev-kits-on-firmware-1-2--3qkawq17a60504j7 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: No Skiff dev kits on firmware 1.2 +kind: blocker +status: resolved +created_at: '2026-02-02T09:00:00Z' +created_by: Priya Natarajan +resolved_by: + - fnd-firmware-1-2-skiff-dev-kits-arrived--7dzaq12qessxaasd +--- +Skiff firmware 1.2 ships to players at launch, but all four of our dev kits run 1.0. Memory and pipeline work on 1.2 cannot start until new kits arrive. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-no-skiff-gpu-timings-for-lantern-passes--mve09m4aktb7tya1.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-no-skiff-gpu-timings-for-lantern-passes--mve09m4aktb7tya1.md new file mode 100644 index 00000000..bd12aa36 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-no-skiff-gpu-timings-for-lantern-passes--mve09m4aktb7tya1.md @@ -0,0 +1,12 @@ +--- +id: iss-no-skiff-gpu-timings-for-lantern-passes--mve09m4aktb7tya1 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: No Skiff GPU timings for Lantern passes +kind: gap +status: deferred +created_at: '2026-02-10T10:00:00Z' +created_by: Tomasz Brandt +resolved_by: + - fnd-skiff-devkits-reach-the-render-team-in-april--bx6zmw2s52vr2t1z +--- +Every Lantern pass has Meridian timings from the nightly capture, but none has Skiff timings. The visibility buffer, Tern and VSM were all chosen without a Skiff number. Tomasz Brandt wants Skiff numbers before alpha. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-nothing-shows-which-system-caused-a-desync--k7w6rvkptez9d48k.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-nothing-shows-which-system-caused-a-desync--k7w6rvkptez9d48k.md new file mode 100644 index 00000000..6d128c8b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-nothing-shows-which-system-caused-a-desync--k7w6rvkptez9d48k.md @@ -0,0 +1,13 @@ +--- +id: iss-nothing-shows-which-system-caused-a-desync--k7w6rvkptez9d48k +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Nothing shows which system caused a desync +kind: gap +status: resolved +created_at: '2026-02-09T10:00:00Z' +created_by: Sofia Marchetti +resolved_by: + - dec-hash-tide-physics-and-gull-state-every-30-frames--yqf2m6hqbjhwvkzq + - fnd-the-first-checksum-mismatch-came-from-gull-rando--wrrrkwvq1d0pc35p +--- +When peers drift we only see the symptom, usually minutes later. We need to know whether tides, physics or Gull diverged first. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-objects-pop-in-for-one-frame-when-the-tide-uncov--6165dkqm91r63ckf.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-objects-pop-in-for-one-frame-when-the-tide-uncov--6165dkqm91r63ckf.md new file mode 100644 index 00000000..50243bb2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-objects-pop-in-for-one-frame-when-the-tide-uncov--6165dkqm91r63ckf.md @@ -0,0 +1,14 @@ +--- +id: iss-objects-pop-in-for-one-frame-when-the-tide-uncov--6165dkqm91r63ckf +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Objects pop in for one frame when the tide uncovers them +kind: defect +status: resolved +created_at: '2026-03-10T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee +resolved_by: + - dec-mark-tide-exposed-instances-visible-for-one-fram--157jf1cesjt3nkrc +--- +When a tide step uncovers rocks and wrecks, they are missing from the previous frame's depth pyramid and from the first culling phase, and appear one frame late. Visible as a flash at the waterline. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-rollback-has-not-been-profiled-on-skiff-with-tid--34pra8d0kj2x92dg.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-rollback-has-not-been-profiled-on-skiff-with-tid--34pra8d0kj2x92dg.md new file mode 100644 index 00000000..d6aa60e4 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-rollback-has-not-been-profiled-on-skiff-with-tid--34pra8d0kj2x92dg.md @@ -0,0 +1,14 @@ +--- +id: iss-rollback-has-not-been-profiled-on-skiff-with-tid--34pra8d0kj2x92dg +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: Rollback has not been profiled on Skiff with tides running +kind: gap +status: resolved +created_at: '2026-03-10T10:00:00Z' +created_by: Sofia Marchetti +derives_from: + - rsk-re-simulation-cost-could-blow-the-skiff-frame-bu--sk2njsp170a3qwyf +resolved_by: + - fnd-re-running-tides-every-rollback-frame-costs-4-8--tp4gxe8prh0bh9h4 +--- +Alpha builds now include tides in the rollback snapshot. Every cost number we have is from PC with tides frozen. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-shadow-pages-run-out-at-spring-low-tide--f4fgy6b44jbkrsmh.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-shadow-pages-run-out-at-spring-low-tide--f4fgy6b44jbkrsmh.md new file mode 100644 index 00000000..25f6a66f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-shadow-pages-run-out-at-spring-low-tide--f4fgy6b44jbkrsmh.md @@ -0,0 +1,12 @@ +--- +id: iss-shadow-pages-run-out-at-spring-low-tide--f4fgy6b44jbkrsmh +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Shadow pages run out at spring low tide +kind: blocker +status: open +created_at: '2026-06-17T10:00:00Z' +created_by: Ines Okafor +derives_from: + - fnd-vsm-page-pool-overflows-during-spring-tides--m2p8e89hhdmh0z8a +--- +Shadow popping on the flats at spring low tide is a ship blocker for Dara Whitlock: the flats are where the main quest line crosses. No fix is chosen. Options discussed in review: a coarser page level for wet sand, or streaming the flats in later. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-should-gull-run-on-a-tree-walking-interpreter-or--dkfsjk9enx1myhff.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-should-gull-run-on-a-tree-walking-interpreter-or--dkfsjk9enx1myhff.md new file mode 100644 index 00000000..9642bbf8 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-should-gull-run-on-a-tree-walking-interpreter-or--dkfsjk9enx1myhff.md @@ -0,0 +1,12 @@ +--- +id: iss-should-gull-run-on-a-tree-walking-interpreter-or--dkfsjk9enx1myhff +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Should Gull run on a tree-walking interpreter or a bytecode VM? +kind: question +status: resolved +created_at: '2025-10-06T10:00:00Z' +created_by: Marta Lindqvist +resolved_by: + - dec-keep-gull-on-the-tree-walking-interpreter--br1kgzfmw57xmm9m +--- +Gull, Kestrel's scripting language, drives creature AI, tide events, and quests. Today it runs on a tree-walking interpreter that came with the language prototype. Designers rely on editing scripts while the game runs. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-should-lantern-replace-clustered-forward-with-a--7c8zxrdsj59q8hmd.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-should-lantern-replace-clustered-forward-with-a--7c8zxrdsj59q8hmd.md new file mode 100644 index 00000000..b8897fb4 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-should-lantern-replace-clustered-forward-with-a--7c8zxrdsj59q8hmd.md @@ -0,0 +1,12 @@ +--- +id: iss-should-lantern-replace-clustered-forward-with-a--7c8zxrdsj59q8hmd +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Should Lantern replace clustered forward+ with a visibility buffer? +kind: question +status: resolved +created_at: '2025-09-03T11:00:00Z' +created_by: Ines Okafor +resolved_by: + - dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4 +--- +Lantern shades with clustered forward+. Saltglass cliffs are dense meshes with many small triangles, and quad overdraw is high. Options on the table: keep forward+ and tune it, move to a deferred G-buffer, or move to a visibility buffer. Decide before the vertical slice so the material system can follow. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-should-skiff-offer-a-40-hz-mode--h83ktxc994y2gvx2.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-should-skiff-offer-a-40-hz-mode--h83ktxc994y2gvx2.md new file mode 100644 index 00000000..33ade9ef --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-should-skiff-offer-a-40-hz-mode--h83ktxc994y2gvx2.md @@ -0,0 +1,13 @@ +--- +id: iss-should-skiff-offer-a-40-hz-mode--h83ktxc994y2gvx2 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Should Skiff offer a 40 Hz mode? +kind: question +status: resolved +created_at: '2025-12-01T09:00:00Z' +created_by: Dara Whitlock +resolved_by: + - dec-offer-a-40-hz-mode-on-skiff-alongside-30-hz--xhcgs101g1stnf05 + - fnd-skiff-40-hz-playtest-9-of-12-testers-preferred-4--8jbe1vyf06rzdcek +--- +The Skiff screen runs at 120 Hz, so 40 Hz divides evenly and paces cleanly. Other Skiff games offer 40 Hz as an option. Dara Whitlock wants a call before the slice review. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-cert-autosave-writes-11-mb-per-minute--z8qh0wed0sga93tw.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-cert-autosave-writes-11-mb-per-minute--z8qh0wed0sga93tw.md new file mode 100644 index 00000000..297bc2a5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-cert-autosave-writes-11-mb-per-minute--z8qh0wed0sga93tw.md @@ -0,0 +1,14 @@ +--- +id: iss-skiff-cert-autosave-writes-11-mb-per-minute--z8qh0wed0sga93tw +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Skiff cert: autosave writes 11 MB per minute' +kind: defect +status: resolved +created_at: '2026-05-18T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-skiff-pre-certification-found-two-failures-and-o--ehe0e727vmd0d1jj +resolved_by: + - dec-write-delta-saves-on-skiff--a0g7x2bvk59t82jw +--- +Autosave rewrites the whole tide state every 30 seconds, about 11 MB a minute on Skiff. Lot check fails it. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-cert-blocker-40-hz-mode-misses-frames-in-t--8r81ajkewab5gymr.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-cert-blocker-40-hz-mode-misses-frames-in-t--8r81ajkewab5gymr.md new file mode 100644 index 00000000..2b0357ee --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-cert-blocker-40-hz-mode-misses-frames-in-t--8r81ajkewab5gymr.md @@ -0,0 +1,12 @@ +--- +id: iss-skiff-cert-blocker-40-hz-mode-misses-frames-in-t--8r81ajkewab5gymr +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Skiff cert blocker: 40 Hz mode misses frames in tide storms' +kind: blocker +status: open +created_at: '2026-08-11T09:00:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-tide-storms-push-skiff-40-hz-frames-to-28-4-ms-o--28gemvtznv4zztdc +--- +Lot check requires a selectable mode to hold its advertised rate. The 40 Hz mode drops to about 35 Hz in storms. Full Skiff submission cannot go in until this is fixed or the mode is pulled. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-cert-docked-30-hz-judder-on-some-tvs--9nq2xg9mzash474g.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-cert-docked-30-hz-judder-on-some-tvs--9nq2xg9mzash474g.md new file mode 100644 index 00000000..3a5de25c --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-cert-docked-30-hz-judder-on-some-tvs--9nq2xg9mzash474g.md @@ -0,0 +1,14 @@ +--- +id: iss-skiff-cert-docked-30-hz-judder-on-some-tvs--9nq2xg9mzash474g +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Skiff cert: docked 30 Hz judder on some TVs' +kind: defect +status: wontfix +created_at: '2026-05-18T10:20:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-skiff-pre-certification-found-two-failures-and-o--ehe0e727vmd0d1jj +resolved_by: + - fnd-platform-holder-waived-the-docked-30-hz-judder-a--7qckhx7c2vfyemqd +--- +Docked at 30 Hz, a few 50 Hz TVs show judder during camera pans. The fix would need a 25 Hz docked mode. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-cert-hud-text-below-minimum-height--va9m4gpjff2vxtrn.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-cert-hud-text-below-minimum-height--va9m4gpjff2vxtrn.md new file mode 100644 index 00000000..5d7d80aa --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-cert-hud-text-below-minimum-height--va9m4gpjff2vxtrn.md @@ -0,0 +1,15 @@ +--- +id: iss-skiff-cert-hud-text-below-minimum-height--va9m4gpjff2vxtrn +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: 'Skiff cert: HUD text below minimum height' +kind: defect +status: resolved +created_at: '2026-05-18T10:10:00Z' +created_by: Priya Natarajan +derives_from: + - con-skiff-minimum-text-height--hhc7n09kx88203zh + - fnd-skiff-pre-certification-found-two-failures-and-o--ehe0e727vmd0d1jj +resolved_by: + - dec-scale-the-skiff-hud-to-125-percent--9gnbdvt72aq3n3vc +--- +The stamina and tide labels render 6 px tall on the Skiff screen. Lot check fails it. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-fast-travel-has-no-load-time-plan--8xqtfd6x0mfvbkts.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-fast-travel-has-no-load-time-plan--8xqtfd6x0mfvbkts.md new file mode 100644 index 00000000..0690f9c0 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-fast-travel-has-no-load-time-plan--8xqtfd6x0mfvbkts.md @@ -0,0 +1,12 @@ +--- +id: iss-skiff-fast-travel-has-no-load-time-plan--8xqtfd6x0mfvbkts +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff fast travel has no load-time plan +kind: gap +status: resolved +created_at: '2026-03-05T09:00:00Z' +created_by: Dara Whitlock +resolved_by: + - dec-show-a-tide-chart-loading-screen-for-skiff-fast--yq2k6tt7gw38wvnh +--- +Fast travel on Meridian takes 3 seconds and hides behind a camera move. Nobody has said what Skiff does. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-memory-limits-for-the-game-are-unknown--3109v2v4p9x931cz.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-memory-limits-for-the-game-are-unknown--3109v2v4p9x931cz.md new file mode 100644 index 00000000..d06fe21f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-skiff-memory-limits-for-the-game-are-unknown--3109v2v4p9x931cz.md @@ -0,0 +1,12 @@ +--- +id: iss-skiff-memory-limits-for-the-game-are-unknown--3109v2v4p9x931cz +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff memory limits for the game are unknown +kind: gap +status: resolved +created_at: '2025-10-16T10:30:00Z' +created_by: Priya Natarajan +resolved_by: + - fnd-skiff-dev-kit-gives-the-game-9-gb--e6h71skfna4ttpd0 +--- +Nobody has measured how much memory Skiff gives a title. The SDK docs mention a system reserve but no title figure. Priya Natarajan will read the memory map on the dev kit before the team sizes any pools. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-tern-ghosting-on-moving-saltglass--2yr3q6zf476wajqp.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-tern-ghosting-on-moving-saltglass--2yr3q6zf476wajqp.md new file mode 100644 index 00000000..73f02142 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-tern-ghosting-on-moving-saltglass--2yr3q6zf476wajqp.md @@ -0,0 +1,14 @@ +--- +id: iss-tern-ghosting-on-moving-saltglass--2yr3q6zf476wajqp +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Tern ghosting on moving saltglass +kind: defect +status: resolved +created_at: '2026-04-03T11:00:00Z' +created_by: Yusuf Demir +derives_from: + - fnd-tern-ghosts-behind-moving-saltglass--j48ss757xfxmw31q +resolved_by: + - dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k +--- +Trails behind moving saltglass and orbiting cameras, up to 14 frames long. Reproduces on every platform and every preset. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-the-gull-debugger-cannot-attach-on-skiff-dev-kit--84pppnx1wzwf33bz.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-the-gull-debugger-cannot-attach-on-skiff-dev-kit--84pppnx1wzwf33bz.md new file mode 100644 index 00000000..e64e4957 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-the-gull-debugger-cannot-attach-on-skiff-dev-kit--84pppnx1wzwf33bz.md @@ -0,0 +1,12 @@ +--- +id: iss-the-gull-debugger-cannot-attach-on-skiff-dev-kit--84pppnx1wzwf33bz +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: The Gull debugger cannot attach on Skiff dev kits +kind: blocker +status: open +created_at: '2026-08-27T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3 +--- +Since the late-August dev kit update, the Gull debugger times out when attaching to a Skiff build. Script bugs that reproduce only on Skiff cannot be stepped through, and three such bugs are open for the release candidate. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-tide-heights-differ-between-co-op-peers--gqmq087dr478v1px.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-tide-heights-differ-between-co-op-peers--gqmq087dr478v1px.md new file mode 100644 index 00000000..54abd438 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-tide-heights-differ-between-co-op-peers--gqmq087dr478v1px.md @@ -0,0 +1,13 @@ +--- +id: iss-tide-heights-differ-between-co-op-peers--gqmq087dr478v1px +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Tide heights differ between co-op peers +kind: defect +status: resolved +created_at: '2025-10-08T10:00:00Z' +created_by: Sofia Marchetti +resolved_by: + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e + - fnd-fixed-point-tides-match-bit-for-bit-across-all-p--kb3ssw5190e93r4m +--- +In a two-player session, one player walked across a sand path that the other player saw under water. Sofia Marchetti logged both machines' tide heights: they agree at session start and differ later. Co-op cannot ship if peers disagree about which ground is walkable. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-tide-turns-leave-inland-terrain-untextured-for-s--ccv6nhwk68kj732c.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-tide-turns-leave-inland-terrain-untextured-for-s--ccv6nhwk68kj732c.md new file mode 100644 index 00000000..7a5d8db9 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-tide-turns-leave-inland-terrain-untextured-for-s--ccv6nhwk68kj732c.md @@ -0,0 +1,12 @@ +--- +id: iss-tide-turns-leave-inland-terrain-untextured-for-s--ccv6nhwk68kj732c +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Tide turns leave inland terrain untextured for seconds +kind: blocker +status: open +created_at: '2026-08-11T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-tide-priority-reads-starve-player-proximity-load--by0d7b0bk39xz3rk +--- +Untextured terrain during spring tides blocks content lock sign-off for the coast region. Streaming needs a read scheduler that serves both the tide deadline and the player. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-tides-feel-identical-every-cycle--e8kc5aah7z7ff50z.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-tides-feel-identical-every-cycle--e8kc5aah7z7ff50z.md new file mode 100644 index 00000000..b4cabcf1 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-tides-feel-identical-every-cycle--e8kc5aah7z7ff50z.md @@ -0,0 +1,12 @@ +--- +id: iss-tides-feel-identical-every-cycle--e8kc5aah7z7ff50z +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Tides feel identical every cycle +kind: gap +status: resolved +created_at: '2026-06-29T10:00:00Z' +created_by: Dara Whitlock +resolved_by: + - dec-add-a-second-tide-harmonic-for-spring-and-neap-t--1c3s7dtyxvj70gvw +--- +Beta playtesters report that every tide looks the same. Design wants spring and neap tides: some cycles reach higher and lower than others, so some paths open only on rare low tides. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-vertical-slice-runs-at-19-4-ms-on-the-dunes-flyo--p26gahekvspjmv06.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-vertical-slice-runs-at-19-4-ms-on-the-dunes-flyo--p26gahekvspjmv06.md new file mode 100644 index 00000000..99e55d9b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-vertical-slice-runs-at-19-4-ms-on-the-dunes-flyo--p26gahekvspjmv06.md @@ -0,0 +1,14 @@ +--- +id: iss-vertical-slice-runs-at-19-4-ms-on-the-dunes-flyo--p26gahekvspjmv06 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Vertical slice runs at 19.4 ms on the dunes flyover +kind: blocker +status: resolved +created_at: '2025-12-01T09:00:00Z' +created_by: Ines Okafor +derives_from: + - con-frame-budget--f5qxxq5572878wrp +resolved_by: + - dec-drop-the-far-sdf-gi-cascade-for-the-vertical-sli--0af6sjseeftc621j +--- +Two weeks before the slice, the dunes flyover runs at 19.4 ms on Meridian, 2.8 ms over the Frame budget. SDF GI with all four clipmap cascades and the saltglass forward pass are the two largest passes. The slice cannot ship at this cost. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-what-cell-size-should-the-world-partition-use--k3bncp2dabkekydq.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-what-cell-size-should-the-world-partition-use--k3bncp2dabkekydq.md new file mode 100644 index 00000000..b5502a97 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-what-cell-size-should-the-world-partition-use--k3bncp2dabkekydq.md @@ -0,0 +1,12 @@ +--- +id: iss-what-cell-size-should-the-world-partition-use--k3bncp2dabkekydq +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: What cell size should the world partition use? +kind: question +status: resolved +created_at: '2025-09-18T14:00:00Z' +created_by: Kenji Arakawa +resolved_by: + - dec-partition-the-world-into-256-m-cells--j002wj4g6pgxg4d3 +--- +The world partition splits the coast into square cells that stream in and out around each player. Full-detail content streams within 768 m of a player; beyond that, distant glass is drawn from impostors. Cell size sets how many cells are resident, how much each costs, and how much a tide change forces us to reload. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-what-meshlet-size-should-lantern-use--myg13k3gkk2b61nj.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-what-meshlet-size-should-lantern-use--myg13k3gkk2b61nj.md new file mode 100644 index 00000000..5a6eb767 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-what-meshlet-size-should-lantern-use--myg13k3gkk2b61nj.md @@ -0,0 +1,12 @@ +--- +id: iss-what-meshlet-size-should-lantern-use--myg13k3gkk2b61nj +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: What meshlet size should Lantern use? +kind: question +status: resolved +created_at: '2025-11-12T11:00:00Z' +created_by: Tomasz Brandt +resolved_by: + - dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h +--- +GPU culling works per meshlet as well as per instance. Meshlet size trades culling precision against per-meshlet overhead. Pick one size for all saltglass and terrain meshes. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-what-should-the-shader-compile-cache-key-hash--y1ja5t3r75r63s28.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-what-should-the-shader-compile-cache-key-hash--y1ja5t3r75r63s28.md new file mode 100644 index 00000000..1f921192 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-what-should-the-shader-compile-cache-key-hash--y1ja5t3r75r63s28.md @@ -0,0 +1,14 @@ +--- +id: iss-what-should-the-shader-compile-cache-key-hash--y1ja5t3r75r63s28 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: What should the shader compile cache key hash? +kind: question +status: resolved +created_at: '2025-09-22T09:00:00Z' +created_by: Liam O'Connell +derives_from: + - dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh +resolved_by: + - dec-key-the-shader-cache-on-preprocessed-source-defi--3a05ff0r954vxh30 +--- +The cache key decides both correctness and hit rate. Two candidates: hash the shader source text with the compiler version, or use file modification times as a cheap proxy. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-codec-should-compress-streamed-assets--9gnh870e1qwzd28r.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-codec-should-compress-streamed-assets--9gnh870e1qwzd28r.md new file mode 100644 index 00000000..18ef1bab --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-codec-should-compress-streamed-assets--9gnh870e1qwzd28r.md @@ -0,0 +1,12 @@ +--- +id: iss-which-codec-should-compress-streamed-assets--9gnh870e1qwzd28r +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Which codec should compress streamed assets? +kind: question +status: resolved +created_at: '2025-10-01T09:00:00Z' +created_by: Kenji Arakawa +resolved_by: + - dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m +--- +Streamed cells are compressed on disk and decoded on job workers. We can use Kelp, the studio's own codec, or an off-the-shelf codec. Decode speed per core matters more than ratio, because decode competes with simulation for workers during a tide turn. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-job-model-should-the-kestrel-scheduler-use--7ghtksxxrxcsxn3q.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-job-model-should-the-kestrel-scheduler-use--7ghtksxxrxcsxn3q.md new file mode 100644 index 00000000..30ac1ec8 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-job-model-should-the-kestrel-scheduler-use--7ghtksxxrxcsxn3q.md @@ -0,0 +1,12 @@ +--- +id: iss-which-job-model-should-the-kestrel-scheduler-use--7ghtksxxrxcsxn3q +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Which job model should the Kestrel scheduler use? +kind: question +status: resolved +created_at: '2025-09-05T10:00:00Z' +created_by: Rhea Valdés +resolved_by: + - dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x +--- +Every Kestrel system will run as jobs: simulation, streaming, decompression, Gull scripts, and render setup. We need to pick the execution model now, because changing it later touches every system that waits on another. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-read-path-should-streaming-use-on-each-pla--v9wd5sxvfjfsgx9r.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-read-path-should-streaming-use-on-each-pla--v9wd5sxvfjfsgx9r.md new file mode 100644 index 00000000..ee708c49 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-read-path-should-streaming-use-on-each-pla--v9wd5sxvfjfsgx9r.md @@ -0,0 +1,12 @@ +--- +id: iss-which-read-path-should-streaming-use-on-each-pla--v9wd5sxvfjfsgx9r +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Which read path should streaming use on each platform? +kind: question +status: resolved +created_at: '2025-09-22T10:00:00Z' +created_by: Kenji Arakawa +resolved_by: + - dec-read-streamed-assets-through-one-async-request-q--rd5c8rxr5pwz50ds +--- +Streaming needs one read path that works on PC, Meridian, and Skiff. The choice is between an explicit async request queue and memory-mapping the packed cell archives and letting page faults pull data in. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-shadow-technique-should-lantern-use-for-lo--90dy5vvmare2h2kz.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-shadow-technique-should-lantern-use-for-lo--90dy5vvmare2h2kz.md new file mode 100644 index 00000000..a8fb602f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-shadow-technique-should-lantern-use-for-lo--90dy5vvmare2h2kz.md @@ -0,0 +1,12 @@ +--- +id: iss-which-shadow-technique-should-lantern-use-for-lo--90dy5vvmare2h2kz +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Which shadow technique should Lantern use for local lights? +kind: question +status: resolved +created_at: '2025-11-10T10:00:00Z' +created_by: Tomasz Brandt +resolved_by: + - dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j +--- +Lanterns, campfires and glowing ruins cast local shadows. There can be 40 shadowed local lights on screen in the harbor. Pick a technique separate from the sun. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-shadow-technique-should-lantern-use-for-su--y4k75xvbgb2fhj85.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-shadow-technique-should-lantern-use-for-su--y4k75xvbgb2fhj85.md new file mode 100644 index 00000000..e1ba459f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-shadow-technique-should-lantern-use-for-su--y4k75xvbgb2fhj85.md @@ -0,0 +1,12 @@ +--- +id: iss-which-shadow-technique-should-lantern-use-for-su--y4k75xvbgb2fhj85 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Which shadow technique should Lantern use for sun shadows? +kind: question +status: resolved +created_at: '2025-09-08T10:00:00Z' +created_by: Ines Okafor +resolved_by: + - dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr +--- +The sun drives most of the light on the coast, and saltglass makes shadow errors easy to see because refraction bends them. Candidates: cascaded shadow maps, virtual shadow maps, or ray-traced sun shadows. Shadows must reach 2 km and fit the Frame budget on Meridian. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-tern-quality-presets-should-ship--7yanr9kzekkky53f.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-tern-quality-presets-should-ship--7yanr9kzekkky53f.md new file mode 100644 index 00000000..89790698 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-tern-quality-presets-should-ship--7yanr9kzekkky53f.md @@ -0,0 +1,12 @@ +--- +id: iss-which-tern-quality-presets-should-ship--7yanr9kzekkky53f +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Which Tern quality presets should ship? +kind: question +status: resolved +created_at: '2026-02-20T10:00:00Z' +created_by: Ines Okafor +resolved_by: + - dec-ship-three-tern-quality-presets--jkdzxsd8wt3w91hb +--- +Players and the ports team need named Tern presets. How many, and at what render scale? Fewer presets means less tuning of saltglass and caustics per preset. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-tonemapping-curve-should-lantern-use--4y8z3rv7fq2j2a2t.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-tonemapping-curve-should-lantern-use--4y8z3rv7fq2j2a2t.md new file mode 100644 index 00000000..762caafd --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-tonemapping-curve-should-lantern-use--4y8z3rv7fq2j2a2t.md @@ -0,0 +1,12 @@ +--- +id: iss-which-tonemapping-curve-should-lantern-use--4y8z3rv7fq2j2a2t +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Which tonemapping curve should Lantern use? +kind: question +status: resolved +created_at: '2025-10-07T10:00:00Z' +created_by: Yusuf Demir +resolved_by: + - dec-use-the-stock-filmic-tonemapping-curve--wefzd9091kztq0wb +--- +Saltglass caustics are the brightest thing on screen, often 30 times brighter than the sand around them. The tonemapping curve decides whether they read as light or as white blobs. Options: a stock filmic curve, or a neutral curve with all the look in grading LUTs. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v.md new file mode 100644 index 00000000..2a18bb02 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v.md @@ -0,0 +1,12 @@ +--- +id: iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Which upscaler should Lantern ship? +kind: question +status: resolved +created_at: '2025-10-01T11:00:00Z' +created_by: Ines Okafor +resolved_by: + - dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e +--- +Lantern renders below output resolution on every platform and needs a temporal upscaler. Options: Tern, the studio upscaler inside Lantern; Halcyon, a vendor upscaler with an SDK; or a split between them by platform. diff --git a/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-upscaler-should-skiff-use--jyp1hqdy0ahwfeej.md b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-upscaler-should-skiff-use--jyp1hqdy0ahwfeej.md new file mode 100644 index 00000000..9bc49930 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/issues/iss-which-upscaler-should-skiff-use--jyp1hqdy0ahwfeej.md @@ -0,0 +1,12 @@ +--- +id: iss-which-upscaler-should-skiff-use--jyp1hqdy0ahwfeej +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Which upscaler should Skiff use? +kind: question +status: resolved +created_at: '2025-11-18T09:00:00Z' +created_by: Priya Natarajan +resolved_by: + - dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3 +--- +Skiff renders below 720p most of the time, so the image needs an upscaler. Options on the table: Tern, a cheap spatial filter, or no upscaling at native 720p. diff --git a/benchmarks/proof-recall/.flatbread-proof/keymap.json b/benchmarks/proof-recall/.flatbread-proof/keymap.json new file mode 100644 index 00000000..a0fde1ab --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/keymap.json @@ -0,0 +1,500 @@ +{ + "netcode.blb-capture": "blb-skiff-rollback-profile-capture-6-frame-window-ti--ffqejdktg6fmth3c", + "netcode.cit-capture": "cit-skiff-rollback-profile-capture--qhbe4rs9ax0h3z3d", + "netcode.cit-primer": "cit-studio-wiki-primer-on-rollback-netcode--mktyz3g3cwfc7xa7", + "netcode.cmp-feb": "fnd-co-op-netcode-where-things-stand-in-february--8b4mdjfnrqfw5d9d", + "netcode.con-determinism": "con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g", + "netcode.con-rtt": "con-co-op-must-stay-playable-at-150-ms-round-trip--q330d4g95q7jtt4q", + "netcode.dec-abandon": "dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b", + "netcode.dec-checksum": "dec-hash-tide-physics-and-gull-state-every-30-frames--yqf2m6hqbjhwvkzq", + "netcode.dec-host": "dec-use-host-authoritative-sync-for-co-op--17hqrmtja7pn98d6", + "netcode.dec-lockstep": "dec-use-deterministic-lockstep-for-co-op--h0agvr5m0d8ndj72", + "netcode.dec-rollback": "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "netcode.dec-tide-lod": "dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f", + "netcode.dec-window-v1": "dec-use-a-4-frame-rollback-window--pqe4hvbgmbp0dmh9", + "netcode.dec-window-v2": "dec-use-a-7-frame-rollback-window--ewptan6y616adtfw", + "netcode.dec-window-v3": "dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk", + "netcode.effort": "eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49", + "netcode.fnd-desync-hash": "fnd-the-first-checksum-mismatch-came-from-gull-rando--wrrrkwvq1d0pc35p", + "netcode.fnd-host-spike": "fnd-host-authoritative-spike-keeps-tides-off-the-cli--dp9vx6afks514js6", + "netcode.fnd-input-delay": "fnd-one-frame-of-input-delay-is-invisible-in-playtes--azn8kxedq3pp1vq0", + "netcode.fnd-lockstep-test": "fnd-lockstep-playtest-at-150-ms-round-trip--hjp498j88mtdbnhs", + "netcode.fnd-lod-desync": "fnd-quarter-resolution-tide-re-simulation-desyncs-pe--064cvn1d3t35bnra", + "netcode.fnd-noise": "fnd-player-snapshot-is-14-kb-per-player--z10z27xaqg1bp451", + "netcode.fnd-prototype-cost": "fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf", + "netcode.fnd-slice": "fnd-two-player-rollback-co-op-ran-the-vertical-slice--p51cfe0dn47vfkya", + "netcode.fnd-snapshot": "fnd-a-rollback-snapshot-is-38-kb-per-player-per-fram--wa18f2emyakt0tgx", + "netcode.fnd-tide-cost": "fnd-re-running-tides-every-rollback-frame-costs-4-8--tp4gxe8prh0bh9h4", + "netcode.fnd-wifi-rtt": "fnd-skiff-co-op-sessions-over-wi-fi-see-180-ms-round--4ttevy0e2zfjqw18", + "netcode.iss-desync-debug": "iss-nothing-shows-which-system-caused-a-desync--k7w6rvkptez9d48k", + "netcode.iss-late-join": "iss-late-join-during-a-tide-surge-desyncs-the-joinin--mya93va0n7s8g7cj", + "netcode.iss-skiff-profile": "iss-rollback-has-not-been-profiled-on-skiff-with-tid--34pra8d0kj2x92dg", + "netcode.iss-sync": "iss-how-should-co-op-keep-up-to-four-players-in-sync--92t2zfsy3etfzr89", + "netcode.rsk-host-upload": "rsk-a-skiff-host-may-lack-the-upload-bandwidth-for-t--kydzk7rb2rf4rw5c", + "netcode.rsk-resim": "rsk-re-simulation-cost-could-blow-the-skiff-frame-bu--sk2njsp170a3qwyf", + "ports.blb-cert-report": "blb-skiff-pre-certification-report-build-5530--1q6hz38801fy3tqk", + "ports.blb-mem-capture": "blb-skiff-harbor-district-memory-capture-build-4127--t40rdrfffc5q5e89", + "ports.blb-pso-stats": "blb-skiff-first-visit-pipeline-compile-capture-build--wfpq5kvqxddn0a9w", + "ports.cit-cert-report": "cit-skiff-pre-certification-report-build-5530--caakwntpfm63vy97", + "ports.cit-mem-capture": "cit-skiff-harbor-memory-capture-build-4127--20svcfra9jy1hd1d", + "ports.cit-meridian-trc": "cit-meridian-technical-requirements-checklist-2-4--xv7xnma0egx0119s", + "ports.cit-pso-capture": "cit-skiff-pipeline-compile-capture-build-3810--2ybmweekyepbf8s4", + "ports.cit-sd-bench": "cit-skiff-storage-benchmark-sheet--rszq3fw5c7eps8a2", + "ports.cit-skiff-cert-guide": "cit-skiff-lot-check-guidelines-v3--2sc7w8gq1ckc26p5", + "ports.cit-skiff-sdk-09": "cit-skiff-sdk-0-9-memory-map--nk82yq60vqfa2g4b", + "ports.cit-skiff-sdk-12": "cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe", + "ports.cmp-1": "fnd-ports-status-after-alpha--yaqm024j41anp4vn", + "ports.cmp-2": "fnd-ports-status-after-beta--g265shcdqe263c44", + "ports.con-frame-1": "con-frame-budget--wt5rfqh5z444g2cg", + "ports.con-frame-2": "con-frame-budget--br0qszfg8fys908n", + "ports.con-meridian-mem": "con-meridian-memory-budget--99q6099e423wdtqn", + "ports.con-noise-frame": "con-frame-budget--k8j04jebm2kx9apw", + "ports.con-skiff-mem-8": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "ports.con-skiff-mem-9": "con-skiff-memory-budget--8ngr8fep3gxdfy80", + "ports.con-skiff-text": "con-skiff-minimum-text-height--hhc7n09kx88203zh", + "ports.con-skiff-write": "con-skiff-storage-write-limit--39sn09p505a1s8j7", + "ports.dec-cards-patch": "dec-ship-the-missing-meridian-activity-cards-in-the--g947vhgwr7smr8dq", + "ports.dec-delta-save": "dec-write-delta-saves-on-skiff--a0g7x2bvk59t82jw", + "ports.dec-dynres-1": "dec-scale-skiff-resolution-dynamically-between-540p--jtytvgh2erd32x68", + "ports.dec-dynres-2": "dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb", + "ports.dec-dynres-3": "dec-lower-the-skiff-dynamic-resolution-floor-to-504p--15esnt90gcn29enn", + "ports.dec-dynres-tiers": "dec-drop-effect-quality-tiers-on-skiff-instead-of-re--jbfzm4ezpd6m7e8a", + "ports.dec-ft-loading": "dec-show-a-tide-chart-loading-screen-for-skiff-fast--yq2k6tt7gw38wvnh", + "ports.dec-hud-scale": "dec-scale-the-skiff-hud-to-125-percent--9gnbdvt72aq3n3vc", + "ports.dec-kelp-skiff": "dec-use-kelp-s-high-ratio-mode-for-skiff-textures--ztsejzpkp6nn13s5", + "ports.dec-pso-ondevice": "dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7", + "ports.dec-pso-ship": "dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn", + "ports.dec-pso-uber": "dec-use-ubershaders-while-skiff-pipelines-compile--bab5rkqkvq647966", + "ports.dec-seamless-ft": "dec-load-skiff-fast-travel-without-a-loading-screen--v4qft5znysjv5f24", + "ports.dec-skiff-30": "dec-lock-skiff-to-30-hz--qs42s8xraw7rkkv4", + "ports.dec-skiff-40": "dec-offer-a-40-hz-mode-on-skiff-alongside-30-hz--xhcgs101g1stnf05", + "ports.dec-skiff-launch": "dec-make-skiff-a-launch-platform--7fh37fbjmqpjgj0a", + "ports.dec-skiff-native": "dec-render-skiff-at-native-720p-without-upscaling--x1gdj55bvfn1f8z9", + "ports.dec-skiff-spatial": "dec-use-a-spatial-upscaler-with-sharpening-on-skiff--cynznx2wg9hswzgb", + "ports.dec-storm-30": "dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc", + "ports.dec-storm-cap": "dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1", + "ports.dec-stream-block": "dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw", + "ports.dec-suspend": "dec-rejoin-the-co-op-session-after-meridian-resumes--gp2btfw62qm4khy9", + "ports.dec-tern-skiff": "dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3", + "ports.effort": "eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx", + "ports.fnd-40hz-test": "fnd-skiff-40-hz-playtest-9-of-12-testers-preferred-4--8jbe1vyf06rzdcek", + "ports.fnd-blob-portable": "fnd-prebuilt-pipeline-blobs-load-on-skiff-dev-firmwa--yzb10ygwr1q151e7", + "ports.fnd-cache-warm": "fnd-skiff-pipeline-cache-removes-second-visit-hitche--kzjtp9dpbpbmrb0x", + "ports.fnd-cert-report": "fnd-skiff-pre-certification-found-two-failures-and-o--ehe0e727vmd0d1jj", + "ports.fnd-devkits": "fnd-firmware-1-2-skiff-dev-kits-arrived--7dzaq12qessxaasd", + "ports.fnd-driver-keyed": "fnd-skiff-firmware-1-2-rejects-pipeline-blobs-built--pernvgb2he7m3z3y", + "ports.fnd-dynres-540": "fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q", + "ports.fnd-dynres-gpu": "fnd-the-576p-floor-misses-the-40-hz-budget-in-tide-s--gqnqc4vef424e5af", + "ports.fnd-mem-capture": "fnd-harbor-district-peaks-at-8-6-gb-on-skiff--vccxye8jy3mkba2v", + "ports.fnd-mem-early": "fnd-skiff-slice-build-peaks-at-6-9-gb--5hqgdkdbk2tsn8cj", + "ports.fnd-mem-kelp": "fnd-kelp-high-ratio-textures-bring-the-skiff-harbor--rnzeng8fj363pr75", + "ports.fnd-noise-shader": "fnd-shader-cache-hit-rate-reaches-97-percent--hv1e342tgdw7fs79", + "ports.fnd-pso-count": "fnd-harbor-district-needs-1-460-pipelines-on-skiff--dwd5ry1wqaeacmpn", + "ports.fnd-retro": "fnd-beta-retrospective-for-the-skiff-port--hwdfe7e67ja5r2h6", + "ports.fnd-sd-speed": "fnd-skiff-microsd-sustains-92-mb-s--xr1fsyjd45y2tqcx", + "ports.fnd-sd-speed-2": "fnd-skiff-microsd-slows-sharply-on-full-warm-cards--p1rgh36hat2egpz3", + "ports.fnd-sdk12": "fnd-skiff-sdk-1-2-takes-1-gb-back-from-games--a0ybdgjzw64hwfqa", + "ports.fnd-skiff-mem-map": "fnd-skiff-dev-kit-gives-the-game-9-gb--e6h71skfna4ttpd0", + "ports.fnd-storm-cap-test": "fnd-prototype-storm-particle-cap-saves-3-5-ms-on-the--p4evjsy9qfaehhg8", + "ports.fnd-storm-capture": "fnd-tide-storms-push-skiff-40-hz-frames-to-28-4-ms-o--28gemvtznv4zztdc", + "ports.fnd-suspend": "fnd-meridian-drops-co-op-sessions-because-the-relay--73hf67080kkyf76j", + "ports.fnd-tern-cost": "fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0", + "ports.fnd-thermal": "fnd-skiff-gpu-clock-drops-8-percent-after-20-minutes--5st35qqh8nwzabb4", + "ports.fnd-waiver": "fnd-platform-holder-waived-the-docked-30-hz-judder-a--7qckhx7c2vfyemqd", + "ports.iss-blk-devkits": "iss-no-skiff-dev-kits-on-firmware-1-2--3qkawq17a60504j7", + "ports.iss-blk-storm": "iss-skiff-cert-blocker-40-hz-mode-misses-frames-in-t--8r81ajkewab5gymr", + "ports.iss-cert-meridian-cards": "iss-meridian-cert-activity-cards-missing-for-two-bio--k214cmfra7pyvvzq", + "ports.iss-cert-meridian-suspend": "iss-meridian-cert-resume-from-suspend-drops-the-co-o--jbqz6wqm1w747bbx", + "ports.iss-cert-skiff-flicker": "iss-skiff-cert-docked-30-hz-judder-on-some-tvs--9nq2xg9mzash474g", + "ports.iss-cert-skiff-hud": "iss-skiff-cert-hud-text-below-minimum-height--va9m4gpjff2vxtrn", + "ports.iss-cert-skiff-save": "iss-skiff-cert-autosave-writes-11-mb-per-minute--z8qh0wed0sga93tw", + "ports.iss-dynres-q": "iss-how-should-skiff-hold-its-frame-budget-when-the--1zdpg3npqmscp42d", + "ports.iss-frame-modes": "iss-should-skiff-offer-a-40-hz-mode--h83ktxc994y2gvx2", + "ports.iss-ft": "iss-skiff-fast-travel-has-no-load-time-plan--8xqtfd6x0mfvbkts", + "ports.iss-hitches": "iss-first-visit-hitches-of-45-to-190-ms-on-skiff--jcraqy468yw51kpf", + "ports.iss-pso-q": "iss-how-should-skiff-avoid-first-use-pipeline-compil--5nvhn8xzyz2d7y7k", + "ports.iss-skiff-mem": "iss-skiff-memory-limits-for-the-game-are-unknown--3109v2v4p9x931cz", + "ports.iss-upscale-q": "iss-which-upscaler-should-skiff-use--jyp1hqdy0ahwfeej", + "ports.rsk-cert-slip": "rsk-skiff-certification-slips-past-the-release-candi--3xe2z6qf5ncxf87h", + "ports.rsk-pso-hitch": "rsk-pipeline-compiles-hitch-skiff-on-first-visits--6sq225m8dx36aefs", + "ports.rsk-skiff-oom": "rsk-skiff-runs-out-of-memory-in-dense-districts--p5pv42sgezzjhpfz", + "ports.rsk-skiff-stream": "rsk-tide-streaming-outruns-skiff-storage--6q8s3b383z2tyeyb", + "ports.rsk-tern-cost": "rsk-tern-takes-too-much-of-the-skiff-frame--xtmh8jzptbwbg907", + "ports.rsk-thermal": "rsk-skiff-throttles-the-gpu-in-long-handheld-session--1nwtqw8gyc9x4h1b", + "render.blb-caustic-trace": "blb-luminance-trace-caustics-under-tern-dunes-at-noo--hg2t94dx5wv08a7r", + "render.blb-cliffs": "blb-gpu-capture-forward-on-the-cliffs-benchmark-meri--f1jwxdgx0fpe0wvs", + "render.blb-gi-recap": "blb-gpu-capture-sdf-gi-on-a-meridian-devkit-dunes-be--9r2nk13cja7s06cx", + "render.blb-gi-sdf": "blb-gpu-capture-sdf-gi-on-the-dunes-benchmark--h1szrk86b69n5b26", + "render.blb-hdr-precheck": "blb-meridian-hdr-certification-pre-check-report-july--6r648dzqhh44mkq7", + "render.blb-highlight": "blb-highlight-histogram-caustic-pixels-under-the-sto--bv0tyatpe22kxqkq", + "render.blb-meshlet-sweep": "blb-meshlet-size-sweep-on-the-cliffs-benchmark--4shwgvp9x310epk7", + "render.blb-skiff-capture": "blb-gpu-capture-visibility-buffer-on-skiff-cliffs-be--x1ynk37229baj5vt", + "render.blb-tern-presets": "blb-tern-preset-table-render-scale-and-cost-per-plat--vzvzz16jyhnr937h", + "render.blb-vb-proto": "blb-timing-table-visibility-buffer-prototype-against--8debfkdp7fz7nwjp", + "render.blb-vsm-cost": "blb-gpu-capture-virtual-shadow-map-prototype-dunes-b--cknjqzqy2mqz93mf", + "render.blb-vsm-pages": "blb-page-pool-trace-virtual-shadow-maps-across-a-spr--6qdd5aahwkcmhyg8", + "render.blb-vsm-recap": "blb-gpu-capture-virtual-shadow-maps-with-page-cachin--sf5pzwgx8fv8gbpb", + "render.cit-caustic-trace": "cit-trace-caustic-luminance-under-tern--55mm8xmemz44s5ah", + "render.cit-cliffs": "cit-capture-forward-cliffs-benchmark--2ykf7yxr2qmwjz23", + "render.cit-gi-recap": "cit-capture-sdf-gi-on-a-meridian-devkit--1hjqjkb1e7z7tryy", + "render.cit-gi-sdf": "cit-capture-sdf-gi-dunes-benchmark--3q4n5ewn42faqaeb", + "render.cit-hdr-precheck": "cit-report-meridian-hdr-pre-check-july--mqw9w3jm6srcm3x0", + "render.cit-highlight": "cit-histogram-caustic-highlights-under-filmic--rr06d7k5s8c05gdw", + "render.cit-meshlet-sweep": "cit-table-meshlet-size-sweep--gw92j9g9071gj8v8", + "render.cit-skiff-capture": "cit-capture-visibility-buffer-on-skiff--ymeda5m6p45hba8f", + "render.cit-tern-presets": "cit-tern-preset-table--6bbg3evqt1zz6smb", + "render.cit-vb-proto": "cit-timing-table-visibility-buffer-prototype--njktyg0k8aej7kpf", + "render.cit-vsm-cost": "cit-capture-virtual-shadow-map-prototype--4122x7gedhmg5v15", + "render.cit-vsm-pages": "cit-trace-vsm-page-pool-across-a-spring-tide--mhwdj0xh0k2wrnpq", + "render.cit-vsm-recap": "cit-capture-virtual-shadow-maps-with-page-caching--xjxn0ftjsfe4dhcq", + "render.cit-wiki": "cit-lantern-overhaul-wiki-page--jz6a6zyvexf2fk8e", + "render.cmp-1": "fnd-lantern-at-the-vertical-slice--10g62g9rfaw438qf", + "render.cmp-2": "fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c", + "render.cmp-3": "fnd-lantern-at-beta--53jwv4ngqk0wf9aw", + "render.cmp-4": "fnd-lantern-at-content-lock--npcagtz7rj6gkasn", + "render.con-120-1": "con-meridian-120-hz-performance-mode-budget--h9zg6vmd70sr78by", + "render.con-120-2": "con-meridian-120-hz-performance-mode-budget--khgjmq18bfr40tyj", + "render.con-budget-1": "con-frame-budget--f5qxxq5572878wrp", + "render.con-budget-2": "con-frame-budget--j6vneva1g2ywj86m", + "render.con-budget-3": "con-frame-budget--fzdrbxns6dmrrmy3", + "render.con-budget-noise": "con-frame-budget--0n9dv0tmytdn3dq6", + "render.con-hdr-cert": "con-meridian-hdr-certification-requirements--nx9pmkwjjvxy1smf", + "render.con-mesh-skiff": "con-skiff-has-no-mesh-shader-support--zz4xpaqy1n0zzrj7", + "render.con-one-upscaler": "con-one-upscaler-path-on-every-platform--f91bgj6n66kwc5d3", + "render.con-saltglass-2km": "con-saltglass-must-read-at-2-km--65a67jbwhr7r73qw", + "render.con-ui-nits": "con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s", + "render.con-vram": "con-render-target-memory-on-meridian--q4szajxse9c1csdv", + "render.dec-brine-1": "dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86", + "render.dec-brine-2": "dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e", + "render.dec-brine-3": "dec-brine-curve-with-an-hdr-shoulder-at-800-nits--fpznx0cnj4avsxk1", + "render.dec-caustic-clamp": "dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4", + "render.dec-caustic-seed": "dec-lock-caustic-photon-jitter-to-the-tide-phase--85x10k4h11t8nx7c", + "render.dec-caustics-photon": "dec-splat-caustic-photons-from-a-sun-space-map--gz19gensacx2zh1w", + "render.dec-caustics-proj": "dec-project-animated-caustic-textures-along-the-sun--xe80zje9085n84q6", + "render.dec-csm": "dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr", + "render.dec-cull-cpu": "dec-keep-cpu-frustum-culling-with-software-occlusion--02qna664kkar8fva", + "render.dec-cull-gpu": "dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee", + "render.dec-cull-tide-hint": "dec-mark-tide-exposed-instances-visible-for-one-fram--157jf1cesjt3nkrc", + "render.dec-deferred": "dec-move-to-a-deferred-g-buffer--16yh63n8kwqevakc", + "render.dec-filmic": "dec-use-the-stock-filmic-tonemapping-curve--wefzd9091kztq0wb", + "render.dec-fplus-tune": "dec-keep-clustered-forward-and-tune-light-culling--18zwcwr0cb3tpmpt", + "render.dec-gi-120-probe": "dec-use-the-probe-grid-alone-in-120-hz-performance-m--6dzm1nt40pjfpyae", + "render.dec-gi-120-quarter": "dec-trace-sdf-gi-at-quarter-resolution-in-performanc--06cqt3mqn3fg5h6e", + "render.dec-gi-hybrid": "dec-use-a-probe-grid-for-the-far-field-and-sdf-traci--sk8asp26gxtq5tdd", + "render.dec-gi-probe": "dec-use-a-relit-probe-grid-for-global-illumination--yvz1bpyrnm75wc5p", + "render.dec-gi-sdf": "dec-use-signed-distance-field-gi--yn366zmp3k7snd9w", + "render.dec-hdr-fixed-pw": "dec-hard-code-hdr-paper-white-at-200-nits-on-meridia--k481dkkr69gf77rr", + "render.dec-hdr-pw-slider": "dec-add-an-in-game-paper-white-slider-from-80-to-400--1phfvxby983z8tjf", + "render.dec-hdr-pw-system": "dec-read-paper-white-from-the-meridian-system-settin--7crbx73gqw1hn7xq", + "render.dec-local-atlas": "dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j", + "render.dec-local-vsm": "dec-use-virtual-shadow-maps-for-local-lights--619ngez1rrf39xa1", + "render.dec-meshlet-128": "dec-use-128-vertex-meshlets-with-up-to-256-triangles--2ta4nkmwjgrd29bh", + "render.dec-meshlet-64": "dec-use-64-vertex-meshlets-with-up-to-124-triangles--67xmt2c2hkv7tr4h", + "render.dec-meshlet-cone": "dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2", + "render.dec-meshlet-skiff": "dec-expand-meshlets-to-index-buffers-in-compute-on-s--bpbtr54dgzgsjgme", + "render.dec-neutral": "dec-use-a-neutral-curve-and-grade-everything-in-luts--g0p17ez0dk3p7sde", + "render.dec-nightly-capture": "dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676", + "render.dec-presets-3": "dec-ship-three-tern-quality-presets--jkdzxsd8wt3w91hb", + "render.dec-presets-4": "dec-ship-four-tern-quality-presets--vjw18d82dx5gath8", + "render.dec-presets-4b": "dec-ship-four-tern-quality-presets-adding-ultra-perf--3jg1wyq3bshv839c", + "render.dec-refr-cube": "dec-refract-into-local-cubemaps--1aek3p2p2hrfg5b6", + "render.dec-refr-hybrid": "dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r", + "render.dec-refr-rm": "dec-ray-march-refraction-through-the-saltglass-dista--wjj9jrek6kkgy04m", + "render.dec-refr-ss": "dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6", + "render.dec-rt-shadows": "dec-use-ray-traced-sun-shadows--9xpd0kwe2v1rwefd", + "render.dec-slice-cut": "dec-drop-the-far-sdf-gi-cascade-for-the-vertical-sli--0af6sjseeftc621j", + "render.dec-split-upscaler": "dec-ship-halcyon-on-pc-and-meridian-and-tern-on-skif--9xaxpqsq997w087x", + "render.dec-tern": "dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e", + "render.dec-tern-dup": "dec-ship-tern-as-the-only-upscaler-in-lantern--a6gbj8djpd8p6w67", + "render.dec-tern-reactive": "dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k", + "render.dec-uber-resolve": "dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r", + "render.dec-vb-1": "dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4", + "render.dec-vb-1-dup": "dec-adopt-a-visibility-buffer-for-all-opaque-geometr--p6xa9a990esdt2ej", + "render.dec-vb-2": "dec-adopt-a-visibility-buffer-with-64-bit-instance-a--zwmywxyvnqzvw5xq", + "render.dec-vb-3": "dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9", + "render.dec-vb-4": "dec-visibility-buffer-with-compute-material-resolve--5s2z9mqmv8vnszed", + "render.dec-vb-5": "dec-visibility-buffer-on-pc-and-meridian-forward-fal--khvgysnhmnkjqe9k", + "render.dec-vb-6": "dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1", + "render.dec-vendor": "dec-ship-the-halcyon-vendor-upscaler-on-pc-and-merid--bbbhavy3fj67x27p", + "render.dec-vsm": "dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4", + "render.effort": "eff-lantern-renderer-overhaul--qwgke408pte4k0ar", + "render.fnd-120-gi-cost": "fnd-quarter-resolution-sdf-gi-costs-1-9-ms-in-perfor--md9qdmtne78wv7mf", + "render.fnd-brine-review": "fnd-concept-match-review-11-of-14-key-shots-pass-und--1sv3grvmm4hbtyf5", + "render.fnd-caustic-clamp-test": "fnd-clamp-exclusion-removes-caustic-flicker-but-ghos--2m4pgjzbz7ze93j5", + "render.fnd-caustic-flicker": "fnd-caustics-flicker-at-3-to-6-hz-under-tern--9je5rqt89es3rcz4", + "render.fnd-caustic-proj-tiling": "fnd-projected-caustic-textures-tile-visibly-past-600--dkyy65zqqh5gx04x", + "render.fnd-caustic-proto": "fnd-photon-caustics-cost-1-1-ms-from-a-512-by-512-su--2rg1xq89re42cgaj", + "render.fnd-caustic-seed-test": "fnd-tide-locked-jitter-halves-caustic-flicker-but-st--nck1ftqr38v01cq1", + "render.fnd-cull-cpu-cost": "fnd-cpu-culling-and-draw-submission-cost-3-2-ms-on-t--1y0j1b9p0zjh0n1g", + "render.fnd-filmic-clip": "fnd-stock-filmic-curve-clips-38-percent-of-caustic-h--7n6g1tssnkwqqwm6", + "render.fnd-foliage-meshlet": "fnd-meshlet-alpha-masks-bring-foliage-back-into-the--672xvn788702zkn6", + "render.fnd-fplus-overdraw": "fnd-forward-overdraw-on-saltglass-cliffs--q9n76frhz7a7ssnp", + "render.fnd-gi-frame-share": "fnd-gi-takes-13-percent-of-the-quality-mode-frame--afshqnfm209zrae9", + "render.fnd-gi-probe-leak": "fnd-probe-grid-leaks-light-through-thin-saltglass-wa--h2hdqdfj92mnmkbj", + "render.fnd-gi-sdf-cost": "fnd-sdf-gi-costs-2-2-ms-on-meridian--r7t7zy97nwxxxctd", + "render.fnd-gi-sdf-cost-noise": "fnd-sdf-gi-costs-2-4-ms-on-meridian--2w6c2pc5zmcsyjre", + "render.fnd-gi-sdf-recapture": "fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr", + "render.fnd-halcyon-eval": "fnd-halcyon-vendor-upscaler-quality-and-platform-cov--xz7hp3e1m1mh44v4", + "render.fnd-hdr-precheck": "fnd-meridian-hdr-certification-pre-check-failed-on-p--qz0rr1cqqmcr6kh9", + "render.fnd-hdr-precheck-2": "fnd-meridian-hdr-certification-pre-check-failed-agai--w4q6pdtqc7akayt0", + "render.fnd-meshlet-cone": "fnd-meshlet-cone-culling-rejects-31-percent-of-trian--7qqt9dr77xyptb85", + "render.fnd-meshlet-cone-recount": "fnd-meshlet-cone-culling-rejects-9-percent-of-triang--t6e5x7trzedex105", + "render.fnd-meshlet-sweep": "fnd-meshlet-size-sweep-on-the-cliffs-benchmark--zeg5q7pn92jd42x3", + "render.fnd-rc-capture": "fnd-release-candidate-capture-quality-mode-14-6-ms-p--rc0kswjvgrwcp8te", + "render.fnd-refr-cost": "fnd-refraction-cost-screen-space-0-9-ms-ray-marched--pr6bzy3tvstaptdc", + "render.fnd-refr-halo": "fnd-screen-space-refraction-halos-around-the-player--6ytj9mvh0v1bfsdf", + "render.fnd-refr-offscreen": "fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy", + "render.fnd-sdf-memory": "fnd-sdf-volumes-use-410-mb-of-render-target-memory--y8bm788y240rqq7d", + "render.fnd-shoulder-clip": "fnd-brine-hdr-shoulder-clips-caustics-on-800-nit-pan--xe75a0mm3sqmtk4r", + "render.fnd-skiff-devkit-eta": "fnd-skiff-devkits-reach-the-render-team-in-april--bx6zmw2s52vr2t1z", + "render.fnd-skiff-vb-cost": "fnd-visibility-buffer-costs-11-2-ms-on-skiff--s3vphdwnhbh4650s", + "render.fnd-skiff-vb-recapture": "fnd-visibility-buffer-costs-7-4-ms-on-skiff-in-a-rel--fs86h16tm5hgempd", + "render.fnd-tern-cost-1": "fnd-tern-cost-at-4k-output-on-meridian--wycx6ek6sfme73k9", + "render.fnd-tern-cost-2": "fnd-tern-cost-at-4k-output-on-meridian-after-fp16-pa--p4gcmzw2a4bvzjev", + "render.fnd-tern-cost-3": "fnd-tern-cost-at-4k-output-on-meridian-with-the-reac--81tcpzvhwzcy6wyn", + "render.fnd-tern-ghost": "fnd-tern-ghosts-behind-moving-saltglass--j48ss757xfxmw31q", + "render.fnd-tern-ghost-fix": "fnd-a-saltglass-reactive-mask-removes-90-percent-of--p2mmqg2yj8nz43st", + "render.fnd-tern-ghost-recheck": "fnd-reactive-mask-removes-61-percent-of-saltglass-gh--csg97ges3067ehrp", + "render.fnd-tern-presets": "fnd-tern-preset-render-scales-and-costs--gjp3q966nngdd580", + "render.fnd-vb-foliage": "fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb", + "render.fnd-vb-idpack": "fnd-32-bit-visibility-ids-overflow-on-the-dunes-benc--eyjs4sekprhhtddp", + "render.fnd-vb-proto": "fnd-visibility-buffer-prototype-timings--qcfzqvyxbxkf2spw", + "render.fnd-vsm-cost": "fnd-virtual-shadow-maps-cost-3-1-ms-on-meridian--r6x0sdfecms7j1yg", + "render.fnd-vsm-overflow": "fnd-vsm-page-pool-overflows-during-spring-tides--m2p8e89hhdmh0z8a", + "render.fnd-vsm-recapture": "fnd-virtual-shadow-maps-cost-1-4-ms-on-meridian-with--mwpybda1vh0ac55e", + "render.iss-120-gi": "iss-gi-does-not-fit-the-120-hz-performance-mode-budg--get9cq6er1ac4vzx", + "render.iss-caustic-flicker": "iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5", + "render.iss-caustic-flicker-dup": "iss-caustics-flicker-under-tern-at-low-internal-reso--gbtcjdby6eyhnjca", + "render.iss-caustics-q": "iss-how-should-lantern-draw-saltglass-caustics--a6wcxavrp4ky319s", + "render.iss-csm-seams": "iss-cascade-seams-visible-through-saltglass-at-300-t--3590ssrc8xxa4ae6", + "render.iss-cull-popping": "iss-objects-pop-in-for-one-frame-when-the-tide-uncov--6165dkqm91r63ckf", + "render.iss-cull-q": "iss-how-should-lantern-cull-geometry--jnrp9qd2fywqvqgw", + "render.iss-gap-capture": "iss-no-automated-gpu-captures-on-nightly-builds--k3vncp4qwzdwc2m6", + "render.iss-gap-skiff-profiles": "iss-no-skiff-gpu-timings-for-lantern-passes--mve09m4aktb7tya1", + "render.iss-gi-q": "iss-how-should-lantern-do-global-illumination--3hs82xftkrdhk3f7", + "render.iss-hdr-banding": "iss-banding-in-the-dusk-sky-with-the-brine-curve-on--qyfqbggg14ckxvc9", + "render.iss-hdr-cert": "iss-meridian-hdr-certification-fails-the-paper-white--bper6nwencgtgf7b", + "render.iss-meshlet-q": "iss-what-meshlet-size-should-lantern-use--myg13k3gkk2b61nj", + "render.iss-presets-q": "iss-which-tern-quality-presets-should-ship--7yanr9kzekkky53f", + "render.iss-refr-q": "iss-how-should-lantern-render-saltglass-refraction--brndmsn2n8jz6yyk", + "render.iss-rt-reflect": "iss-no-ray-traced-reflections-on-saltglass--pdcbm94d32f55fa0", + "render.iss-shadow-local-q": "iss-which-shadow-technique-should-lantern-use-for-lo--90dy5vvmare2h2kz", + "render.iss-shadow-q": "iss-which-shadow-technique-should-lantern-use-for-su--y4k75xvbgb2fhj85", + "render.iss-slice-budget": "iss-vertical-slice-runs-at-19-4-ms-on-the-dunes-flyo--p26gahekvspjmv06", + "render.iss-tern-ghost": "iss-tern-ghosting-on-moving-saltglass--2yr3q6zf476wajqp", + "render.iss-tonemap-q": "iss-which-tonemapping-curve-should-lantern-use--4y8z3rv7fq2j2a2t", + "render.iss-upscaler-q": "iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v", + "render.iss-vb-q": "iss-should-lantern-replace-clustered-forward-with-a--7c8zxrdsj59q8hmd", + "render.iss-vsm-tide": "iss-shadow-pages-run-out-at-spring-low-tide--f4fgy6b44jbkrsmh", + "render.rsk-120-gi": "rsk-gi-cannot-fit-the-120-hz-performance-mode--tqt3fj839dqfq5s7", + "render.rsk-brine-match": "rsk-artists-cannot-match-concept-paintings-under-the--6cfh9vkamn0kbtcx", + "render.rsk-caustic-flicker": "rsk-caustic-flicker-fails-photosensitivity-review--vrpf3390abxh1q4d", + "render.rsk-hdr-cert": "rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4", + "render.rsk-meshlet-skiff": "rsk-compute-meshlet-expansion-is-too-slow-on-skiff--b1915sgdsr1bpwda", + "render.rsk-sdf-memory": "rsk-sdf-volumes-outgrow-the-render-target-memory-bud--xfd2pfztvskdcd2c", + "render.rsk-shader-perm": "rsk-visibility-buffer-material-resolve-multiplies-sh--e0sam0jrjgsvx0gj", + "render.rsk-tern-ghost": "rsk-tern-ghosting-on-saltglass-draws-reviewer-compla--rg0rjrs6n2x53w56", + "render.rsk-vb-skiff": "rsk-visibility-buffer-bandwidth-is-too-high-for-skif--5gwb2hcd41ctyhrx", + "render.rsk-vsm-overflow": "rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty", + "tools.blb-hitrate": "blb-shader-cache-hit-rate-report-four-weeks-after-th--g0383kwnqtjdh4jz", + "tools.cit-dxc": "cit-shader-compiler-release-notes-for-build-1-8-2407--j9egrx9rnpp9ne9x", + "tools.cit-hitrate": "cit-weekly-shader-cache-hit-rate-report--821p29gvf3dtcssg", + "tools.cmp-feb": "fnd-shader-compile-cache-where-things-stand-in-febru--xnwv3jqqg71tb370", + "tools.con-farm": "con-the-build-farm-stays-at-12-agents-until-alpha--w7e1xfex9z2ycpx1", + "tools.con-repro": "con-a-cache-hit-must-give-the-same-bytes-as-a-fresh--3gmcswztxzpmpz83", + "tools.dec-agents": "dec-buy-eight-more-build-agents-for-shader-compiles--a1sr7ek33s1jr1rv", + "tools.dec-cache": "dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh", + "tools.dec-cap-jobs": "dec-cap-each-farm-agent-at-6-parallel-shader-compile--q5w4sfjm73tsj8x8", + "tools.dec-incremental": "dec-keep-a-local-incremental-shader-build-on-each-ag--5zr06bg4kpth9ha3", + "tools.dec-key-mtime": "dec-key-the-shader-cache-on-file-modification-times--0ckga1dkdtc81k9g", + "tools.dec-key-v1": "dec-key-the-shader-cache-on-raw-source-text-and-comp--hp6awmx3gq5rn9nc", + "tools.dec-key-v2": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tools.dec-key-v3": "dec-key-the-shader-cache-on-preprocessed-source-defi--3a05ff0r954vxh30", + "tools.dec-remote": "dec-fan-shader-cache-misses-out-to-every-farm-agent--pwrf9w720rf4hd27", + "tools.dec-ship": "dec-turn-the-shader-compile-cache-on-for-every-farm--4rr3b12b4sasdmaj", + "tools.dec-timeout": "dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6", + "tools.dec-verify": "dec-recompile-a-1-in-50-sample-of-cache-hits-and-com--9n176hnc9w0tax3s", + "tools.effort": "eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn", + "tools.fnd-baseline": "fnd-most-shader-compile-time-on-the-farm-repeats-ide--n7mr2yxxxtzpak35", + "tools.fnd-compiler-drift": "fnd-two-compiler-builds-with-the-same-version-string--gmgr4ha0ndxqmcn9", + "tools.fnd-flaky-net": "fnd-flaky-nightly-builds-trace-to-cache-server-fetch--v4wsxzj1x72zz8rs", + "tools.fnd-flaky-oom": "fnd-flaky-nightly-builds-are-compiler-processes-runn--1sabnpb1s7004jkb", + "tools.fnd-hitrate": "fnd-shader-cache-hit-rate-climbs-steadily-after-the--2d268h587na645rx", + "tools.fnd-noise": "fnd-shader-cache-warms-in-40-seconds-on-first-boot--eadc6xjwgfhmbg86", + "tools.fnd-remote-bench": "fnd-remote-execution-spreads-cache-misses-across-all--120mx6z98n6qfmwh", + "tools.fnd-retro": "fnd-retrospective-on-the-shader-compile-cache--9rpv2a60ach04cx6", + "tools.fnd-stale-include": "fnd-raw-source-cache-keys-served-stale-shaders-after--f32vyjth0qtmr6wb", + "tools.iss-approach": "iss-how-should-the-farm-stop-recompiling-unchanged-s--b2kcgasfccnydkjp", + "tools.iss-devws": "iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj", + "tools.iss-flaky": "iss-nightly-builds-fail-about-1-in-9-runs-with-shade--ka2xgkfgaepemgbh", + "tools.iss-key": "iss-what-should-the-shader-compile-cache-key-hash--y1ja5t3r75r63s28", + "tools.iss-slow": "iss-full-shader-rebuilds-take-47-minutes-on-the-buil--4bnh1e17snf5y3h6", + "tools.rsk-poison": "rsk-a-bad-cache-entry-could-ship-broken-bytecode-to--9w76xhyz9xy8g5k5", + "tools.rsk-storage": "rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd", + "world.blob-codec-1": "blb-codec-benchmark-warm-cache-october-2025--kcybvms2ttten909", + "world.blob-codec-2": "blb-codec-benchmark-cold-cache-on-skiff-january-2026--wczvq0srnnzjs407", + "world.blob-ecs-profile": "blb-ecs-storage-microbenchmark-profile-september-202--csvrtfr7ce23yzz5", + "world.blob-pool-occupancy": "blb-streaming-pool-occupancy-alpha-playtest--bahqk0svngyshny0", + "world.blob-save-sizes": "blb-delta-save-sizes-by-hours-played--x6mda6tam40w26t5", + "world.blob-tide-drift": "blb-tide-drift-log-pc-meridian-and-skiff-over-6-minu--vyzb37vz3nrts95v", + "world.blob-trace-retail": "blb-streaming-read-trace-retail-skiff-against-dev-ki--5pj5rh05kbsc6gcj", + "world.blob-trace-starve": "blb-streaming-trace-inland-sprint-during-a-falling-t--91wvax8b1e5f0qvw", + "world.blob-trace-tide-turn": "blb-streaming-trace-of-a-falling-tide-on-skiff-256-m--g5wcgz9426mk1y45", + "world.cit-codec-1": "cit-codec-benchmark-table-october-2025--wg58ryzjhtpaca3x", + "world.cit-codec-2": "cit-codec-benchmark-table-january-2026-skiff-cold-ca--sztretts5cxatw6c", + "world.cit-ecs-profile": "cit-ecs-bench-profile-run-0909--m0zy2gppwwgsv5zh", + "world.cit-pool-occupancy": "cit-pool-occupancy-capture-pool-occupancy-0303--5k8w8xj2a4g21wtm", + "world.cit-save-sizes": "cit-save-size-sweep-from-the-playtest-save-corpus--5d385vtvgmy4qtmz", + "world.cit-tide-drift": "cit-tide-drift-log-tide-drift-1028--3dpqqgs1ep6qm1wc", + "world.cit-trace-retail": "cit-retail-skiff-streaming-trace-stream-trace-0217--gsdd04w1pck5s0am", + "world.cit-trace-starve": "cit-skiff-streaming-trace-stream-trace-0807--e4vdxvga0amqyzjb", + "world.cit-trace-tide-turn": "cit-skiff-streaming-trace-stream-trace-1110--fn7z3ms8hsz2tw9c", + "world.cmp-1": "fnd-world-core-state-before-the-vertical-slice--rbpesp345hf8mesp", + "world.cmp-2": "fnd-world-core-state-at-alpha--tkbsm4867h65jqq8", + "world.cmp-3": "fnd-world-core-state-after-beta--v9mfhngtx7m2bdkk", + "world.cmp-4": "fnd-world-core-state-before-content-lock--15jbzxzr0wj9gsd2", + "world.con-cell-deadline": "con-cell-load-deadline--m20x64m5eh7q2bh6", + "world.con-ecs-structural": "con-archetype-changes-happen-only-at-frame-sync-poin--kcsrz5g8g8yndwnx", + "world.con-gull-tick": "con-gull-script-tick-budget--4p9jp4dj1njf7q9m", + "world.con-io-budget": "con-streaming-i-o-budget--a99y4h0e7xmhp5qk", + "world.con-io-budget-2": "con-streaming-i-o-budget--vhc7mrmpqv9qcfdc", + "world.con-no-jit": "con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73", + "world.con-pool-1": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "world.con-pool-2": "con-streaming-pool-budget--kca88sgh2j6sxvd5", + "world.con-pool-3": "con-streaming-pool-budget--8czwb4fjr5p5vpy7", + "world.con-pool-draft": "con-streaming-pool-budget-draft--kx5m370w3w6mxz7d", + "world.con-save-compat": "con-saves-from-beta-onward-must-load-in-every-later--v6z856sxtgc5sb09", + "world.con-tide-bitexact": "con-tide-state-must-be-bit-identical-on-every-peer--zrpnp8qjyxzkas7t", + "world.dec-cell-128": "dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw", + "world.dec-cell-192": "dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc", + "world.dec-cell-192-dup": "dec-partition-the-world-into-192-meter-cells--q62ddwdv2n8wxay6", + "world.dec-cell-256": "dec-partition-the-world-into-256-m-cells--j002wj4g6pgxg4d3", + "world.dec-cell-512": "dec-partition-the-world-into-512-m-cells--hgbn5yem7vx1hxtt", + "world.dec-codec-dict": "dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew", + "world.dec-codec-kelp": "dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m", + "world.dec-codec-lz4": "dec-compress-streamed-assets-with-lz4--v1pfsgfp0b3yjv4s", + "world.dec-codec-zstd": "dec-compress-streamed-assets-with-zstandard--bs1t15cygc51cpje", + "world.dec-ecs-archetype": "dec-store-all-components-in-archetype-tables--59zqp578hnw072z1", + "world.dec-ecs-chunk": "dec-group-archetype-chunks-by-tide-band-to-cut-fragm--qxnkv5bxqz1r7afv", + "world.dec-ecs-hybrid": "dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9", + "world.dec-ecs-hybrid-dup": "dec-store-components-in-archetype-tables-and-volatil--8679sjn071ycsbpv", + "world.dec-ecs-sparse": "dec-store-all-components-in-sparse-sets--fywmr5yvt68xnrpx", + "world.dec-gull-bytecode": "dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3", + "world.dec-gull-reload": "dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42", + "world.dec-gull-transpile": "dec-transpile-gull-to-c-at-build-time--ytm47gyt6x8j6xx7", + "world.dec-gull-tree": "dec-keep-gull-on-the-tree-walking-interpreter--br1kgzfmw57xmm9m", + "world.dec-io-deadline": "dec-schedule-streaming-reads-by-deadline-instead-of--q2x5aknabgcssdj2", + "world.dec-io-mmap": "dec-memory-map-packed-cell-archives-and-fault-data-i--ekwscq306qv3t7dq", + "world.dec-io-queue": "dec-read-streamed-assets-through-one-async-request-q--rd5c8rxr5pwz50ds", + "world.dec-io-tide-priority": "dec-give-reads-for-tide-exposed-cells-top-priority--8ftkvqhawbdf5djh", + "world.dec-jobs-1": "dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x", + "world.dec-jobs-2": "dec-run-engine-jobs-on-a-work-stealing-thread-pool-w--8zpbcym92dkh87f1", + "world.dec-jobs-3": "dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq", + "world.dec-jobs-4": "dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te", + "world.dec-jobs-5": "dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h", + "world.dec-jobs-5-dup": "dec-return-engine-jobs-to-the-thread-pool-with-conti--547qbweqvrp1j5g3", + "world.dec-jobs-6": "dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3", + "world.dec-jobs-fibers-early": "dec-run-engine-jobs-on-fibers-from-the-start--2vyf6raa3ntt2dsr", + "world.dec-nav-64": "dec-cut-navigation-tiles-to-64-m-so-three-fit-along--snvepk8ygeb3qsjs", + "world.dec-pool-fifo": "dec-evict-cells-in-the-order-they-were-loaded--xyp7a3e2cyjgfkcq", + "world.dec-pool-forecast": "dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg", + "world.dec-pool-lru": "dec-evict-the-least-recently-used-cells-first--4eap3mr9tkafxy2p", + "world.dec-save-defer-turn": "dec-delay-autosaves-until-the-tide-turn-finishes--4agcgjjj70djdv6b", + "world.dec-save-delta": "dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw", + "world.dec-save-delta-2": "dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8", + "world.dec-save-harmonic-clock": "dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw", + "world.dec-save-harmonic-zero": "dec-start-the-second-harmonic-at-zero-phase-for-beta--vq8av7c58fmaq9jg", + "world.dec-save-snapshot": "dec-save-full-world-snapshots--296ytcmq2f4kpahk", + "world.dec-save-version": "dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w", + "world.dec-tide-fixed": "dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e", + "world.dec-tide-harmonic": "dec-add-a-second-tide-harmonic-for-spring-and-neap-t--1c3s7dtyxvj70gvw", + "world.dec-tide-host": "dec-have-the-host-stream-tide-heights-to-every-peer--a3rb1seedn2bj7k8", + "world.dec-tide-strict": "dec-force-strict-ieee-float-mode-for-the-tide-simula--ecwmqt7ncjngysqw", + "world.dec-tide-wrap": "dec-wrap-the-tide-phase-accumulator-at-each-40-minut--hx88m4hbg27n0xwy", + "world.effort": "eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4", + "world.fnd-cell-128-estimate": "fnd-128-m-cells-should-add-only-40-mb-of-per-cell-ov--ape0tgv597x77p6z", + "world.fnd-cell-overhead": "fnd-128-m-cells-cost-216-mb-of-per-cell-overhead-on--05dnx4k8a0wjtzdw", + "world.fnd-cell-sweep": "fnd-cell-size-sweep-for-the-768-m-streaming-radius--q3qfh6cp8a0k0f7g", + "world.fnd-codec-1": "fnd-kelp-decodes-streamed-assets-at-2-9-gb-s-per-cor--32tjx83v8ky28sz4", + "world.fnd-codec-1-typo": "fnd-kelp-decodes-streamed-assets-at-29-gb-s-per-core--9wkngsymce4v33pf", + "world.fnd-codec-2": "fnd-kelp-decodes-at-1-1-gb-s-on-skiff-with-a-cold-ca--vef244qjn2mjf07x", + "world.fnd-codec-3": "fnd-kelp-with-a-1-mb-dictionary-decodes-at-2-2-gb-s--vkt1dgk99x2xrmbs", + "world.fnd-codec-4": "fnd-kelp-with-a-1-mb-dictionary-decodes-at-1-5-gb-s--y9v8jrxgbv6abrx5", + "world.fnd-ecs-chunk-gain": "fnd-tide-band-chunks-cut-the-skiff-crab-join-to-3-2--v7q7jytpsd3zf06x", + "world.fnd-ecs-churn": "fnd-tide-turns-toggle-the-submerged-tag-on-40-000-en--a95p39zkd5ckmg5y", + "world.fnd-ecs-iter-bench": "fnd-archetype-tables-iterate-transforms-2-4x-faster--3xtpgtqs17zzq6v3", + "world.fnd-ecs-iter-redo": "fnd-archetype-iteration-takes-3-4-ms-in-the-alpha-wo--dawb9m0pa999mhpe", + "world.fnd-ecs-names-cost": "fnd-shipping-entity-names-costs-57-mb-at-full-popula--6w7gjvy7wdmdx9qx", + "world.fnd-fiber-crash-stacks": "fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m", + "world.fnd-gull-alpha-tick": "fnd-alpha-content-needs-6-2-ms-of-gull-time-per-fram--4mekgdpsdv5nk085", + "world.fnd-gull-debug-cause": "fnd-skiff-dev-kit-firmware-blocks-the-gull-debugger--hjkc0v1fjd4qfxj4", + "world.fnd-gull-fiber-tls": "fnd-the-gull-vm-reads-thread-local-registers-after-f--1qser43b9j8ac5pf", + "world.fnd-gull-interp": "fnd-gull-s-tree-walking-interpreter-spends-1-8-ms-on--bj1ge76d3wy5aqq3", + "world.fnd-gull-reload-coro": "fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws", + "world.fnd-gull-reload-proto": "fnd-bytecode-swap-at-frame-boundaries-reloads-94-of--rqrk03vvef5jgv2x", + "world.fnd-gull-threads-idle": "fnd-gull-s-two-dedicated-threads-sit-idle-70-of-each--qekr5vjr9pand9rs", + "world.fnd-gull-vm-proto": "fnd-register-vm-prototype-runs-the-crab-herd-4-1x-fa--1eb9hfat7611jksr", + "world.fnd-io-mmap-skiff": "fnd-skiff-s-file-system-cannot-memory-map-packed-arc--00ecsf304vk38ajb", + "world.fnd-io-starve": "fnd-tide-priority-reads-starve-player-proximity-load--by0d7b0bk39xz3rk", + "world.fnd-io-trace-1": "fnd-skiff-streaming-reads-sustain-260-mb-s--s1gkt975grre2ewr", + "world.fnd-io-trace-2": "fnd-retail-skiff-units-sustain-only-190-mb-s-of-stre--485sdcmm3gweevvn", + "world.fnd-jobs-continuations": "fnd-a-thread-pool-with-continuation-waits-keeps-work--3nryg6kq6w7236ae", + "world.fnd-jobs-idle": "fnd-priority-lanes-still-leave-workers-28-idle-durin--fhswesk5c086dk1y", + "world.fnd-jobs-stalls": "fnd-streaming-jobs-block-workers-while-waiting-on-re--sn2bmfdgjeqwkk3p", + "world.fnd-jobs-survey": "fnd-fibers-hide-waits-but-need-custom-stacks-and-deb--0ynync38mj13w03k", + "world.fnd-pool-cut-notice": "fnd-ports-cut-the-skiff-memory-total-and-streaming-m--1p8b10ttb07jkznx", + "world.fnd-pool-field": "fnd-field-captures-show-forecast-eviction-cuts-reloa--ee6m7fwv4798jdmv", + "world.fnd-pool-sim": "fnd-simulated-forecast-eviction-cuts-reloads-by-63--7c086ee2h8dw247k", + "world.fnd-pool-thrash": "fnd-lru-eviction-thrashes-during-tide-turns--0tvj4hmg42jy5d3f", + "world.fnd-pool-tideband": "fnd-tide-band-cells-need-320-mb-resident-during-a-sp--0erj5eqw3ved35t0", + "world.fnd-save-cloud-scope": "fnd-cross-platform-cloud-saves-need-platform-agreeme--4qgfc1a4nq4padvz", + "world.fnd-save-midturn": "fnd-3-of-200-saves-taken-mid-turn-fail-to-load--4j1kafsdeq0wedhf", + "world.fnd-save-size": "fnd-delta-saves-reach-6-2-mb-after-40-hours--8g1j04z0vhjwrkyn", + "world.fnd-save-snapshot-size": "fnd-a-full-world-snapshot-save-is-310-mb--2c7a78gjb54ygkj4", + "world.fnd-save-tide-mismatch": "fnd-deltas-saved-at-low-tide-replay-wrongly-at-high--25b4vwytarw8ej50", + "world.fnd-save-upgrade-cost": "fnd-each-save-upgrade-step-costs-under-5-ms--qs1rweqqgj7kweem", + "world.fnd-save-upgrade-real": "fnd-a-40-hour-save-takes-1-9-s-to-upgrade-through-si--gw6ahjtssbrm2jwx", + "world.fnd-tide-burst": "fnd-a-falling-tide-reloads-18-cells-at-410-mb-s-peak--tjz5vscfrdtazcms", + "world.fnd-tide-drift-1": "fnd-float-tide-heights-drift-apart-between-pcs-after--emk2nb56tej8t2jx", + "world.fnd-tide-drift-2": "fnd-float-tide-heights-drift-apart-between-pc-and-me--7jb0fg4b5xzr7q5e", + "world.fnd-tide-drift-3": "fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss", + "world.fnd-tide-drift-dup": "fnd-float-tides-drift-apart-between-machines-within--43a3rsxjp296ns6b", + "world.fnd-tide-fixed-meridian": "fnd-fixed-point-tide-step-costs-0-3-ms-on-meridian--jzxe4pa936rxawns", + "world.fnd-tide-fixed-skiff": "fnd-fixed-point-tide-step-costs-0-9-ms-on-skiff--mfc73bg9wwaxtfra", + "world.fnd-tide-fixed-verify": "fnd-fixed-point-tides-match-bit-for-bit-across-all-p--kb3ssw5190e93r4m", + "world.fnd-tide-host-bw": "fnd-streaming-tide-heights-costs-46-kb-s-per-peer--knxqtyqh6xcz1tp9", + "world.fnd-tide-strict-test": "fnd-strict-float-mode-still-diverges-because-skiff-s--z811r28v0a1wzb13", + "world.iss-blk-crash-triage": "iss-crash-triage-stalls-because-fiber-stacks-are-unr--dyr12bpb18sav85g", + "world.iss-blk-gull-debug": "iss-the-gull-debugger-cannot-attach-on-skiff-dev-kit--84pppnx1wzwf33bz", + "world.iss-blk-io-starve": "iss-tide-turns-leave-inland-terrain-untextured-for-s--ccv6nhwk68kj732c", + "world.iss-blk-save-harmonic": "iss-beta-saves-lack-the-second-tide-harmonic-s-phase--gmhrjdy35pjfq651", + "world.iss-cell-size": "iss-what-cell-size-should-the-world-partition-use--k3bncp2dabkekydq", + "world.iss-codec": "iss-which-codec-should-compress-streamed-assets--9gnh870e1qwzd28r", + "world.iss-ecs-names": "iss-entity-debug-names-are-missing-in-release-builds--e00p8nba80n2ykb8", + "world.iss-ecs-storage": "iss-how-should-kestrel-store-entity-components--aj37s7xz78dszyzp", + "world.iss-gull-reload-coro": "iss-gull-hot-reload-drops-suspended-coroutines--z7j2gmyny6gdxd07", + "world.iss-gull-reload-coro-dup": "iss-gull-hot-reload-drops-suspended-coroutines--26y5hmqf24s1kwjx", + "world.iss-gull-reload-structs": "iss-gull-hot-reload-rejects-struct-layout-changes--3v2w2f9hg2gwy6aj", + "world.iss-gull-vm": "iss-should-gull-run-on-a-tree-walking-interpreter-or--dkfsjk9enx1myhff", + "world.iss-io-api": "iss-which-read-path-should-streaming-use-on-each-pla--v9wd5sxvfjfsgx9r", + "world.iss-jobs-gull-crash": "iss-gull-scripts-crash-after-a-fiber-resumes-on-anot--n2hvwg59w0rem0te", + "world.iss-jobs-model": "iss-which-job-model-should-the-kestrel-scheduler-use--7ghtksxxrxcsxn3q", + "world.iss-pool-evict": "iss-how-should-the-streaming-pool-choose-cells-to-ev--4j47zrsgtxncn9dk", + "world.iss-save-cloud": "iss-cross-platform-cloud-saves-are-unplanned--5bk0k4wrgj42ztfy", + "world.iss-save-format": "iss-how-should-save-games-store-the-changing-world--kpdhcdkax56a7b7d", + "world.iss-save-tide": "iss-loaded-saves-misplace-objects-the-tide-moved--4jy763bv4xn9j5eh", + "world.iss-tide-desync": "iss-tide-heights-differ-between-co-op-peers--gqmq087dr478v1px", + "world.iss-tide-flat": "iss-tides-feel-identical-every-cycle--e8kc5aah7z7ff50z", + "world.iss-tide-math": "iss-how-do-we-make-the-tide-simulation-deterministic--48yc2jreapt0n7jf", + "world.rsk-cell-seams": "rsk-192-m-cells-split-the-128-m-navigation-tiles--dwyy783vnxfshkfd", + "world.rsk-ecs-join": "rsk-queries-that-join-tables-with-sparse-tags-may-lo--2h5br5crhfn1nb8c", + "world.rsk-fiber-debug": "rsk-fiber-stacks-may-make-crash-dumps-unreadable--b7c1mkn9ygvmsy57", + "world.rsk-gull-reload-state": "rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew", + "world.rsk-io-rework": "rsk-reworking-the-read-scheduler-may-slip-the-coast--9jzvs7etvb5jxqtp", + "world.rsk-kelp-cache": "rsk-kelp-s-4-mb-dictionary-may-thrash-the-skiff-cach--rv7ac1hedneqkp0v", + "world.rsk-pool-cut": "rsk-ports-may-need-to-shrink-the-streaming-pool-for--1gtjkygrtkb5kgww", + "world.rsk-save-midturn": "rsk-saving-during-a-tide-turn-may-record-a-half-appl--zezc1pxx8zp5b82m", + "world.rsk-save-size": "rsk-delta-saves-may-outgrow-console-save-slots--8re48mgme427hzds", + "world.rsk-tide-overflow": "rsk-the-fixed-point-tide-phase-may-overflow-in-long--wvaysxbvtnehxfka", + "world.rsk-tide-skiff-cost": "rsk-fixed-point-tides-may-crowd-the-skiff-simulation--ryrspezykww86qkm" +} diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-192-m-cells-split-the-128-m-navigation-tiles--dwyy783vnxfshkfd.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-192-m-cells-split-the-128-m-navigation-tiles--dwyy783vnxfshkfd.md new file mode 100644 index 00000000..e2446a7e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-192-m-cells-split-the-128-m-navigation-tiles--dwyy783vnxfshkfd.md @@ -0,0 +1,14 @@ +--- +id: rsk-192-m-cells-split-the-128-m-navigation-tiles--dwyy783vnxfshkfd +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: 192 m cells split the 128 m navigation tiles +state: mitigated +created_at: '2026-04-08T10:00:00Z' +created_by: Kenji Arakawa +derives_from: + - dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc +mitigated_by: dec-cut-navigation-tiles-to-64-m-so-three-fit-along--snvepk8ygeb3qsjs +likelihood: high +severity: medium +--- +Navigation tiles are 128 m, sized for the old cells. A 192 m cell edge cuts every second tile in half, so a tile would belong to two cells and reload with either. Path queries across a seam could fail while one half is missing. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-a-bad-cache-entry-could-ship-broken-bytecode-to--9w76xhyz9xy8g5k5.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-a-bad-cache-entry-could-ship-broken-bytecode-to--9w76xhyz9xy8g5k5.md new file mode 100644 index 00000000..ddff1ace --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-a-bad-cache-entry-could-ship-broken-bytecode-to--9w76xhyz9xy8g5k5.md @@ -0,0 +1,15 @@ +--- +id: rsk-a-bad-cache-entry-could-ship-broken-bytecode-to--9w76xhyz9xy8g5k5 +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: A bad cache entry could ship broken bytecode to every build +state: mitigated +created_at: '2025-11-10T11:00:00Z' +created_by: Liam O'Connell +derives_from: + - con-a-cache-hit-must-give-the-same-bytes-as-a-fresh--3gmcswztxzpmpz83 + - dec-fan-shader-cache-misses-out-to-every-farm-agent--pwrf9w720rf4hd27 +mitigated_by: dec-recompile-a-1-in-50-sample-of-cache-hits-and-com--9n176hnc9w0tax3s +likelihood: low +severity: high +--- +If an agent with a broken compiler install uploads bad output, every later build fetches it. One poisoned entry for the water shader would reach every platform build until someone noticed. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-a-skiff-host-may-lack-the-upload-bandwidth-for-t--kydzk7rb2rf4rw5c.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-a-skiff-host-may-lack-the-upload-bandwidth-for-t--kydzk7rb2rf4rw5c.md new file mode 100644 index 00000000..76a6aedf --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-a-skiff-host-may-lack-the-upload-bandwidth-for-t--kydzk7rb2rf4rw5c.md @@ -0,0 +1,13 @@ +--- +id: rsk-a-skiff-host-may-lack-the-upload-bandwidth-for-t--kydzk7rb2rf4rw5c +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: A Skiff host may lack the upload bandwidth for three clients +state: open +created_at: '2026-04-03T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - dec-use-host-authoritative-sync-for-co-op--17hqrmtja7pn98d6 +likelihood: medium +severity: medium +--- +With host-authoritative sync the host sends world state to every client. Priya Natarajan has not yet measured Skiff upload on home Wi-Fi, and a Skiff hosting three clients may not keep up. Nobody owns this now that the netcode Effort is stopping. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-artists-cannot-match-concept-paintings-under-the--6cfh9vkamn0kbtcx.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-artists-cannot-match-concept-paintings-under-the--6cfh9vkamn0kbtcx.md new file mode 100644 index 00000000..170da615 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-artists-cannot-match-concept-paintings-under-the--6cfh9vkamn0kbtcx.md @@ -0,0 +1,15 @@ +--- +id: rsk-artists-cannot-match-concept-paintings-under-the--6cfh9vkamn0kbtcx +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Artists cannot match concept paintings under the Brine curve +state: accepted +created_at: '2026-02-03T10:00:00Z' +created_by: Yusuf Demir +derives_from: + - dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86 +evidence: + - fnd-concept-match-review-11-of-14-key-shots-pass-und--1sv3grvmm4hbtyf5 +likelihood: medium +severity: low +--- +The concept paintings were made against the stock filmic look. Under the Brine curve some key shots may never match them. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-caustic-flicker-fails-photosensitivity-review--vrpf3390abxh1q4d.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-caustic-flicker-fails-photosensitivity-review--vrpf3390abxh1q4d.md new file mode 100644 index 00000000..aa5383d5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-caustic-flicker-fails-photosensitivity-review--vrpf3390abxh1q4d.md @@ -0,0 +1,13 @@ +--- +id: rsk-caustic-flicker-fails-photosensitivity-review--vrpf3390abxh1q4d +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Caustic flicker fails photosensitivity review +state: open +created_at: '2026-01-27T11:00:00Z' +created_by: Dara Whitlock +derives_from: + - iss-caustics-flicker-under-tern-at-low-internal-reso--he94mq6rr7tr5yv5 +likelihood: medium +severity: high +--- +Platform photosensitivity review rejects flashing between 3 and 30 Hz over large areas. If the caustic flicker survives to submission, both consoles can fail review. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-compute-meshlet-expansion-is-too-slow-on-skiff--b1915sgdsr1bpwda.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-compute-meshlet-expansion-is-too-slow-on-skiff--b1915sgdsr1bpwda.md new file mode 100644 index 00000000..50a93ca1 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-compute-meshlet-expansion-is-too-slow-on-skiff--b1915sgdsr1bpwda.md @@ -0,0 +1,13 @@ +--- +id: rsk-compute-meshlet-expansion-is-too-slow-on-skiff--b1915sgdsr1bpwda +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Compute meshlet expansion is too slow on Skiff +state: open +created_at: '2025-12-06T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - dec-expand-meshlets-to-index-buffers-in-compute-on-s--bpbtr54dgzgsjgme +likelihood: medium +severity: medium +--- +Writing index buffers every frame costs bandwidth Skiff does not have much of. On the cliffs benchmark the expansion could take 1.5 ms or more. No Skiff measurement exists yet. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-delta-saves-may-outgrow-console-save-slots--8re48mgme427hzds.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-delta-saves-may-outgrow-console-save-slots--8re48mgme427hzds.md new file mode 100644 index 00000000..fd63d57b --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-delta-saves-may-outgrow-console-save-slots--8re48mgme427hzds.md @@ -0,0 +1,15 @@ +--- +id: rsk-delta-saves-may-outgrow-console-save-slots--8re48mgme427hzds +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Delta saves may outgrow console save slots +state: accepted +created_at: '2026-03-14T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8 +evidence: + - fnd-delta-saves-reach-6-2-mb-after-40-hours--8g1j04z0vhjwrkyn +likelihood: medium +severity: low +--- +Tide-keyed deltas never merge, because two changes at different tide phases cannot collapse into one. A long game could accumulate tens of thousands of deltas. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-fiber-stacks-may-make-crash-dumps-unreadable--b7c1mkn9ygvmsy57.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-fiber-stacks-may-make-crash-dumps-unreadable--b7c1mkn9ygvmsy57.md new file mode 100644 index 00000000..ec41201e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-fiber-stacks-may-make-crash-dumps-unreadable--b7c1mkn9ygvmsy57.md @@ -0,0 +1,15 @@ +--- +id: rsk-fiber-stacks-may-make-crash-dumps-unreadable--b7c1mkn9ygvmsy57 +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Fiber stacks may make crash dumps unreadable +state: realized +created_at: '2025-11-28T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq +evidence: + - fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m +likelihood: medium +severity: high +--- +Crash dumps capture thread stacks. A crash inside a fiber shows the worker's scheduler frames, not the job's frames, unless the dump tool walks fiber stacks too. The console vendor plug-in for that is still in beta. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-fixed-point-tides-may-crowd-the-skiff-simulation--ryrspezykww86qkm.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-fixed-point-tides-may-crowd-the-skiff-simulation--ryrspezykww86qkm.md new file mode 100644 index 00000000..3ae69f11 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-fixed-point-tides-may-crowd-the-skiff-simulation--ryrspezykww86qkm.md @@ -0,0 +1,15 @@ +--- +id: rsk-fixed-point-tides-may-crowd-the-skiff-simulation--ryrspezykww86qkm +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Fixed-point tides may crowd the Skiff simulation budget +state: accepted +created_at: '2025-12-05T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - fnd-fixed-point-tide-step-costs-0-9-ms-on-skiff--mfc73bg9wwaxtfra +evidence: + - fnd-fixed-point-tide-step-costs-0-9-ms-on-skiff--mfc73bg9wwaxtfra +likelihood: medium +severity: medium +--- +At 0.9 ms per step, the tide costs more than twice its float price on Skiff. If other simulation work grows, the tide step could push frames over budget. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-gi-cannot-fit-the-120-hz-performance-mode--tqt3fj839dqfq5s7.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-gi-cannot-fit-the-120-hz-performance-mode--tqt3fj839dqfq5s7.md new file mode 100644 index 00000000..9c43cfde --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-gi-cannot-fit-the-120-hz-performance-mode--tqt3fj839dqfq5s7.md @@ -0,0 +1,15 @@ +--- +id: rsk-gi-cannot-fit-the-120-hz-performance-mode--tqt3fj839dqfq5s7 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: GI cannot fit the 120 Hz performance mode +state: realized +created_at: '2026-03-25T10:00:00Z' +created_by: Dara Whitlock +derives_from: + - iss-gi-does-not-fit-the-120-hz-performance-mode-budg--get9cq6er1ac4vzx +evidence: + - fnd-quarter-resolution-sdf-gi-costs-1-9-ms-in-perfor--md9qdmtne78wv7mf +likelihood: high +severity: high +--- +If no GI path fits the performance-mode budget, the 120 Hz mode either ships with flat lighting or does not ship. Marketing has already announced it. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4.md new file mode 100644 index 00000000..57929431 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4.md @@ -0,0 +1,15 @@ +--- +id: rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: HDR certification slips the release candidate +state: realized +created_at: '2026-07-17T10:00:00Z' +created_by: Dara Whitlock +derives_from: + - iss-meridian-hdr-certification-fails-the-paper-white--bper6nwencgtgf7b +evidence: + - fnd-meridian-hdr-certification-pre-check-failed-agai--w4q6pdtqc7akayt0 +likelihood: medium +severity: high +--- +Each certification resubmission takes about ten days. If the paper-white fix fails a second time, the Meridian release candidate on 2026-09-30 slips. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew.md new file mode 100644 index 00000000..ee83d5d0 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew.md @@ -0,0 +1,13 @@ +--- +id: rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Hot reload may corrupt live script state +state: open +created_at: '2026-02-26T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42 +likelihood: medium +severity: medium +--- +A swapped function may read locals or object fields in a different order than the old version wrote them. Designers would see creatures behave strangely after a reload and blame their own edit. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-kelp-s-4-mb-dictionary-may-thrash-the-skiff-cach--rv7ac1hedneqkp0v.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-kelp-s-4-mb-dictionary-may-thrash-the-skiff-cach--rv7ac1hedneqkp0v.md new file mode 100644 index 00000000..e3d3759f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-kelp-s-4-mb-dictionary-may-thrash-the-skiff-cach--rv7ac1hedneqkp0v.md @@ -0,0 +1,15 @@ +--- +id: rsk-kelp-s-4-mb-dictionary-may-thrash-the-skiff-cach--rv7ac1hedneqkp0v +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Kelp's 4 MB dictionary may thrash the Skiff cache +state: realized +created_at: '2025-10-22T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m +evidence: + - fnd-kelp-decodes-at-1-1-gb-s-on-skiff-with-a-cold-ca--vef244qjn2mjf07x +likelihood: medium +severity: high +--- +Kelp's speed comes from a 4 MB shared dictionary. The October run used a PC with a large cache. Skiff's last-level cache is much smaller, and a dictionary that does not fit could make every decode a cache miss. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-pipeline-compiles-hitch-skiff-on-first-visits--6sq225m8dx36aefs.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-pipeline-compiles-hitch-skiff-on-first-visits--6sq225m8dx36aefs.md new file mode 100644 index 00000000..1ba8df46 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-pipeline-compiles-hitch-skiff-on-first-visits--6sq225m8dx36aefs.md @@ -0,0 +1,14 @@ +--- +id: rsk-pipeline-compiles-hitch-skiff-on-first-visits--6sq225m8dx36aefs +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Pipeline compiles hitch Skiff on first visits +state: mitigated +created_at: '2025-12-10T09:00:00Z' +created_by: Priya Natarajan +derives_from: + - fnd-harbor-district-needs-1-460-pipelines-on-skiff--dwd5ry1wqaeacmpn +mitigated_by: dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7 +likelihood: high +severity: medium +--- +If first-visit compiles stay, every new player meets hitches in the first hour. Reviewers play the first hour. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-ports-may-need-to-shrink-the-streaming-pool-for--1gtjkygrtkb5kgww.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-ports-may-need-to-shrink-the-streaming-pool-for--1gtjkygrtkb5kgww.md new file mode 100644 index 00000000..5aa9a0b5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-ports-may-need-to-shrink-the-streaming-pool-for--1gtjkygrtkb5kgww.md @@ -0,0 +1,15 @@ +--- +id: rsk-ports-may-need-to-shrink-the-streaming-pool-for--1gtjkygrtkb5kgww +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Ports may need to shrink the streaming pool for Skiff +state: realized +created_at: '2026-02-02T10:00:00Z' +created_by: Dara Whitlock +derives_from: + - con-streaming-pool-budget--632bkbs79bwj4cr5 +evidence: + - fnd-ports-cut-the-skiff-memory-total-and-streaming-m--1p8b10ttb07jkznx +likelihood: medium +severity: high +--- +Skiff has the smallest memory of the three platforms, and every system's budget is still provisional. If the Skiff total shrinks, the 2.0 GB streaming pool is the largest single budget and the likeliest to be cut. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-queries-that-join-tables-with-sparse-tags-may-lo--2h5br5crhfn1nb8c.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-queries-that-join-tables-with-sparse-tags-may-lo--2h5br5crhfn1nb8c.md new file mode 100644 index 00000000..1bdb7321 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-queries-that-join-tables-with-sparse-tags-may-lo--2h5br5crhfn1nb8c.md @@ -0,0 +1,15 @@ +--- +id: rsk-queries-that-join-tables-with-sparse-tags-may-lo--2h5br5crhfn1nb8c +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Queries that join tables with sparse tags may lose cache locality +state: realized +created_at: '2025-09-25T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9 +evidence: + - fnd-archetype-iteration-takes-3-4-ms-in-the-alpha-wo--dawb9m0pa999mhpe +likelihood: medium +severity: medium +--- +A query such as "every transform that is Submerged" walks an archetype column and probes a sparse set per row. If the sparse set is large and the archetype count grows, the probe pattern could thrash the cache, especially on Skiff's smaller caches. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-re-simulation-cost-could-blow-the-skiff-frame-bu--sk2njsp170a3qwyf.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-re-simulation-cost-could-blow-the-skiff-frame-bu--sk2njsp170a3qwyf.md new file mode 100644 index 00000000..24a130ca --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-re-simulation-cost-could-blow-the-skiff-frame-bu--sk2njsp170a3qwyf.md @@ -0,0 +1,18 @@ +--- +id: rsk-re-simulation-cost-could-blow-the-skiff-frame-bu--sk2njsp170a3qwyf +effort: eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49 +title: >- + Re-simulation cost could blow the Skiff frame budget once tides join the + snapshot +state: realized +created_at: '2026-01-20T10:00:00Z' +created_by: Sofia Marchetti +derives_from: + - dec-use-a-7-frame-rollback-window--ewptan6y616adtfw + - fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf +evidence: + - fnd-re-running-tides-every-rollback-frame-costs-4-8--tp4gxe8prh0bh9h4 +likelihood: medium +severity: high +--- +Every prototype number so far ran with tides frozen. Once tides are in the snapshot, every rolled-back frame re-runs the tide step too. Sofia Marchetti does not yet know what one tide step costs on Skiff. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-reworking-the-read-scheduler-may-slip-the-coast--9jzvs7etvb5jxqtp.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-reworking-the-read-scheduler-may-slip-the-coast--9jzvs7etvb5jxqtp.md new file mode 100644 index 00000000..83c61e40 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-reworking-the-read-scheduler-may-slip-the-coast--9jzvs7etvb5jxqtp.md @@ -0,0 +1,16 @@ +--- +id: rsk-reworking-the-read-scheduler-may-slip-the-coast--9jzvs7etvb5jxqtp +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: >- + Reworking the read scheduler may slip the coast sign-off past the release + candidate +state: open +created_at: '2026-08-28T10:00:00Z' +created_by: Dara Whitlock +derives_from: + - dec-schedule-streaming-reads-by-deadline-instead-of--q2x5aknabgcssdj2 + - iss-tide-turns-leave-inland-terrain-untextured-for-s--ccv6nhwk68kj732c +likelihood: high +severity: medium +--- +Content lock has passed and the deadline scheduler is still a proposal. Dara Whitlock estimates three weeks to build and soak it, which lands within days of the release candidate on 2026-09-30. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-saving-during-a-tide-turn-may-record-a-half-appl--zezc1pxx8zp5b82m.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-saving-during-a-tide-turn-may-record-a-half-appl--zezc1pxx8zp5b82m.md new file mode 100644 index 00000000..c2161d7e --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-saving-during-a-tide-turn-may-record-a-half-appl--zezc1pxx8zp5b82m.md @@ -0,0 +1,15 @@ +--- +id: rsk-saving-during-a-tide-turn-may-record-a-half-appl--zezc1pxx8zp5b82m +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: Saving during a tide turn may record a half-applied tide +state: realized +created_at: '2026-04-28T10:00:00Z' +created_by: Marta Lindqvist +derives_from: + - dec-save-player-changes-as-deltas-keyed-to-the-tide--1qxvc9985c8pzke8 +evidence: + - fnd-3-of-200-saves-taken-mid-turn-fail-to-load--4j1kafsdeq0wedhf +likelihood: medium +severity: high +--- +The tide applies terrain changes over several frames during a turn. An autosave in that window could record deltas against terrain that is half old and half new. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-sdf-volumes-outgrow-the-render-target-memory-bud--xfd2pfztvskdcd2c.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-sdf-volumes-outgrow-the-render-target-memory-bud--xfd2pfztvskdcd2c.md new file mode 100644 index 00000000..0a7970af --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-sdf-volumes-outgrow-the-render-target-memory-bud--xfd2pfztvskdcd2c.md @@ -0,0 +1,16 @@ +--- +id: rsk-sdf-volumes-outgrow-the-render-target-memory-bud--xfd2pfztvskdcd2c +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: SDF volumes outgrow the render-target memory budget +state: accepted +created_at: '2025-11-06T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - con-render-target-memory-on-meridian--q4szajxse9c1csdv + - dec-use-signed-distance-field-gi--yn366zmp3k7snd9w +evidence: + - fnd-sdf-volumes-use-410-mb-of-render-target-memory--y8bm788y240rqq7d +likelihood: medium +severity: medium +--- +Four 64-cubed clipmaps plus the per-mesh distance fields could pass 500 MB once all the ruins are in. That would squeeze shadow pages and the visibility buffer inside 1.8 GB. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd.md new file mode 100644 index 00000000..1d7f2bda --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd.md @@ -0,0 +1,16 @@ +--- +id: rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd +effort: eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn +title: Shader cache storage could outgrow the 4 TB farm volume +state: accepted +created_at: '2025-11-18T14:00:00Z' +created_by: Liam O'Connell +derives_from: + - con-the-build-farm-stays-at-12-agents-until-alpha--w7e1xfex9z2ycpx1 + - dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh +evidence: + - fnd-retrospective-on-the-shader-compile-cache--9rpv2a60ach04cx6 +likelihood: medium +severity: medium +--- +Every key change, compiler update and define tweak adds new entries; nothing evicts old ones yet. At the current rate the cache grows about 210 GB a month. Liam O'Connell is not sure an eviction policy is worth building before release. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-skiff-certification-slips-past-the-release-candi--3xe2z6qf5ncxf87h.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-skiff-certification-slips-past-the-release-candi--3xe2z6qf5ncxf87h.md new file mode 100644 index 00000000..88b19e2a --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-skiff-certification-slips-past-the-release-candi--3xe2z6qf5ncxf87h.md @@ -0,0 +1,13 @@ +--- +id: rsk-skiff-certification-slips-past-the-release-candi--3xe2z6qf5ncxf87h +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff certification slips past the release candidate +state: open +created_at: '2026-06-03T10:00:00Z' +created_by: Dara Whitlock +derives_from: + - dec-make-skiff-a-launch-platform--7fh37fbjmqpjgj0a +likelihood: medium +severity: high +--- +Full Skiff lot check takes 10 working days and a failure restarts the clock. If the first full submission fails, Skiff misses the 2026-09-30 release candidate. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-skiff-runs-out-of-memory-in-dense-districts--p5pv42sgezzjhpfz.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-skiff-runs-out-of-memory-in-dense-districts--p5pv42sgezzjhpfz.md new file mode 100644 index 00000000..cc5a2f58 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-skiff-runs-out-of-memory-in-dense-districts--p5pv42sgezzjhpfz.md @@ -0,0 +1,15 @@ +--- +id: rsk-skiff-runs-out-of-memory-in-dense-districts--p5pv42sgezzjhpfz +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff runs out of memory in dense districts +state: realized +created_at: '2025-11-14T10:00:00Z' +created_by: Priya Natarajan +derives_from: + - con-skiff-memory-budget--8ngr8fep3gxdfy80 +evidence: + - fnd-harbor-district-peaks-at-8-6-gb-on-skiff--vccxye8jy3mkba2v +likelihood: medium +severity: high +--- +The harbor and the ruins stack audio, tide state, and saltglass textures in one place. If the peak passes the Skiff memory budget, Skiff kills the game with no warning. Cert treats that as a crash. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-skiff-throttles-the-gpu-in-long-handheld-session--1nwtqw8gyc9x4h1b.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-skiff-throttles-the-gpu-in-long-handheld-session--1nwtqw8gyc9x4h1b.md new file mode 100644 index 00000000..4da8a7bb --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-skiff-throttles-the-gpu-in-long-handheld-session--1nwtqw8gyc9x4h1b.md @@ -0,0 +1,13 @@ +--- +id: rsk-skiff-throttles-the-gpu-in-long-handheld-session--1nwtqw8gyc9x4h1b +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Skiff throttles the GPU in long handheld sessions +state: accepted +created_at: '2026-01-26T09:00:00Z' +created_by: Priya Natarajan +evidence: + - fnd-skiff-gpu-clock-drops-8-percent-after-20-minutes--5st35qqh8nwzabb4 +likelihood: low +severity: medium +--- +Skiff lowers clocks when the handheld runs hot. A big drop would push the frame past budget after an hour of play. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-tern-ghosting-on-saltglass-draws-reviewer-compla--rg0rjrs6n2x53w56.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-tern-ghosting-on-saltglass-draws-reviewer-compla--rg0rjrs6n2x53w56.md new file mode 100644 index 00000000..6d6a86b5 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-tern-ghosting-on-saltglass-draws-reviewer-compla--rg0rjrs6n2x53w56.md @@ -0,0 +1,14 @@ +--- +id: rsk-tern-ghosting-on-saltglass-draws-reviewer-compla--rg0rjrs6n2x53w56 +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Tern ghosting on saltglass draws reviewer complaints +state: mitigated +created_at: '2026-04-03T10:00:00Z' +created_by: Ines Okafor +derives_from: + - fnd-tern-ghosts-behind-moving-saltglass--j48ss757xfxmw31q +mitigated_by: dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k +likelihood: high +severity: medium +--- +Saltglass is in every marketing shot. If reviewers notice trails behind it, the signature feature looks broken. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-tern-takes-too-much-of-the-skiff-frame--xtmh8jzptbwbg907.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-tern-takes-too-much-of-the-skiff-frame--xtmh8jzptbwbg907.md new file mode 100644 index 00000000..c05949e6 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-tern-takes-too-much-of-the-skiff-frame--xtmh8jzptbwbg907.md @@ -0,0 +1,15 @@ +--- +id: rsk-tern-takes-too-much-of-the-skiff-frame--xtmh8jzptbwbg907 +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Tern takes too much of the Skiff frame +state: mitigated +created_at: '2025-11-20T13:30:00Z' +created_by: Tomasz Brandt +derives_from: + - con-frame-budget--wt5rfqh5z444g2cg + - fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0 +mitigated_by: dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3 +likelihood: medium +severity: medium +--- +At 3.9 ms, Tern Quality eats 12 percent of the 33.3 ms Skiff frame. If Skiff ever runs faster than 30 Hz, that share grows and something else must give. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-the-fixed-point-tide-phase-may-overflow-in-long--wvaysxbvtnehxfka.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-the-fixed-point-tide-phase-may-overflow-in-long--wvaysxbvtnehxfka.md new file mode 100644 index 00000000..8525f469 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-the-fixed-point-tide-phase-may-overflow-in-long--wvaysxbvtnehxfka.md @@ -0,0 +1,14 @@ +--- +id: rsk-the-fixed-point-tide-phase-may-overflow-in-long--wvaysxbvtnehxfka +effort: eff-kestrel-world-streaming-and-simulation-core--3evfpn88ghjnnfk4 +title: The fixed-point tide phase may overflow in long sessions +state: mitigated +created_at: '2025-11-10T10:00:00Z' +created_by: Rhea Valdés +derives_from: + - dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e +mitigated_by: dec-wrap-the-tide-phase-accumulator-at-each-40-minut--hx88m4hbg27n0xwy +likelihood: low +severity: high +--- +The tide phase accumulates every step. With 32 integer bits, a phase counted in milliseconds overflows after about 24 days of play, and a phase counted in microseconds after 36 minutes. A bad unit choice anywhere in the accumulation would wrap mid-session. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-tide-streaming-outruns-skiff-storage--6q8s3b383z2tyeyb.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-tide-streaming-outruns-skiff-storage--6q8s3b383z2tyeyb.md new file mode 100644 index 00000000..95eebf5f --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-tide-streaming-outruns-skiff-storage--6q8s3b383z2tyeyb.md @@ -0,0 +1,13 @@ +--- +id: rsk-tide-streaming-outruns-skiff-storage--6q8s3b383z2tyeyb +effort: eff-meridian-and-skiff-ports--ns2t7htkafx7v3xx +title: Tide streaming outruns Skiff storage +state: open +created_at: '2026-03-06T11:00:00Z' +created_by: Kenji Arakawa +derives_from: + - fnd-skiff-microsd-sustains-92-mb-s--xr1fsyjd45y2tqcx +likelihood: medium +severity: high +--- +When the tide turns, the world swaps tide cells while the player moves. If storage falls behind, players see low-detail saltglass or fall through a newly exposed path. The margin on Skiff assumes the 92 MB/s read rate. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-visibility-buffer-bandwidth-is-too-high-for-skif--5gwb2hcd41ctyhrx.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-visibility-buffer-bandwidth-is-too-high-for-skif--5gwb2hcd41ctyhrx.md new file mode 100644 index 00000000..c65026cf --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-visibility-buffer-bandwidth-is-too-high-for-skif--5gwb2hcd41ctyhrx.md @@ -0,0 +1,14 @@ +--- +id: rsk-visibility-buffer-bandwidth-is-too-high-for-skif--5gwb2hcd41ctyhrx +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Visibility buffer bandwidth is too high for Skiff +state: mitigated +created_at: '2026-04-09T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - fnd-visibility-buffer-costs-11-2-ms-on-skiff--s3vphdwnhbh4650s +mitigated_by: dec-visibility-buffer-on-pc-and-meridian-forward-fal--khvgysnhmnkjqe9k +likelihood: medium +severity: high +--- +If the visibility buffer stays 2.3 ms slower than forward+ on Skiff, the Skiff port cannot hold its frame rate with saltglass on screen. Skiff becomes a launch platform at beta, so this cannot wait. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-visibility-buffer-material-resolve-multiplies-sh--e0sam0jrjgsvx0gj.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-visibility-buffer-material-resolve-multiplies-sh--e0sam0jrjgsvx0gj.md new file mode 100644 index 00000000..84f3dfb0 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-visibility-buffer-material-resolve-multiplies-sh--e0sam0jrjgsvx0gj.md @@ -0,0 +1,14 @@ +--- +id: rsk-visibility-buffer-material-resolve-multiplies-sh--e0sam0jrjgsvx0gj +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: Visibility buffer material resolve multiplies shader permutations +state: mitigated +created_at: '2025-11-20T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9 +mitigated_by: dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r +likelihood: high +severity: medium +--- +Resolving materials per tile class means one shader per material per tile class. With 310 saltglass and terrain materials and 6 tile classes that is 1,860 resolve shaders on top of the forward ones. Compile times and the shader count both grow past what the build farm handles today. diff --git a/benchmarks/proof-recall/.flatbread-proof/risks/rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty.md b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty.md new file mode 100644 index 00000000..9da072e2 --- /dev/null +++ b/benchmarks/proof-recall/.flatbread-proof/risks/rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty.md @@ -0,0 +1,15 @@ +--- +id: rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty +effort: eff-lantern-renderer-overhaul--qwgke408pte4k0ar +title: VSM page pool overflows when tides expose the flats +state: realized +created_at: '2026-02-18T10:00:00Z' +created_by: Tomasz Brandt +derives_from: + - dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4 +evidence: + - fnd-vsm-page-pool-overflows-during-spring-tides--m2p8e89hhdmh0z8a +likelihood: medium +severity: high +--- +A falling tide exposes kilometres of wet flats at once, all needing fresh shadow pages. If the requests exceed the 4,096-page pool, shadows drop to low resolution or pop. Nobody has measured a spring tide yet. diff --git a/benchmarks/proof-recall/README.md b/benchmarks/proof-recall/README.md new file mode 100644 index 00000000..7c93c600 --- /dev/null +++ b/benchmarks/proof-recall/README.md @@ -0,0 +1,537 @@ +# Proof recall benchmark + +This benchmark measures how well an agent recalls project decisions from a +Proof graph, and what that recall costs in tokens and tool calls. It answers +the open Proof Issue "Proof has no recall benchmark to test reads against". + +The graph describes a fictional game, set out in [WORLD.md](./WORLD.md). It +holds hundreds of records across five Efforts. Decisions change, evidence is +proved wrong, alternatives are rejected and reopened, and noise is retracted. +Each question has a known answer and a stated path through the graph. + +## Layout + +| Path | What it holds | +| ------------------------- | -------------------------------------------------------- | +| `WORLD.md` | The shared facts every Effort must agree on | +| `spec/<effort>.mjs` | One Effort's history, as an ordered list of mutations | +| `questions/<effort>.json` | That Effort's questions and answers | +| `questions/cross.json` | Questions that need two or more Efforts | +| `scripts/build.mjs` | Replays every spec through the Proof writer | +| `scripts/check.mjs` | Proves each answer against the built graph | +| `scripts/grade.mjs` | Scores one run | +| `scripts/run.mjs` | Runs one headless agent session per question | +| `scripts/task.mjs` | The task text each session reads | +| `scripts/compare.mjs` | Compares two runs question by question | +| `runs/` | Answers and costs from each pilot and full run | +| `.flatbread-proof/` | The built graph, committed so runs need no build | +| `flatbread.config.js` | Lets `flatbread proof …` read the graph from this folder | + +## Build and check + +Run these from this folder after `pnpm build` at the repository root: + +```bash +node scripts/build.mjs # rebuild .flatbread-proof/ from spec/ +node scripts/check.mjs # validate every question; exits 1 on error +``` + +While authoring one Effort, build it alone into a scratch folder: + +```bash +node scripts/build.mjs --only render --out /tmp/bench-render +node scripts/check.mjs --only render --graph /tmp/bench-render +``` + +To read the graph the way a benchmark agent does: + +```bash +../../node_modules/.bin/flatbread proof list --status active,paused,completed,abandoned +``` + +## How a spec works + +A spec is an ES module whose default export describes one Effort: + +```js +export default { + key: 'render', // the Effort's key; prefixes every record key + effort: { + title: 'Lantern renderer overhaul', + body: '…', + created_at: '2025-09-01T09:00:00Z', + }, + events: [ + { + at: '2025-09-04T10:00:00Z', + key: 'dec-vsm', // local key; only create events take one + type: 'WriteDecision', + title: 'Use virtual shadow maps', + body: '…', + created_by: 'Ines Okafor', + derives_from: ['iss-shadows', 'fnd-csm-cost'], + }, + { + at: '2025-09-05T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-vsm', + }, + ], +}; +``` + +The builder replays events in order through the real Proof writer, so every +rule in [the Proof reference](../../packages/proof/skills/proof/reference.md) +applies. In particular: + +- Every event needs `at`. Times must never go backwards. +- Create events (`WriteIssue`, `WriteFinding`, `WriteDecision`, + `WriteConstraint`, `WriteRisk`, `WriteCitation`, `WriteBlob`, + `WriteCompaction`) need a unique local `key`. The builder fills in `effort`, + `id`, and `created_at`. +- Fields that name records take local keys: `derives_from`, `supersedes`, + `invalidates`, `cites`, `blob`, `supersederId`, `targetId`, `findingId`, + `issueId`, `resolvedBy`, `decisionId`, `rejects`, `riskId`, `evidence`, + `recordId`, `effortId`. The key `effort` names the spec's own Effort. +- `SetEffortStatus` needs only `status`. +- The writer's clock is set to `at`, so lifecycle timestamps match the story. +- A spec may be a folder with `index.mjs` if one file grows too long. + +The writer enforces Proof's rules. The ones authors trip on most: + +1. `AcceptDecision` rejects every other proposed Decision that derives from + the same `question` Issue. It fails if that question already has an + accepted Decision. Supersede the old answer first. +2. A reopened Decision can be accepted only after the Decision that rejected + it stops being accepted, for example by being superseded. +3. `Supersede` and a create's `supersedes` need the same kind, and the target + must not already be superseded. +4. `Invalidate` needs a Finding as its source and a Finding or Decision as + its target. +5. `Retract` fails if the target is the last record in another live record's + `resolved_by`, `mitigated_by`, `evidence`, `rejected_by`, or + `superseded_by`. +6. `MitigateRisk` needs an accepted Decision. `SetRiskState` with `realized` + needs at least one Finding in `evidence`. +7. `WriteCompaction` takes at most 10 `derives_from` ids and never names + another compaction. The writer records `covers` and supersedes the old + head. + +## How a question works + +Each question file holds one Effort's questions: + +```json +{ + "effort": "render", + "questions": [ + { + "id": "render-017", + "tier": 2, + "hops": 2, + "categories": ["supersession", "temporal"], + "question": "Which shadow technique did Lantern use at the vertical slice?", + "answer": { "kind": "record", "value": "dec-csm-4" }, + "evidence": ["dec-csm-4", "dec-csm-3", "dec-vsm"], + "path": [ + ["dec-csm-3", "superseded_by", "dec-csm-4"], + ["dec-csm-4", "superseded_by", "dec-vsm"] + ], + "checks": [ + { "type": "asof", "start": "dec-vsm", "at": "2025-12-15T00:00:00Z" } + ], + "traps": ["The current head is VSM, adopted after the slice."] + } + ] +} +``` + +| Field | Meaning | +| ------------ | --------------------------------------------------------------- | +| `id` | Unique: `<effort>-NNN` | +| `tier` | Difficulty, 0 to 4 (below) | +| `hops` | Edges walked from the entry record to the answer | +| `categories` | One or more from the list in `scripts/check.mjs` | +| `question` | Plain English; never contains an id or a key | +| `answer` | `kind` and `value`; `text` answers carry a `rubric` instead | +| `evidence` | Every record a careful reader must open | +| `path` | The edges walked, as `[from, relation, to]`; tiers 1-3 need one | +| `checks` | Machine checks that compute or confirm the answer | +| `traps` | The wrong answers a careless reader gives, and why | +| `scoped` | `true` when wording other than the title pins the Effort down | + +### Answer kinds + +| Kind | `value` | Graded by | +| --------- | ------------------------ | ------------------------------- | +| `record` | one key | exact match (id or key) | +| `records` | a list of keys | exact set match | +| `value` | a short string or number | exact match, or one of `accept` | +| `boolean` | `true` or `false` | exact match | +| `count` | a whole number | exact match | +| `text` | none; uses `rubric` | share of rubric items found | + +A `rubric` is a list of items. Each item is a phrase or a list of phrases; it +counts when the answer contains any one of them. Keep `text` answers under 15 +percent of an Effort's questions. + +When the graph does not answer a question, its answer is the `value` +`"unknown"`. Benchmark agents are told to reply `unknown` in that case. + +### Tiers and hops + +The **entry record** is the record a reader reaches first: one the question +names, or one a single filtered `proof records` listing turns up. `hops` +counts the edges from there to the answer, along the shortest route a reader +can follow. A reader sees only the links stored on the record in hand: +supersession and invalidation links run both ways, but `derives_from`, +`rejected_by`, `resolved_by`, and `cites` run only from the record that +stores them. `check.mjs` warns when a shorter route exists than the stated +path; treat that warning as a mistake to fix. + +| Tier | Meaning | +| ---- | --------------------------------------------------------------------------------------------- | +| 0 | One record holds the answer (0 hops) | +| 1 | One edge away | +| 2 | Two or three edges | +| 3 | Four to six edges, or two branches that must be joined | +| 4 | Needs a set or count across the Effort, a timeline, or a lifecycle rule, rather than one path | + +The `path` relations are the stored edge names (`derives_from`, `supersedes`, +`superseded_by`, `invalidates`, `invalidated_by`, `resolved_by`, +`rejected_by`, `mitigated_by`, `evidence`, `cites`, `blob`, `effort`) plus +three reverse readings: `supports` (the next record derives from this one), +`cited_by`, and `reopen_history` (a reopened Decision's earlier rejecter). + +### Checks + +A check without `expect` must compute the answer itself. A `select` scans the question file's Effort; set its `effort` to a list of Effort keys, or to `"*"`, to scan several. A check with +`expect` must return exactly that value. `record`, `records`, and `count` +answers need at least one computing check. + +| `type` | Fields | Returns | +| ------------ | -------------------------------------------------------------------------------------------------- | -------------------------------------------------- | +| `field` | `record`, `field` (or `standing`) | that frontmatter value | +| `head` | `start` | the newest version's key | +| `chain` | `start` | every version's key, oldest first | +| `asof` | `start`, `at` | the version current at `at` | +| `select` | `kinds`, `where`, `live`, `retracted`, `derivesFrom`, `restsOn`, `bodyIncludes`, `count`, `effort` | matching keys, or their count | +| `efforts` | `where`, `count` | matching Efforts' keys, or their count | +| `compaction` | `field`: `head`, `heads`, `stale`, `changes`, `changed`, `staleTargets` | the Effort's compaction state | +| `body` | `record`, `includes`, `afterExcerpt` | whether the text is present (and past the excerpt) | +| `edge` | `edge` | whether the edge exists | + +A record's **standing** is its state or status, or `live`, overridden by +`retracted`, `superseded`, or `invalidated`. `select` with `live: true` keeps +open Issues, proposed and accepted Decisions, open and realized Risks, and +Findings and Constraints that nothing has superseded or invalidated. +`restsOn: ["invalidated"]` keeps records with at least one `derives_from` +support of that standing. + +## Authoring rules + +1. **Answers come from the graph alone.** A reader with only Proof reads must + be able to reach every answer. Never rely on WORLD.md, the spec, or general + knowledge. +2. **One right answer.** If two records could fairly answer a question, fix + the graph or the question. +3. **Questions never leak.** No ids or keys, and no wording that names the + answer. +4. **Plant edge cases on purpose, then ask about them.** Design questions + first and build the history that makes them hard, or build the history and + ask about every turn. Record in `traps` the wrong answer each one invites. +5. **Write like real engineers.** Bodies hold numbers, captures, trade-offs, + and doubts. Most are 2 to 8 sentences; some are long on purpose. +6. **Keep to WORLD.md.** Names, dates, platforms, and shared facts must agree + across Efforts. + +## Running the benchmark + +A benchmark agent must never see `spec/`, `questions/`, or `keymap.json`. + +1. Build the workspace (`pnpm build` at the repository root), so the + `flatbread` binary exists. +2. Run the benchmark: + + ```bash + node scripts/run.mjs /tmp/recall --name <run> --model haiku --jobs 12 + ``` + + `run.mjs` gives every question its own folder and its own fresh, + headless `claude -p` session, once per strategy (`brief` first, or + no `brief`). Each folder holds the graph without the key map, the + config, a `./flatbread` wrapper, `TASK.md`, and, afterwards, the + agent's `answer.json` and `transcript.jsonl`. Sessions get only the + Bash, Read, and Write tools, no MCP servers, and no settings files. + Runs share one read-only copy of each built graph and one + `flatbread proof serve` process, both under + `<tmp>/flatbread-proof-recall/`. The server keeps each graph loaded + and answers every session's reads; on the 10x graph a read drops from + about 7 seconds to under 1. The first run that finds no server starts + one and leaves it running for later or parallel runs. Stop it with + `node scripts/run.mjs --stop-server`, and restart it that way after + rebuilding the CLI, since it keeps running the code it started with. + `--no-serve` makes reads run locally. + Keep the work folder outside the repository. A rerun skips finished + sessions. When every session ends, `run.mjs` writes + `runs/<run>-brief.json` and `runs/<run>-nobrief.json`, taking tokens + and tool calls from the transcripts. + +3. Score each run with `node scripts/grade.mjs runs/<run>-brief.json`. +4. Compare the two strategies question by question with + `node scripts/compare.mjs runs/<run>-brief.json runs/<run>-nobrief.json`. + It reports both scores, the questions only one got right, a sign test + on those, and read tokens, which leave out each session's fixed first + turn. + +Three rules shaped this protocol, each learned from a pilot below: + +- **One session per question.** A session that answers many questions + loads the graph once and spreads that cost across all of them, which + hides both the cost and the difficulty. +- **One graph command per tool call.** A shell loop that dumps every + Effort turns a recall test into a reading test. +- **Cost from the harness, never from the agent.** In pilot 1, agents' + own tallies were 2.4 and 4.5 times the harness counts. + +`scripts/prepare-run.mjs` and `scripts/collect.mjs` remain for runs +driven by hand. + +## Pilot results + +The first pilot (`runs/pilot-1-*.json`) drew a stratified sample of 46 +questions: 8 at each of tiers 0 to 3 and 14 at tier 4, from every Effort. Two +fresh agents answered all 46 in one session each, from clean run folders. +Audits of their tool calls found no access to answers. + +| Strategy | Correct | Tool calls | Tokens | Time | +| ------------- | -------- | ---------- | ------- | ------- | +| `brief` first | 46 of 46 | 46 | 203,004 | 7.3 min | +| no `brief` | 45 of 46 | 27 | 239,556 | 5.2 min | + +What it showed: + +1. **One session per batch puts the benchmark at its ceiling.** Both agents + read most of the graph early, then answered from it. Tiers stopped + mattering. The protocol above now asks for one session per question. +2. **The one miss was an exact count.** The no-`brief` agent counted 6 records + changed since the world compaction; there are 7. The `brief` envelope + reports that count directly. +3. **The grader was too strict.** Four answers carried the right value plus + detail ("46 player-proximity reads"). `grade.mjs` now accepts those. +4. **One run per strategy proves nothing about strategies.** The token gap is + a single pair of runs. + +### Pilot 2: one session per question + +The second pilot (`runs/pilot-2-*.json`) asked the same 46 questions, one +fresh Sonnet session per question and per strategy: 92 sessions. Costs come +from each session's transcript (`scripts/collect.mjs`). Every session ran on +Sonnet and wrote its answer. + +Five questions did not name their Effort, so agents could not tell which +Effort they meant, and both strategies missed all five. They now name it, and +`check.mjs` warns when an Effort-wide check would also find answers in +another Effort. Results on the other 41: + +| Strategy | Correct | Read tokens, mean | Read tokens, median | Tool calls, mean | +| ------------- | -------- | ----------------- | ------------------- | ---------------- | +| `brief` first | 38 of 41 | 15,365 | 14,786 | 12.3 | +| no `brief` | 39 of 41 | 18,624 | 18,014 | 12.1 | + +Read tokens leave out the roughly 19,300 tokens each session spent before +its first read. + +What it showed: + +1. **One session per question moves the benchmark off its ceiling, but not + far.** Accuracy fell from 98 to 100 percent in pilot 1 to 93 to 95 + percent. Tier 4 questions used about two-thirds more context tokens than + the rest. Both strategies missed the same two questions, `cross-017` and + `render-040`. Pilot 3 showed that both were flawed questions, not fair + traps (see below). Without them, `brief` scored 38 of 39 and no `brief` + 39 of 39. +2. **`brief` did not change accuracy.** Its one extra miss gave the right + record's id where the question asked for the title. +3. **`brief` cut read tokens by 17.5 percent on average, but not reliably.** + The median question saved about 1,000 tokens, and `brief` was cheaper on + only 22 of 41. + +### Pilot 3: Haiku + +The third pilot (`runs/pilot-3-*.json`) repeated pilot 2 on Haiku: the same +46 questions, one fresh session per question and per strategy. Every session +ran on Haiku and wrote its answer. + +Two questions were flawed, and are left out of the results below: + +- `render-040` did not name its Effort. Across all Efforts, the ports + compaction of 2026-03-10 really was newer than "Lantern at alpha" on beta + day, so that answer was a fair reading. `check.mjs` missed it because its + scope warning only tests Effort-wide checks, and this question's check + starts from one record. +- `cross-017` asked whether a quoted title was the Decision another Effort + names. Browse reads hide the retracted record with that exact title, so a + reader can fairly take the quote as a paraphrase of the live title. All + four runs across pilots 2 and 3 answered `true`. + +Both questions now say what they mean. One graph fact was wrong too: the +Skiff beta retrospective put the 6-week cost on a span the record dates make +about 18 weeks. It now says the beta slipped 6 weeks, and the answer is +unchanged. + +| Strategy | Correct | Read tokens, mean | Read tokens, median | Tool calls, mean | +| ------------- | -------- | ----------------- | ------------------- | ---------------- | +| `brief` first | 44 of 44 | 31,918 | 29,250 | 15.0 | +| no `brief` | 41 of 44 | 43,391 | 30,548 | 15.0 | + +Read tokens here leave out each session's own first turn, which varied more +on Haiku (median 12,200, mean 19,800) than the fixed 19,300 used for pilot 2. + +What it showed: + +1. **`brief` helped where the model was weaker.** The three questions that + only the no-`brief` arm missed were: + + - `world-069`, which asks how many records changed since the head + compaction. The agent counted 6; there are 7. It said itself that a + record changed in place leaves no dated trace in browse reads. The + `brief` envelope reports this count directly, and pilot 1 missed the + same question the same way. + - `tools-015` and `world-053`, where the agent gave up and answered + "unknown". On `world-053` it did so after 37 tool calls. + + That is 3 to 0 on the paired questions, still too few to rule out chance + (a two-sided sign test gives p = 0.25). + +2. **`brief` cut read tokens by 26 percent on average.** The median question + saved about 4,000 tokens, and `brief` was cheaper on 25 of 44. The mean + gap is larger than the median because the no-`brief` arm had a few very + long sessions, which is the cost `brief` is meant to remove. +3. **Haiku agents called tools they had no reason to call.** Most were + `send_message` calls to sessions that do not exist. One created an empty + cloud session and one scheduled a reminder, then deleted it. Midway + through the run, task files began to say "Use only the Bash, Read, and + Write tools". That cut the share of sessions making such calls from 24 of + 38 to 25 of 54, but did not stop them. Future runs should start agents + without session-control tools at all. + +All three steps this pilot called for are done: the scope warning covers +single-record checks, `run.mjs` starts agents without session-control +tools, and the full run below asks every question. + +### Full run: every question on Haiku + +The full run (`runs/full-haiku-*.json`) asked all 246 questions, one fresh +headless session per question and per strategy, through `run.mjs`: 492 +sessions, all on Haiku, all of which wrote an answer. No session could call +anything but Bash, Read, and Write. + +| Strategy | Correct | Read tokens, mean | Read tokens, median | Tool calls, mean | +| ------------- | ------------ | ----------------- | ------------------- | ---------------- | +| `brief` first | 221.4 of 246 | 25,949 | 20,848 | 13.0 | +| no `brief` | 226.3 of 246 | 33,703 | 29,233 | 13.0 | + +Fractions come from the rubric scores of text answers. Read tokens leave +out each session's first turn, about 1,200 tokens here: a headless session +carries a much smaller system prompt than the subagents of pilots 2 and 3. +That also changes how hard agents try, so accuracy here should not be +compared with the earlier pilots; compare the two strategies within a run. + +What it showed: + +1. **`brief` does not raise accuracy.** Twelve questions were right only + without `brief` and six only with it (two-sided sign test p = 0.24). Nine + of the twelve were "unknown" answers, where the `brief` agent gave up on + a fact the other agent found. Pilot 3's 3-to-0 edge for `brief` came + from which 46 questions it drew. On the 44 sound questions both runs + asked, each strategy changed its result on only 1 or 2, so the reversal + comes from the 200 questions pilot 3 left out, not from run-to-run + noise. +2. **`brief` cuts reading, reliably.** Read tokens fell by 23 percent on + average and 5,300 on the median question, and `brief` was cheaper on 157 + of 246. The gain is largest where `brief` was built to help: on the 20 + compaction questions it read 13,100 tokens against 44,000 and answered + all 20, against 19. +3. **Eight questions ask what no read command can show.** They ask about + retracted records: how many there are, or what one said. Browse reads + hide retracted records, and `get` needs an id the agent has no way to + learn. Every run in every pilot answered "unknown" to all eight + (`cross-003`, `cross-017`, `ports-032`, `render-011`, `render-074`, + `world-010`, `world-074`, `world-075`). They do not separate the + strategies, but they hold the retraction category at 38 percent. Proof + now lists them on request (see below). +4. **The runner ran every `brief` session first.** It now alternates + strategies question by question, so a change in API speed over a run + falls on both alike. + +### Retracted records become readable + +`proof records <effortId> --retracted only` now lists an Effort's retracted +records, and `--retracted include` lists them beside live ones. Every digest +marks each one: its index line ends in `(retracted)`, and a **RETRACTED** +banner with the date and reason sits under its heading. The task text tells +agents about the flag. + +A rerun of the eight retraction questions (`runs/retracted-haiku-*.json`) +scored 7 of 8 in each strategy, up from 0 of 8. Each strategy missed a +different question: `brief` answered "unknown" to `cross-017`, and no +`brief` did the same on `world-010`. + +### A graph ten times larger + +If the original graph were small enough to read whole, `brief` could only +save reading. A graph too large to read should let it help agents answer. +The 10x run (`runs/x10-haiku-*.json`) tested that. + +`node scripts/build.mjs --scale 10 --out <dir>` grew the graph from 498 +records to 4,980. The filler is routine measurements, captures, and small +question-to-decision threads about subsystems no question names. It never +links to a real record, and the head compaction of each Effort covers it. +`check.mjs --graph <dir>` showed every answer unchanged but one: +`world-077` counts question Issues, and filler adds 242. The run asked all +246 questions on Haiku, once per strategy, through one read server. + +On the 237 questions comparable with the full run (all but `world-077` and +the eight retraction questions, whose task text changed between runs): + +| Graph | Strategy | Correct | Read tokens, mean | Tool calls, mean | "unknown" | +| ----- | ------------- | ------- | ----------------- | ---------------- | --------- | +| 1x | `brief` first | 220.4 | 25,699 | 13 | 27 | +| 1x | no `brief` | 225.3 | 33,728 | 13 | 22 | +| 10x | `brief` first | 197.4 | 26,050 | 17 | 49 | +| 10x | no `brief` | 198.7 | 36,238 | 21 | 43 | + +What it showed: + +1. **A larger graph costs both strategies about ten points.** Accuracy fell + from 93 to 83 percent with `brief` and from 95 to 84 percent without. Most + new misses were give-ups: "unknown" answers nearly doubled. Agents named a + filler record once in 474 sessions, so noise hid answers rather than + misled agents. +2. **`brief` still does not raise accuracy.** Its deficit shrank from 4.8 + questions to 1.3, but per question it held up better on 26 and worse on + 22 (sign test p = 0.67). On render, the largest Effort, `brief` fell from + 75 to 69 against 77 to 66; on ports it fell further. The first theory, + that the graph was small enough to read whole, does not explain the + missing gain. +3. **Agents read about the same amount whatever the graph's size.** Read + tokens barely moved (26,000 and 36,000); tool calls rose from 13 to 17 + and 21. With roughly fixed reading, more noise means more misses. The + limit is finding a record by what it says, which neither a summary nor + paging through records does well. +4. **`brief` keeps its saving.** It read 28 percent less than no `brief`, + used 17 tool calls against 21, and was cheaper on 166 of 237. +5. **Reads were slow at this size.** Each read built the whole graph: 6 to + 9 seconds. `flatbread proof serve` now keeps it loaded, and a later read + takes 0.2 to 0.4 seconds. The first 29 sessions ran before the server + existed; that changes speed, not what an agent sees. A rebuild during the + run broke 22 sessions' reads; their answers were discarded and rerun. + +Next steps, in order: + +1. Test a read that finds records by their text, such as + `proof search <effortId> <words>`, against both strategies on the 10x + graph. Give-ups, not wrong answers, are what grew. +2. Look at the questions `brief` agents gave up on, to see whether the + summary steers agents away from records they should read. diff --git a/benchmarks/proof-recall/WORLD.md b/benchmarks/proof-recall/WORLD.md new file mode 100644 index 00000000..8d07e455 --- /dev/null +++ b/benchmarks/proof-recall/WORLD.md @@ -0,0 +1,103 @@ +# The benchmark world: Saltglass Reach + +Every record in this benchmark describes one fictional game project. The names +are invented so that no model can answer from what it already knows. Authors +must keep to the facts below so that the five Efforts agree with each other. + +## The game + +**Saltglass Reach** is a co-op exploration game for one to four players. +Players cross a coast of dunes made of _saltglass_: a refractive, partly +transparent crystal. Tides rise and fall on a 40-minute cycle and reshape the +terrain as they go, burying or exposing paths. A day lasts 90 minutes. + +The two features that drive the hardest engineering are: + +1. **Saltglass rendering.** Light refracts and casts caustics through glass + dunes, cliffs, and ruins seen from up to 2 km away. +2. **Tides.** The tide simulation changes the walkable world, so streaming, + physics, save games, and co-op sync all depend on it. + +## The studio and its people + +The studio is **Tidewater Forge**. Use these names in `created_by` and in +prose. Refer to people by name, never by pronoun. + +| Name | Role | Usual Effort | +| --------------- | ------------------------- | ------------ | +| Ines Okafor | Rendering lead | render | +| Tomasz Brandt | Graphics engineer | render | +| Yusuf Demir | Technical artist | render | +| Rhea Valdés | Engine lead | world | +| Kenji Arakawa | Streaming engineer | world | +| Marta Lindqvist | Gameplay systems engineer | world | +| Priya Natarajan | Platform engineer | ports | +| Liam O'Connell | Build and tools engineer | tools | +| Sofia Marchetti | Network engineer | netcode | +| Dara Whitlock | Producer | any | + +## The technology + +- **Kestrel** is the in-house engine. +- **Lantern** is Kestrel's renderer. +- **Gull** is Kestrel's gameplay scripting language. +- **Tern** is the studio's own temporal upscaler, written inside Lantern. +- **Kelp** is the studio's own asset compression codec. + +## Platforms + +| Platform | Kind | Memory for the game | Display targets | +| -------- | ---------------- | ------------------- | ------------------------ | +| PC | Desktop | varies | 60 Hz and 120 Hz | +| Meridian | Home console | 13.5 GB | 60 Hz; 120 Hz mode later | +| Skiff | Handheld console | 9 GB, later 8 GB | 30 Hz and 40 Hz | + +Meridian and Skiff are fictional consoles. Ports own Skiff's numbers. + +## Timeline + +The project runs from **2025-09-01** to **2026-09-30**. All record times fall +inside it. + +| Date | Milestone | +| ---------- | ------------------------------------------ | +| 2025-09-01 | Pre-production starts | +| 2025-12-15 | Vertical slice | +| 2026-03-02 | Alpha | +| 2026-06-01 | Beta; Skiff port becomes a launch platform | +| 2026-08-24 | Content lock | +| 2026-09-30 | Release candidate | + +## The Efforts + +Five Efforts hold the work. Each has its own spec file and question file. + +| Key | Title | Size | Final status | +| --------- | ------------------------------------------- | ------- | ------------ | +| `render` | Lantern renderer overhaul | complex | active | +| `world` | Kestrel world streaming and simulation core | complex | active | +| `ports` | Meridian and Skiff ports | medium | active | +| `tools` | Shader compile cache and build farm | small | completed | +| `netcode` | Co-op rollback netcode prototype | small | abandoned | + +Proof forbids links between Efforts. When one Effort depends on another, its +record names the other record by its exact title in prose. These shared facts +must appear on both sides, in the form given here: + +1. **Tide determinism.** `world` decides the tide simulation uses 32.32 + fixed-point math, after a finding that float tides drift apart between + machines within 6 minutes. `netcode`'s final Decision to abandon rollback + names that world Decision by title, and its reason: rollback must re-run + tides every frame, which costs 4.8 ms on Skiff. +2. **Memory.** `ports` owns the Skiff memory Constraint (9 GB, later cut to + 8 GB). `world` owns the streaming pool Constraint (2.0 GB, later 1.6 GB); + its cut names the Skiff Constraint by title as the reason. +3. **Frame rates.** `render` owns the Meridian 120 Hz performance mode and its + 8.3 ms budget. `ports` owns the Skiff 40 Hz mode and its 25 ms budget. Both + Efforts contain a Constraint titled "Frame budget", so a careless reader + confuses them. +4. **Shader caches.** `tools` owns the build farm's shader compile cache. + `ports` owns the on-device pipeline cache for Skiff. Both are called + "shader cache" in casual prose. +5. **Upscaling.** `render` owns Tern. `ports` decides Skiff runs Tern at a + lower quality preset; that record names the render Decision by title. diff --git a/benchmarks/proof-recall/flatbread.config.js b/benchmarks/proof-recall/flatbread.config.js new file mode 100644 index 00000000..0563dd50 --- /dev/null +++ b/benchmarks/proof-recall/flatbread.config.js @@ -0,0 +1,12 @@ +import { source as filesystem } from '@flatbread/source-filesystem'; +import { transformer as markdownTransformer } from '@flatbread/transformer-markdown'; +import { defineConfig } from '@flatbread/config'; +import { proofContent } from '@flatbread/proof'; + +// The benchmark graph is a separate Proof root, so its fictional records never +// mix with the repository's own memory. Run `flatbread proof …` from here. +export default defineConfig({ + source: filesystem(), + transformer: markdownTransformer(), + content: proofContent(), +}); diff --git a/benchmarks/proof-recall/questions/cross.json b/benchmarks/proof-recall/questions/cross.json new file mode 100644 index 00000000..c6bd6477 --- /dev/null +++ b/benchmarks/proof-recall/questions/cross.json @@ -0,0 +1,458 @@ +{ + "effort": "cross", + "questions": [ + { + "id": "cross-001", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "distractor", "current-state"], + "question": "Which record sets the current per-frame budget for Skiff's 40 Hz mode?", + "answer": { "kind": "record", "value": "ports.con-frame-2" }, + "evidence": [ + "ports.con-frame-2", + "ports.con-frame-1", + "render.con-budget-3", + "render.con-budget-noise", + "ports.con-noise-frame" + ], + "checks": [ + { + "type": "select", + "effort": "*", + "kinds": ["constraint"], + "where": { "title": "Frame budget" }, + "live": true, + "bodyIncludes": "40 Hz mode: 25 ms" + }, + { + "type": "head", + "start": "ports.con-frame-1", + "expect": "ports.con-frame-2" + } + ], + "traps": [ + "Four Constraints share the title \"Frame budget\". The render Effort's live one covers Meridian at 16.6 ms.", + "The render Effort holds a retracted \"Frame budget\" with the 25 ms Skiff figure; retracted records are not current." + ] + }, + { + "id": "cross-002", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "aggregate", "distractor"], + "question": "Across every Effort, how many live Constraints are titled \"Frame budget\"?", + "answer": { "kind": "count", "value": 2 }, + "evidence": ["render.con-budget-3", "ports.con-frame-2"], + "checks": [ + { + "type": "select", + "effort": "*", + "kinds": ["constraint"], + "where": { "title": "Frame budget" }, + "live": true, + "count": true + } + ], + "traps": [ + "Counting superseded or retracted versions gives 7.", + "Reading one Effort gives 1." + ] + }, + { + "id": "cross-003", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "aggregate", "retraction"], + "question": "Across every Effort, how many retracted records are titled exactly \"Frame budget\"?", + "answer": { "kind": "count", "value": 2 }, + "evidence": ["render.con-budget-noise", "ports.con-noise-frame"], + "checks": [ + { + "type": "select", + "effort": "*", + "where": { "title": "Frame budget" }, + "retracted": "only", + "count": true + } + ], + "traps": [ + "Browse reads omit retracted records, so a reader using only `records` finds none." + ] + }, + { + "id": "cross-004", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "lookup", "lifecycle"], + "question": "The co-op rollback prototype was abandoned because of a Decision made in a different Effort. Which Decision?", + "answer": { "kind": "record", "value": "world.dec-tide-fixed" }, + "evidence": ["netcode.dec-abandon", "world.dec-tide-fixed"], + "checks": [ + { + "type": "select", + "effort": "world", + "kinds": ["decision"], + "where": { "title": "Run the tide simulation in 32.32 fixed point" } + }, + { + "type": "body", + "record": "netcode.dec-abandon", + "includes": "Run the tide simulation in 32.32 fixed point", + "expect": true + } + ], + "traps": [ + "The netcode Effort is abandoned, so `proof list` with its default status hides it.", + "The answer is named only by title in prose; no edge links the two Efforts." + ] + }, + { + "id": "cross-005", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "lookup"], + "question": "Who wrote the Decision that the netcode Effort cites as the reason it abandoned rollback?", + "answer": { + "kind": "value", + "value": "Rhea Valdés", + "accept": ["Rhea Valdes"] + }, + "evidence": ["netcode.dec-abandon", "world.dec-tide-fixed"], + "checks": [ + { + "type": "field", + "record": "world.dec-tide-fixed", + "field": "created_by" + } + ], + "traps": [ + "Sofia Marchetti wrote the abandonment Decision, not the Decision it cites." + ] + }, + { + "id": "cross-006", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "lookup"], + "question": "Rollback had to re-run the tides every frame on Skiff. Roughly what share of the Skiff 40 Hz frame budget did that cost?", + "answer": { + "kind": "value", + "value": "a fifth", + "accept": ["one fifth", "1/5", "19.2%", "19%", "about 20%", "20%"] + }, + "evidence": ["netcode.dec-abandon", "ports.con-frame-2"], + "checks": [ + { + "type": "body", + "record": "netcode.dec-abandon", + "includes": ["4.8 ms", "a fifth of the 25 ms frame"], + "expect": true + }, + { + "type": "body", + "record": "ports.con-frame-2", + "includes": "40 Hz mode: 25 ms", + "expect": true + } + ], + "traps": [ + "Using the 33.3 ms 30 Hz frame gives about 14 percent.", + "Using the render Effort's 16.6 ms Frame budget gives about 29 percent." + ] + }, + { + "id": "cross-007", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "current-state", "supersession"], + "question": "The streaming pool's last size cut names a Skiff memory limit from another Effort as its reason. What is that Skiff limit today?", + "answer": { "kind": "value", "value": "8 GB", "accept": ["8GB"] }, + "evidence": [ + "world.con-pool-2", + "world.con-pool-3", + "ports.con-skiff-mem-9", + "ports.con-skiff-mem-8" + ], + "checks": [ + { + "type": "head", + "start": "ports.con-skiff-mem-9", + "expect": "ports.con-skiff-mem-8" + }, + { + "type": "body", + "record": "ports.con-skiff-mem-8", + "includes": "at most 8 GB on Skiff", + "expect": true + } + ], + "traps": [ + "Both versions of \"Skiff memory budget\" share a title; the 9 GB one is superseded.", + "The streaming pool's own figure, 1.6 GB, is not the Skiff limit." + ] + }, + { + "id": "cross-008", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "temporal", "negative"], + "question": "What Skiff memory budget was in force when the world Effort first set the streaming pool budget?", + "answer": { "kind": "value", "value": "unknown" }, + "evidence": ["world.con-pool-1", "ports.con-skiff-mem-9"], + "checks": [ + { + "type": "asof", + "start": "ports.con-skiff-mem-8", + "at": "2025-09-12T23:59:59Z", + "expect": null + }, + { + "type": "field", + "record": "world.con-pool-1", + "field": "created_at", + "expect": "2025-09-12T10:00:00Z" + } + ], + "traps": [ + "The first streaming pool budget dates from September 2025; the first Skiff memory budget was written in late October 2025. Answering 9 GB assumes a record that did not yet exist." + ] + }, + { + "id": "cross-009", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "temporal", "supersession"], + "question": "When the world Effort cut the streaming pool to 1.6 GB, which version of the Skiff memory budget was current?", + "answer": { "kind": "record", "value": "ports.con-skiff-mem-8" }, + "evidence": [ + "world.con-pool-2", + "ports.con-skiff-mem-9", + "ports.con-skiff-mem-8" + ], + "checks": [ + { + "type": "asof", + "start": "ports.con-skiff-mem-9", + "at": "2026-06-04T09:00:00Z" + } + ], + "traps": [ + "The cut was made in June, four months after the 8 GB version replaced the 9 GB one in February." + ] + }, + { + "id": "cross-010", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "distractor", "lookup"], + "question": "Skiff players stop hitching on their second visit to a district because of a shader cache. Which Decision created that cache?", + "answer": { "kind": "record", "value": "ports.dec-pso-ondevice" }, + "evidence": [ + "ports.dec-pso-ondevice", + "ports.fnd-cache-warm", + "tools.dec-cache" + ], + "checks": [ + { + "type": "select", + "effort": ["ports", "tools"], + "kinds": ["decision"], + "where": { "state": "accepted" }, + "bodyIncludes": "Everyone on the team calls this the shader cache" + } + ], + "traps": [ + "The tools Effort's content-addressed shader compile cache speeds up the build farm and never reaches players." + ] + }, + { + "id": "cross-011", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "distractor", "negative"], + "question": "Does the build farm's shader compile cache ship to players on Skiff?", + "answer": { "kind": "boolean", "value": false }, + "evidence": ["ports.dec-pso-ondevice", "tools.dec-cache"], + "checks": [ + { + "type": "body", + "record": "ports.dec-pso-ondevice", + "includes": "never ships to players", + "expect": true + } + ], + "traps": [ + "Both caches are called \"shader cache\" in casual prose; only the on-device pipeline cache runs on Skiff." + ] + }, + { + "id": "cross-012", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "truncation", "invalidation"], + "question": "Streaming on Skiff must also work for players who install to budget microSD cards. What is the worst sustained read rate measured on those cards when full and warm?", + "answer": { "kind": "value", "value": "61 MB/s", "accept": ["61"] }, + "evidence": [ + "ports.fnd-sd-speed-2", + "ports.fnd-sd-speed", + "world.fnd-io-trace-2" + ], + "checks": [ + { + "type": "body", + "record": "ports.fnd-sd-speed-2", + "includes": "61 MB/s", + "afterExcerpt": true, + "expect": true + }, + { + "type": "field", + "record": "ports.fnd-sd-speed", + "field": "standing", + "expect": "invalidated" + } + ], + "traps": [ + "The world Effort's 190 MB/s is internal storage on retail units.", + "The ports Finding of 92 MB/s used new, empty cards on a cold Skiff and was invalidated.", + "The 61 MB/s figure sits past the browse excerpt." + ] + }, + { + "id": "cross-013", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "lookup"], + "question": "The Meridian 120 Hz mode lets Tern drop to its lowest preset. Which preset does the Skiff port run Tern at, and how many milliseconds does it save over Quality?", + "answer": { + "kind": "text", + "rubric": [["Performance"], ["1.8 ms", "1.8ms"]] + }, + "evidence": [ + "ports.dec-tern-skiff", + "render.con-120-2", + "render.dec-tern" + ], + "checks": [ + { + "type": "body", + "record": "ports.dec-tern-skiff", + "includes": ["Performance preset", "The 1.8 ms saved"], + "expect": true + } + ], + "traps": [ + "The render Effort owns Tern, but the Skiff preset choice lives in the ports Effort." + ] + }, + { + "id": "cross-014", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "aggregate", "lifecycle"], + "question": "How many Efforts are still active?", + "answer": { "kind": "count", "value": 3 }, + "evidence": [ + "render.effort", + "world.effort", + "ports.effort", + "tools.effort", + "netcode.effort" + ], + "checks": [ + { "type": "efforts", "where": { "status": "active" }, "count": true } + ], + "traps": [ + "Counting every Effort gives 5; the tools Effort is completed and the netcode Effort abandoned." + ] + }, + { + "id": "cross-015", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "lifecycle"], + "question": "Which Efforts are no longer active, and how did each one end?", + "answer": { + "kind": "text", + "rubric": [ + ["shader compile cache", "build farm", "tools"], + ["completed"], + ["rollback", "netcode"], + ["abandoned"] + ] + }, + "evidence": ["tools.effort", "netcode.effort"], + "checks": [ + { + "type": "efforts", + "where": { "status": ["completed", "abandoned"] }, + "expect": ["netcode.effort", "tools.effort"] + } + ], + "traps": [ + "`proof list` shows only active Efforts unless asked for other statuses." + ] + }, + { + "id": "cross-016", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "distractor", "current-state"], + "question": "How many milliseconds per frame separate the Meridian 120 Hz mode's budget from the Skiff 40 Hz mode's budget?", + "answer": { + "kind": "value", + "value": "16.7 ms", + "accept": ["16.7", "16.7ms"] + }, + "evidence": ["render.con-120-2", "ports.con-frame-2"], + "checks": [ + { + "type": "body", + "record": "render.con-120-2", + "includes": "Each frame gets 8.3 ms", + "expect": true + }, + { + "type": "body", + "record": "ports.con-frame-2", + "includes": "40 Hz mode: 25 ms", + "expect": true + } + ], + "traps": [ + "Using the render Effort's \"Frame budget\" of 16.6 ms gives 8.4 ms.", + "The 120 Hz budget's first version was soft and superseded; the current one is hard at 8.3 ms." + ] + }, + { + "id": "cross-017", + "tier": 4, + "hops": 0, + "categories": ["cross-effort", "retraction", "distractor"], + "question": "Is the record titled exactly \"Ship Tern as the only upscaler in Lantern\" the Decision that the Skiff port names as its reason for using Tern?", + "answer": { "kind": "boolean", "value": false }, + "evidence": [ + "render.dec-tern", + "render.dec-tern-dup", + "ports.dec-tern-skiff" + ], + "checks": [ + { + "type": "field", + "record": "render.dec-tern-dup", + "field": "standing", + "expect": "retracted" + }, + { + "type": "body", + "record": "ports.dec-tern-skiff", + "includes": "\"Ship Tern as Lantern's only upscaler\"", + "expect": true + } + ], + "traps": [ + "The near-identical title is a retracted duplicate; the ports Decision names \"Ship Tern as Lantern's only upscaler\"." + ] + } + ] +} diff --git a/benchmarks/proof-recall/questions/netcode.json b/benchmarks/proof-recall/questions/netcode.json new file mode 100644 index 00000000..0452de1f --- /dev/null +++ b/benchmarks/proof-recall/questions/netcode.json @@ -0,0 +1,492 @@ +{ + "effort": "netcode", + "questions": [ + { + "id": "netcode-001", + "tier": 0, + "hops": 0, + "categories": ["lifecycle", "current-state"], + "question": "What is the status of the Effort that prototyped rollback netcode for co-op?", + "answer": { + "kind": "value", + "value": "abandoned" + }, + "evidence": ["effort"], + "checks": [ + { + "type": "field", + "record": "effort", + "field": "status" + } + ], + "traps": [ + "A plain `proof list` shows only active Efforts, so a reader who stops there may say the Effort does not exist or still call it active." + ] + }, + { + "id": "netcode-002", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "Where was the rollback prototype code kept after the team stopped work on it?", + "answer": { + "kind": "value", + "value": "netcode/rollback-archive", + "accept": [ + "branch netcode/rollback-archive", + "the netcode/rollback-archive branch" + ] + }, + "evidence": ["dec-abandon"], + "checks": [ + { + "type": "body", + "record": "dec-abandon", + "includes": "netcode/rollback-archive", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "The branch name sits at the end of a long Decision body, past the 600-character excerpt that list and records digests show." + ] + }, + { + "id": "netcode-003", + "tier": 0, + "hops": 0, + "categories": ["lookup", "retraction", "distractor"], + "question": "How large is one player's rollback snapshot for a single frame?", + "answer": { + "kind": "value", + "value": "38 KB", + "accept": ["38", "38 kilobytes"] + }, + "evidence": ["fnd-snapshot", "fnd-noise"], + "checks": [ + { + "type": "body", + "record": "fnd-snapshot", + "includes": "38 KB per frame", + "expect": true + }, + { + "type": "field", + "record": "fnd-noise", + "field": "standing", + "expect": "retracted" + } + ], + "traps": [ + "A retracted Finding gives 14 KB per player; it measured save-game snapshots and was filed here by mistake.", + "About 600 KB is the whole 4-frame ring for four players, not one player's frame." + ] + }, + { + "id": "netcode-004", + "tier": 0, + "hops": 0, + "categories": ["rationale", "lookup"], + "question": "Why did the team abandon rollback netcode for co-op, and which world Decision does the reason depend on?", + "answer": { + "kind": "text", + "rubric": [ + ["4.8 ms"], + ["Skiff"], + [ + "every frame", + "each frame", + "every rolled-back frame", + "re-run tides", + "re-running tides", + "re-simulate tides" + ], + [ + "Run the tide simulation in 32.32 fixed point", + "32.32 fixed point", + "32.32 fixed-point", + "32-32-fixed-point" + ] + ] + }, + "evidence": ["dec-abandon"], + "checks": [ + { + "type": "body", + "record": "dec-abandon", + "includes": [ + "4.8 ms on Skiff", + "Run the tide simulation in 32.32 fixed point", + "re-run tides every frame" + ], + "expect": true + } + ], + "traps": [ + "Lockstep's input delay was the reason lockstep lost, not rollback.", + "The world Decision is named only by title; Proof forbids links between Efforts." + ] + }, + { + "id": "netcode-005", + "tier": 0, + "hops": 0, + "categories": ["negative"], + "question": "What snapshot send rate did the team choose for host-authoritative co-op?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": ["dec-host"], + "checks": [ + { + "type": "body", + "record": "dec-host", + "includes": "send rate is not chosen yet", + "expect": true + } + ], + "traps": [ + "The checksum Decision sends hashes every 30 frames; that is not a snapshot send rate.", + "Lockstep's 1.2 KB/s per peer is network traffic for a rejected model." + ] + }, + { + "id": "netcode-006", + "tier": 1, + "hops": 1, + "categories": ["rejected-alternative"], + "question": "Which Decision rejected deterministic lockstep for co-op?", + "answer": { + "kind": "record", + "value": "dec-rollback" + }, + "evidence": ["dec-lockstep", "dec-rollback"], + "path": [["dec-lockstep", "rejected_by", "dec-rollback"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "where": { + "standing": "superseded" + }, + "derivesFrom": "iss-sync" + }, + { + "type": "edge", + "edge": ["dec-lockstep", "rejected_by", "dec-rollback"], + "expect": true + } + ], + "traps": [ + "The host-authoritative Decision is today's answer to the sync question, but it rejected nothing; lockstep was already rejected.", + "The lockstep playtest Finding explains the loss but is not a Decision." + ] + }, + { + "id": "netcode-007", + "tier": 1, + "hops": 1, + "categories": ["supersession", "current-state"], + "question": "Which Decision replaced the plan to prototype rollback netcode for co-op?", + "answer": { + "kind": "record", + "value": "dec-abandon" + }, + "evidence": ["dec-rollback", "dec-abandon"], + "path": [["dec-rollback", "superseded_by", "dec-abandon"]], + "checks": [ + { + "type": "head", + "start": "dec-rollback" + } + ], + "traps": [ + "The host-authoritative Decision came next and derives from the abandonment, but it does not supersede the rollback Decision." + ] + }, + { + "id": "netcode-008", + "tier": 2, + "hops": 2, + "categories": ["temporal", "supersession"], + "question": "Which rollback window Decision was in force at the vertical slice on 15 December 2025?", + "answer": { + "kind": "record", + "value": "dec-window-v1" + }, + "evidence": ["dec-window-v3", "dec-window-v2", "dec-window-v1"], + "path": [ + ["dec-window-v3", "supersedes", "dec-window-v2"], + ["dec-window-v2", "supersedes", "dec-window-v1"] + ], + "checks": [ + { + "type": "asof", + "start": "dec-window-v3", + "at": "2025-12-15T00:00:00Z" + } + ], + "traps": [ + "The current head is the 6-frame window with 1 frame of input delay, adopted in February 2026.", + "The 7-frame window came in January 2026, after the Skiff Wi-Fi measurements." + ] + }, + { + "id": "netcode-009", + "tier": 2, + "hops": 3, + "categories": ["blob"], + "question": "In the Skiff profile capture behind the decision to abandon rollback, how long did physics re-simulation take per rollback?", + "answer": { + "kind": "value", + "value": "1.9 ms", + "accept": ["1.9", "1.9 milliseconds"] + }, + "evidence": [ + "dec-abandon", + "fnd-tide-cost", + "cit-capture", + "blb-capture" + ], + "path": [ + ["dec-abandon", "derives_from", "fnd-tide-cost"], + ["fnd-tide-cost", "cites", "cit-capture"], + ["cit-capture", "blob", "blb-capture"] + ], + "checks": [ + { + "type": "body", + "record": "blb-capture", + "includes": "\"physics_resim\": 1.9", + "expect": true + } + ], + "traps": [ + "4.8 ms is the tide re-simulation, not physics.", + "0.8 ms is one tide step.", + "Blob bodies are left out of list and records digests; only `proof get` on the Blob shows the numbers." + ] + }, + { + "id": "netcode-010", + "tier": 2, + "hops": 2, + "categories": ["dead-evidence", "invalidation"], + "question": "Which accepted Decision in the co-op netcode Effort still rests on a cost measurement that was later shown to be wrong?", + "answer": { + "kind": "record", + "value": "dec-window-v3" + }, + "evidence": ["dec-window-v3", "fnd-prototype-cost", "fnd-tide-cost"], + "path": [ + ["dec-window-v3", "derives_from", "fnd-prototype-cost"], + ["fnd-prototype-cost", "invalidated_by", "fnd-tide-cost"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "where": { + "standing": "accepted" + }, + "restsOn": ["invalidated"] + } + ], + "traps": [ + "The 4-frame window also rests on the 1.1 ms measurement, but it is superseded, not accepted.", + "The realized re-simulation Risk rests on the same measurement but is a Risk, not a Decision." + ], + "scoped": true + }, + { + "id": "netcode-011", + "tier": 2, + "hops": 2, + "categories": ["rejected-alternative", "rationale"], + "question": "The quarter-resolution tide re-simulation proposal was disproved by one Finding and rejected by one Decision. Which Constraint do both that Finding and that Decision rest on?", + "answer": { + "kind": "record", + "value": "con-determinism" + }, + "evidence": [ + "dec-tide-lod", + "fnd-lod-desync", + "dec-abandon", + "con-determinism" + ], + "path": [ + ["dec-tide-lod", "rejected_by", "dec-abandon"], + ["dec-abandon", "derives_from", "con-determinism"] + ], + "checks": [ + { + "type": "select", + "kinds": ["constraint"], + "bodyIncludes": "single cell" + }, + { + "type": "edge", + "edge": ["dec-abandon", "derives_from", "con-determinism"], + "expect": true + }, + { + "type": "edge", + "edge": ["fnd-lod-desync", "derives_from", "con-determinism"], + "expect": true + } + ], + "traps": [ + "The 150 ms round-trip Constraint feeds the rollback and host-authoritative Decisions, not the abandonment or the desync Finding.", + "The 25 ms Skiff frame appears in prose but is not a Constraint record in this Effort." + ] + }, + { + "id": "netcode-012", + "tier": 3, + "hops": 4, + "categories": ["rejected-alternative", "supersession"], + "question": "Start from the lockstep playtest. The option it tested lost to another Decision, and that winner was later replaced. Which proposal did the replacing Decision reject?", + "answer": { + "kind": "record", + "value": "dec-tide-lod" + }, + "evidence": [ + "fnd-lockstep-test", + "dec-lockstep", + "dec-rollback", + "dec-abandon", + "dec-tide-lod" + ], + "path": [ + ["fnd-lockstep-test", "derives_from", "dec-lockstep"], + ["dec-lockstep", "rejected_by", "dec-rollback"], + ["dec-rollback", "superseded_by", "dec-abandon"], + ["dec-tide-lod", "rejected_by", "dec-abandon"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "where": { + "standing": "rejected" + }, + "derivesFrom": "fnd-tide-cost" + }, + { + "type": "edge", + "edge": ["dec-tide-lod", "rejected_by", "dec-abandon"], + "expect": true + } + ], + "traps": [ + "Lockstep is also rejected, but by the rollback Decision, not by its replacement.", + "The host-authoritative Decision rejected nothing." + ] + }, + { + "id": "netcode-013", + "tier": 4, + "hops": 1, + "categories": ["compaction", "aggregate"], + "question": "Which of the records the latest co-op netcode summary rests on have changed standing since that summary was written?", + "answer": { + "kind": "records", + "value": ["dec-rollback", "fnd-prototype-cost", "rsk-resim"] + }, + "evidence": [ + "cmp-feb", + "dec-rollback", + "fnd-prototype-cost", + "rsk-resim", + "dec-abandon", + "fnd-tide-cost" + ], + "path": [ + ["cmp-feb", "derives_from", "dec-rollback"], + ["cmp-feb", "derives_from", "fnd-prototype-cost"], + ["cmp-feb", "derives_from", "rsk-resim"] + ], + "checks": [ + { + "type": "compaction", + "field": "staleTargets" + }, + { + "type": "compaction", + "field": "stale", + "expect": true + } + ], + "traps": [ + "The summary still calls rollback the chosen model and gives the disproved 1.1 ms cost; it predates the abandonment.", + "The 6-frame window Decision is still accepted, so it has not changed standing even though the Effort was abandoned." + ], + "scoped": true + }, + { + "id": "netcode-014", + "tier": 4, + "hops": 0, + "categories": ["lifecycle", "blocker", "current-state"], + "question": "Which Issues were still open when the co-op netcode Effort was abandoned?", + "answer": { + "kind": "records", + "value": ["iss-late-join"] + }, + "evidence": [ + "iss-late-join", + "iss-sync", + "iss-skiff-profile", + "iss-desync-debug" + ], + "checks": [ + { + "type": "select", + "kinds": ["issue"], + "where": { + "standing": "open" + } + } + ], + "traps": [ + "The sync question was resolved by the host-authoritative Decision.", + "The Skiff profiling gap and the desync tooling gap were both resolved." + ], + "scoped": true + }, + { + "id": "netcode-015", + "tier": 4, + "hops": 0, + "categories": ["aggregate", "rejected-alternative"], + "question": "How many Decisions in the co-op netcode Effort ended up rejected?", + "answer": { + "kind": "count", + "value": 2 + }, + "evidence": [ + "dec-lockstep", + "dec-tide-lod", + "dec-rollback", + "dec-window-v1", + "dec-window-v2" + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "where": { + "standing": "rejected" + }, + "count": true + } + ], + "traps": [ + "The rollback Decision was superseded by the abandonment, not rejected.", + "The two older window sizes were superseded, not rejected; counting superseded Decisions gives 5." + ], + "scoped": true + } + ] +} diff --git a/benchmarks/proof-recall/questions/ports.json b/benchmarks/proof-recall/questions/ports.json new file mode 100644 index 00000000..5e2b455d --- /dev/null +++ b/benchmarks/proof-recall/questions/ports.json @@ -0,0 +1,1060 @@ +{ + "effort": "ports", + "questions": [ + { + "id": "ports-001", + "tier": 0, + "hops": 0, + "categories": ["lookup", "distractor"], + "question": "How many milliseconds does each frame get in the Skiff 40 Hz mode?", + "answer": { + "kind": "value", + "value": "25", + "accept": ["25 ms", "25 milliseconds"] + }, + "evidence": ["con-frame-2"], + "path": [], + "checks": [ + { + "type": "body", + "record": "con-frame-2", + "includes": "Skiff 40 Hz mode: 25 ms per frame", + "expect": true + } + ], + "traps": [ + "33.3 ms is the 30 Hz budget, and the only figure in the older Frame budget record.", + "8.3 ms comes from a retracted Frame budget copied from the render Effort's Meridian 120 Hz mode." + ] + }, + { + "id": "ports-002", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "How large may the on-device pipeline cache grow on a Skiff's storage?", + "answer": { + "kind": "value", + "value": "384 MB", + "accept": ["384", "384 megabytes"] + }, + "evidence": ["dec-pso-ondevice"], + "path": [], + "checks": [ + { + "type": "body", + "record": "dec-pso-ondevice", + "includes": "capped at 384 MB", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "212 MB is how much the cache held after a full playthrough, not its cap.", + "140 MB is the size of the prebuilt blobs the cache replaced." + ] + }, + { + "id": "ports-003", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "What was the worst sustained read rate on a Skiff microSD card that was nearly full and warm?", + "answer": { + "kind": "value", + "value": "61 MB/s", + "accept": ["61", "61 MB per second"] + }, + "evidence": ["fnd-sd-speed-2"], + "path": [], + "checks": [ + { + "type": "body", + "record": "fnd-sd-speed-2", + "includes": "61 MB/s", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "92 MB/s is the March figure from new, empty cards on a cold Skiff, later shown wrong." + ] + }, + { + "id": "ports-004", + "tier": 0, + "hops": 0, + "categories": ["lifecycle"], + "question": "In what state did the ports team leave the risk that Skiff throttles its GPU in long handheld sessions?", + "answer": { + "kind": "value", + "value": "accepted" + }, + "evidence": ["rsk-thermal", "fnd-thermal"], + "path": [], + "checks": [ + { + "type": "field", + "record": "rsk-thermal", + "field": "state" + } + ], + "traps": [ + "The risk was neither mitigated by a Decision nor realized; the 8 percent drop was absorbed and the risk accepted." + ] + }, + { + "id": "ports-005", + "tier": 0, + "hops": 0, + "categories": ["negative", "lifecycle"], + "question": "On what date did Saltglass Reach pass full Skiff certification?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": ["iss-blk-storm", "rsk-cert-slip", "fnd-cert-report"], + "path": [], + "checks": [ + { + "type": "field", + "record": "iss-blk-storm", + "field": "status", + "expect": "open" + }, + { + "type": "field", + "record": "rsk-cert-slip", + "field": "state", + "expect": "open" + } + ], + "traps": [ + "2026-05-15 is when the pre-certification report came back, with two failures.", + "2026-06-01 is when Skiff became a launch platform, not a certification date." + ] + }, + { + "id": "ports-034", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "According to the Skiff beta retrospective, how much schedule did the wrong pipeline choice cost?", + "answer": { + "kind": "value", + "value": "6 weeks", + "accept": ["6", "six weeks"] + }, + "evidence": ["fnd-retro"], + "path": [], + "checks": [ + { + "type": "body", + "record": "fnd-retro", + "includes": "cost 6 weeks of schedule", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "The Kelp switch took one week; that figure sits earlier in the same record." + ] + }, + { + "id": "ports-006", + "tier": 1, + "hops": 1, + "categories": ["supersession", "current-state"], + "question": "Which record holds the Skiff memory budget the ports team works to today?", + "answer": { + "kind": "record", + "value": "con-skiff-mem-8" + }, + "evidence": ["con-skiff-mem-9", "con-skiff-mem-8"], + "path": [["con-skiff-mem-9", "superseded_by", "con-skiff-mem-8"]], + "checks": [ + { + "type": "head", + "start": "con-skiff-mem-9" + } + ], + "traps": [ + "Both versions share the title Skiff memory budget; the 9 GB version was superseded." + ] + }, + { + "id": "ports-007", + "tier": 1, + "hops": 1, + "categories": ["blob"], + "question": "In the Skiff pre-certification report attached to the ports work, what defect code did the platform holder give the HUD text failure?", + "answer": { + "kind": "value", + "value": "SKF-UI-031" + }, + "evidence": ["cit-cert-report", "blb-cert-report"], + "path": [["cit-cert-report", "blob", "blb-cert-report"]], + "checks": [ + { + "type": "body", + "record": "blb-cert-report", + "includes": "| SKF-UI-031 | Interface | Fail |", + "expect": true + } + ], + "traps": [ + "SKF-ST-012 is the autosave failure and SKF-DSP-004 the docked judder advisory." + ] + }, + { + "id": "ports-008", + "tier": 1, + "hops": 1, + "categories": ["rejected-alternative"], + "question": "Which Decision's acceptance rejected the spatial upscaler option for Skiff?", + "answer": { + "kind": "record", + "value": "dec-tern-skiff" + }, + "evidence": ["dec-skiff-spatial", "dec-tern-skiff"], + "path": [["dec-skiff-spatial", "rejected_by", "dec-tern-skiff"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "iss-upscale-q", + "where": { + "state": "accepted" + } + }, + { + "type": "edge", + "edge": ["dec-skiff-spatial", "rejected_by", "dec-tern-skiff"], + "expect": true + } + ], + "traps": [ + "The native 720p option was rejected by the same acceptance; it is a fellow loser, not the rejecter." + ] + }, + { + "id": "ports-009", + "tier": 1, + "hops": 1, + "categories": ["invalidation"], + "question": "Which Decision did the full-card microSD measurement prove wrong?", + "answer": { + "kind": "record", + "value": "dec-seamless-ft" + }, + "evidence": ["fnd-sd-speed-2", "dec-seamless-ft"], + "path": [["fnd-sd-speed-2", "invalidates", "dec-seamless-ft"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "where": { + "standing": "invalidated" + } + }, + { + "type": "edge", + "edge": ["fnd-sd-speed-2", "invalidates", "dec-seamless-ft"], + "expect": true + } + ], + "traps": [ + "The same Finding also invalidates the 92 MB/s Finding, but that is a Finding, not a Decision.", + "The 2 MB streaming read Decision rests on the bad number but was never invalidated." + ], + "scoped": true + }, + { + "id": "ports-010", + "tier": 1, + "hops": 1, + "categories": ["temporal", "supersession", "distractor"], + "question": "In the \"Meridian and Skiff ports\" Effort, which Frame budget record was in force for Skiff at the vertical slice?", + "answer": { + "kind": "record", + "value": "con-frame-1" + }, + "evidence": ["con-frame-2", "con-frame-1"], + "path": [["con-frame-2", "supersedes", "con-frame-1"]], + "checks": [ + { + "type": "asof", + "start": "con-frame-2", + "at": "2025-12-15T23:59:59Z" + } + ], + "traps": [ + "The current Frame budget with the 25 ms 40 Hz mode came in January 2026, after the slice.", + "A third Frame budget record with 8.3 ms was retracted noise copied from the render Effort." + ] + }, + { + "id": "ports-011", + "tier": 1, + "hops": 1, + "categories": ["distractor", "retraction"], + "question": "On second visits, what share of pipeline lookups hit the Skiff on-device pipeline cache?", + "answer": { + "kind": "value", + "value": "99.6 percent", + "accept": ["99.6%", "99.6"] + }, + "evidence": ["dec-pso-ondevice", "fnd-cache-warm"], + "path": [["dec-pso-ondevice", "supports", "fnd-cache-warm"]], + "checks": [ + { + "type": "body", + "record": "fnd-cache-warm", + "includes": "99.6 percent of pipeline lookups hit the cache", + "expect": true + } + ], + "traps": [ + "97 percent is the build farm's shader compile cache hit rate, in a retracted Finding posted here by mistake." + ] + }, + { + "id": "ports-012", + "tier": 1, + "hops": 1, + "categories": ["rationale"], + "question": "Why did the ports team raise the Skiff dynamic resolution floor above 540p?", + "answer": { + "kind": "text", + "rubric": [["caustic"], ["shimmer"], ["576p"]] + }, + "evidence": ["dec-dynres-2", "fnd-dynres-540"], + "path": [["dec-dynres-2", "derives_from", "fnd-dynres-540"]], + "checks": [ + { + "type": "body", + "record": "fnd-dynres-540", + "includes": ["caustic patterns under saltglass shimmer", "576p"], + "expect": true + } + ], + "traps": ["Frame time was not the reason; 540p fit the 33.3 ms budget."] + }, + { + "id": "ports-013", + "tier": 1, + "hops": 1, + "categories": ["lookup"], + "question": "The Skiff upscaler choice depends on a render Decision. What is that render Decision's exact title?", + "answer": { + "kind": "value", + "value": "Ship Tern as Lantern's only upscaler" + }, + "evidence": ["iss-upscale-q", "dec-tern-skiff"], + "path": [["iss-upscale-q", "resolved_by", "dec-tern-skiff"]], + "checks": [ + { + "type": "body", + "record": "dec-tern-skiff", + "includes": "\"Ship Tern as Lantern's only upscaler\"", + "expect": true + } + ], + "traps": [ + "The Skiff Decision's own title is about the Performance preset; the render title is quoted in its body." + ] + }, + { + "id": "ports-014", + "tier": 2, + "hops": 2, + "categories": ["temporal", "supersession"], + "question": "Which Skiff dynamic resolution Decision was in force at the vertical slice?", + "answer": { + "kind": "record", + "value": "dec-dynres-1" + }, + "evidence": ["dec-dynres-3", "dec-dynres-2", "dec-dynres-1"], + "path": [ + ["dec-dynres-3", "supersedes", "dec-dynres-2"], + ["dec-dynres-2", "supersedes", "dec-dynres-1"] + ], + "checks": [ + { + "type": "asof", + "start": "dec-dynres-3", + "at": "2025-12-15T23:59:59Z" + } + ], + "traps": [ + "The 504p floor is today's, adopted in July 2026.", + "The 576p floor came in January 2026 and was the floor at alpha, not at the slice." + ] + }, + { + "id": "ports-015", + "tier": 2, + "hops": 2, + "categories": ["blob", "distractor"], + "question": "The Finding that measured the Skiff harbor district memory peak attaches a capture. Which memory category was largest in that capture?", + "answer": { + "kind": "value", + "value": "textures", + "accept": ["texture", "textures (3184 MB)"] + }, + "evidence": ["fnd-mem-capture", "cit-mem-capture", "blb-mem-capture"], + "path": [ + ["fnd-mem-capture", "cites", "cit-mem-capture"], + ["cit-mem-capture", "blob", "blb-mem-capture"] + ], + "checks": [ + { + "type": "body", + "record": "blb-mem-capture", + "includes": "\"textures\": 3184", + "expect": true + } + ], + "traps": [ + "The Finding says audio banks grew the most; growth is not size.", + "The streaming pool is the second largest at 2048 MB." + ] + }, + { + "id": "ports-016", + "tier": 2, + "hops": 2, + "categories": ["reopened", "rejected-alternative"], + "question": "The Decision that resolved the Skiff first-visit hitch defect had once been rejected. Which Decision rejected it?", + "answer": { + "kind": "record", + "value": "dec-pso-ship" + }, + "evidence": ["iss-hitches", "dec-pso-ondevice", "dec-pso-ship"], + "path": [ + ["iss-hitches", "resolved_by", "dec-pso-ondevice"], + ["dec-pso-ondevice", "reopen_history", "dec-pso-ship"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "iss-pso-q", + "where": { + "standing": "superseded" + } + }, + { + "type": "edge", + "edge": ["dec-pso-ondevice", "reopen_history", "dec-pso-ship"], + "expect": true + } + ], + "traps": [ + "The on-device cache now has no live rejected_by link; the rejecter is only in its reopen history.", + "The ubershader option was rejected alongside it, not the cause of its rejection." + ] + }, + { + "id": "ports-017", + "tier": 2, + "hops": 2, + "categories": ["dead-evidence", "invalidation"], + "question": "The Decision to stream Skiff world tiles in 2 MB reads rests on a storage measurement. Which Finding showed that measurement was wrong?", + "answer": { + "kind": "record", + "value": "fnd-sd-speed-2" + }, + "evidence": ["dec-stream-block", "fnd-sd-speed", "fnd-sd-speed-2"], + "path": [ + ["dec-stream-block", "derives_from", "fnd-sd-speed"], + ["fnd-sd-speed", "invalidated_by", "fnd-sd-speed-2"] + ], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "bodyIncludes": "Worst sustained read across the budget cards" + }, + { + "type": "field", + "record": "fnd-sd-speed", + "field": "standing", + "expect": "invalidated" + } + ], + "traps": [ + "The 2 MB read Decision is still accepted; nothing invalidated it directly, so reading only its state hides the problem." + ] + }, + { + "id": "ports-018", + "tier": 2, + "hops": 2, + "categories": ["compaction", "supersession"], + "question": "The newest summary of the ports work gives a Skiff dynamic resolution floor. What floor is in force today?", + "answer": { + "kind": "value", + "value": "504p", + "accept": ["504"] + }, + "evidence": ["cmp-2", "dec-dynres-2", "dec-dynres-3"], + "path": [ + ["cmp-2", "derives_from", "dec-dynres-2"], + ["dec-dynres-2", "superseded_by", "dec-dynres-3"] + ], + "checks": [ + { + "type": "compaction", + "field": "stale", + "expect": true + }, + { + "type": "compaction", + "field": "staleTargets", + "expect": ["ports.dec-dynres-2"] + }, + { + "type": "head", + "start": "dec-dynres-2", + "expect": "ports.dec-dynres-3" + } + ], + "traps": [ + "The summary says 576p; it was written before the July 2026 change to 504p and is stale." + ], + "scoped": true + }, + { + "id": "ports-019", + "tier": 2, + "hops": 2, + "categories": ["lookup", "lifecycle"], + "question": "The Skiff autosave certification defect was fixed by a Decision. What write limit does the Constraint behind that Decision set?", + "answer": { + "kind": "value", + "value": "4 MB per minute", + "accept": ["4 MB a minute", "4 MB/min", "4"] + }, + "evidence": ["iss-cert-skiff-save", "dec-delta-save", "con-skiff-write"], + "path": [ + ["iss-cert-skiff-save", "resolved_by", "dec-delta-save"], + ["dec-delta-save", "derives_from", "con-skiff-write"] + ], + "checks": [ + { + "type": "body", + "record": "con-skiff-write", + "includes": "at most 4 MB per minute", + "expect": true + } + ], + "traps": [ + "11 MB per minute is what the old autosave wrote.", + "2.6 MB per minute is what the delta saves are expected to write." + ] + }, + { + "id": "ports-020", + "tier": 2, + "hops": 2, + "categories": ["supersession", "rationale"], + "question": "Which Finding explains why the Skiff memory budget dropped from its first value?", + "answer": { + "kind": "record", + "value": "fnd-sdk12" + }, + "evidence": ["con-skiff-mem-9", "con-skiff-mem-8", "fnd-sdk12"], + "path": [ + ["con-skiff-mem-9", "superseded_by", "con-skiff-mem-8"], + ["con-skiff-mem-8", "derives_from", "fnd-sdk12"] + ], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "derivesFrom": "con-skiff-mem-9" + } + ], + "traps": [ + "The harbor capture at 8.6 GB came after the cut and measured against it; it did not cause it.", + "The 6.9 GB slice capture was invalidated, but it has nothing to do with the budget change." + ] + }, + { + "id": "ports-021", + "tier": 2, + "hops": 3, + "categories": ["blob", "lifecycle"], + "question": "The Skiff pre-certification report gives each problem a code. What code does it give the Skiff defect that the ports team closed as won't fix?", + "answer": { + "kind": "value", + "value": "SKF-DSP-004" + }, + "evidence": [ + "iss-cert-skiff-flicker", + "fnd-cert-report", + "cit-cert-report", + "blb-cert-report" + ], + "path": [ + ["iss-cert-skiff-flicker", "derives_from", "fnd-cert-report"], + ["fnd-cert-report", "cites", "cit-cert-report"], + ["cit-cert-report", "blob", "blb-cert-report"] + ], + "checks": [ + { + "type": "field", + "record": "iss-cert-skiff-flicker", + "field": "status", + "expect": "wontfix" + }, + { + "type": "body", + "record": "blb-cert-report", + "includes": "| SKF-DSP-004 | Display | Advisory |", + "expect": true + } + ], + "traps": [ + "The Meridian activity card defect was deferred, not closed as won't fix, and has no Skiff code.", + "SKF-UI-031 and SKF-ST-012 were fixed." + ] + }, + { + "id": "ports-022", + "tier": 3, + "hops": 4, + "categories": ["supersession", "lifecycle"], + "question": "The Finding used as evidence that the Skiff out-of-memory risk came true was measured against a memory budget. Which Citation explains why that budget is lower than the first one?", + "answer": { + "kind": "record", + "value": "cit-skiff-sdk-12" + }, + "evidence": [ + "rsk-skiff-oom", + "fnd-mem-capture", + "con-skiff-mem-8", + "fnd-sdk12", + "cit-skiff-sdk-12" + ], + "path": [ + ["rsk-skiff-oom", "evidence", "fnd-mem-capture"], + ["fnd-mem-capture", "derives_from", "con-skiff-mem-8"], + ["con-skiff-mem-8", "derives_from", "fnd-sdk12"], + ["fnd-sdk12", "cites", "cit-skiff-sdk-12"] + ], + "checks": [ + { + "type": "select", + "kinds": ["citation"], + "bodyIncludes": "/sdk/1.2/" + }, + { + "type": "edge", + "edge": ["fnd-sdk12", "cites", "cit-skiff-sdk-12"], + "expect": true + } + ], + "traps": [ + "The SDK 0.9 memory map is the source of the original 9 GB figure.", + "The harbor memory capture Citation backs the measurement, not the budget cut." + ] + }, + { + "id": "ports-023", + "tier": 3, + "hops": 4, + "categories": ["blocker", "supersession", "lookup"], + "question": "The open Skiff storm blocker came from a capture taken at the dynamic resolution floor in force today. That floor relies on an upscaler Decision. Which Finding measured that upscaler's cost on Skiff?", + "answer": { + "kind": "record", + "value": "fnd-tern-cost" + }, + "evidence": [ + "iss-blk-storm", + "fnd-storm-capture", + "dec-dynres-3", + "dec-tern-skiff", + "fnd-tern-cost" + ], + "path": [ + ["iss-blk-storm", "derives_from", "fnd-storm-capture"], + ["fnd-storm-capture", "derives_from", "dec-dynres-3"], + ["dec-dynres-3", "derives_from", "dec-tern-skiff"], + ["dec-tern-skiff", "derives_from", "fnd-tern-cost"] + ], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "derivesFrom": "iss-upscale-q" + }, + { + "type": "edge", + "edge": ["dec-tern-skiff", "derives_from", "fnd-tern-cost"], + "expect": true + } + ], + "traps": [ + "The storm GPU capture is the floor's own evidence and measures resolution, not the upscaler.", + "The prototype particle-cap test measures the proposed blocker fix, not Tern." + ] + }, + { + "id": "ports-024", + "tier": 3, + "hops": 4, + "categories": ["invalidation", "supersession"], + "question": "The Skiff first-visit hitch defect led to a question whose first recorded answer was later replaced. Which Finding disproved the evidence behind that first answer?", + "answer": { + "kind": "record", + "value": "fnd-driver-keyed" + }, + "evidence": [ + "iss-hitches", + "iss-pso-q", + "dec-pso-ship", + "fnd-blob-portable", + "fnd-driver-keyed" + ], + "path": [ + ["iss-hitches", "supports", "iss-pso-q"], + ["iss-pso-q", "resolved_by", "dec-pso-ship"], + ["dec-pso-ship", "derives_from", "fnd-blob-portable"], + ["fnd-blob-portable", "invalidated_by", "fnd-driver-keyed"] + ], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "bodyIncludes": "checks a driver hash in every blob" + }, + { + "type": "edge", + "edge": ["fnd-blob-portable", "invalidated_by", "fnd-driver-keyed"], + "expect": true + } + ], + "traps": [ + "The pipeline count Finding backs the on-device cache but disproved nothing.", + "The question Issue still lists the superseded prebuilt-blob Decision as its resolver, so a reader who stops there misses the invalidation." + ] + }, + { + "id": "ports-025", + "tier": 3, + "hops": 4, + "categories": ["supersession", "distractor"], + "question": "Follow the Skiff dynamic resolution question to the floor in force today. Which upscaler Decision does that floor rely on?", + "answer": { + "kind": "record", + "value": "dec-tern-skiff" + }, + "evidence": [ + "iss-dynres-q", + "dec-dynres-1", + "dec-dynres-2", + "dec-dynres-3", + "dec-tern-skiff" + ], + "path": [ + ["iss-dynres-q", "resolved_by", "dec-dynres-1"], + ["dec-dynres-1", "superseded_by", "dec-dynres-2"], + ["dec-dynres-2", "superseded_by", "dec-dynres-3"], + ["dec-dynres-3", "derives_from", "dec-tern-skiff"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "iss-upscale-q", + "where": { + "state": "accepted" + } + }, + { + "type": "head", + "start": "dec-dynres-1", + "expect": "ports.dec-dynres-3" + } + ], + "traps": [ + "The Issue still points at the first, superseded floor; stopping there finds no upscaler link.", + "The spatial upscaler was rejected; the render Effort's Tern Decision is not a record in this Effort." + ] + }, + { + "id": "ports-026", + "tier": 3, + "hops": 4, + "categories": ["blob", "lifecycle"], + "question": "The Decision to use Kelp's high-ratio mode for Skiff textures answered a risk that came true. In the capture attached to that risk's evidence, how many MB did audio banks use?", + "answer": { + "kind": "value", + "value": "912", + "accept": ["912 MB"] + }, + "evidence": [ + "dec-kelp-skiff", + "rsk-skiff-oom", + "fnd-mem-capture", + "cit-mem-capture", + "blb-mem-capture" + ], + "path": [ + ["dec-kelp-skiff", "derives_from", "rsk-skiff-oom"], + ["rsk-skiff-oom", "evidence", "fnd-mem-capture"], + ["fnd-mem-capture", "cites", "cit-mem-capture"], + ["cit-mem-capture", "blob", "blb-mem-capture"] + ], + "checks": [ + { + "type": "field", + "record": "rsk-skiff-oom", + "field": "state", + "expect": "realized" + }, + { + "type": "body", + "record": "blb-mem-capture", + "includes": "\"audio_banks\": 912", + "expect": true + } + ], + "traps": [ + "388 MB is how much audio banks grew since the slice, the only audio figure in the Finding's body." + ] + }, + { + "id": "ports-027", + "tier": 4, + "hops": 0, + "categories": ["dead-evidence", "aggregate"], + "question": "Which live Decisions and Risks in the ports work still rest directly on a Finding that was later proven wrong?", + "answer": { + "kind": "records", + "value": ["dec-stream-block", "rsk-skiff-stream"] + }, + "evidence": [ + "fnd-sd-speed", + "fnd-sd-speed-2", + "dec-stream-block", + "rsk-skiff-stream", + "dec-seamless-ft", + "fnd-blob-portable", + "dec-pso-ship", + "fnd-mem-early" + ], + "path": [], + "checks": [ + { + "type": "select", + "kinds": ["decision", "risk"], + "live": true, + "restsOn": ["invalidated"] + } + ], + "traps": [ + "The seamless fast travel Decision was itself invalidated, so it is not live.", + "The prebuilt blob Decision rested on a disproved Finding but was superseded." + ], + "scoped": true + }, + { + "id": "ports-028", + "tier": 4, + "hops": 0, + "categories": ["lifecycle", "aggregate"], + "question": "How many Risks in the ports work are still open?", + "answer": { + "kind": "count", + "value": 2 + }, + "evidence": [ + "rsk-skiff-oom", + "rsk-tern-cost", + "rsk-pso-hitch", + "rsk-thermal", + "rsk-skiff-stream", + "rsk-cert-slip" + ], + "path": [], + "checks": [ + { + "type": "select", + "kinds": ["risk"], + "where": { + "state": "open" + }, + "count": true + } + ], + "traps": [ + "The out-of-memory risk is realized, which is live but not open." + ], + "scoped": true + }, + { + "id": "ports-029", + "tier": 4, + "hops": 0, + "categories": ["compaction", "aggregate"], + "question": "Since the newest summary of the ports work was written, how many records have joined the live set, left it, or changed standing?", + "answer": { + "kind": "count", + "value": 8 + }, + "evidence": [ + "cmp-2", + "dec-dynres-2", + "dec-dynres-3", + "fnd-dynres-gpu", + "fnd-storm-capture", + "iss-blk-storm", + "dec-storm-cap", + "dec-storm-30", + "fnd-storm-cap-test" + ], + "path": [], + "checks": [ + { + "type": "compaction", + "field": "changes" + } + ], + "traps": [ + "The summary's own text reads as current; only the changes since it was taken show how far it has drifted." + ], + "scoped": true + }, + { + "id": "ports-030", + "tier": 4, + "hops": 0, + "categories": ["blocker", "lifecycle"], + "question": "Which proposed Decisions are waiting on an open blocker in the ports work?", + "answer": { + "kind": "records", + "value": ["dec-storm-cap", "dec-storm-30"] + }, + "evidence": [ + "iss-blk-storm", + "dec-storm-cap", + "dec-storm-30", + "iss-blk-devkits" + ], + "path": [], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "where": { + "state": "proposed" + } + }, + { + "type": "select", + "kinds": ["issue"], + "where": { + "kind": "blocker", + "status": "open" + }, + "expect": ["ports.iss-blk-storm"] + } + ], + "traps": [ + "The dev kit blocker was resolved in March 2026 and no Decision waits on it.", + "The prototype test of the particle cap is a Finding, not a Decision, and settles nothing." + ], + "scoped": true + }, + { + "id": "ports-031", + "tier": 4, + "hops": 0, + "categories": ["lifecycle", "aggregate"], + "question": "Which certification defects did the ports team close as deferred or won't fix rather than resolved?", + "answer": { + "kind": "records", + "value": ["iss-cert-meridian-cards", "iss-cert-skiff-flicker"] + }, + "evidence": [ + "iss-cert-meridian-cards", + "iss-cert-skiff-flicker", + "iss-cert-skiff-save", + "iss-cert-skiff-hud", + "iss-cert-meridian-suspend" + ], + "path": [], + "checks": [ + { + "type": "select", + "kinds": ["issue"], + "where": { + "status": ["deferred", "wontfix"] + } + } + ], + "traps": [ + "The autosave, HUD, and Meridian suspend defects were all resolved with fixes." + ], + "scoped": true + }, + { + "id": "ports-032", + "tier": 4, + "hops": 0, + "categories": ["retraction", "aggregate"], + "question": "How many records in the ports work were retracted as noise?", + "answer": { + "kind": "count", + "value": 2 + }, + "evidence": ["fnd-noise-shader", "con-noise-frame"], + "path": [], + "checks": [ + { + "type": "select", + "retracted": "only", + "count": true + } + ], + "traps": [ + "Superseded and invalidated records are not retracted; they stay on the live browse reads with their history." + ], + "scoped": true + }, + { + "id": "ports-033", + "tier": 4, + "hops": 0, + "categories": ["negative", "distractor", "retraction"], + "question": "What frame budget does the ports work set for Meridian's 120 Hz mode?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": ["con-frame-2", "con-noise-frame"], + "path": [], + "checks": [ + { + "type": "field", + "record": "con-noise-frame", + "field": "standing", + "expect": "retracted" + }, + { + "type": "body", + "record": "con-frame-2", + "includes": "belong to the render Effort", + "expect": true + } + ], + "traps": [ + "8.3 ms appears only in a retracted record copied from the render Effort by mistake.", + "16.6 ms is the Meridian 60 Hz budget, not 120 Hz." + ] + } + ] +} diff --git a/benchmarks/proof-recall/questions/render.json b/benchmarks/proof-recall/questions/render.json new file mode 100644 index 00000000..37d80b26 --- /dev/null +++ b/benchmarks/proof-recall/questions/render.json @@ -0,0 +1,2296 @@ +{ + "effort": "render", + "questions": [ + { + "id": "render-001", + "tier": 0, + "hops": 0, + "categories": ["lookup", "current-state"], + "question": "How many milliseconds of each frame do Lantern's GPU passes get in the Meridian 120 Hz performance mode?", + "answer": { + "kind": "value", + "value": "7.4", + "accept": ["7.4 ms"] + }, + "evidence": ["con-120-2"], + "checks": [ + { + "type": "body", + "record": "con-120-2", + "includes": "Lantern GPU passes get 7.4 ms", + "expect": true + } + ], + "traps": ["8.3 ms is the whole 120 Hz frame, not the GPU share."] + }, + { + "id": "render-002", + "tier": 0, + "hops": 0, + "categories": ["lookup"], + "question": "What average quad overdraw did the forward+ capture of the cliffs benchmark show?", + "answer": { + "kind": "value", + "value": "3.4x", + "accept": ["3.4", "3.4 times"] + }, + "evidence": ["fnd-fplus-overdraw"], + "checks": [ + { + "type": "body", + "record": "fnd-fplus-overdraw", + "includes": "Quad overdraw averages 3.4x", + "expect": true + } + ], + "traps": ["7.9 ms is the shading time, not the overdraw."] + }, + { + "id": "render-003", + "tier": 0, + "hops": 0, + "categories": ["lookup", "rejected-alternative"], + "question": "Who proposed keeping clustered forward+ and tuning light culling instead of a visibility buffer?", + "answer": { + "kind": "value", + "value": "Tomasz Brandt" + }, + "evidence": ["dec-fplus-tune"], + "checks": [ + { + "type": "field", + "record": "dec-fplus-tune", + "field": "created_by" + } + ], + "traps": [ + "Ines Okafor wrote the winning visibility buffer Decision; Yusuf Demir proposed the G-buffer." + ] + }, + { + "id": "render-004", + "tier": 0, + "hops": 0, + "categories": ["current-state", "reopened"], + "question": "What state is the Decision to ship the Halcyon vendor upscaler on PC and Meridian in now?", + "answer": { + "kind": "value", + "value": "rejected" + }, + "evidence": ["dec-vendor"], + "checks": [ + { + "type": "field", + "record": "dec-vendor", + "field": "standing" + } + ], + "traps": [ + "It was reopened in April 2026, so a reader who stops at the reopen history answers proposed." + ] + }, + { + "id": "render-005", + "tier": 0, + "hops": 0, + "categories": ["lifecycle", "blocker"], + "question": "Is the blocker about shadow pages running out at spring low tide still open?", + "answer": { + "kind": "boolean", + "value": true + }, + "evidence": ["iss-vsm-tide"], + "checks": [ + { + "type": "field", + "record": "iss-vsm-tide", + "field": "status", + "expect": "open" + } + ], + "traps": [ + "The overflow Risk was set to realized, which a reader may confuse with the blocker being closed." + ] + }, + { + "id": "render-006", + "tier": 0, + "hops": 0, + "categories": ["negative"], + "question": "What did the team measure as the cost of the Halcyon vendor upscaler on Skiff?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": ["fnd-halcyon-eval"], + "checks": [ + { + "type": "body", + "record": "fnd-halcyon-eval", + "includes": "there is no Skiff build", + "expect": true + } + ], + "traps": [ + "1.2 ms is the Meridian cost at 4K. Halcyon has no Skiff build, so nobody measured it there." + ] + }, + { + "id": "render-007", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "On what date is the Skiff forward+ path to be deleted from the codebase?", + "answer": { + "kind": "value", + "value": "2026-07-24", + "accept": ["July 24, 2026", "24 July 2026"] + }, + "evidence": ["dec-vb-6"], + "checks": [ + { + "type": "body", + "record": "dec-vb-6", + "includes": "deleted from the codebase on 2026-07-24", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "The date sits past the browse excerpt; a reader who does not open the record says unknown." + ] + }, + { + "id": "render-008", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "How many times may the game fail the Meridian HDR certification pass in one release candidate before the whole submission goes back for a full re-review?", + "answer": { + "kind": "value", + "value": "2", + "accept": ["two", "twice", "at most twice"] + }, + "evidence": ["con-hdr-cert"], + "checks": [ + { + "type": "body", + "record": "con-hdr-cert", + "includes": "at most twice per release candidate", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "The limit sits past the browse excerpt of the certification Constraint." + ] + }, + { + "id": "render-009", + "tier": 0, + "hops": 0, + "categories": ["truncation", "current-state"], + "question": "At how many steps is the ray-marched fallback capped in the refraction Decision now in force?", + "answer": { + "kind": "value", + "value": "32", + "accept": ["32 steps"] + }, + "evidence": ["dec-refr-hybrid"], + "checks": [ + { + "type": "body", + "record": "dec-refr-hybrid", + "includes": "capped at 32 steps", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "64 steps is what the October cost Finding and the rejected full ray-march used." + ] + }, + { + "id": "render-010", + "tier": 0, + "hops": 0, + "categories": ["negative", "distractor", "retraction"], + "question": "What frame budget does the render Effort set for the Skiff 40 Hz mode?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": ["con-budget-3", "con-budget-noise"], + "checks": [ + { + "type": "body", + "record": "con-budget-3", + "includes": "Skiff budgets belong to the ports Effort", + "expect": true + }, + { + "type": "field", + "record": "con-budget-noise", + "field": "standing", + "expect": "retracted" + } + ], + "traps": [ + "A retracted Constraint titled Frame budget says 25 ms; it was written to this Effort by mistake.", + "The ports Effort has its own Frame budget; this Effort does not own Skiff numbers." + ] + }, + { + "id": "render-011", + "tier": 0, + "hops": 0, + "categories": ["retraction", "distractor"], + "question": "Two Findings report an SDF GI cost on Meridian under 3 ms. Which one was retracted as noise?", + "answer": { + "kind": "record", + "value": "fnd-gi-sdf-cost-noise" + }, + "evidence": ["fnd-gi-sdf-cost-noise", "fnd-gi-sdf-cost"], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "retracted": "only" + } + ], + "traps": ["The 2.2 ms Finding was invalidated, not retracted."], + "scoped": true + }, + { + "id": "render-012", + "tier": 0, + "hops": 0, + "categories": ["lifecycle"], + "question": "How was the gap about missing Skiff GPU timings for Lantern passes closed: resolved, deferred, or wontfix?", + "answer": { + "kind": "value", + "value": "deferred" + }, + "evidence": ["iss-gap-skiff-profiles"], + "checks": [ + { + "type": "field", + "record": "iss-gap-skiff-profiles", + "field": "standing" + } + ], + "traps": [ + "Skiff numbers did arrive in April, but the gap itself was closed as deferred." + ] + }, + { + "id": "render-013", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "What precision does Tern's history buffer use?", + "answer": { + "kind": "value", + "value": "16-bit float", + "accept": ["FP16", "16-bit float per channel", "half float"] + }, + "evidence": ["dec-tern"], + "checks": [ + { + "type": "body", + "record": "dec-tern", + "includes": "stored as 16-bit float per channel", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "FP16 packing of reprojection inputs is a different change, in a Tern cost Finding." + ] + }, + { + "id": "render-014", + "tier": 0, + "hops": 0, + "categories": ["truncation", "invalidation"], + "question": "In the Finding that put SDF GI at 4.7 ms on Meridian, what L2 hit rate did the trace pass fall to on the devkit?", + "answer": { + "kind": "value", + "value": "52 percent", + "accept": ["52%", "52", "0.52"] + }, + "evidence": ["fnd-gi-sdf-recapture"], + "checks": [ + { + "type": "body", + "record": "fnd-gi-sdf-recapture", + "includes": "to 52 percent on the devkit", + "afterExcerpt": true, + "expect": true + } + ], + "traps": ["81 percent is the rate in the October capture."] + }, + { + "id": "render-015", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "With caustic photon jitter locked to the tide phase, for about how many minutes of each tide cycle does the caustic pattern freeze?", + "answer": { + "kind": "value", + "value": "4", + "accept": ["4 minutes", "about 4 minutes", "four"] + }, + "evidence": ["fnd-caustic-seed-test"], + "checks": [ + { + "type": "body", + "record": "fnd-caustic-seed-test", + "includes": "freezes for about 4 minutes", + "afterExcerpt": true, + "expect": true + } + ], + "traps": ["40 minutes is the whole tide cycle."] + }, + { + "id": "render-016", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "Beyond what distance does the sun virtual shadow map Decision stop allocating pages?", + "answer": { + "kind": "value", + "value": "1.2 km", + "accept": ["1.2 kilometres", "1.2 kilometers", "1200 m"] + }, + "evidence": ["dec-vsm"], + "checks": [ + { + "type": "body", + "record": "dec-vsm", + "includes": "Beyond 1.2 km, VSM pages are not allocated", + "afterExcerpt": true, + "expect": true + } + ], + "traps": ["2 km is how far shadows must reach in total."] + }, + { + "id": "render-017", + "tier": 0, + "hops": 0, + "categories": ["negative"], + "question": "How much memory do the SDF GI volumes use on Skiff?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": ["fnd-sdf-memory"], + "checks": [ + { + "type": "body", + "record": "fnd-sdf-memory", + "includes": "410 MB of the 1.8 GB render-target budget", + "expect": true + } + ], + "traps": ["410 MB is the Meridian figure; no record measures Skiff."] + }, + { + "id": "render-018", + "tier": 0, + "hops": 0, + "categories": ["negative", "reopened"], + "question": "What did ray-traced sun shadows cost on Meridian?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": ["dec-rt-shadows"], + "checks": [ + { + "type": "body", + "record": "dec-rt-shadows", + "includes": "Skiff has no ray-tracing hardware", + "expect": true + } + ], + "traps": [ + "3.1 ms and 1.4 ms are virtual shadow map costs; 1.6 ms is the cascade cost. Nobody measured ray-traced shadows." + ] + }, + { + "id": "render-019", + "tier": 1, + "hops": 1, + "categories": ["supersession"], + "question": "Which Decision directly replaced the stock filmic tonemapping curve?", + "answer": { + "kind": "record", + "value": "dec-brine-1" + }, + "evidence": ["dec-filmic", "dec-brine-1"], + "path": [["dec-filmic", "superseded_by", "dec-brine-1"]], + "checks": [ + { + "type": "asof", + "start": "dec-filmic", + "at": "2026-03-01T00:00:00Z" + } + ], + "traps": [ + "The current head is the 800-nit version; the question asks for the direct replacement." + ] + }, + { + "id": "render-020", + "tier": 1, + "hops": 1, + "categories": ["invalidation"], + "question": "Which Finding showed that screen-space refraction on its own was wrong for saltglass?", + "answer": { + "kind": "record", + "value": "fnd-refr-offscreen" + }, + "evidence": ["dec-refr-ss", "fnd-refr-offscreen"], + "path": [["dec-refr-ss", "invalidated_by", "fnd-refr-offscreen"]], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "bodyIncludes": "refracted rays leave the screen" + }, + { + "type": "edge", + "edge": ["dec-refr-ss", "invalidated_by", "fnd-refr-offscreen"], + "expect": true + } + ], + "traps": [ + "The halo Finding describes an artifact but did not invalidate the Decision." + ] + }, + { + "id": "render-021", + "tier": 1, + "hops": 1, + "categories": ["rejected-alternative"], + "question": "Which Decision rejected the proposal to move to a deferred G-buffer?", + "answer": { + "kind": "record", + "value": "dec-vb-1" + }, + "evidence": ["dec-deferred", "dec-vb-1"], + "path": [["dec-deferred", "rejected_by", "dec-vb-1"]], + "checks": [ + { + "type": "asof", + "start": "dec-vb-6", + "at": "2025-10-05T00:00:00Z" + } + ], + "traps": [ + "The current visibility buffer head is a much later version; the rejecter is the first one." + ] + }, + { + "id": "render-022", + "tier": 1, + "hops": 1, + "categories": ["reopened", "rejected-alternative"], + "question": "Before it was reopened, which Decision had rejected virtual shadow maps for the sun?", + "answer": { + "kind": "record", + "value": "dec-csm" + }, + "evidence": ["dec-vsm", "dec-csm"], + "path": [["dec-vsm", "reopen_history", "dec-csm"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "bodyIncludes": "four cascaded shadow maps out to 2 km" + }, + { + "type": "edge", + "edge": ["dec-vsm", "reopen_history", "dec-csm"], + "expect": true + } + ], + "traps": [ + "The reopened Decision has no live rejected_by link any more; the rejecter lives in its reopen history." + ] + }, + { + "id": "render-023", + "tier": 1, + "hops": 1, + "categories": ["lifecycle"], + "question": "What resolved the gap about missing automated GPU captures on nightly builds?", + "answer": { + "kind": "record", + "value": "dec-nightly-capture" + }, + "evidence": ["iss-gap-capture", "dec-nightly-capture"], + "path": [["iss-gap-capture", "resolved_by", "dec-nightly-capture"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "where": { + "created_by": "Liam O'Connell" + } + } + ], + "traps": [ + "The Skiff timings gap is a different gap, closed as deferred." + ], + "scoped": true + }, + { + "id": "render-024", + "tier": 1, + "hops": 1, + "categories": ["lifecycle"], + "question": "Which Decision mitigates the risk that visibility buffer material resolve multiplies shader permutations?", + "answer": { + "kind": "record", + "value": "dec-uber-resolve" + }, + "evidence": ["rsk-shader-perm", "dec-uber-resolve"], + "path": [["rsk-shader-perm", "mitigated_by", "dec-uber-resolve"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "bodyIncludes": "one uber shader per tile class" + } + ], + "traps": [ + "The compute-resolve visibility buffer version builds on the uber shader but is not the mitigation." + ] + }, + { + "id": "render-025", + "tier": 1, + "hops": 1, + "categories": ["temporal", "supersession"], + "question": "Tern's cost at 4K output on Meridian was measured in a chain of Findings, each replacing the one before. Which version of that measurement was current on alpha day, 2026-03-02?", + "answer": { + "kind": "record", + "value": "fnd-tern-cost-2" + }, + "evidence": ["fnd-tern-cost-3", "fnd-tern-cost-2"], + "path": [["fnd-tern-cost-3", "supersedes", "fnd-tern-cost-2"]], + "checks": [ + { + "type": "asof", + "start": "fnd-tern-cost-1", + "at": "2026-03-02T23:59:00Z" + } + ], + "traps": [ + "The 1.6 ms Finding is current today but was written in May 2026." + ] + }, + { + "id": "render-026", + "tier": 1, + "hops": 1, + "categories": ["rejected-alternative", "distractor"], + "question": "Two Decisions propose shipping four Tern quality presets. Which of them was rejected?", + "answer": { + "kind": "record", + "value": "dec-presets-4" + }, + "evidence": ["iss-presets-q", "dec-presets-4"], + "path": [["iss-presets-q", "supports", "dec-presets-4"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "iss-presets-q", + "where": { + "standing": "rejected" + } + } + ], + "traps": [ + "The other four-preset Decision, adding Ultra Performance for 120 Hz mode, is accepted." + ] + }, + { + "id": "render-027", + "tier": 1, + "hops": 1, + "categories": ["temporal", "supersession"], + "question": "In the \"Lantern renderer overhaul\" Effort, which version of the Frame budget Constraint was current on alpha day, 2026-03-02?", + "answer": { + "kind": "record", + "value": "con-budget-2" + }, + "evidence": ["con-budget-3", "con-budget-2"], + "path": [["con-budget-3", "supersedes", "con-budget-2"]], + "checks": [ + { + "type": "asof", + "start": "con-budget-1", + "at": "2026-03-02T23:59:00Z" + } + ], + "traps": ["The 15.0 ms version was written in April 2026."] + }, + { + "id": "render-028", + "tier": 1, + "hops": 1, + "categories": ["rejected-alternative"], + "question": "Which Decision rejected the proposal to keep CPU frustum culling with software occlusion?", + "answer": { + "kind": "record", + "value": "dec-cull-gpu" + }, + "evidence": ["dec-cull-cpu", "dec-cull-gpu"], + "path": [["dec-cull-cpu", "rejected_by", "dec-cull-gpu"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "iss-cull-q", + "where": { + "standing": "accepted" + } + } + ], + "traps": [ + "The tide-hint Decision later patched GPU culling but rejected nothing." + ] + }, + { + "id": "render-029", + "tier": 1, + "hops": 1, + "categories": ["lifecycle"], + "question": "Which Finding is the evidence that the VSM page pool overflow Risk came true?", + "answer": { + "kind": "record", + "value": "fnd-vsm-overflow" + }, + "evidence": ["rsk-vsm-overflow", "fnd-vsm-overflow"], + "path": [["rsk-vsm-overflow", "evidence", "fnd-vsm-overflow"]], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "derivesFrom": "rsk-vsm-overflow" + } + ], + "traps": [ + "The spring-tide blocker derives from the evidence; it is an Issue, not the evidence." + ] + }, + { + "id": "render-030", + "tier": 1, + "hops": 1, + "categories": ["temporal", "invalidation"], + "question": "Which saltglass refraction Decision was the accepted one on the day of the vertical slice, 2025-12-15?", + "answer": { + "kind": "record", + "value": "dec-refr-ss" + }, + "evidence": ["dec-refr-hybrid", "dec-refr-ss"], + "path": [["dec-refr-hybrid", "supersedes", "dec-refr-ss"]], + "checks": [ + { + "type": "asof", + "start": "dec-refr-ss", + "at": "2025-12-15T23:59:00Z" + } + ], + "traps": [ + "The hybrid Decision came in January 2026.", + "The screen-space Decision had already been invalidated on 2025-12-04, but no replacement existed yet." + ] + }, + { + "id": "render-031", + "tier": 1, + "hops": 1, + "categories": ["rationale"], + "question": "Why did the third version of the visibility buffer Decision move foliage and saltglass out of the buffer?", + "answer": { + "kind": "text", + "rubric": [ + ["alpha-test", "alpha test", "alpha-tested"], + ["2.1 ms"], + ["refract"] + ] + }, + "evidence": ["dec-vb-3", "fnd-vb-foliage"], + "path": [["dec-vb-3", "derives_from", "fnd-vb-foliage"]], + "checks": [], + "traps": ["Meshlet alpha masks came later and moved foliage back."] + }, + { + "id": "render-032", + "tier": 1, + "hops": 1, + "categories": ["rationale", "rejected-alternative"], + "question": "Why did the team choose Tern over the Halcyon vendor upscaler?", + "answer": { + "kind": "text", + "rubric": [ + ["Skiff"], + [ + "one upscaler", + "one-upscaler", + "single upscaler", + "second upscaler" + ], + ["vendor ticket", "owning the code", "own the code", "license"] + ] + }, + "evidence": ["iss-upscaler-q", "dec-tern"], + "path": [["iss-upscaler-q", "resolved_by", "dec-tern"]], + "checks": [], + "traps": ["Halcyon was cheaper on Meridian, so cost was not the reason."] + }, + { + "id": "render-033", + "tier": 1, + "hops": 1, + "categories": ["truncation", "lifecycle"], + "question": "The VSM page pool overflow Risk came true. According to its evidence, how much more memory would it cost to raise the pool to 6,144 pages?", + "answer": { + "kind": "value", + "value": "128 MB", + "accept": ["128", "128 megabytes"] + }, + "evidence": ["rsk-vsm-overflow", "fnd-vsm-overflow"], + "path": [["rsk-vsm-overflow", "evidence", "fnd-vsm-overflow"]], + "checks": [ + { + "type": "body", + "record": "fnd-vsm-overflow", + "includes": "cost another 128 MB", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "256 MB is what the existing 4,096-page pool takes, from the VSM Decision." + ] + }, + { + "id": "render-034", + "tier": 2, + "hops": 2, + "categories": ["blob", "invalidation"], + "question": "On what kind of machine was the original 2.2 ms SDF GI capture actually taken?", + "answer": { + "kind": "value", + "value": "PC workstation", + "accept": [ + "a PC workstation", + "PC workstation (Meridian clock profile)", + "a PC workstation with the Meridian clock profile" + ] + }, + "evidence": ["fnd-gi-sdf-cost", "cit-gi-sdf", "blb-gi-sdf"], + "path": [ + ["fnd-gi-sdf-cost", "cites", "cit-gi-sdf"], + ["cit-gi-sdf", "blob", "blb-gi-sdf"] + ], + "checks": [ + { + "type": "body", + "record": "blb-gi-sdf", + "includes": "PC workstation (Meridian clock profile)", + "expect": true + } + ], + "traps": [ + "The Finding title says Meridian; only the attached capture names the real machine." + ] + }, + { + "id": "render-035", + "tier": 2, + "hops": 3, + "categories": ["blob", "lifecycle"], + "question": "The VSM page pool overflow Risk came true. At its peak, how many shadow pages did the trace behind that evidence request?", + "answer": { + "kind": "value", + "value": "5912", + "accept": ["5,912"] + }, + "evidence": [ + "rsk-vsm-overflow", + "fnd-vsm-overflow", + "cit-vsm-pages", + "blb-vsm-pages" + ], + "path": [ + ["rsk-vsm-overflow", "evidence", "fnd-vsm-overflow"], + ["fnd-vsm-overflow", "cites", "cit-vsm-pages"], + ["cit-vsm-pages", "blob", "blb-vsm-pages"] + ], + "checks": [ + { + "type": "body", + "record": "blb-vsm-pages", + "includes": "\"peak_pages_requested\": 5912", + "expect": true + } + ], + "traps": ["4,096 is the pool size, not the peak request."] + }, + { + "id": "render-036", + "tier": 2, + "hops": 2, + "categories": ["blob", "blocker"], + "question": "Which numbered certification test did the first Meridian HDR pre-check fail?", + "answer": { + "kind": "value", + "value": "HDR-07" + }, + "evidence": ["fnd-hdr-precheck", "cit-hdr-precheck", "blb-hdr-precheck"], + "path": [ + ["fnd-hdr-precheck", "cites", "cit-hdr-precheck"], + ["cit-hdr-precheck", "blob", "blb-hdr-precheck"] + ], + "checks": [ + { + "type": "body", + "record": "blb-hdr-precheck", + "includes": "| HDR-07 | Paper white follows system setting and range | FAIL |", + "expect": true + } + ], + "traps": [ + "The Finding names the paper-white failure but not the test number." + ] + }, + { + "id": "render-037", + "tier": 2, + "hops": 3, + "categories": ["blob", "current-state"], + "question": "What render scale does the Ultra Performance preset use in the measurements behind the Tern preset Decision now in force?", + "answer": { + "kind": "value", + "value": "0.33", + "accept": ["33%", "33 percent", "one third"] + }, + "evidence": [ + "dec-presets-4b", + "fnd-tern-presets", + "cit-tern-presets", + "blb-tern-presets" + ], + "path": [ + ["dec-presets-4b", "derives_from", "fnd-tern-presets"], + ["fnd-tern-presets", "cites", "cit-tern-presets"], + ["cit-tern-presets", "blob", "blb-tern-presets"] + ], + "checks": [ + { + "type": "body", + "record": "blb-tern-presets", + "includes": "\"scale\": 0.33", + "expect": true + } + ], + "traps": ["0.5 is the Performance preset."] + }, + { + "id": "render-038", + "tier": 2, + "hops": 3, + "categories": ["temporal", "supersession"], + "question": "Which version of the visibility buffer Decision was the newest on the day of the vertical slice, 2025-12-15?", + "answer": { + "kind": "record", + "value": "dec-vb-3" + }, + "evidence": ["dec-vb-6", "dec-vb-5", "dec-vb-4", "dec-vb-3"], + "path": [ + ["dec-vb-6", "supersedes", "dec-vb-5"], + ["dec-vb-5", "supersedes", "dec-vb-4"], + ["dec-vb-4", "supersedes", "dec-vb-3"] + ], + "checks": [ + { + "type": "asof", + "start": "dec-vb-1", + "at": "2025-12-15T23:59:00Z" + } + ], + "traps": [ + "The current head runs the buffer on every platform; at the slice foliage and saltglass were still forward." + ] + }, + { + "id": "render-039", + "tier": 2, + "hops": 3, + "categories": ["temporal", "supersession"], + "question": "Which tonemapping curve Decision was current on beta day, 2026-06-01?", + "answer": { + "kind": "record", + "value": "dec-brine-2" + }, + "evidence": ["iss-tonemap-q", "dec-filmic", "dec-brine-1", "dec-brine-2"], + "path": [ + ["iss-tonemap-q", "resolved_by", "dec-filmic"], + ["dec-filmic", "superseded_by", "dec-brine-1"], + ["dec-brine-1", "superseded_by", "dec-brine-2"] + ], + "checks": [ + { + "type": "asof", + "start": "dec-filmic", + "at": "2026-06-01T23:59:00Z" + } + ], + "traps": [ + "The question Issue was resolved by the stock filmic curve; the 800-nit version came in September." + ] + }, + { + "id": "render-040", + "tier": 2, + "hops": 2, + "categories": ["temporal", "compaction"], + "question": "In the \"Lantern renderer overhaul\" Effort, which compaction was the newest on beta day, 2026-06-01?", + "answer": { + "kind": "record", + "value": "cmp-2" + }, + "evidence": ["cmp-4", "cmp-3", "cmp-2"], + "path": [ + ["cmp-4", "supersedes", "cmp-3"], + ["cmp-3", "supersedes", "cmp-2"] + ], + "checks": [ + { + "type": "asof", + "start": "cmp-1", + "at": "2026-06-01T23:59:00Z" + } + ], + "traps": [ + "The compaction titled \"Lantern at beta\" was written three days after beta." + ] + }, + { + "id": "render-041", + "tier": 2, + "hops": 2, + "categories": ["invalidation", "dead-evidence"], + "question": "The accepted GI Decision rests on a cost Finding that was later overturned. What does SDF GI cost on Meridian according to the Finding that overturned it?", + "answer": { + "kind": "value", + "value": "4.7 ms", + "accept": ["4.7"] + }, + "evidence": ["dec-gi-sdf", "fnd-gi-sdf-cost", "fnd-gi-sdf-recapture"], + "path": [ + ["dec-gi-sdf", "derives_from", "fnd-gi-sdf-cost"], + ["fnd-gi-sdf-cost", "invalidated_by", "fnd-gi-sdf-recapture"] + ], + "checks": [ + { + "type": "body", + "record": "fnd-gi-sdf-recapture", + "includes": "puts SDF GI at 4.7 ms", + "expect": true + } + ], + "traps": ["2.2 ms is the overturned number; 2.4 ms is retracted noise."] + }, + { + "id": "render-042", + "tier": 2, + "hops": 2, + "categories": ["lifecycle", "supersession"], + "question": "The Risk that visibility buffer bandwidth is too high for Skiff names a mitigating Decision. Which Decision now heads that Decision’s chain?", + "answer": { + "kind": "record", + "value": "dec-vb-6" + }, + "evidence": ["rsk-vb-skiff", "dec-vb-5", "dec-vb-6"], + "path": [ + ["rsk-vb-skiff", "mitigated_by", "dec-vb-5"], + ["dec-vb-5", "superseded_by", "dec-vb-6"] + ], + "checks": [ + { + "type": "head", + "start": "dec-vb-5" + } + ], + "traps": [ + "The mitigating Decision is superseded, and its replacement undid the Skiff fallback the mitigation relied on." + ] + }, + { + "id": "render-043", + "tier": 2, + "hops": 2, + "categories": ["dead-evidence", "invalidation"], + "question": "Which Finding showed that the evidence for enabling meshlet cone culling on all platforms was wrong?", + "answer": { + "kind": "record", + "value": "fnd-meshlet-cone-recount" + }, + "evidence": [ + "dec-meshlet-cone", + "fnd-meshlet-cone", + "fnd-meshlet-cone-recount" + ], + "path": [ + ["dec-meshlet-cone", "derives_from", "fnd-meshlet-cone"], + ["fnd-meshlet-cone", "invalidated_by", "fnd-meshlet-cone-recount"] + ], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "bodyIncludes": "counted twice" + } + ], + "traps": [ + "The cone-culling Decision is still accepted, so it looks sound unless its evidence is opened." + ] + }, + { + "id": "render-044", + "tier": 2, + "hops": 2, + "categories": ["rejected-alternative", "supersession"], + "question": "The Decision that rejected ray-marching refraction through the saltglass distance field has itself been replaced. By which Decision?", + "answer": { + "kind": "record", + "value": "dec-refr-hybrid" + }, + "evidence": ["dec-refr-rm", "dec-refr-ss", "dec-refr-hybrid"], + "path": [ + ["dec-refr-rm", "rejected_by", "dec-refr-ss"], + ["dec-refr-ss", "superseded_by", "dec-refr-hybrid"] + ], + "checks": [ + { + "type": "head", + "start": "dec-refr-ss" + } + ], + "traps": [ + "The ray-march proposal was never reopened; the hybrid uses a march only as a fallback." + ] + }, + { + "id": "render-045", + "tier": 2, + "hops": 2, + "categories": ["compaction", "negative"], + "question": "The newest compaction says the Brine curve's HDR shoulder starts at 1,000 nits. Does that still hold?", + "answer": { + "kind": "boolean", + "value": false + }, + "evidence": ["cmp-4", "dec-brine-2", "dec-brine-3"], + "path": [ + ["cmp-4", "derives_from", "dec-brine-2"], + ["dec-brine-2", "superseded_by", "dec-brine-3"] + ], + "checks": [ + { + "type": "head", + "start": "dec-brine-2", + "expect": "render.dec-brine-3" + }, + { + "type": "body", + "record": "dec-brine-3", + "includes": "start at 800 nits", + "expect": true + } + ], + "traps": [ + "The compaction was right when written; the shoulder moved to 800 nits in September." + ] + }, + { + "id": "render-046", + "tier": 2, + "hops": 3, + "categories": ["rationale", "reopened"], + "question": "Why were virtual shadow maps for the sun reopened after being rejected?", + "answer": { + "kind": "text", + "rubric": [ + ["capture error", "debug flag", "whole pool", "every frame"], + ["1.4 ms"], + ["seam"] + ] + }, + "evidence": ["dec-vsm", "dec-csm", "fnd-vsm-cost", "fnd-vsm-recapture"], + "path": [ + ["dec-vsm", "reopen_history", "dec-csm"], + ["dec-csm", "derives_from", "fnd-vsm-cost"], + ["fnd-vsm-cost", "invalidated_by", "fnd-vsm-recapture"] + ], + "checks": [], + "traps": [ + "Cost was the reason for rejection, and the cost turned out to be wrong." + ] + }, + { + "id": "render-047", + "tier": 2, + "hops": 2, + "categories": ["rationale", "invalidation"], + "question": "Why did the newest visibility buffer Decision bring the buffer back to Skiff?", + "answer": { + "kind": "text", + "rubric": [ + ["validation"], + ["7.4 ms"], + ["half rate", "half-rate", "every other pixel"] + ] + }, + "evidence": ["dec-vb-6", "fnd-skiff-vb-recapture", "fnd-skiff-vb-cost"], + "path": [ + ["dec-vb-6", "derives_from", "fnd-skiff-vb-recapture"], + ["fnd-skiff-vb-recapture", "invalidates", "fnd-skiff-vb-cost"] + ], + "checks": [], + "traps": ["11.2 ms came from a build with GPU validation on."] + }, + { + "id": "render-048", + "tier": 2, + "hops": 2, + "categories": ["blocker"], + "question": "Which proposed fix for the open caustic flicker blocker has a test showing it makes caustics ghost?", + "answer": { + "kind": "record", + "value": "dec-caustic-clamp" + }, + "evidence": [ + "iss-caustic-flicker", + "dec-caustic-clamp", + "fnd-caustic-clamp-test" + ], + "path": [ + ["iss-caustic-flicker", "supports", "dec-caustic-clamp"], + ["dec-caustic-clamp", "supports", "fnd-caustic-clamp-test"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "iss-caustic-flicker", + "bodyIncludes": "clamp" + } + ], + "traps": [ + "The tide-locked seed test found frozen caustics, not ghosting." + ] + }, + { + "id": "render-049", + "tier": 2, + "hops": 2, + "categories": ["reopened", "supersession"], + "question": "The reopened ray-traced sun shadow proposal was first rejected by a Decision that has since been replaced. Which Decision replaced it?", + "answer": { + "kind": "record", + "value": "dec-vsm" + }, + "evidence": ["dec-rt-shadows", "dec-csm", "dec-vsm"], + "path": [ + ["dec-rt-shadows", "reopen_history", "dec-csm"], + ["dec-csm", "superseded_by", "dec-vsm"] + ], + "checks": [ + { + "type": "head", + "start": "dec-csm" + } + ], + "traps": [ + "The replacement was itself a rejected alternative that was reopened first." + ] + }, + { + "id": "render-050", + "tier": 2, + "hops": 2, + "categories": ["distractor", "supersession", "current-state"], + "question": "The \"Lantern renderer overhaul\" Effort holds several Constraints titled Frame budget. Which one is current?", + "answer": { + "kind": "record", + "value": "con-budget-3" + }, + "evidence": ["con-budget-1", "con-budget-2", "con-budget-3"], + "path": [ + ["con-budget-1", "superseded_by", "con-budget-2"], + ["con-budget-2", "superseded_by", "con-budget-3"] + ], + "checks": [ + { + "type": "head", + "start": "con-budget-1" + } + ], + "traps": [ + "A retracted Frame budget holds the Skiff 40 Hz number and belongs to ports.", + "The ports Effort has its own Frame budget." + ] + }, + { + "id": "render-051", + "tier": 2, + "hops": 2, + "categories": ["reopened", "rejected-alternative"], + "question": "The Halcyon vendor upscaler was rejected a second time. Which defect Issue does the Decision that rejected it the second time derive from?", + "answer": { + "kind": "record", + "value": "iss-tern-ghost" + }, + "evidence": ["dec-vendor", "dec-tern-reactive", "iss-tern-ghost"], + "path": [ + ["dec-vendor", "rejected_by", "dec-tern-reactive"], + ["dec-tern-reactive", "derives_from", "iss-tern-ghost"] + ], + "checks": [ + { + "type": "select", + "kinds": ["issue"], + "where": { + "kind": "defect" + }, + "derivesFrom": "fnd-tern-ghost" + } + ], + "traps": [ + "The first rejecter answered the upscaler question Issue, not a defect." + ] + }, + { + "id": "render-052", + "tier": 2, + "hops": 3, + "categories": ["compaction", "invalidation"], + "question": "The beta compaction rests on the reactive mask Decision and repeats its ghosting figure. What share of ghosting does the mask actually remove, according to the Finding that overturned that figure?", + "answer": { + "kind": "value", + "value": "61 percent", + "accept": ["61%", "61"] + }, + "evidence": [ + "cmp-3", + "dec-tern-reactive", + "fnd-tern-ghost-fix", + "fnd-tern-ghost-recheck" + ], + "path": [ + ["cmp-3", "derives_from", "dec-tern-reactive"], + ["dec-tern-reactive", "derives_from", "fnd-tern-ghost-fix"], + ["fnd-tern-ghost-fix", "invalidated_by", "fnd-tern-ghost-recheck"] + ], + "checks": [ + { + "type": "body", + "record": "fnd-tern-ghost-recheck", + "includes": "removes 61 percent of ghosting energy", + "expect": true + } + ], + "traps": [ + "90 percent is the overturned figure that the compaction repeats." + ] + }, + { + "id": "render-053", + "tier": 3, + "hops": 4, + "categories": ["blob", "supersession", "invalidation"], + "question": "Virtual shadow maps replaced a sun-shadow Decision that had rested on a cost Finding. According to the capture attached to that Finding, how often was the shadow page pool cleared?", + "answer": { + "kind": "value", + "value": "every frame", + "accept": ["every_frame", "each frame"] + }, + "evidence": [ + "dec-vsm", + "dec-csm", + "fnd-vsm-cost", + "cit-vsm-cost", + "blb-vsm-cost" + ], + "path": [ + ["dec-vsm", "supersedes", "dec-csm"], + ["dec-csm", "derives_from", "fnd-vsm-cost"], + ["fnd-vsm-cost", "cites", "cit-vsm-cost"], + ["cit-vsm-cost", "blob", "blb-vsm-cost"] + ], + "checks": [ + { + "type": "body", + "record": "blb-vsm-cost", + "includes": "\"page_pool_clear\": \"every_frame\"", + "expect": true + } + ], + "traps": [ + "The recapture clears on invalidation only; the question asks about the capture behind the rejected Decision." + ] + }, + { + "id": "render-054", + "tier": 3, + "hops": 4, + "categories": ["blob", "supersession", "invalidation"], + "question": "The newest visibility buffer Decision replaced a version with a forward+ fallback on Skiff. What build configuration was the Skiff capture behind that fallback taken with?", + "answer": { + "kind": "value", + "value": "debug-gpu-validation", + "accept": ["debug with GPU validation", "GPU validation"] + }, + "evidence": [ + "dec-vb-6", + "dec-vb-5", + "fnd-skiff-vb-cost", + "cit-skiff-capture", + "blb-skiff-capture" + ], + "path": [ + ["dec-vb-6", "supersedes", "dec-vb-5"], + ["dec-vb-5", "derives_from", "fnd-skiff-vb-cost"], + ["fnd-skiff-vb-cost", "cites", "cit-skiff-capture"], + ["cit-skiff-capture", "blob", "blb-skiff-capture"] + ], + "checks": [ + { + "type": "body", + "record": "blb-skiff-capture", + "includes": "\"build_config\": \"debug-gpu-validation\"", + "expect": true + } + ], + "traps": [ + "The 11.2 ms Finding does not name the build configuration; only its capture does." + ] + }, + { + "id": "render-055", + "tier": 3, + "hops": 4, + "categories": ["reopened", "supersession"], + "question": "The Halcyon vendor upscaler has been rejected twice. The Decision that rejected it first rested on a measurement of Tern's 4K cost on Meridian. Which Finding is the newest version of that measurement?", + "answer": { + "kind": "record", + "value": "fnd-tern-cost-3" + }, + "evidence": [ + "dec-vendor", + "dec-tern", + "fnd-tern-cost-1", + "fnd-tern-cost-2", + "fnd-tern-cost-3" + ], + "path": [ + ["dec-vendor", "reopen_history", "dec-tern"], + ["dec-tern", "derives_from", "fnd-tern-cost-1"], + ["fnd-tern-cost-1", "superseded_by", "fnd-tern-cost-2"], + ["fnd-tern-cost-2", "superseded_by", "fnd-tern-cost-3"] + ], + "checks": [ + { + "type": "head", + "start": "fnd-tern-cost-1" + } + ], + "traps": [ + "The live rejected_by link names the reactive mask Decision, the second rejecter.", + "The 1.9 ms Finding is the version the Decision cites, not the newest." + ] + }, + { + "id": "render-056", + "tier": 3, + "hops": 5, + "categories": ["blob", "supersession"], + "question": "The visibility buffer version that brought foliage back into the buffer rests on a Finding about meshlet alpha masks, which rests on a meshlet size Decision. According to the sweep behind that Decision, how many meshlets does the cliffs benchmark have at the chosen size?", + "answer": { + "kind": "value", + "value": "208,000", + "accept": ["208000", "208k"] + }, + "evidence": [ + "dec-vb-4", + "fnd-foliage-meshlet", + "dec-meshlet-64", + "fnd-meshlet-sweep", + "cit-meshlet-sweep", + "blb-meshlet-sweep" + ], + "path": [ + ["dec-vb-4", "derives_from", "fnd-foliage-meshlet"], + ["fnd-foliage-meshlet", "derives_from", "dec-meshlet-64"], + ["dec-meshlet-64", "derives_from", "fnd-meshlet-sweep"], + ["fnd-meshlet-sweep", "cites", "cit-meshlet-sweep"], + ["cit-meshlet-sweep", "blob", "blb-meshlet-sweep"] + ], + "checks": [ + { + "type": "body", + "record": "blb-meshlet-sweep", + "includes": "| 64 | 124 | 208,000 |", + "expect": true + } + ], + "traps": ["104,000 is the 128-vertex row, the rejected size."] + }, + { + "id": "render-057", + "tier": 3, + "hops": 4, + "categories": ["compaction", "supersession"], + "question": "The vertical-slice compaction rests on one version of the visibility buffer Decision. Which Decision now heads that version’s chain?", + "answer": { + "kind": "record", + "value": "dec-vb-6" + }, + "evidence": ["cmp-1", "dec-vb-3", "dec-vb-4", "dec-vb-5", "dec-vb-6"], + "path": [ + ["cmp-1", "derives_from", "dec-vb-3"], + ["dec-vb-3", "superseded_by", "dec-vb-4"], + ["dec-vb-4", "superseded_by", "dec-vb-5"], + ["dec-vb-5", "superseded_by", "dec-vb-6"] + ], + "checks": [ + { + "type": "head", + "start": "dec-vb-3" + } + ], + "traps": [ + "The Skiff forward+ fallback version looks final but was replaced in July 2026." + ] + }, + { + "id": "render-058", + "tier": 3, + "hops": 4, + "categories": ["lifecycle", "rejected-alternative"], + "question": "The reactive mask Decision resolved a defect. That defect came from a ghosting Finding, which derives from an earlier Decision. Which question Issue did that earlier Decision derive from?", + "answer": { + "kind": "record", + "value": "iss-upscaler-q" + }, + "evidence": [ + "dec-tern-reactive", + "iss-tern-ghost", + "fnd-tern-ghost", + "dec-tern", + "iss-upscaler-q" + ], + "path": [ + ["dec-tern-reactive", "derives_from", "iss-tern-ghost"], + ["iss-tern-ghost", "derives_from", "fnd-tern-ghost"], + ["fnd-tern-ghost", "derives_from", "dec-tern"], + ["dec-tern", "derives_from", "iss-upscaler-q"] + ], + "checks": [ + { + "type": "select", + "kinds": ["issue"], + "where": { + "kind": "question" + }, + "bodyIncludes": "Halcyon" + } + ], + "traps": [ + "The Tern presets question also concerns Tern but is not where the upscaler Decision came from." + ] + }, + { + "id": "render-059", + "tier": 3, + "hops": 4, + "categories": ["invalidation", "lifecycle", "temporal"], + "question": "The vertical-slice frame-time blocker was resolved by a Decision that cut part of the accepted GI Decision. Which Finding later showed that the GI cost that GI Decision was accepted on was wrong?", + "answer": { + "kind": "record", + "value": "fnd-gi-sdf-recapture" + }, + "evidence": [ + "iss-slice-budget", + "dec-slice-cut", + "dec-gi-sdf", + "fnd-gi-sdf-cost", + "fnd-gi-sdf-recapture" + ], + "path": [ + ["iss-slice-budget", "resolved_by", "dec-slice-cut"], + ["dec-slice-cut", "derives_from", "dec-gi-sdf"], + ["dec-gi-sdf", "derives_from", "fnd-gi-sdf-cost"], + ["fnd-gi-sdf-cost", "invalidated_by", "fnd-gi-sdf-recapture"] + ], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "bodyIncludes": "more than twice the 2.2 ms" + } + ], + "traps": ["The retracted 2.4 ms draft is noise, not the correction."] + }, + { + "id": "render-060", + "tier": 3, + "hops": 5, + "categories": ["blob", "blocker"], + "question": "A test Finding shows that tide-locked caustic jitter stalls caustic motion. Trace that proposal back through the blocker it answers to the capture behind the blocker. What is the largest frame-to-frame luminance change in that capture?", + "answer": { + "kind": "value", + "value": "0.31" + }, + "evidence": [ + "fnd-caustic-seed-test", + "dec-caustic-seed", + "iss-caustic-flicker", + "fnd-caustic-flicker", + "cit-caustic-trace", + "blb-caustic-trace" + ], + "path": [ + ["fnd-caustic-seed-test", "derives_from", "dec-caustic-seed"], + ["dec-caustic-seed", "derives_from", "iss-caustic-flicker"], + ["iss-caustic-flicker", "derives_from", "fnd-caustic-flicker"], + ["fnd-caustic-flicker", "cites", "cit-caustic-trace"], + ["cit-caustic-trace", "blob", "blb-caustic-trace"] + ], + "checks": [ + { + "type": "body", + "record": "blb-caustic-trace", + "includes": "\"max_luma_delta\": 0.31", + "expect": true + } + ], + "traps": [ + "4.7 is the peak flicker frequency in hertz, not the luminance change." + ] + }, + { + "id": "render-061", + "tier": 3, + "hops": 4, + "categories": ["invalidation", "blocker", "lifecycle"], + "question": "The Risk that HDR certification slips the release candidate traces back, through its blocker and the pre-check behind that blocker, to an accepted Decision that was shown wrong. Which Constraint did that Decision rest on?", + "answer": { + "kind": "record", + "value": "con-ui-nits" + }, + "evidence": [ + "rsk-hdr-cert", + "iss-hdr-cert", + "fnd-hdr-precheck", + "dec-hdr-fixed-pw", + "con-ui-nits" + ], + "path": [ + ["rsk-hdr-cert", "derives_from", "iss-hdr-cert"], + ["iss-hdr-cert", "derives_from", "fnd-hdr-precheck"], + ["fnd-hdr-precheck", "invalidates", "dec-hdr-fixed-pw"], + ["dec-hdr-fixed-pw", "derives_from", "con-ui-nits"] + ], + "checks": [ + { + "type": "select", + "kinds": ["constraint"], + "bodyIncludes": "composite at a fixed 203 nits" + } + ], + "traps": [ + "The blocker also derives from the certification requirements Constraint, but the invalidated Decision did not." + ] + }, + { + "id": "render-062", + "tier": 3, + "hops": 2, + "categories": ["temporal", "supersession", "distractor"], + "question": "In the \"Lantern renderer overhaul\" Effort, when the Meridian 120 Hz performance mode budget was first recorded, which version of the Frame budget Constraint was current?", + "answer": { + "kind": "record", + "value": "con-budget-2" + }, + "evidence": ["con-120-2", "con-120-1", "con-budget-3", "con-budget-2"], + "path": [ + ["con-120-2", "supersedes", "con-120-1"], + ["con-budget-3", "supersedes", "con-budget-2"] + ], + "checks": [ + { + "type": "asof", + "start": "con-budget-1", + "at": "2026-03-20T10:00:00Z" + } + ], + "traps": [ + "The 120 Hz budget is a separate Constraint; its first version dates from 2026-03-20, before the 15.0 ms Frame budget." + ] + }, + { + "id": "render-063", + "tier": 3, + "hops": 3, + "categories": ["lifecycle", "supersession"], + "question": "Two Risks about the visibility buffer are mitigated: Skiff bandwidth and shader permutations. Which of the two mitigating Decisions is still in force?", + "answer": { + "kind": "record", + "value": "dec-uber-resolve" + }, + "evidence": [ + "rsk-vb-skiff", + "dec-vb-5", + "dec-vb-6", + "rsk-shader-perm", + "dec-uber-resolve" + ], + "path": [ + ["rsk-vb-skiff", "mitigated_by", "dec-vb-5"], + ["dec-vb-5", "superseded_by", "dec-vb-6"], + ["rsk-shader-perm", "mitigated_by", "dec-uber-resolve"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "where": { + "standing": "accepted" + }, + "bodyIncludes": "one uber shader per tile class" + } + ], + "traps": [ + "The Skiff mitigation is superseded, though the Risk still reads mitigated." + ] + }, + { + "id": "render-064", + "tier": 3, + "hops": 2, + "categories": ["distractor", "reopened", "rejected-alternative"], + "question": "Ines Okafor proposed virtual shadow maps twice, for different lights. One was reopened and later accepted. Which Decision rejected the other?", + "answer": { + "kind": "record", + "value": "dec-local-atlas" + }, + "evidence": ["dec-vsm", "dec-csm", "dec-local-vsm", "dec-local-atlas"], + "path": [ + ["dec-vsm", "reopen_history", "dec-csm"], + ["dec-local-vsm", "rejected_by", "dec-local-atlas"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "iss-shadow-local-q", + "where": { + "standing": "accepted" + } + } + ], + "traps": [ + "Cascaded shadow maps rejected the sun proposal, not the local-light one." + ] + }, + { + "id": "render-065", + "tier": 3, + "hops": 4, + "categories": ["invalidation", "lifecycle"], + "question": "The Finding that cut the reactive mask’s ghosting figure to 61 percent overturned an earlier measurement. Follow that measurement back through the defect it addressed to the Finding that first reported the ghosting. Which Decision did that first report derive from?", + "answer": { + "kind": "record", + "value": "dec-tern" + }, + "evidence": [ + "fnd-tern-ghost-recheck", + "fnd-tern-ghost-fix", + "iss-tern-ghost", + "fnd-tern-ghost", + "dec-tern" + ], + "path": [ + ["fnd-tern-ghost-recheck", "invalidates", "fnd-tern-ghost-fix"], + ["fnd-tern-ghost-fix", "derives_from", "iss-tern-ghost"], + ["iss-tern-ghost", "derives_from", "fnd-tern-ghost"], + ["fnd-tern-ghost", "derives_from", "dec-tern"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "bodyIncludes": "only temporal upscaler" + } + ], + "traps": [ + "The recheck derives from the reactive mask Decision, which is not the origin of the ghosting report." + ] + }, + { + "id": "render-066", + "tier": 3, + "hops": 4, + "categories": ["lifecycle", "supersession", "blocker"], + "question": "The blocker about shadow pages at spring low tide derives from a Finding, which derives from a Risk, which derives from a shadow Decision. Which Decision did that shadow Decision replace?", + "answer": { + "kind": "record", + "value": "dec-csm" + }, + "evidence": [ + "iss-vsm-tide", + "fnd-vsm-overflow", + "rsk-vsm-overflow", + "dec-vsm", + "dec-csm" + ], + "path": [ + ["iss-vsm-tide", "derives_from", "fnd-vsm-overflow"], + ["fnd-vsm-overflow", "derives_from", "rsk-vsm-overflow"], + ["rsk-vsm-overflow", "derives_from", "dec-vsm"], + ["dec-vsm", "supersedes", "dec-csm"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "bodyIncludes": "four cascaded shadow maps out to 2 km" + } + ], + "traps": [ + "Ray-traced shadows were rejected by the same Decision, but nothing replaced them." + ] + }, + { + "id": "render-067", + "tier": 4, + "hops": 1, + "categories": ["aggregate", "blocker"], + "question": "How many blocker Issues are open in the \"Lantern renderer overhaul\" Effort now?", + "answer": { + "kind": "count", + "value": 4 + }, + "evidence": [ + "iss-120-gi", + "iss-caustic-flicker", + "iss-hdr-cert", + "iss-vsm-tide" + ], + "checks": [ + { + "type": "select", + "kinds": ["issue"], + "where": { + "kind": "blocker", + "standing": "open" + }, + "count": true + } + ], + "traps": [ + "The vertical-slice blocker was resolved.", + "A duplicate caustic flicker blocker was retracted." + ] + }, + { + "id": "render-068", + "tier": 4, + "hops": 1, + "categories": ["aggregate", "blocker"], + "question": "In the \"Lantern renderer overhaul\" Effort, which proposed Decisions derive directly from an open blocker?", + "answer": { + "kind": "records", + "value": [ + "dec-caustic-clamp", + "dec-caustic-seed", + "dec-gi-120-probe", + "dec-gi-120-quarter", + "dec-hdr-pw-slider", + "dec-hdr-pw-system" + ] + }, + "evidence": [ + "iss-120-gi", + "iss-caustic-flicker", + "iss-hdr-cert", + "iss-vsm-tide" + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "where": { + "standing": "proposed" + }, + "restsOn": ["open"] + } + ], + "traps": [ + "Ray-traced sun shadows are proposed again but derive from a resolved question, not a blocker." + ] + }, + { + "id": "render-069", + "tier": 4, + "hops": 1, + "categories": ["blocker", "aggregate"], + "question": "In the \"Lantern renderer overhaul\" Effort, which open blocker has no proposed Decision deriving from it?", + "answer": { + "kind": "record", + "value": "iss-vsm-tide" + }, + "evidence": [ + "iss-120-gi", + "iss-caustic-flicker", + "iss-hdr-cert", + "iss-vsm-tide" + ], + "checks": [ + { + "type": "select", + "kinds": ["issue"], + "where": { + "kind": "blocker", + "standing": "open" + }, + "bodyIncludes": "No fix is chosen" + } + ], + "traps": [ + "The caustic flicker blocker is the oldest, but it has two proposed fixes." + ] + }, + { + "id": "render-070", + "tier": 4, + "hops": 2, + "categories": ["dead-evidence", "aggregate"], + "question": "In the \"Lantern renderer overhaul\" Effort, which live Decisions rest directly on a record that has since been invalidated?", + "answer": { + "kind": "records", + "value": ["dec-gi-sdf", "dec-meshlet-cone", "dec-tern-reactive"] + }, + "evidence": ["fnd-gi-sdf-cost", "fnd-meshlet-cone", "fnd-tern-ghost-fix"], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "live": true, + "restsOn": ["invalidated"] + } + ], + "traps": [ + "The cascaded shadow map and Skiff fallback Decisions also rested on invalidated Findings, but both are superseded.", + "A Finding about the GI share of the frame also rests on dead evidence, but it is not a Decision." + ] + }, + { + "id": "render-071", + "tier": 4, + "hops": 1, + "categories": ["aggregate", "lifecycle"], + "question": "How many Risks in the \"Lantern renderer overhaul\" Effort are mitigated?", + "answer": { + "kind": "count", + "value": 3 + }, + "evidence": ["rsk-shader-perm", "rsk-tern-ghost", "rsk-vb-skiff"], + "checks": [ + { + "type": "select", + "kinds": ["risk"], + "where": { + "standing": "mitigated" + }, + "count": true + } + ], + "traps": [ + "Accepted Risks were not mitigated; they were taken on as they are." + ] + }, + { + "id": "render-072", + "tier": 4, + "hops": 1, + "categories": ["aggregate", "lifecycle"], + "question": "In the \"Lantern renderer overhaul\" Effort, which Risks were accepted as they stand rather than mitigated or left open?", + "answer": { + "kind": "records", + "value": ["rsk-brine-match", "rsk-sdf-memory"] + }, + "evidence": ["rsk-brine-match", "rsk-sdf-memory"], + "checks": [ + { + "type": "select", + "kinds": ["risk"], + "where": { + "standing": "accepted" + } + } + ], + "traps": [ + "Both accepted Risks carry Finding evidence, which a reader may mistake for realized.", + "Mitigated Risks were handled by a Decision, not accepted." + ] + }, + { + "id": "render-073", + "tier": 4, + "hops": 1, + "categories": ["aggregate", "lifecycle"], + "question": "In the \"Lantern renderer overhaul\" Effort, which Risks came true?", + "answer": { + "kind": "records", + "value": ["rsk-120-gi", "rsk-hdr-cert", "rsk-vsm-overflow"] + }, + "evidence": ["rsk-120-gi", "rsk-hdr-cert", "rsk-vsm-overflow"], + "checks": [ + { + "type": "select", + "kinds": ["risk"], + "where": { + "standing": "realized" + } + } + ], + "traps": [ + "The HDR certification Risk turned realized only after the newest compaction, which still calls it open." + ] + }, + { + "id": "render-074", + "tier": 4, + "hops": 1, + "categories": ["retraction", "aggregate"], + "question": "How many records in the \"Lantern renderer overhaul\" Effort have been retracted?", + "answer": { + "kind": "count", + "value": 5 + }, + "evidence": [ + "con-budget-noise", + "dec-tern-dup", + "dec-vb-1-dup", + "fnd-gi-sdf-cost-noise", + "iss-caustic-flicker-dup" + ], + "checks": [ + { + "type": "select", + "retracted": "only", + "count": true + } + ], + "traps": [ + "Browse reads omit retracted records, so a reader who only lists records finds none." + ] + }, + { + "id": "render-075", + "tier": 4, + "hops": 1, + "categories": ["reopened", "aggregate"], + "question": "How many Decisions in the \"Lantern renderer overhaul\" Effort have been reopened at least once?", + "answer": { + "kind": "value", + "value": "3", + "accept": ["three"] + }, + "evidence": ["dec-vsm", "dec-rt-shadows", "dec-vendor"], + "checks": [ + { + "type": "edge", + "edge": ["dec-vsm", "reopen_history", "dec-csm"], + "expect": true + }, + { + "type": "edge", + "edge": ["dec-rt-shadows", "reopen_history", "dec-csm"], + "expect": true + }, + { + "type": "edge", + "edge": ["dec-vendor", "reopen_history", "dec-tern"], + "expect": true + } + ], + "traps": [ + "Only one of the three is accepted now; one is proposed and one was rejected again." + ] + }, + { + "id": "render-076", + "tier": 4, + "hops": 2, + "categories": ["reopened", "lifecycle"], + "question": "Could the reopened ray-traced sun shadows Decision be accepted today without first superseding another Decision?", + "answer": { + "kind": "boolean", + "value": false + }, + "evidence": ["dec-rt-shadows", "dec-vsm", "iss-shadow-q", "dec-csm"], + "checks": [ + { + "type": "field", + "record": "dec-vsm", + "field": "standing", + "expect": "accepted" + }, + { + "type": "edge", + "edge": ["dec-rt-shadows", "derives_from", "iss-shadow-q"], + "expect": true + }, + { + "type": "edge", + "edge": ["dec-vsm", "derives_from", "iss-shadow-q"], + "expect": true + }, + { + "type": "field", + "record": "dec-csm", + "field": "standing", + "expect": "superseded" + } + ], + "traps": [ + "Its old rejecter is superseded, so the reopen rule does not block it; but the sun-shadow question already has an accepted answer, so acceptance fails." + ] + }, + { + "id": "render-077", + "tier": 4, + "hops": 1, + "categories": ["compaction"], + "question": "In the \"Lantern renderer overhaul\" Effort, is the newest compaction stale?", + "answer": { + "kind": "boolean", + "value": true + }, + "evidence": ["cmp-4", "dec-brine-2", "rsk-hdr-cert"], + "checks": [ + { + "type": "compaction", + "field": "stale" + } + ], + "traps": [ + "Nothing invalidated the compaction itself; two of the records it rests on changed standing." + ] + }, + { + "id": "render-078", + "tier": 4, + "hops": 1, + "categories": ["compaction", "aggregate"], + "question": "In the \"Lantern renderer overhaul\" Effort, which records that the newest compaction rests on have changed standing since it was written?", + "answer": { + "kind": "records", + "value": ["dec-brine-2", "rsk-hdr-cert"] + }, + "evidence": [ + "cmp-4", + "dec-brine-2", + "dec-brine-3", + "rsk-hdr-cert", + "fnd-hdr-precheck-2" + ], + "checks": [ + { + "type": "compaction", + "field": "staleTargets" + } + ], + "traps": [ + "New Findings written after the compaction are changes, but the compaction does not rest on them." + ] + }, + { + "id": "render-079", + "tier": 4, + "hops": 1, + "categories": ["compaction", "aggregate"], + "question": "In the \"Lantern renderer overhaul\" Effort, how many records were added to, changed in, or left the live set since the newest compaction was written?", + "answer": { + "kind": "count", + "value": 6 + }, + "evidence": [ + "cmp-4", + "dec-brine-2", + "dec-brine-3", + "fnd-hdr-precheck-2", + "fnd-rc-capture", + "fnd-shoulder-clip", + "rsk-hdr-cert" + ], + "checks": [ + { + "type": "compaction", + "field": "changes" + } + ], + "traps": ["Counting only the two stale derivations gives 2."] + }, + { + "id": "render-080", + "tier": 4, + "hops": 5, + "categories": ["supersession", "aggregate"], + "question": "How many versions has the visibility buffer Decision had, counting the current one?", + "answer": { + "kind": "value", + "value": "6", + "accept": ["six"] + }, + "evidence": [ + "dec-vb-1", + "dec-vb-2", + "dec-vb-3", + "dec-vb-4", + "dec-vb-5", + "dec-vb-6" + ], + "checks": [ + { + "type": "chain", + "start": "dec-vb-1", + "expect": [ + "render.dec-vb-1", + "render.dec-vb-2", + "render.dec-vb-3", + "render.dec-vb-4", + "render.dec-vb-5", + "render.dec-vb-6" + ] + } + ], + "traps": ["A retracted duplicate of the first version is not a version."] + }, + { + "id": "render-081", + "tier": 4, + "hops": 1, + "categories": ["negative", "lifecycle"], + "question": "On what date did Lantern pass Meridian HDR certification?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": [ + "iss-hdr-cert", + "rsk-hdr-cert", + "fnd-hdr-precheck", + "fnd-hdr-precheck-2" + ], + "checks": [ + { + "type": "field", + "record": "rsk-hdr-cert", + "field": "standing", + "expect": "realized" + }, + { + "type": "field", + "record": "iss-hdr-cert", + "field": "status", + "expect": "open" + } + ], + "traps": [ + "The newest compaction expected the 2026-09-12 resubmission to pass; it failed." + ] + }, + { + "id": "render-082", + "tier": 4, + "hops": 1, + "categories": ["negative", "invalidation"], + "question": "Is it true that a Finding invalidated one of the Brine curve Decisions?", + "answer": { + "kind": "boolean", + "value": false + }, + "evidence": [ + "dec-brine-1", + "dec-brine-2", + "dec-brine-3", + "dec-filmic", + "fnd-filmic-clip" + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "where": { + "standing": "invalidated" + }, + "expect": ["render.dec-caustics-proj", "render.dec-hdr-fixed-pw"] + }, + { + "type": "edge", + "edge": ["dec-filmic", "invalidated_by", "fnd-filmic-clip"], + "expect": true + } + ], + "traps": [ + "The stock filmic curve was invalidated; each Brine version was superseded, never invalidated." + ], + "scoped": true + }, + { + "id": "render-083", + "tier": 4, + "hops": 2, + "categories": ["dead-evidence", "aggregate"], + "question": "In the \"Lantern renderer overhaul\" Effort, how many live records of any kind rest directly on a record that has since been invalidated?", + "answer": { + "kind": "count", + "value": 4 + }, + "evidence": [ + "dec-gi-sdf", + "dec-meshlet-cone", + "dec-tern-reactive", + "fnd-gi-frame-share" + ], + "checks": [ + { + "type": "select", + "live": true, + "restsOn": ["invalidated"], + "count": true + } + ], + "traps": [ + "Counting only Decisions gives 3; the GI frame-share Finding also rests on the overturned 2.2 ms figure." + ] + } + ] +} diff --git a/benchmarks/proof-recall/questions/tools.json b/benchmarks/proof-recall/questions/tools.json new file mode 100644 index 00000000..3c2fcb07 --- /dev/null +++ b/benchmarks/proof-recall/questions/tools.json @@ -0,0 +1,513 @@ +{ + "effort": "tools", + "questions": [ + { + "id": "tools-001", + "tier": 0, + "hops": 0, + "categories": ["lifecycle", "current-state"], + "question": "What is the status of the Effort that built the build farm's shader compile cache?", + "answer": { + "kind": "value", + "value": "completed" + }, + "evidence": ["effort"], + "checks": [ + { + "type": "field", + "record": "effort", + "field": "status" + } + ], + "traps": [ + "A plain `proof list` shows only active Efforts, so a reader who stops there may say the Effort does not exist or still call it active." + ] + }, + { + "id": "tools-002", + "tier": 0, + "hops": 0, + "categories": ["lookup"], + "question": "Before the compile cache existed, how long did a clean rebuild of every shader permutation take on the build farm?", + "answer": { + "kind": "value", + "value": "47 minutes", + "accept": ["47", "47 min", "47 minutes"] + }, + "evidence": ["iss-slow"], + "checks": [ + { + "type": "body", + "record": "iss-slow", + "includes": "47 minutes", + "expect": true + } + ], + "traps": [ + "The 6 min 40 s figure is the final warm-cache rebuild, not the starting point." + ] + }, + { + "id": "tools-003", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "According to the retrospective on the shader compile cache, what was the final clean rebuild time with a warm cache?", + "answer": { + "kind": "value", + "value": "6 min 40 s", + "accept": ["6 minutes 40 seconds", "6:40", "400 seconds", "6m40s"] + }, + "evidence": ["fnd-retro"], + "checks": [ + { + "type": "body", + "record": "fnd-retro", + "includes": "6 min 40 s", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "The figure sits at the end of a long body, past the 600-character excerpt that list and records digests show.", + "The hit-rate report's 7.2-minute median build time is a different measure." + ] + }, + { + "id": "tools-004", + "tier": 0, + "hops": 0, + "categories": ["negative", "distractor", "retraction"], + "question": "Which Decision in the shader compile cache Effort sets how the on-device pipeline cache warms up on Skiff?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": ["fnd-noise", "effort"], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "bodyIncludes": "pipeline cache", + "expect": [] + }, + { + "type": "field", + "record": "fnd-noise", + "field": "standing", + "expect": "retracted" + } + ], + "traps": [ + "A retracted Finding about the Skiff pipeline cache warming in 40 seconds was filed here by mistake; it is not a Decision and belongs to the ports Effort.", + "Casual prose calls both caches the \"shader cache\"; this Effort owns only the build farm's compile cache." + ], + "scoped": true + }, + { + "id": "tools-005", + "tier": 1, + "hops": 1, + "categories": ["supersession"], + "question": "Which Decision directly replaced the first design for the shader cache key?", + "answer": { + "kind": "record", + "value": "dec-key-v2" + }, + "evidence": ["dec-key-v1", "dec-key-v2"], + "path": [["dec-key-v1", "superseded_by", "dec-key-v2"]], + "checks": [ + { + "type": "asof", + "start": "dec-key-v1", + "at": "2025-12-01T00:00:00Z" + }, + { + "type": "edge", + "edge": ["dec-key-v1", "superseded_by", "dec-key-v2"], + "expect": true + } + ], + "traps": [ + "The current head of the chain is the binary-hash key, which replaced the second design, not the first." + ] + }, + { + "id": "tools-006", + "tier": 1, + "hops": 1, + "categories": ["rejected-alternative"], + "question": "Which Decision rejected the plan to buy more build agents for shader compiles?", + "answer": { + "kind": "record", + "value": "dec-cache" + }, + "evidence": ["dec-agents", "dec-cache"], + "path": [["dec-agents", "rejected_by", "dec-cache"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "where": { + "standing": "accepted" + }, + "derivesFrom": "iss-approach" + }, + { + "type": "edge", + "edge": ["dec-agents", "rejected_by", "dec-cache"], + "expect": true + } + ], + "traps": [ + "The 12-agent Constraint explains why the plan lost, but a Constraint cannot reject a Decision.", + "Remote execution came later and rejected nothing." + ] + }, + { + "id": "tools-007", + "tier": 2, + "hops": 2, + "categories": ["dead-evidence", "invalidation"], + "question": "Which accepted Decision in the shader compile cache Effort still rests on a Finding that was later shown to be wrong?", + "answer": { + "kind": "record", + "value": "dec-timeout" + }, + "evidence": ["dec-timeout", "fnd-flaky-net", "fnd-flaky-oom"], + "path": [ + ["dec-timeout", "derives_from", "fnd-flaky-net"], + ["fnd-flaky-net", "invalidated_by", "fnd-flaky-oom"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "where": { + "standing": "accepted" + }, + "restsOn": ["invalidated"] + } + ], + "traps": [ + "The job cap is the real fix for the flaky builds, but it rests on the correct memory diagnosis.", + "The superseded cache keys rest on superseded or live records, not on a disproved Finding." + ], + "scoped": true + }, + { + "id": "tools-008", + "tier": 2, + "hops": 2, + "categories": ["temporal", "supersession"], + "question": "Which shader cache key design was in force on 1 October 2025?", + "answer": { + "kind": "record", + "value": "dec-key-v1" + }, + "evidence": ["dec-key-v3", "dec-key-v2", "dec-key-v1"], + "path": [ + ["dec-key-v3", "supersedes", "dec-key-v2"], + ["dec-key-v2", "supersedes", "dec-key-v1"] + ], + "checks": [ + { + "type": "asof", + "start": "dec-key-v3", + "at": "2025-10-01T00:00:00Z" + } + ], + "traps": [ + "The current head, the binary-hash key, arrived in January 2026.", + "The preprocessed-source key arrived on 16 October 2025, after the stale-header builds.", + "The modification-time key was rejected and never in force." + ] + }, + { + "id": "tools-009", + "tier": 2, + "hops": 2, + "categories": ["blob"], + "question": "In the weekly shader cache hit-rate report, what hit rate did the fourth week reach?", + "answer": { + "kind": "value", + "value": "92.4%", + "accept": ["92.4", "92.4 percent"] + }, + "evidence": ["fnd-hitrate", "cit-hitrate", "blb-hitrate"], + "path": [ + ["fnd-hitrate", "cites", "cit-hitrate"], + ["cit-hitrate", "blob", "blb-hitrate"] + ], + "checks": [ + { + "type": "body", + "record": "blb-hitrate", + "includes": "\"hit_rate\": 92.4", + "expect": true + } + ], + "traps": [ + "The Finding body gives only week 1 (71%).", + "The retrospective's 94% is the later steady-state rate, and the February summary says only \"low 90s\".", + "Blob bodies are left out of list and records digests; only `proof get` on the Blob shows the series." + ] + }, + { + "id": "tools-010", + "tier": 2, + "hops": 2, + "categories": ["compaction", "invalidation", "lifecycle"], + "question": "The February summary of the shader compile cache work names a cause for the flaky nightly builds. Which Decision was built on the diagnosis that replaced that cause?", + "answer": { + "kind": "record", + "value": "dec-cap-jobs" + }, + "evidence": [ + "cmp-feb", + "fnd-flaky-net", + "fnd-flaky-oom", + "dec-cap-jobs", + "iss-flaky" + ], + "path": [ + ["cmp-feb", "derives_from", "iss-flaky"], + ["iss-flaky", "resolved_by", "dec-cap-jobs"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "fnd-flaky-oom" + }, + { + "type": "edge", + "edge": ["iss-flaky", "resolved_by", "dec-cap-jobs"], + "expect": true + } + ], + "traps": [ + "The summary names the 30-second fetch timeout as the fix; that Decision rests on the network diagnosis, which was disproved.", + "The flaky-build Issue was still open when the summary was written.", + "Walking from the summary to the flaky-build Issue and its resolver also lands here, but a reader who trusts the summary stops at the fetch-timeout Decision." + ] + }, + { + "id": "tools-011", + "tier": 2, + "hops": 3, + "categories": ["rejected-alternative", "supersession"], + "question": "The Decision that rejected timestamp-based cache keys was itself replaced twice. Which Finding prompted the second replacement?", + "answer": { + "kind": "record", + "value": "fnd-compiler-drift" + }, + "evidence": [ + "dec-key-mtime", + "dec-key-v1", + "dec-key-v2", + "dec-key-v3", + "fnd-compiler-drift", + "iss-key" + ], + "path": [ + ["dec-key-mtime", "derives_from", "iss-key"], + ["iss-key", "resolved_by", "dec-key-v3"], + ["dec-key-v3", "derives_from", "fnd-compiler-drift"] + ], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "bodyIncludes": "agent 8" + }, + { + "type": "edge", + "edge": ["fnd-compiler-drift", "supports", "dec-key-v3"], + "expect": true + } + ], + "traps": [ + "The stale-header Finding prompted the first replacement, not the second.", + "The byte-compare sampling Decision caught the mismatches but is not a Finding." + ] + }, + { + "id": "tools-012", + "tier": 4, + "hops": 0, + "categories": ["aggregate", "rejected-alternative"], + "question": "How many Decisions in the shader compile cache Effort ended up rejected?", + "answer": { + "kind": "count", + "value": 3 + }, + "evidence": [ + "dec-agents", + "dec-incremental", + "dec-key-mtime", + "dec-key-v1", + "dec-key-v2" + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "where": { + "standing": "rejected" + }, + "count": true + } + ], + "traps": [ + "The two superseded cache keys were replaced, not rejected; counting them gives 5.", + "The fetch-timeout Decision rests on a disproved Finding but is still accepted." + ], + "scoped": true + }, + { + "id": "tools-013", + "tier": 4, + "hops": 0, + "categories": ["compaction", "aggregate"], + "question": "Since the latest summary of the shader compile cache Effort was written, how many records have entered, left, or changed standing in its live set?", + "answer": { + "kind": "count", + "value": 8 + }, + "evidence": [ + "cmp-feb", + "dec-cap-jobs", + "dec-ship", + "fnd-flaky-net", + "fnd-flaky-oom", + "fnd-retro", + "iss-flaky", + "iss-slow", + "rsk-storage" + ], + "checks": [ + { + "type": "compaction", + "field": "changes" + }, + { + "type": "compaction", + "field": "head", + "expect": "tools.cmp-feb" + } + ], + "traps": [ + "The summary predates the end of the Effort; reading it alone suggests nothing has changed.", + "The workstation-access Issue was added and deferred after the summary, so it nets out of the change list." + ], + "scoped": true + }, + { + "id": "tools-014", + "tier": 2, + "hops": 2, + "categories": ["compaction", "invalidation"], + "question": "Does the latest summary of the shader compile cache Effort still give the right cause for the flaky nightly builds?", + "answer": { + "kind": "boolean", + "value": false + }, + "evidence": ["cmp-feb", "fnd-flaky-net", "fnd-flaky-oom"], + "path": [ + ["cmp-feb", "derives_from", "fnd-flaky-net"], + ["fnd-flaky-net", "invalidated_by", "fnd-flaky-oom"] + ], + "checks": [ + { + "type": "compaction", + "field": "stale", + "expect": true + }, + { + "type": "field", + "record": "fnd-flaky-net", + "field": "standing", + "expect": "invalidated" + } + ], + "traps": [ + "The summary blames cache server fetch timeouts. A later Finding showed the cause was compiler memory on agents 7 and 11." + ], + "scoped": true + }, + { + "id": "tools-015", + "tier": 4, + "hops": 0, + "categories": ["lifecycle", "aggregate", "current-state"], + "question": "When the shader compile cache Effort was completed, which Issues and Risks were closed out without being fixed or mitigated?", + "answer": { + "kind": "records", + "value": ["iss-devws", "rsk-storage"] + }, + "evidence": [ + "iss-devws", + "rsk-storage", + "fnd-retro", + "rsk-poison", + "iss-flaky", + "iss-slow" + ], + "checks": [ + { + "type": "select", + "kinds": ["issue", "risk"], + "where": { + "standing": ["deferred", "accepted", "wontfix"] + } + } + ], + "traps": [ + "The poisoned-entry Risk was mitigated by the byte-compare sample.", + "The flaky-build and rebuild-time Issues were resolved, not deferred." + ], + "scoped": true + }, + { + "id": "tools-016", + "tier": 3, + "hops": 4, + "categories": ["supersession", "lifecycle"], + "question": "The Risk of a bad cache entry reaching every build was mitigated by a Decision. A Finding that rests on that Decision prompted a new cache key. Which key design did that new key directly replace?", + "answer": { + "kind": "record", + "value": "dec-key-v2" + }, + "evidence": [ + "rsk-poison", + "dec-verify", + "fnd-compiler-drift", + "dec-key-v3", + "dec-key-v2" + ], + "path": [ + ["rsk-poison", "mitigated_by", "dec-verify"], + ["fnd-compiler-drift", "derives_from", "dec-verify"], + ["fnd-compiler-drift", "supports", "dec-key-v3"], + ["dec-key-v3", "supersedes", "dec-key-v2"] + ], + "checks": [ + { + "type": "asof", + "start": "dec-key-v3", + "at": "2026-01-14T00:00:00Z" + }, + { + "type": "edge", + "edge": ["dec-key-v3", "supersedes", "dec-key-v2"], + "expect": true + } + ], + "traps": [ + "The raw-source key is the first design; the binary-hash key replaced the preprocessed-source key, not it.", + "The binary-hash key is the new key itself, not the one it replaced." + ] + } + ] +} diff --git a/benchmarks/proof-recall/questions/world.json b/benchmarks/proof-recall/questions/world.json new file mode 100644 index 00000000..d5723937 --- /dev/null +++ b/benchmarks/proof-recall/questions/world.json @@ -0,0 +1,2337 @@ +{ + "effort": "world", + "questions": [ + { + "id": "world-001", + "tier": 0, + "hops": 0, + "categories": ["lookup"], + "question": "In the decision that moved engine jobs to fibers, how large was each fiber's stack?", + "answer": { + "kind": "value", + "value": "64 KB", + "accept": ["64KB", "64 kilobytes", "64 kB"] + }, + "evidence": ["dec-jobs-3"], + "checks": [ + { + "type": "body", + "record": "dec-jobs-3", + "includes": "64 KB stacks", + "expect": true + } + ], + "traps": [ + "The fiber decision is superseded; a reader who looks only at live records will not find the stack size." + ] + }, + { + "id": "world-002", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "According to the measurement that rechecked archetype iteration on the alpha world, how long does the Skiff join of transforms with the Submerged tag across the crab herd take?", + "answer": { + "kind": "value", + "value": "5.1 ms", + "accept": ["5.1", "5.1 milliseconds"] + }, + "evidence": ["fnd-ecs-iter-redo"], + "checks": [ + { + "type": "body", + "record": "fnd-ecs-iter-redo", + "includes": "takes 5.1 ms", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "The figure sits past the browse excerpt; a reader of the excerpt sees only 3.4 ms and 4.9 ms, which are iteration times, not the join.", + "3.2 ms is the later figure after tide-band chunks." + ] + }, + { + "id": "world-003", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "Measured on the alpha build, how often did Gull scripts crash after fiber migration?", + "answer": { + "kind": "value", + "value": "one crash per 900 script waits", + "accept": [ + "1 in 900", + "1 per 900", + "one per 900", + "1/900", + "one in 900 script waits", + "1 crash per 900 script waits" + ] + }, + "evidence": ["fnd-gull-fiber-tls"], + "checks": [ + { + "type": "body", + "record": "fnd-gull-fiber-tls", + "includes": "one crash per 900 script waits", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "The rate is in the last paragraph, past the browse excerpt.", + "1,400 is the number of native bindings, not a crash rate." + ] + }, + { + "id": "world-004", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "Over one tide turn, how many file opens did the 128 m cell layout perform?", + "answer": { + "kind": "value", + "value": "4,100", + "accept": ["4100", "4,100 file opens"] + }, + "evidence": ["fnd-cell-overhead"], + "checks": [ + { + "type": "body", + "record": "fnd-cell-overhead", + "includes": "4,100 file opens", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "600 is the old 256 m layout's figure.", + "196 is the number of resident cells." + ] + }, + { + "id": "world-005", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "In the worst case of the low-tide save bug, how far inland did the terrain solver push a salvage chest?", + "answer": { + "kind": "value", + "value": "11 m", + "accept": ["11 metres", "11 meters", "11"] + }, + "evidence": ["fnd-save-tide-mismatch"], + "checks": [ + { + "type": "body", + "record": "fnd-save-tide-mismatch", + "includes": "11 m inland", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "The distance is in the final paragraph, past the browse excerpt; 31 of 50 is the repro count." + ] + }, + { + "id": "world-006", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "In the alpha playtest field captures of streaming pool behaviour, how often did players reverse direction on average?", + "answer": { + "kind": "value", + "value": "3.4 times per minute", + "accept": ["3.4", "3.4 per minute", "3.4 reversals per minute"] + }, + "evidence": ["fnd-pool-field"], + "checks": [ + { + "type": "body", + "record": "fnd-pool-field", + "includes": "3.4 times per minute", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "The figure is past the excerpt; 22% and 63% are reload reductions." + ] + }, + { + "id": "world-007", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "When the streaming pool was cut by 400 MB, how much of that came from texture mips?", + "answer": { + "kind": "value", + "value": "260 MB", + "accept": ["260"] + }, + "evidence": ["con-pool-2"], + "checks": [ + { + "type": "body", + "record": "con-pool-2", + "includes": "texture mips give back 260 MB", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "The split is in the last paragraph of a superseded constraint; the current constraint does not repeat it.", + "320 MB is the tide-band reservation, not part of the cut." + ] + }, + { + "id": "world-008", + "tier": 0, + "hops": 0, + "categories": ["truncation", "lookup"], + "question": "At what rate does the fixed-point tide simulation step?", + "answer": { + "kind": "value", + "value": "10 Hz", + "accept": ["10", "10 times a second", "ten times per second"] + }, + "evidence": ["dec-tide-fixed"], + "checks": [ + { + "type": "body", + "record": "dec-tide-fixed", + "includes": "steps at 10 Hz", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "The rate is in the last paragraph of the decision, past the excerpt.", + "The 10 updates a second in the host-streaming finding describe network updates for a rejected option." + ] + }, + { + "id": "world-009", + "tier": 0, + "hops": 0, + "categories": ["lookup", "distractor"], + "question": "How much does one fixed-point tide step cost on Meridian?", + "answer": { + "kind": "value", + "value": "0.3 ms", + "accept": ["0.3", "0.3 milliseconds"] + }, + "evidence": ["fnd-tide-fixed-meridian"], + "checks": [ + { + "type": "body", + "record": "fnd-tide-fixed-meridian", + "includes": "0.3 ms on Meridian", + "expect": true + } + ], + "traps": ["A near-identical finding gives 0.9 ms, but for Skiff."] + }, + { + "id": "world-010", + "tier": 0, + "hops": 0, + "categories": ["retraction", "lookup"], + "question": "A finding about Kelp's decode speed was retracted within an hour of being written. What per-core decode rate did the retracted record claim?", + "answer": { + "kind": "value", + "value": "29 GB/s", + "accept": ["29", "29 GB/s per core"] + }, + "evidence": ["fnd-codec-1-typo"], + "checks": [ + { + "type": "field", + "record": "fnd-codec-1-typo", + "field": "standing", + "expect": "retracted" + }, + { + "type": "body", + "record": "fnd-codec-1-typo", + "includes": "29 GB/s", + "expect": true + } + ], + "traps": [ + "Browse reads omit the retracted record; 2.9 GB/s is the corrected live finding." + ] + }, + { + "id": "world-011", + "tier": 0, + "hops": 0, + "categories": ["lifecycle"], + "question": "How was the gap about missing entity debug names in release builds closed?", + "answer": { + "kind": "value", + "value": "wontfix", + "accept": ["won't fix", "wont fix"] + }, + "evidence": ["iss-ecs-names", "fnd-ecs-names-cost"], + "checks": [ + { + "type": "field", + "record": "iss-ecs-names", + "field": "status" + } + ], + "traps": [ + "It was not resolved or deferred; the 57 MB cost closed it as wontfix." + ] + }, + { + "id": "world-012", + "tier": 0, + "hops": 0, + "categories": ["current-state"], + "question": "Which decision currently defines how engine jobs are scheduled?", + "answer": { + "kind": "record", + "value": "dec-jobs-6" + }, + "evidence": ["dec-jobs-6"], + "checks": [ + { + "type": "head", + "start": "dec-jobs-1" + } + ], + "traps": [ + "The April decision that returned jobs to a thread pool is superseded; the current one also folds Gull scripts into the pool.", + "A retracted draft has an almost identical title to the April decision." + ] + }, + { + "id": "world-013", + "tier": 0, + "hops": 0, + "categories": ["negative", "blocker"], + "question": "On what date was the deadline-based streaming read scheduler accepted?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": ["dec-io-deadline"], + "checks": [ + { + "type": "field", + "record": "dec-io-deadline", + "field": "state", + "expect": "proposed" + } + ], + "traps": [ + "The premise is false: the deadline scheduler is still proposed. 2026-08-14 is its creation date." + ] + }, + { + "id": "world-014", + "tier": 0, + "hops": 0, + "categories": ["negative", "distractor"], + "question": "What frame budget in milliseconds does the \"Kestrel world streaming and simulation core\" Effort set for Skiff's 40 Hz mode?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": ["con-gull-tick"], + "checks": [ + { + "type": "select", + "bodyIncludes": "40 Hz", + "count": true, + "expect": 0 + } + ], + "traps": [ + "The world Effort sets no frame budget; 3.0 ms is the Gull tick budget on Skiff, a share of a frame, not the frame budget." + ] + }, + { + "id": "world-015", + "tier": 0, + "hops": 0, + "categories": ["lookup"], + "question": "What is the Gull script tick budget per frame on Skiff?", + "answer": { + "kind": "value", + "value": "3.0 ms", + "accept": ["3 ms", "3.0", "3"] + }, + "evidence": ["con-gull-tick"], + "checks": [ + { + "type": "body", + "record": "con-gull-tick", + "includes": "3.0 ms per frame on Skiff", + "expect": true + } + ], + "traps": ["2.0 ms is Meridian's budget."] + }, + { + "id": "world-016", + "tier": 0, + "hops": 0, + "categories": ["negative", "lifecycle"], + "question": "On what date was the world streaming and simulation Effort paused?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": ["effort"], + "checks": [ + { + "type": "field", + "record": "effort", + "field": "status", + "expect": "active" + } + ], + "traps": [ + "The premise is false: the Effort is active and nothing records a pause." + ] + }, + { + "id": "world-017", + "tier": 1, + "hops": 1, + "categories": ["temporal", "supersession"], + "question": "Which cell size decision was in force at the vertical slice on 2025-12-15?", + "answer": { + "kind": "record", + "value": "dec-cell-128" + }, + "evidence": ["dec-cell-192", "dec-cell-128"], + "path": [["dec-cell-192", "supersedes", "dec-cell-128"]], + "checks": [ + { + "type": "asof", + "start": "dec-cell-192", + "at": "2025-12-15T00:00:00Z" + } + ], + "traps": [ + "192 m cells came in April 2026; 256 m cells were replaced in November 2025." + ] + }, + { + "id": "world-018", + "tier": 1, + "hops": 1, + "categories": ["rejected-alternative"], + "question": "Which decision rejected the proposal to run engine jobs on fibers from the start?", + "answer": { + "kind": "record", + "value": "dec-jobs-1" + }, + "evidence": ["dec-jobs-fibers-early", "dec-jobs-1"], + "path": [["dec-jobs-fibers-early", "rejected_by", "dec-jobs-1"]], + "checks": [ + { + "type": "asof", + "start": "dec-jobs-6", + "at": "2025-09-13T00:00:00Z" + } + ], + "traps": [ + "The later move to fibers did not reopen this proposal; it stays rejected by the first thread-pool decision." + ] + }, + { + "id": "world-019", + "tier": 1, + "hops": 1, + "categories": ["invalidation"], + "question": "Which finding showed that giving reads for tide-exposed cells top priority was wrong?", + "answer": { + "kind": "record", + "value": "fnd-io-starve" + }, + "evidence": ["dec-io-tide-priority", "fnd-io-starve"], + "path": [["dec-io-tide-priority", "invalidated_by", "fnd-io-starve"]], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "derivesFrom": "dec-io-tide-priority" + } + ], + "traps": [ + "The blocker about untextured terrain is an Issue, not the invalidating finding." + ] + }, + { + "id": "world-020", + "tier": 1, + "hops": 1, + "categories": ["blocker"], + "question": "Which proposed decision answers the open blocker about inland terrain staying untextured during tide turns?", + "answer": { + "kind": "record", + "value": "dec-io-deadline" + }, + "evidence": ["iss-blk-io-starve", "dec-io-deadline"], + "path": [["iss-blk-io-starve", "supports", "dec-io-deadline"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "iss-blk-io-starve" + } + ], + "traps": [ + "The tide-priority decision caused the blocker; it does not answer it." + ] + }, + { + "id": "world-021", + "tier": 1, + "hops": 1, + "categories": ["lifecycle"], + "question": "Which decision mitigated the risk that 192 m cells split the navigation tiles?", + "answer": { + "kind": "record", + "value": "dec-nav-64" + }, + "evidence": ["rsk-cell-seams", "dec-nav-64"], + "path": [["rsk-cell-seams", "mitigated_by", "dec-nav-64"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "rsk-cell-seams" + } + ], + "traps": [ + "The 192 m cell decision created the risk; it did not mitigate it." + ] + }, + { + "id": "world-022", + "tier": 1, + "hops": 1, + "categories": ["lifecycle"], + "question": "Which finding was recorded as evidence when the risk that fiber stacks make crash dumps unreadable was realized?", + "answer": { + "kind": "record", + "value": "fnd-fiber-crash-stacks" + }, + "evidence": ["rsk-fiber-debug", "fnd-fiber-crash-stacks"], + "path": [["rsk-fiber-debug", "evidence", "fnd-fiber-crash-stacks"]], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "derivesFrom": "rsk-fiber-debug" + } + ], + "traps": [ + "The Gull thread-local finding is about fibers too, but it is not this risk's evidence." + ] + }, + { + "id": "world-023", + "tier": 1, + "hops": 1, + "categories": ["reopened", "rejected-alternative"], + "question": "Before the Zstandard codec proposal was reopened, which decision had rejected it?", + "answer": { + "kind": "record", + "value": "dec-codec-kelp" + }, + "evidence": ["dec-codec-zstd", "dec-codec-kelp"], + "path": [["dec-codec-zstd", "reopen_history", "dec-codec-kelp"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "iss-codec", + "where": { + "standing": "accepted" + } + } + ], + "traps": [ + "The current rejected_by link names the 1 MB dictionary decision, which rejected it the second time; the first rejecter is only in the reopen history." + ] + }, + { + "id": "world-024", + "tier": 1, + "hops": 1, + "categories": ["reopened", "rejected-alternative"], + "question": "After the Zstandard codec proposal was reopened, which decision rejected it again?", + "answer": { + "kind": "record", + "value": "dec-codec-dict" + }, + "evidence": ["dec-codec-zstd", "dec-codec-dict"], + "path": [["dec-codec-zstd", "rejected_by", "dec-codec-dict"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "fnd-codec-3" + } + ], + "traps": [ + "The original Kelp decision rejected it the first time, before the reopening." + ] + }, + { + "id": "world-025", + "tier": 1, + "hops": 1, + "categories": ["supersession", "distractor"], + "question": "Which constraint directly replaced the original 2.0 GB streaming pool budget?", + "answer": { + "kind": "record", + "value": "con-pool-2" + }, + "evidence": ["con-pool-1", "con-pool-2"], + "path": [["con-pool-1", "superseded_by", "con-pool-2"]], + "checks": [ + { + "type": "asof", + "start": "con-pool-1", + "at": "2026-06-30T00:00:00Z" + } + ], + "traps": [ + "Three live-looking records share the title; the current one adds the tide-band reservation and replaced the June cut, not the original.", + "A retracted draft proposed 1.8 GB." + ] + }, + { + "id": "world-026", + "tier": 1, + "hops": 1, + "categories": ["invalidation", "distractor"], + "question": "Which finding showed that the December measurement of sustained Skiff streaming reads was wrong?", + "answer": { + "kind": "record", + "value": "fnd-io-trace-2" + }, + "evidence": ["fnd-io-trace-1", "fnd-io-trace-2"], + "path": [["fnd-io-trace-1", "invalidated_by", "fnd-io-trace-2"]], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "derivesFrom": "fnd-io-trace-1" + } + ], + "traps": [ + "The I/O budget constraint was superseded, not invalidated, and it is not a finding." + ] + }, + { + "id": "world-027", + "tier": 1, + "hops": 1, + "categories": ["current-state", "distractor"], + "question": "What sustained read rate does the current streaming I/O budget allow on Skiff?", + "answer": { + "kind": "value", + "value": "160 MB/s", + "accept": ["160"] + }, + "evidence": ["con-io-budget", "con-io-budget-2"], + "path": [["con-io-budget", "superseded_by", "con-io-budget-2"]], + "checks": [ + { + "type": "body", + "record": "con-io-budget-2", + "includes": "under 160 MB/s", + "expect": true + } + ], + "traps": [ + "220 MB/s is the superseded December budget.", + "The streaming pool budget has a near-identical title but limits memory, not reads." + ] + }, + { + "id": "world-028", + "tier": 1, + "hops": 1, + "categories": ["rejected-alternative"], + "question": "Which finding measured the cost that ruled out having the host stream tide heights to every peer?", + "answer": { + "kind": "record", + "value": "fnd-tide-host-bw" + }, + "evidence": ["dec-tide-host", "fnd-tide-host-bw"], + "path": [["dec-tide-host", "supports", "fnd-tide-host-bw"]], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "derivesFrom": "dec-tide-host" + } + ], + "traps": ["The strict-float finding ruled out a different alternative."] + }, + { + "id": "world-029", + "tier": 1, + "hops": 1, + "categories": ["blocker", "lifecycle"], + "question": "Which decision resolved the blocker about crash triage stalling on unreadable fiber stacks?", + "answer": { + "kind": "record", + "value": "dec-jobs-5" + }, + "evidence": ["iss-blk-crash-triage", "dec-jobs-5"], + "path": [["iss-blk-crash-triage", "resolved_by", "dec-jobs-5"]], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "iss-blk-crash-triage" + } + ], + "traps": [ + "A retracted draft with a near-identical title is not the resolver.", + "The current job decision came later and did not resolve the blocker." + ] + }, + { + "id": "world-030", + "tier": 1, + "hops": 1, + "categories": ["compaction", "invalidation"], + "question": "Which compaction did the finding that hot reload drops suspended Gull coroutines invalidate?", + "answer": { + "kind": "record", + "value": "cmp-2" + }, + "evidence": ["fnd-gull-reload-coro", "cmp-2"], + "path": [["fnd-gull-reload-coro", "invalidates", "cmp-2"]], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "compactions": true, + "where": { + "kind": "compaction" + }, + "bodyIncludes": "94% of edits" + } + ], + "traps": [ + "The finding also invalidates the reload prototype finding, but that is not a compaction.", + "The head compaction is not invalidated." + ] + }, + { + "id": "world-031", + "tier": 1, + "hops": 1, + "categories": ["current-state", "compaction", "supersession"], + "question": "What is the latest measured cold decode rate on Skiff for Kelp with a 1 MB dictionary?", + "answer": { + "kind": "value", + "value": "1.5 GB/s", + "accept": ["1.5"] + }, + "evidence": ["fnd-codec-3", "fnd-codec-4", "cmp-4"], + "path": [["fnd-codec-3", "superseded_by", "fnd-codec-4"]], + "checks": [ + { + "type": "body", + "record": "fnd-codec-4", + "includes": "now decodes at 1.5 GB/s", + "expect": true + } + ], + "traps": [ + "The head compaction and the superseded finding say 2.2 GB/s; firmware 3.2 changed it after the compaction was written." + ] + }, + { + "id": "world-032", + "tier": 1, + "hops": 1, + "categories": ["temporal", "supersession"], + "question": "Which tide drift measurement was the current one on 2025-10-25?", + "answer": { + "kind": "record", + "value": "fnd-tide-drift-2" + }, + "evidence": ["fnd-tide-drift-3", "fnd-tide-drift-2"], + "path": [["fnd-tide-drift-3", "supersedes", "fnd-tide-drift-2"]], + "checks": [ + { + "type": "asof", + "start": "fnd-tide-drift-3", + "at": "2025-10-25T00:00:00Z" + } + ], + "traps": [ + "The 6-minute finding came on 2025-10-29; a retracted duplicate of it has a near-identical title." + ] + }, + { + "id": "world-033", + "tier": 1, + "hops": 1, + "categories": ["temporal", "supersession"], + "question": "Which save format decision was in force at the vertical slice on 2025-12-15?", + "answer": { + "kind": "record", + "value": "dec-save-delta" + }, + "evidence": ["dec-save-delta-2", "dec-save-delta"], + "path": [["dec-save-delta-2", "supersedes", "dec-save-delta"]], + "checks": [ + { + "type": "asof", + "start": "dec-save-delta-2", + "at": "2025-12-15T00:00:00Z" + } + ], + "traps": [ + "The tide-phase deltas came in February 2026.", + "Full snapshots were rejected; the near-identical title of the current decision differs only in what deltas are keyed to." + ] + }, + { + "id": "world-034", + "tier": 1, + "hops": 1, + "categories": ["negative", "lifecycle"], + "question": "What did the \"Kestrel world streaming and simulation core\" Effort decide about cross-platform cloud saves?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": ["iss-save-cloud", "fnd-save-cloud-scope"], + "path": [["iss-save-cloud", "resolved_by", "fnd-save-cloud-scope"]], + "checks": [ + { + "type": "field", + "record": "iss-save-cloud", + "field": "status", + "expect": "deferred" + } + ], + "traps": [ + "No decision exists: the issue was deferred by a survey finding to a post-launch patch." + ] + }, + { + "id": "world-035", + "tier": 1, + "hops": 1, + "categories": ["negative", "lookup"], + "question": "Does the accepted Gull VM compile scripts to machine code at run time?", + "answer": { + "kind": "boolean", + "value": false + }, + "evidence": ["dec-gull-bytecode", "con-no-jit"], + "path": [["dec-gull-bytecode", "derives_from", "con-no-jit"]], + "checks": [ + { + "type": "field", + "record": "dec-gull-bytecode", + "field": "state", + "expect": "accepted" + } + ], + "traps": [ + "The VM runs bytecode with no JIT because consoles forbid runtime code generation; the build-time C++ transpiler was rejected." + ] + }, + { + "id": "world-036", + "tier": 1, + "hops": 1, + "categories": ["rationale"], + "question": "Why did Kestrel retire fibers for engine jobs in April 2026?", + "answer": { + "kind": "text", + "rubric": [ + ["41%", "41 percent"], + ["crash", "stack"], + ["continuation"], + ["93%", "7%", "idle", "busy"] + ] + }, + "evidence": [ + "dec-jobs-5", + "fnd-fiber-crash-stacks", + "fnd-jobs-continuations" + ], + "path": [["dec-jobs-5", "derives_from", "fnd-fiber-crash-stacks"]], + "checks": [ + { + "type": "body", + "record": "dec-jobs-5", + "includes": "41% of alpha crash reports", + "expect": true + } + ], + "traps": [ + "The Gull thread-local bug had already been handled by pinning Gull threads; the April reversal was driven by unreadable crash stacks and the continuation prototype." + ] + }, + { + "id": "world-037", + "tier": 2, + "hops": 2, + "categories": ["dead-evidence", "invalidation"], + "question": "The accepted decision to hot-reload Gull functions by swapping bytecode rests on a finding that has since been invalidated. Which finding invalidated that support?", + "answer": { + "kind": "record", + "value": "fnd-gull-reload-coro" + }, + "evidence": [ + "dec-gull-reload", + "fnd-gull-reload-proto", + "fnd-gull-reload-coro" + ], + "path": [ + ["dec-gull-reload", "derives_from", "fnd-gull-reload-proto"], + ["fnd-gull-reload-proto", "invalidated_by", "fnd-gull-reload-coro"] + ], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "derivesFrom": "fnd-gull-reload-proto" + } + ], + "traps": [ + "The coroutine defect Issue has a near-identical title but is an Issue, not the invalidating finding.", + "The reload decision itself is still accepted, not invalidated." + ] + }, + { + "id": "world-038", + "tier": 2, + "hops": 3, + "categories": ["blob", "invalidation"], + "question": "How many archetypes existed in the world used by the ECS iteration benchmark that the alpha-world recheck invalidated?", + "answer": { + "kind": "value", + "value": "3", + "accept": ["three"] + }, + "evidence": [ + "fnd-ecs-iter-redo", + "fnd-ecs-iter-bench", + "cit-ecs-profile", + "blob-ecs-profile" + ], + "path": [ + ["fnd-ecs-iter-redo", "invalidates", "fnd-ecs-iter-bench"], + ["fnd-ecs-iter-bench", "cites", "cit-ecs-profile"], + ["cit-ecs-profile", "blob", "blob-ecs-profile"] + ], + "checks": [ + { + "type": "body", + "record": "blob-ecs-profile", + "includes": "\"archetype_count\": 3", + "expect": true + } + ], + "traps": [ + "912 is the alpha world's archetype count.", + "The findings say only that one spawn template was used; the count is only in the attached profile." + ] + }, + { + "id": "world-039", + "tier": 2, + "hops": 2, + "categories": ["blob"], + "question": "In the cold-cache Skiff codec benchmark, how fast did Zstandard decode geometry?", + "answer": { + "kind": "value", + "value": "1.2 GB/s", + "accept": ["1.2"] + }, + "evidence": ["fnd-codec-2", "cit-codec-2", "blob-codec-2"], + "path": [ + ["fnd-codec-2", "cites", "cit-codec-2"], + ["cit-codec-2", "blob", "blob-codec-2"] + ], + "checks": [ + { + "type": "body", + "record": "blob-codec-2", + "includes": "| Geometry | 0.8 | 1.2 |", + "expect": true + } + ], + "traps": [ + "1.3 GB/s is Zstandard's weighted figure for all assets, and also its warm geometry figure in the October table." + ] + }, + { + "id": "world-040", + "tier": 2, + "hops": 2, + "categories": ["blob", "negative"], + "question": "What LZ4 decode rate did the cold-cache Skiff codec benchmark record?", + "answer": { + "kind": "value", + "value": "unknown" + }, + "evidence": ["fnd-codec-2", "cit-codec-2", "blob-codec-2"], + "path": [ + ["fnd-codec-2", "cites", "cit-codec-2"], + ["cit-codec-2", "blob", "blob-codec-2"] + ], + "checks": [ + { + "type": "body", + "record": "blob-codec-2", + "includes": "LZ4 was not rerun", + "expect": true + } + ], + "traps": [ + "3.8 GB/s is LZ4's warm-cache figure from the invalidated October benchmark; LZ4 was not rerun cold." + ] + }, + { + "id": "world-041", + "tier": 2, + "hops": 2, + "categories": ["blob"], + "question": "In the Skiff streaming trace of a falling tide with 256 m cells, what share of the reads were textures?", + "answer": { + "kind": "value", + "value": "61%", + "accept": ["0.61", "61 percent"] + }, + "evidence": [ + "fnd-tide-burst", + "cit-trace-tide-turn", + "blob-trace-tide-turn" + ], + "path": [ + ["fnd-tide-burst", "cites", "cit-trace-tide-turn"], + ["cit-trace-tide-turn", "blob", "blob-trace-tide-turn"] + ], + "checks": [ + { + "type": "body", + "record": "blob-trace-tide-turn", + "includes": "\"textures\": 0.61", + "expect": true + } + ], + "traps": [ + "30% is the share of a cell that changes when the tide falls, not a read share." + ] + }, + { + "id": "world-042", + "tier": 2, + "hops": 3, + "categories": ["blob", "lifecycle"], + "question": "The risk that delta saves outgrow console save slots was accepted on the strength of one measurement. In the data behind that measurement, how long does an 80-hour save take to load on Skiff?", + "answer": { + "kind": "value", + "value": "5.4 s", + "accept": ["5.4", "5.4 seconds"] + }, + "evidence": [ + "rsk-save-size", + "fnd-save-size", + "cit-save-sizes", + "blob-save-sizes" + ], + "path": [ + ["rsk-save-size", "evidence", "fnd-save-size"], + ["fnd-save-size", "cites", "cit-save-sizes"], + ["cit-save-sizes", "blob", "blob-save-sizes"] + ], + "checks": [ + { + "type": "body", + "record": "blob-save-sizes", + "includes": "80,69800,12.3,5.4", + "expect": true + } + ], + "traps": [ + "2.9 s is the 40-hour load time; 12.3 is the 80-hour save size in MB." + ] + }, + { + "id": "world-043", + "tier": 2, + "hops": 2, + "categories": ["blob"], + "question": "According to the log behind the finding that float tides drift apart between machines within 6 minutes, at what minute did the first walkable tile flip?", + "answer": { + "kind": "value", + "value": "5.8", + "accept": ["5.8 minutes", "minute 5.8"] + }, + "evidence": ["fnd-tide-drift-3", "cit-tide-drift", "blob-tide-drift"], + "path": [ + ["fnd-tide-drift-3", "cites", "cit-tide-drift"], + ["cit-tide-drift", "blob", "blob-tide-drift"] + ], + "checks": [ + { + "type": "body", + "record": "blob-tide-drift", + "includes": "\"minute\": 5.8", + "expect": true + } + ], + "traps": [ + "5.6 minutes is when PC and Skiff first passed the 1 cm threshold, not when a tile flipped.", + "6 minutes is the rounded headline." + ] + }, + { + "id": "world-044", + "tier": 2, + "hops": 3, + "categories": ["temporal", "supersession"], + "question": "Which job model decision was in force at the vertical slice on 2025-12-15?", + "answer": { + "kind": "record", + "value": "dec-jobs-3" + }, + "evidence": ["dec-jobs-6", "dec-jobs-5", "dec-jobs-4", "dec-jobs-3"], + "path": [ + ["dec-jobs-6", "supersedes", "dec-jobs-5"], + ["dec-jobs-5", "supersedes", "dec-jobs-4"], + ["dec-jobs-4", "supersedes", "dec-jobs-3"] + ], + "checks": [ + { + "type": "asof", + "start": "dec-jobs-6", + "at": "2025-12-15T00:00:00Z" + } + ], + "traps": [ + "The current decision is a thread pool, so a reader may assume the slice used one; at the slice, jobs ran on fibers.", + "The early fiber proposal was rejected and never in force." + ] + }, + { + "id": "world-045", + "tier": 2, + "hops": 2, + "categories": ["temporal", "supersession"], + "question": "Which job model decision was in force at alpha on 2026-03-02?", + "answer": { + "kind": "record", + "value": "dec-jobs-4" + }, + "evidence": ["dec-jobs-6", "dec-jobs-5", "dec-jobs-4"], + "path": [ + ["dec-jobs-6", "supersedes", "dec-jobs-5"], + ["dec-jobs-5", "supersedes", "dec-jobs-4"] + ], + "checks": [ + { + "type": "asof", + "start": "dec-jobs-6", + "at": "2026-03-02T00:00:00Z" + } + ], + "traps": [ + "Plain fibers were replaced in February by fibers with Gull pinned to dedicated threads; the return to a thread pool came in April." + ] + }, + { + "id": "world-046", + "tier": 2, + "hops": 2, + "categories": ["temporal", "supersession", "distractor"], + "question": "Which streaming pool budget constraint applied at alpha on 2026-03-02?", + "answer": { + "kind": "record", + "value": "con-pool-1" + }, + "evidence": ["con-pool-3", "con-pool-2", "con-pool-1"], + "path": [ + ["con-pool-3", "supersedes", "con-pool-2"], + ["con-pool-2", "supersedes", "con-pool-1"] + ], + "checks": [ + { + "type": "asof", + "start": "con-pool-3", + "at": "2026-03-02T00:00:00Z" + } + ], + "traps": [ + "All three versions share one title; the 1.6 GB cut came in June 2026, after alpha." + ] + }, + { + "id": "world-047", + "tier": 2, + "hops": 2, + "categories": ["temporal", "compaction"], + "question": "In the \"Kestrel world streaming and simulation core\" Effort, which compaction was the head compaction when beta started on 2026-06-01?", + "answer": { + "kind": "record", + "value": "cmp-2" + }, + "evidence": ["cmp-4", "cmp-3", "cmp-2"], + "path": [ + ["cmp-4", "supersedes", "cmp-3"], + ["cmp-3", "supersedes", "cmp-2"] + ], + "checks": [ + { + "type": "asof", + "start": "cmp-4", + "at": "2026-06-01T00:00:00Z" + } + ], + "traps": [ + "The compaction titled 'after beta' was written on 2026-06-10.", + "The head at beta had already been invalidated, but it was still the head." + ] + }, + { + "id": "world-048", + "tier": 2, + "hops": 2, + "categories": ["rejected-alternative"], + "question": "The measurement that alpha content needs 6.2 ms of Gull time per frame prompted a build-time alternative to the VM. Which decision rejected that alternative?", + "answer": { + "kind": "record", + "value": "dec-gull-bytecode" + }, + "evidence": [ + "fnd-gull-alpha-tick", + "dec-gull-transpile", + "dec-gull-bytecode" + ], + "path": [ + ["fnd-gull-alpha-tick", "supports", "dec-gull-transpile"], + ["dec-gull-transpile", "rejected_by", "dec-gull-bytecode"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "con-no-jit" + } + ], + "traps": [ + "The transpiler did not answer the Gull VM question, so no sibling rule rejected it; the bytecode decision named it explicitly when accepted.", + "The tree-walking interpreter decision was superseded, not the rejecter." + ] + }, + { + "id": "world-049", + "tier": 2, + "hops": 2, + "categories": ["dead-evidence", "invalidation"], + "question": "The accepted policy to evict cells by distance and tide forecast rests on a simulation. What reload reduction did field captures measure instead?", + "answer": { + "kind": "value", + "value": "22%", + "accept": ["22", "22 percent"] + }, + "evidence": ["dec-pool-forecast", "fnd-pool-sim", "fnd-pool-field"], + "path": [ + ["dec-pool-forecast", "derives_from", "fnd-pool-sim"], + ["fnd-pool-sim", "invalidated_by", "fnd-pool-field"] + ], + "checks": [ + { + "type": "body", + "record": "fnd-pool-field", + "includes": "cuts reloads by 22%", + "expect": true + } + ], + "traps": [ + "63% is the simulated figure, which was invalidated.", + "38% is LRU's share of tide-turn reloads that had just been evicted." + ] + }, + { + "id": "world-050", + "tier": 2, + "hops": 2, + "categories": ["reopened"], + "question": "The proposal to compile Gull to bytecode was rejected and later reopened. Which finding about the decision that had rejected it prompted the reopening?", + "answer": { + "kind": "record", + "value": "fnd-gull-alpha-tick" + }, + "evidence": ["dec-gull-bytecode", "dec-gull-tree", "fnd-gull-alpha-tick"], + "path": [ + ["dec-gull-bytecode", "reopen_history", "dec-gull-tree"], + ["dec-gull-tree", "supports", "fnd-gull-alpha-tick"] + ], + "checks": [ + { + "type": "select", + "kinds": ["finding"], + "derivesFrom": "dec-gull-tree" + } + ], + "traps": [ + "The register VM prototype finding came after the reopening.", + "The 1.8 ms interpreter finding came before the first rejection." + ] + }, + { + "id": "world-051", + "tier": 2, + "hops": 2, + "categories": ["rationale", "rejected-alternative"], + "question": "Why did the tide simulation move to fixed point instead of compiling the float code in strict IEEE mode?", + "answer": { + "kind": "text", + "rubric": [ + ["sin", "math library"], + ["ulp"], + ["Skiff"], + ["bit-identical", "bit for bit", "bit-exact", "same bits"] + ] + }, + "evidence": [ + "dec-tide-strict", + "dec-tide-fixed", + "fnd-tide-strict-test", + "con-tide-bitexact" + ], + "path": [ + ["dec-tide-strict", "rejected_by", "dec-tide-fixed"], + ["dec-tide-strict", "supports", "fnd-tide-strict-test"] + ], + "checks": [ + { + "type": "body", + "record": "fnd-tide-strict-test", + "includes": "differs by one ulp", + "expect": true + } + ], + "traps": [ + "Strict mode fixed the compiler contraction and matched PC with Meridian; it failed only because Skiff's sin() differs by one ulp." + ] + }, + { + "id": "world-052", + "tier": 2, + "hops": 3, + "categories": ["lookup", "lifecycle"], + "question": "The current streaming pool constraint descends from a cut that an earlier risk predicted. Who wrote that risk?", + "answer": { + "kind": "value", + "value": "Dara Whitlock", + "accept": ["Dara"] + }, + "evidence": [ + "con-pool-3", + "con-pool-2", + "fnd-pool-cut-notice", + "rsk-pool-cut" + ], + "path": [ + ["con-pool-3", "supersedes", "con-pool-2"], + ["con-pool-2", "derives_from", "fnd-pool-cut-notice"], + ["fnd-pool-cut-notice", "derives_from", "rsk-pool-cut"] + ], + "checks": [ + { + "type": "field", + "record": "rsk-pool-cut", + "field": "created_by" + } + ], + "traps": [ + "Priya Natarajan wrote the notice of the cut and Kenji Arakawa wrote the constraints; the risk is Dara Whitlock's." + ] + }, + { + "id": "world-053", + "tier": 2, + "hops": 2, + "categories": ["truncation", "aggregate"], + "question": "By how many milliseconds did grouping archetype chunks by tide band cut the Skiff crab join, compared with the alpha-world measurement?", + "answer": { + "kind": "value", + "value": "1.9 ms", + "accept": ["1.9", "1.9 milliseconds"] + }, + "evidence": ["fnd-ecs-chunk-gain", "dec-ecs-chunk", "fnd-ecs-iter-redo"], + "path": [ + ["fnd-ecs-chunk-gain", "derives_from", "dec-ecs-chunk"], + ["dec-ecs-chunk", "derives_from", "fnd-ecs-iter-redo"] + ], + "checks": [ + { + "type": "body", + "record": "fnd-ecs-chunk-gain", + "includes": "takes 3.2 ms", + "expect": true + }, + { + "type": "body", + "record": "fnd-ecs-iter-redo", + "includes": "takes 5.1 ms", + "afterExcerpt": true, + "expect": true + } + ], + "traps": [ + "The 5.1 ms baseline is past the excerpt of the alpha-world finding.", + "The chunk decision's 3.5 ms is a target, not a measurement." + ] + }, + { + "id": "world-054", + "tier": 2, + "hops": 3, + "categories": ["lookup", "supersession"], + "question": "Starting from the current job model decision, walk back through the decisions it replaced to the defect that forced Gull scripts out of the fiber pool. Who filed that defect?", + "answer": { + "kind": "value", + "value": "Marta Lindqvist", + "accept": ["Marta"] + }, + "evidence": [ + "dec-jobs-6", + "dec-jobs-5", + "dec-jobs-4", + "iss-jobs-gull-crash" + ], + "path": [ + ["dec-jobs-6", "supersedes", "dec-jobs-5"], + ["dec-jobs-5", "supersedes", "dec-jobs-4"], + ["dec-jobs-4", "derives_from", "iss-jobs-gull-crash"] + ], + "checks": [ + { + "type": "field", + "record": "iss-jobs-gull-crash", + "field": "created_by" + } + ], + "traps": [ + "Rhea Valdés wrote the job decisions; the defect was filed by Marta Lindqvist." + ] + }, + { + "id": "world-055", + "tier": 2, + "hops": 2, + "categories": ["rationale"], + "question": "Why does Kelp remain the streaming codec after the cold-cache rerun showed Zstandard beating it on Skiff?", + "answer": { + "kind": "text", + "rubric": [ + ["1 MB"], + ["dictionary"], + ["2.2 GB/s", "1.7x"], + ["cache", "cold"] + ] + }, + "evidence": ["dec-codec-dict", "fnd-codec-3", "fnd-codec-2"], + "path": [ + ["dec-codec-dict", "derives_from", "fnd-codec-3"], + ["fnd-codec-3", "derives_from", "fnd-codec-2"] + ], + "checks": [ + { + "type": "body", + "record": "fnd-codec-3", + "includes": "2.2 GB/s", + "expect": true + } + ], + "traps": [ + "The original Kelp decision still rests on the invalidated warm-cache benchmark; the reason Kelp survives is the 1 MB dictionary result, not that benchmark." + ] + }, + { + "id": "world-056", + "tier": 3, + "hops": 5, + "categories": ["temporal", "supersession"], + "question": "Which job model decision was in force on 2025-10-01?", + "answer": { + "kind": "record", + "value": "dec-jobs-1" + }, + "evidence": [ + "dec-jobs-6", + "dec-jobs-5", + "dec-jobs-4", + "dec-jobs-3", + "dec-jobs-2", + "dec-jobs-1" + ], + "path": [ + ["dec-jobs-6", "supersedes", "dec-jobs-5"], + ["dec-jobs-5", "supersedes", "dec-jobs-4"], + ["dec-jobs-4", "supersedes", "dec-jobs-3"], + ["dec-jobs-3", "supersedes", "dec-jobs-2"], + ["dec-jobs-2", "supersedes", "dec-jobs-1"] + ], + "checks": [ + { + "type": "asof", + "start": "dec-jobs-6", + "at": "2025-10-01T00:00:00Z" + } + ], + "traps": [ + "Priority lanes came on 2025-10-21, so the plain work-stealing pool was still in force.", + "The early fiber proposal was rejected on 2025-09-12." + ] + }, + { + "id": "world-057", + "tier": 3, + "hops": 5, + "categories": ["blob", "blocker"], + "question": "The open blocker about beta saves lacking the second harmonic's phase traces back through the tide decisions to the drift measurement that started fixed-point work. In that measurement's attached log, which tile flipped walkability first?", + "answer": { + "kind": "value", + "value": "212, 87", + "accept": ["(212, 87)", "[212, 87]", "212,87", "tile 212, 87"] + }, + "evidence": [ + "iss-blk-save-harmonic", + "dec-tide-harmonic", + "dec-tide-fixed", + "fnd-tide-drift-3", + "cit-tide-drift", + "blob-tide-drift" + ], + "path": [ + ["iss-blk-save-harmonic", "derives_from", "dec-tide-harmonic"], + ["dec-tide-harmonic", "derives_from", "dec-tide-fixed"], + ["dec-tide-fixed", "derives_from", "fnd-tide-drift-3"], + ["fnd-tide-drift-3", "cites", "cit-tide-drift"], + ["cit-tide-drift", "blob", "blob-tide-drift"] + ], + "checks": [ + { + "type": "body", + "record": "blob-tide-drift", + "includes": ["\"tile\"", "212", "87"], + "expect": true + } + ], + "traps": [ + "The tile appears only in the attached log; the findings give times, not tiles." + ] + }, + { + "id": "world-058", + "tier": 3, + "hops": 4, + "categories": ["blob", "supersession"], + "question": "The decision to shrink Kelp's dictionary rests on a measurement that built on a cold-cache rerun. In that rerun's table, how fast did Kelp with its original 4 MB dictionary decode geometry?", + "answer": { + "kind": "value", + "value": "0.8 GB/s", + "accept": ["0.8"] + }, + "evidence": [ + "dec-codec-dict", + "fnd-codec-3", + "fnd-codec-2", + "cit-codec-2", + "blob-codec-2" + ], + "path": [ + ["dec-codec-dict", "derives_from", "fnd-codec-3"], + ["fnd-codec-3", "derives_from", "fnd-codec-2"], + ["fnd-codec-2", "cites", "cit-codec-2"], + ["cit-codec-2", "blob", "blob-codec-2"] + ], + "checks": [ + { + "type": "body", + "record": "blob-codec-2", + "includes": "| Geometry | 0.8 | 1.2 |", + "expect": true + } + ], + "traps": [ + "2.8 GB/s is Kelp's warm geometry figure in the invalidated October table.", + "1.1 GB/s is Kelp's weighted cold figure across all assets." + ] + }, + { + "id": "world-059", + "tier": 3, + "hops": 4, + "categories": ["blocker", "dead-evidence"], + "question": "Two proposed fixes answer the open blocker about beta saves lacking the second harmonic's phase. Which one builds on a decision that still rests on an invalidated cost estimate?", + "answer": { + "kind": "record", + "value": "dec-save-harmonic-clock" + }, + "evidence": [ + "iss-blk-save-harmonic", + "dec-save-harmonic-clock", + "dec-save-harmonic-zero", + "dec-save-version", + "fnd-save-upgrade-cost", + "fnd-save-upgrade-real" + ], + "path": [ + ["iss-blk-save-harmonic", "supports", "dec-save-harmonic-clock"], + ["dec-save-harmonic-clock", "derives_from", "dec-save-version"], + ["dec-save-version", "derives_from", "fnd-save-upgrade-cost"], + ["fnd-save-upgrade-cost", "invalidated_by", "fnd-save-upgrade-real"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "dec-save-version" + } + ], + "traps": [ + "The zero-phase fix derives only from the blocker.", + "The versioning decision is accepted; its support, the 5 ms estimate, is what was invalidated." + ] + }, + { + "id": "world-060", + "tier": 3, + "hops": 4, + "categories": ["invalidation", "blocker"], + "question": "Start from the open risk that reworking the read scheduler may slip the coast sign-off. Follow its blocker to the finding behind it, then to the decision that finding proved wrong. Which cell size decision did that wrong decision build on?", + "answer": { + "kind": "record", + "value": "dec-cell-192" + }, + "evidence": [ + "rsk-io-rework", + "iss-blk-io-starve", + "fnd-io-starve", + "dec-io-tide-priority", + "dec-cell-192" + ], + "path": [ + ["rsk-io-rework", "derives_from", "iss-blk-io-starve"], + ["iss-blk-io-starve", "derives_from", "fnd-io-starve"], + ["fnd-io-starve", "invalidates", "dec-io-tide-priority"], + ["dec-io-tide-priority", "derives_from", "dec-cell-192"] + ], + "checks": [ + { + "type": "head", + "start": "dec-cell-256" + } + ], + "traps": [ + "The tide-priority decision is invalidated, but the cell size decision it built on is still accepted.", + "The retracted 192 m duplicate is not the decision." + ] + }, + { + "id": "world-061", + "tier": 3, + "hops": 4, + "categories": ["blob", "dead-evidence"], + "question": "The realized risk about join queries losing cache locality has evidence that discredited an earlier benchmark. In that earlier benchmark's attached profile, how much memory did the hybrid layout use?", + "answer": { + "kind": "value", + "value": "236 MB", + "accept": ["236"] + }, + "evidence": [ + "rsk-ecs-join", + "fnd-ecs-iter-redo", + "fnd-ecs-iter-bench", + "cit-ecs-profile", + "blob-ecs-profile" + ], + "path": [ + ["rsk-ecs-join", "evidence", "fnd-ecs-iter-redo"], + ["fnd-ecs-iter-redo", "invalidates", "fnd-ecs-iter-bench"], + ["fnd-ecs-iter-bench", "cites", "cit-ecs-profile"], + ["cit-ecs-profile", "blob", "blob-ecs-profile"] + ], + "checks": [ + { + "type": "body", + "record": "blob-ecs-profile", + "includes": "\"memory_mb\": 236", + "expect": true + } + ], + "traps": [ + "212 MB and 340 MB are the archetype and sparse-set layouts.", + "Memory per layout appears only in the profile." + ] + }, + { + "id": "world-062", + "tier": 3, + "hops": 4, + "categories": ["supersession", "blocker"], + "question": "One proposed fix for the save-harmonic blocker builds on the save versioning decision. Follow that decision back to the first delta-format decision it built on. How large was a full world snapshot save in the finding that first delta decision rested on?", + "answer": { + "kind": "value", + "value": "310 MB", + "accept": ["310"] + }, + "evidence": [ + "dec-save-harmonic-clock", + "dec-save-version", + "dec-save-delta-2", + "dec-save-delta", + "fnd-save-snapshot-size" + ], + "path": [ + ["dec-save-harmonic-clock", "derives_from", "dec-save-version"], + ["dec-save-version", "derives_from", "dec-save-delta-2"], + ["dec-save-delta-2", "supersedes", "dec-save-delta"], + ["dec-save-delta", "derives_from", "fnd-save-snapshot-size"] + ], + "checks": [ + { + "type": "body", + "record": "fnd-save-snapshot-size", + "includes": "310 MB", + "expect": true + } + ], + "traps": ["6.2 MB is a 40-hour delta save, not a snapshot."] + }, + { + "id": "world-063", + "tier": 3, + "hops": 4, + "categories": ["supersession", "distractor"], + "question": "Follow the current cell size decision back through the cell decisions it replaced to the first cell size sweep. Which streaming pool constraint record did that sweep measure against?", + "answer": { + "kind": "record", + "value": "con-pool-1" + }, + "evidence": [ + "dec-cell-192", + "dec-cell-128", + "dec-cell-256", + "fnd-cell-sweep", + "con-pool-1" + ], + "path": [ + ["dec-cell-192", "supersedes", "dec-cell-128"], + ["dec-cell-128", "supersedes", "dec-cell-256"], + ["dec-cell-256", "derives_from", "fnd-cell-sweep"], + ["fnd-cell-sweep", "derives_from", "con-pool-1"] + ], + "checks": [ + { + "type": "asof", + "start": "con-pool-3", + "at": "2025-09-25T00:00:00Z" + } + ], + "traps": [ + "Three records are titled 'Streaming pool budget'; the sweep used the original 2.0 GB one, not the current 1.6 GB one." + ] + }, + { + "id": "world-064", + "tier": 3, + "hops": 4, + "categories": ["rejected-alternative"], + "question": "The accepted risk that fixed-point tides crowd the Skiff simulation budget traces back to a decision that answered a question. Which alternatives did that question reject?", + "answer": { + "kind": "records", + "value": ["dec-tide-strict", "dec-tide-host"] + }, + "evidence": [ + "rsk-tide-skiff-cost", + "fnd-tide-fixed-skiff", + "dec-tide-fixed", + "iss-tide-math", + "dec-tide-strict", + "dec-tide-host" + ], + "path": [ + ["rsk-tide-skiff-cost", "evidence", "fnd-tide-fixed-skiff"], + ["fnd-tide-fixed-skiff", "derives_from", "dec-tide-fixed"], + ["dec-tide-fixed", "derives_from", "iss-tide-math"], + ["iss-tide-math", "supports", "dec-tide-strict"] + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "iss-tide-math", + "where": { + "standing": "rejected" + } + } + ], + "traps": [ + "The phase-wrap decision derives from the fixed-point decision but answered the overflow risk, not the question." + ] + }, + { + "id": "world-065", + "tier": 3, + "hops": 4, + "categories": ["lookup", "blocker"], + "question": "Start from the blocker about crash triage. Follow the decision that resolved it back through its prototype to the first measurement of workers blocking on reads. How much idle time per frame did that first measurement report on Meridian?", + "answer": { + "kind": "value", + "value": "3.1 ms", + "accept": ["3.1"] + }, + "evidence": [ + "iss-blk-crash-triage", + "dec-jobs-5", + "fnd-jobs-continuations", + "fnd-jobs-idle", + "fnd-jobs-stalls" + ], + "path": [ + ["iss-blk-crash-triage", "resolved_by", "dec-jobs-5"], + ["dec-jobs-5", "derives_from", "fnd-jobs-continuations"], + ["fnd-jobs-continuations", "derives_from", "fnd-jobs-idle"], + ["fnd-jobs-idle", "derives_from", "fnd-jobs-stalls"] + ], + "checks": [ + { + "type": "body", + "record": "fnd-jobs-stalls", + "includes": "3.1 ms per frame", + "expect": true + } + ], + "traps": [ + "28% is the later idle share during tide turns, and 7% is the continuation prototype's." + ] + }, + { + "id": "world-066", + "tier": 3, + "hops": 4, + "categories": ["blob", "compaction"], + "question": "One of the blockers the head compaction names traces to a streaming trace. How many player-proximity reads were delayed in that trace?", + "answer": { + "kind": "value", + "value": "46" + }, + "evidence": [ + "cmp-4", + "iss-blk-io-starve", + "fnd-io-starve", + "cit-trace-starve", + "blob-trace-starve" + ], + "path": [ + ["cmp-4", "derives_from", "iss-blk-io-starve"], + ["iss-blk-io-starve", "derives_from", "fnd-io-starve"], + ["fnd-io-starve", "cites", "cit-trace-starve"], + ["cit-trace-starve", "blob", "blob-trace-starve"] + ], + "checks": [ + { + "type": "body", + "record": "blob-trace-starve", + "includes": "\"proximity_reads_delayed\": 46", + "expect": true + } + ], + "traps": [ + "11 is the number of tide cells queued; 32 is the maximum queue depth." + ] + }, + { + "id": "world-067", + "tier": 3, + "hops": 4, + "categories": ["invalidation", "blob"], + "question": "Start from the realized risk about Kelp's dictionary thrashing the Skiff cache. In the table attached to the benchmark that the risk's evidence invalidated, how fast did Zstandard decode audio banks?", + "answer": { + "kind": "value", + "value": "1.2 GB/s", + "accept": ["1.2"] + }, + "evidence": [ + "rsk-kelp-cache", + "fnd-codec-2", + "fnd-codec-1", + "cit-codec-1", + "blob-codec-1" + ], + "path": [ + ["rsk-kelp-cache", "evidence", "fnd-codec-2"], + ["fnd-codec-2", "invalidates", "fnd-codec-1"], + ["fnd-codec-1", "cites", "cit-codec-1"], + ["cit-codec-1", "blob", "blob-codec-1"] + ], + "checks": [ + { + "type": "body", + "record": "blob-codec-1", + "includes": "| Audio banks | 1.6 | 2.4 | 1.7 | 1.2 |", + "expect": true + } + ], + "traps": [ + "1.1 GB/s is Zstandard's audio figure in the cold-cache table attached to the evidence itself, not to the invalidated benchmark." + ] + }, + { + "id": "world-068", + "tier": 4, + "hops": 0, + "categories": ["compaction", "lifecycle"], + "question": "In the \"Kestrel world streaming and simulation core\" Effort, is the head compaction stale?", + "answer": { + "kind": "boolean", + "value": false + }, + "evidence": ["cmp-4"], + "checks": [ + { + "type": "compaction", + "field": "stale" + }, + { + "type": "compaction", + "field": "changes", + "expect": 7 + } + ], + "traps": [ + "Seven records changed since it was written, so brief asks for a new compaction, but none of the records it derives from moved and no finding invalidated it, so it is not stale.", + "An older compaction was invalidated; it is no longer the head." + ] + }, + { + "id": "world-069", + "tier": 4, + "hops": 0, + "categories": ["compaction", "aggregate"], + "question": "In the \"Kestrel world streaming and simulation core\" Effort, how many records have joined, left, or changed standing in the live set since the head compaction was written?", + "answer": { + "kind": "count", + "value": 7 + }, + "evidence": [ + "cmp-4", + "iss-blk-gull-debug", + "rsk-io-rework", + "fnd-codec-3", + "fnd-codec-4", + "fnd-gull-debug-cause", + "fnd-ecs-chunk-gain", + "iss-gull-reload-coro" + ], + "checks": [ + { + "type": "compaction", + "field": "changes" + } + ], + "traps": [ + "A superseded finding counts as leaving and its replacement as joining; the deferred coroutine defect counts as leaving." + ] + }, + { + "id": "world-070", + "tier": 4, + "hops": 0, + "categories": ["blocker", "compaction", "aggregate"], + "question": "In the \"Kestrel world streaming and simulation core\" Effort, how many blocker Issues are open now?", + "answer": { + "kind": "count", + "value": 3 + }, + "evidence": [ + "iss-blk-save-harmonic", + "iss-blk-io-starve", + "iss-blk-gull-debug", + "cmp-4" + ], + "checks": [ + { + "type": "select", + "kinds": ["issue"], + "where": { + "kind": "blocker", + "status": "open" + }, + "count": true + } + ], + "traps": [ + "The head compaction says two blockers are open; the Gull debugger blocker was filed after it.", + "The crash triage blocker is resolved." + ] + }, + { + "id": "world-071", + "tier": 4, + "hops": 0, + "categories": ["dead-evidence", "aggregate"], + "question": "In the \"Kestrel world streaming and simulation core\" Effort, which live Decisions still derive from a support that has been invalidated?", + "answer": { + "kind": "records", + "value": [ + "dec-codec-kelp", + "dec-ecs-hybrid", + "dec-gull-reload", + "dec-pool-forecast", + "dec-save-version" + ] + }, + "evidence": [ + "dec-codec-kelp", + "fnd-codec-1", + "dec-ecs-hybrid", + "fnd-ecs-iter-bench", + "dec-gull-reload", + "fnd-gull-reload-proto", + "dec-pool-forecast", + "fnd-pool-sim", + "dec-save-version", + "fnd-save-upgrade-cost" + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "live": true, + "restsOn": ["invalidated"] + } + ], + "traps": [ + "The tide-priority decision is itself invalidated, so it is not live.", + "The cell and job decisions rest on superseded records, which is not the same as invalidated." + ] + }, + { + "id": "world-072", + "tier": 4, + "hops": 0, + "categories": ["rejected-alternative", "aggregate"], + "question": "Which codec proposals did the October 2025 codec question reject?", + "answer": { + "kind": "records", + "value": ["dec-codec-zstd", "dec-codec-lz4"] + }, + "evidence": [ + "iss-codec", + "dec-codec-kelp", + "dec-codec-zstd", + "dec-codec-lz4" + ], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "iss-codec", + "where": { + "standing": "rejected" + } + } + ], + "traps": [ + "Zstandard was reopened and rejected again by the dictionary decision; it still counts.", + "The dictionary decision did not answer the question." + ] + }, + { + "id": "world-073", + "tier": 4, + "hops": 0, + "categories": ["reopened", "lifecycle"], + "question": "If someone reopened the Zstandard codec proposal again today, could it be accepted without first superseding another decision?", + "answer": { + "kind": "boolean", + "value": false + }, + "evidence": [ + "dec-codec-zstd", + "dec-codec-dict", + "dec-codec-kelp", + "iss-codec" + ], + "checks": [ + { + "type": "field", + "record": "dec-codec-dict", + "field": "state", + "expect": "accepted" + }, + { + "type": "field", + "record": "dec-codec-kelp", + "field": "state", + "expect": "accepted" + } + ], + "traps": [ + "Its last rejecter, the dictionary decision, is still accepted, and the codec question already has an accepted answer in the original Kelp decision; either blocks acceptance." + ] + }, + { + "id": "world-074", + "tier": 4, + "hops": 0, + "categories": ["retraction", "aggregate"], + "question": "How many records in the \"Kestrel world streaming and simulation core\" Effort have been retracted?", + "answer": { + "kind": "count", + "value": 7 + }, + "evidence": [ + "dec-ecs-hybrid-dup", + "dec-jobs-5-dup", + "dec-cell-192-dup", + "fnd-tide-drift-dup", + "fnd-codec-1-typo", + "iss-gull-reload-coro-dup", + "con-pool-draft" + ], + "checks": [ + { + "type": "select", + "retracted": "only", + "count": true + } + ], + "traps": [ + "Browse reads hide retracted records; superseded and invalidated records are not retracted." + ] + }, + { + "id": "world-075", + "tier": 4, + "hops": 0, + "categories": ["retraction", "aggregate"], + "question": "Which Decisions in the \"Kestrel world streaming and simulation core\" Effort were retracted?", + "answer": { + "kind": "records", + "value": ["dec-ecs-hybrid-dup", "dec-jobs-5-dup", "dec-cell-192-dup"] + }, + "evidence": ["dec-ecs-hybrid-dup", "dec-jobs-5-dup", "dec-cell-192-dup"], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "retracted": "only" + } + ], + "traps": [ + "Each retracted Decision has a near-identical live twin; the twins are not retracted." + ] + }, + { + "id": "world-076", + "tier": 4, + "hops": 0, + "categories": ["reopened", "lifecycle"], + "question": "Of the Decisions that were ever reopened, which one ended up accepted?", + "answer": { + "kind": "record", + "value": "dec-gull-bytecode" + }, + "evidence": ["dec-gull-bytecode", "dec-gull-tree", "dec-codec-zstd"], + "checks": [ + { + "type": "select", + "kinds": ["decision"], + "derivesFrom": "iss-gull-vm", + "where": { + "standing": "accepted" + } + } + ], + "traps": [ + "The Zstandard proposal was reopened too, but it was rejected again." + ] + }, + { + "id": "world-077", + "tier": 4, + "hops": 0, + "categories": ["aggregate"], + "question": "How many question Issues does the \"Kestrel world streaming and simulation core\" Effort hold?", + "answer": { + "kind": "count", + "value": 9 + }, + "evidence": [ + "iss-ecs-storage", + "iss-jobs-model", + "iss-cell-size", + "iss-io-api", + "iss-codec", + "iss-gull-vm", + "iss-tide-math", + "iss-pool-evict", + "iss-save-format" + ], + "checks": [ + { + "type": "select", + "kinds": ["issue"], + "where": { + "kind": "question" + }, + "count": true + } + ], + "traps": [ + "The tide desync and hot reload Issues are defects, not questions." + ] + }, + { + "id": "world-078", + "tier": 4, + "hops": 0, + "categories": ["lifecycle", "aggregate"], + "question": "In the \"Kestrel world streaming and simulation core\" Effort, which Risks are still open?", + "answer": { + "kind": "records", + "value": ["rsk-gull-reload-state", "rsk-io-rework"] + }, + "evidence": ["rsk-gull-reload-state", "rsk-io-rework"], + "checks": [ + { + "type": "select", + "kinds": ["risk"], + "where": { + "standing": "open" + } + } + ], + "traps": [ + "Realized risks are live but not open.", + "The pool cut risk was realized in June 2026." + ] + }, + { + "id": "world-079", + "tier": 4, + "hops": 0, + "categories": ["current-state", "aggregate", "distractor"], + "question": "In the \"Kestrel world streaming and simulation core\" Effort, which hard Constraints are in force now?", + "answer": { + "kind": "records", + "value": [ + "con-no-jit", + "con-pool-3", + "con-save-compat", + "con-tide-bitexact" + ] + }, + "evidence": [ + "con-no-jit", + "con-pool-3", + "con-save-compat", + "con-tide-bitexact", + "con-pool-1", + "con-pool-2", + "con-pool-draft" + ], + "checks": [ + { + "type": "select", + "kinds": ["constraint"], + "where": { + "kind": "hard" + }, + "live": true + } + ], + "traps": [ + "Only the newest of the three 'Streaming pool budget' records is in force, and the draft is retracted.", + "The I/O budget, cell deadline, and Gull tick budget are soft." + ] + }, + { + "id": "world-080", + "tier": 4, + "hops": 0, + "categories": ["lifecycle", "aggregate"], + "question": "In the \"Kestrel world streaming and simulation core\" Effort, which Issues were closed as deferred?", + "answer": { + "kind": "records", + "value": [ + "iss-gull-reload-structs", + "iss-save-cloud", + "iss-gull-reload-coro" + ] + }, + "evidence": [ + "iss-gull-reload-structs", + "iss-save-cloud", + "iss-gull-reload-coro" + ], + "checks": [ + { + "type": "select", + "kinds": ["issue"], + "where": { + "status": "deferred" + } + } + ], + "traps": [ + "The entity names gap was closed as wontfix, not deferred.", + "The coroutine defect was deferred in September 2026, after the head compaction." + ] + }, + { + "id": "world-081", + "tier": 4, + "hops": 0, + "categories": ["dead-evidence", "lifecycle"], + "question": "Which open Risk derives from an accepted Decision that rests on an invalidated Finding?", + "answer": { + "kind": "record", + "value": "rsk-gull-reload-state" + }, + "evidence": [ + "rsk-gull-reload-state", + "dec-gull-reload", + "fnd-gull-reload-proto", + "rsk-io-rework" + ], + "checks": [ + { + "type": "select", + "kinds": ["risk"], + "derivesFrom": "dec-gull-reload", + "where": { + "standing": "open" + } + } + ], + "traps": [ + "The other open risk derives from a proposed decision and a blocker, not from a decision resting on dead evidence." + ] + } + ] +} diff --git a/benchmarks/proof-recall/runs/full-haiku-brief.json b/benchmarks/proof-recall/runs/full-haiku-brief.json new file mode 100644 index 00000000..13516bbe --- /dev/null +++ b/benchmarks/proof-recall/runs/full-haiku-brief.json @@ -0,0 +1,2040 @@ +{ + "run": { + "name": "full-haiku-brief", + "protocol": "one fresh session per question", + "models": ["claude-haiku-5-5"] + }, + "answers": { + "cross-001": { + "answer": "con-frame-budget--br0qszfg8fys908n", + "tokens": 24138, + "fixed_tokens": 1232, + "processed_tokens": 112842, + "tool_calls": 9, + "turns": 8 + }, + "cross-002": { + "answer": 2, + "tokens": 29001, + "fixed_tokens": 1228, + "processed_tokens": 116141, + "tool_calls": 18, + "turns": 7 + }, + "cross-003": { + "answer": "unknown", + "tokens": 13542, + "fixed_tokens": 1229, + "processed_tokens": 146410, + "tool_calls": 11, + "turns": 12 + }, + "cross-004": { + "answer": "dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e", + "tokens": 14732, + "fixed_tokens": 1229, + "processed_tokens": 161936, + "tool_calls": 11, + "turns": 12 + }, + "cross-005": { + "answer": "unknown", + "tokens": 14435, + "fixed_tokens": 1227, + "processed_tokens": 123797, + "tool_calls": 9, + "turns": 10 + }, + "cross-006": { + "answer": "~19%", + "tokens": 13155, + "fixed_tokens": 1224, + "processed_tokens": 152552, + "tool_calls": 11, + "turns": 12 + }, + "cross-007": { + "answer": "8 GB", + "tokens": 17492, + "fixed_tokens": 1231, + "processed_tokens": 179958, + "tool_calls": 12, + "turns": 13 + }, + "cross-008": { + "answer": "unknown", + "tokens": 20615, + "fixed_tokens": 1229, + "processed_tokens": 285235, + "tool_calls": 18, + "turns": 19 + }, + "cross-009": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tokens": 27263, + "fixed_tokens": 1231, + "processed_tokens": 280227, + "tool_calls": 14, + "turns": 15 + }, + "cross-010": { + "answer": "dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7", + "tokens": 38737, + "fixed_tokens": 1226, + "processed_tokens": 376875, + "tool_calls": 15, + "turns": 16 + }, + "cross-011": { + "answer": false, + "tokens": 33737, + "fixed_tokens": 1227, + "processed_tokens": 274914, + "tool_calls": 12, + "turns": 13 + }, + "cross-012": { + "answer": "61 MB/s", + "tokens": 54819, + "fixed_tokens": 1231, + "processed_tokens": 967878, + "tool_calls": 25, + "turns": 26 + }, + "cross-013": { + "answer": "The Skiff port runs Tern at the Performance preset (dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3), which saves 1.8 ms over Quality (2.1 ms vs 3.9 ms, per fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0). The lowest preset, Ultra Performance, exists only for the Meridian 120 Hz mode (dec-ship-four-tern-quality-presets-adding-ultra-perf--3jg1wyq3bshv839c).", + "tokens": 88424, + "fixed_tokens": 1230, + "processed_tokens": 824006, + "tool_calls": 18, + "turns": 19 + }, + "cross-014": { + "answer": 3, + "tokens": 5812, + "fixed_tokens": 1227, + "processed_tokens": 41665, + "tool_calls": 4, + "turns": 5 + }, + "cross-015": { + "answer": "Two Efforts are no longer active. Shader compile cache and build farm (eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn) completed, since its retrospective fnd-retrospective-on-the-shader-compile-cache--9rpv2a60ach04cx6 says the cache has run on every farm build for five weeks. Co-op rollback netcode prototype (eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49) was abandoned via dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b, because re-running tide simulation on each rollback frame costs 4.8 ms on Skiff.", + "tokens": 16065, + "fixed_tokens": 1228, + "processed_tokens": 165325, + "tool_calls": 11, + "turns": 12 + }, + "cross-016": { + "answer": "16.7 ms", + "tokens": 16808, + "fixed_tokens": 1228, + "processed_tokens": 216536, + "tool_calls": 14, + "turns": 15 + }, + "cross-017": { + "answer": "unknown", + "tokens": 34917, + "fixed_tokens": 1229, + "processed_tokens": 288191, + "tool_calls": 13, + "turns": 14 + }, + "netcode-001": { + "answer": "abandoned", + "tokens": 10225, + "fixed_tokens": 1231, + "processed_tokens": 71696, + "tool_calls": 6, + "turns": 7 + }, + "netcode-002": { + "answer": "netcode/rollback-archive", + "tokens": 10258, + "fixed_tokens": 1232, + "processed_tokens": 85425, + "tool_calls": 7, + "turns": 8 + }, + "netcode-003": { + "answer": "38 KB", + "tokens": 28786, + "fixed_tokens": 1226, + "processed_tokens": 274766, + "tool_calls": 13, + "turns": 14 + }, + "netcode-004": { + "answer": "Rollback re-runs the tide simulation on every rolled-back frame, which costs 4.8 ms on Skiff (about a fifth of the 25 ms frame), and co-op needs tides to stay bit-for-bit deterministic, so the prototype was abandoned (dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b). The reason depends on the world Decision dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e.", + "tokens": 38973, + "fixed_tokens": 1225, + "processed_tokens": 233171, + "tool_calls": 11, + "turns": 12 + }, + "netcode-005": { + "answer": "unknown", + "tokens": 27958, + "fixed_tokens": 1229, + "processed_tokens": 231821, + "tool_calls": 12, + "turns": 13 + }, + "netcode-006": { + "answer": "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "tokens": 15257, + "fixed_tokens": 1224, + "processed_tokens": 94847, + "tool_calls": 7, + "turns": 8 + }, + "netcode-007": { + "answer": "dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b", + "tokens": 11842, + "fixed_tokens": 1234, + "processed_tokens": 116756, + "tool_calls": 9, + "turns": 10 + }, + "netcode-008": { + "answer": "dec-use-a-4-frame-rollback-window--pqe4hvbgmbp0dmh9", + "tokens": 16824, + "fixed_tokens": 1238, + "processed_tokens": 137791, + "tool_calls": 9, + "turns": 10 + }, + "netcode-009": { + "answer": "1.9 ms", + "tokens": 15185, + "fixed_tokens": 1234, + "processed_tokens": 194299, + "tool_calls": 13, + "turns": 14 + }, + "netcode-010": { + "answer": "dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk", + "tokens": 14015, + "fixed_tokens": 1226, + "processed_tokens": 126118, + "tool_calls": 9, + "turns": 10 + }, + "netcode-011": { + "answer": "con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g", + "tokens": 42601, + "fixed_tokens": 1231, + "processed_tokens": 593568, + "tool_calls": 20, + "turns": 21 + }, + "netcode-012": { + "answer": "dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f", + "tokens": 27168, + "fixed_tokens": 1231, + "processed_tokens": 135351, + "tool_calls": 8, + "turns": 9 + }, + "netcode-013": { + "answer": [ + "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf", + "rsk-re-simulation-cost-could-blow-the-skiff-frame-bu--sk2njsp170a3qwyf" + ], + "tokens": 17201, + "fixed_tokens": 1228, + "processed_tokens": 101683, + "tool_calls": 15, + "turns": 8 + }, + "netcode-014": { + "answer": [ + "iss-how-should-co-op-keep-up-to-four-players-in-sync--92t2zfsy3etfzr89", + "iss-late-join-during-a-tide-surge-desyncs-the-joinin--mya93va0n7s8g7cj" + ], + "tokens": 20375, + "fixed_tokens": 1227, + "processed_tokens": 239749, + "tool_calls": 14, + "turns": 15 + }, + "netcode-015": { + "answer": 2, + "tokens": 14855, + "fixed_tokens": 1228, + "processed_tokens": 93765, + "tool_calls": 7, + "turns": 8 + }, + "ports-001": { + "answer": "25 ms", + "tokens": 9929, + "fixed_tokens": 1223, + "processed_tokens": 84571, + "tool_calls": 7, + "turns": 8 + }, + "ports-002": { + "answer": "384 MB", + "tokens": 23457, + "fixed_tokens": 1226, + "processed_tokens": 209059, + "tool_calls": 11, + "turns": 12 + }, + "ports-003": { + "answer": "61 MB/s", + "tokens": 54292, + "fixed_tokens": 1226, + "processed_tokens": 640177, + "tool_calls": 18, + "turns": 18 + }, + "ports-004": { + "answer": "accepted", + "tokens": 10215, + "fixed_tokens": 1227, + "processed_tokens": 95590, + "tool_calls": 8, + "turns": 9 + }, + "ports-005": { + "answer": "unknown", + "tokens": 62873, + "fixed_tokens": 1228, + "processed_tokens": 637739, + "tool_calls": 19, + "turns": 20 + }, + "ports-034": { + "answer": "6 weeks", + "tokens": 33814, + "fixed_tokens": 1222, + "processed_tokens": 439633, + "tool_calls": 17, + "turns": 18 + }, + "ports-006": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tokens": 9893, + "fixed_tokens": 1223, + "processed_tokens": 84216, + "tool_calls": 7, + "turns": 8 + }, + "ports-007": { + "answer": "SKF-UI-031", + "tokens": 49799, + "fixed_tokens": 1226, + "processed_tokens": 378514, + "tool_calls": 12, + "turns": 13 + }, + "ports-008": { + "answer": "dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3", + "tokens": 22581, + "fixed_tokens": 1224, + "processed_tokens": 109561, + "tool_calls": 7, + "turns": 8 + }, + "ports-009": { + "answer": "unknown", + "tokens": 37137, + "fixed_tokens": 1227, + "processed_tokens": 683825, + "tool_calls": 35, + "turns": 28 + }, + "ports-010": { + "answer": "con-frame-budget--wt5rfqh5z444g2cg", + "tokens": 32238, + "fixed_tokens": 1225, + "processed_tokens": 292335, + "tool_calls": 13, + "turns": 14 + }, + "ports-011": { + "answer": "99.6 percent", + "tokens": 26230, + "fixed_tokens": 1229, + "processed_tokens": 250053, + "tool_calls": 13, + "turns": 14 + }, + "ports-012": { + "answer": "Because saltglass caustics shimmered badly at the 540p floor, even with Tern: 7 of 10 dune views showed visible shimmer, dropping to 2 of 10 at 576p (fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q), which led to the 576p decision (dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb). That decision was later superseded by the 504p floor (dec-lower-the-skiff-dynamic-resolution-floor-to-504p--15esnt90gcn29enn).", + "tokens": 13914, + "fixed_tokens": 1227, + "processed_tokens": 154444, + "tool_calls": 11, + "turns": 12 + }, + "ports-013": { + "answer": "Ship Tern as Lantern's only upscaler", + "tokens": 26857, + "fixed_tokens": 1226, + "processed_tokens": 208147, + "tool_calls": 10, + "turns": 11 + }, + "ports-014": { + "answer": "dec-scale-skiff-resolution-dynamically-between-540p--jtytvgh2erd32x68", + "tokens": 25246, + "fixed_tokens": 1225, + "processed_tokens": 197114, + "tool_calls": 10, + "turns": 11 + }, + "ports-015": { + "answer": "textures", + "tokens": 18070, + "fixed_tokens": 1230, + "processed_tokens": 290048, + "tool_calls": 19, + "turns": 20 + }, + "ports-016": { + "answer": "dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn", + "tokens": 10748, + "fixed_tokens": 1224, + "processed_tokens": 105425, + "tool_calls": 9, + "turns": 10 + }, + "ports-017": { + "answer": "fnd-skiff-microsd-slows-sharply-on-full-warm-cards--p1rgh36hat2egpz3", + "tokens": 50008, + "fixed_tokens": 1226, + "processed_tokens": 689075, + "tool_calls": 19, + "turns": 20 + }, + "ports-018": { + "answer": "504p", + "tokens": 10320, + "fixed_tokens": 1234, + "processed_tokens": 85003, + "tool_calls": 7, + "turns": 8 + }, + "ports-019": { + "answer": "4 MB per minute", + "tokens": 16640, + "fixed_tokens": 1230, + "processed_tokens": 223246, + "tool_calls": 15, + "turns": 16 + }, + "ports-020": { + "answer": "fnd-skiff-sdk-1-2-takes-1-gb-back-from-games--a0ybdgjzw64hwfqa", + "tokens": 28575, + "fixed_tokens": 1225, + "processed_tokens": 183718, + "tool_calls": 11, + "turns": 12 + }, + "ports-021": { + "answer": "SKF-DSP-004", + "tokens": 41726, + "fixed_tokens": 1228, + "processed_tokens": 461826, + "tool_calls": 15, + "turns": 16 + }, + "ports-022": { + "answer": "cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe", + "tokens": 22287, + "fixed_tokens": 1228, + "processed_tokens": 122246, + "tool_calls": 8, + "turns": 9 + }, + "ports-023": { + "answer": "fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0", + "tokens": 30700, + "fixed_tokens": 1226, + "processed_tokens": 225888, + "tool_calls": 13, + "turns": 14 + }, + "ports-024": { + "answer": "fnd-skiff-firmware-1-2-rejects-pipeline-blobs-built--pernvgb2he7m3z3y", + "tokens": 49592, + "fixed_tokens": 1222, + "processed_tokens": 660652, + "tool_calls": 20, + "turns": 21 + }, + "ports-025": { + "answer": "dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3", + "tokens": 14127, + "fixed_tokens": 1226, + "processed_tokens": 142173, + "tool_calls": 10, + "turns": 11 + }, + "ports-026": { + "answer": "912 MB", + "tokens": 29615, + "fixed_tokens": 1228, + "processed_tokens": 373199, + "tool_calls": 17, + "turns": 18 + }, + "ports-027": { + "answer": [ + "dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw", + "rsk-tide-streaming-outruns-skiff-storage--6q8s3b383z2tyeyb" + ], + "tokens": 43995, + "fixed_tokens": 1232, + "processed_tokens": 306847, + "tool_calls": 12, + "turns": 13 + }, + "ports-028": { + "answer": 2, + "tokens": 12245, + "fixed_tokens": 1228, + "processed_tokens": 88661, + "tool_calls": 7, + "turns": 8 + }, + "ports-029": { + "answer": 8, + "tokens": 9899, + "fixed_tokens": 1227, + "processed_tokens": 71500, + "tool_calls": 6, + "turns": 7 + }, + "ports-030": { + "answer": [ + "dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1", + "dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc" + ], + "tokens": 11210, + "fixed_tokens": 1228, + "processed_tokens": 86972, + "tool_calls": 7, + "turns": 8 + }, + "ports-031": { + "answer": [ + "iss-meridian-cert-activity-cards-missing-for-two-bio--k214cmfra7pyvvzq", + "iss-skiff-cert-docked-30-hz-judder-on-some-tvs--9nq2xg9mzash474g" + ], + "tokens": 13277, + "fixed_tokens": 1226, + "processed_tokens": 74488, + "tool_calls": 6, + "turns": 7 + }, + "ports-032": { + "answer": "unknown", + "tokens": 20921, + "fixed_tokens": 1226, + "processed_tokens": 272462, + "tool_calls": 16, + "turns": 17 + }, + "ports-033": { + "answer": "unknown", + "tokens": 11367, + "fixed_tokens": 1225, + "processed_tokens": 116556, + "tool_calls": 9, + "turns": 10 + }, + "render-001": { + "answer": "7.4 ms", + "tokens": 11430, + "fixed_tokens": 1224, + "processed_tokens": 87294, + "tool_calls": 9, + "turns": 8 + }, + "render-002": { + "answer": "3.4x", + "tokens": 19866, + "fixed_tokens": 1223, + "processed_tokens": 143442, + "tool_calls": 10, + "turns": 10 + }, + "render-003": { + "answer": "Tomasz Brandt", + "tokens": 9774, + "fixed_tokens": 1232, + "processed_tokens": 106846, + "tool_calls": 9, + "turns": 10 + }, + "render-004": { + "answer": "rejected", + "tokens": 17118, + "fixed_tokens": 1227, + "processed_tokens": 188176, + "tool_calls": 13, + "turns": 14 + }, + "render-005": { + "answer": true, + "tokens": 25689, + "fixed_tokens": 1230, + "processed_tokens": 406570, + "tool_calls": 20, + "turns": 21 + }, + "render-006": { + "answer": "unknown", + "tokens": 11982, + "fixed_tokens": 1222, + "processed_tokens": 127104, + "tool_calls": 10, + "turns": 11 + }, + "render-007": { + "answer": "unknown", + "tokens": 44361, + "fixed_tokens": 1232, + "processed_tokens": 746927, + "tool_calls": 29, + "turns": 27 + }, + "render-008": { + "answer": "2 failures", + "tokens": 17475, + "fixed_tokens": 1223, + "processed_tokens": 152255, + "tool_calls": 10, + "turns": 11 + }, + "render-009": { + "answer": "32 steps", + "tokens": 17987, + "fixed_tokens": 1220, + "processed_tokens": 137687, + "tool_calls": 11, + "turns": 11 + }, + "render-010": { + "answer": "unknown", + "tokens": 33214, + "fixed_tokens": 1227, + "processed_tokens": 271179, + "tool_calls": 12, + "turns": 13 + }, + "render-011": { + "answer": "unknown", + "tokens": 17731, + "fixed_tokens": 1229, + "processed_tokens": 273189, + "tool_calls": 17, + "turns": 18 + }, + "render-012": { + "answer": "deferred", + "tokens": 32195, + "fixed_tokens": 1232, + "processed_tokens": 348128, + "tool_calls": 14, + "turns": 15 + }, + "render-013": { + "answer": "FP16", + "tokens": 51784, + "fixed_tokens": 1226, + "processed_tokens": 804881, + "tool_calls": 23, + "turns": 24 + }, + "render-014": { + "answer": "52 percent", + "tokens": 29401, + "fixed_tokens": 1221, + "processed_tokens": 266464, + "tool_calls": 13, + "turns": 14 + }, + "render-015": { + "answer": "unknown", + "tokens": 51184, + "fixed_tokens": 1225, + "processed_tokens": 773988, + "tool_calls": 23, + "turns": 24 + }, + "render-016": { + "answer": "1.2 km", + "tokens": 10155, + "fixed_tokens": 1228, + "processed_tokens": 84957, + "tool_calls": 7, + "turns": 8 + }, + "render-017": { + "answer": "unknown", + "tokens": 92473, + "fixed_tokens": 1219, + "processed_tokens": 1100376, + "tool_calls": 26, + "turns": 25 + }, + "render-018": { + "answer": "unknown", + "tokens": 17009, + "fixed_tokens": 1221, + "processed_tokens": 258478, + "tool_calls": 17, + "turns": 18 + }, + "render-019": { + "answer": "dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86", + "tokens": 45109, + "fixed_tokens": 1225, + "processed_tokens": 515888, + "tool_calls": 17, + "turns": 16 + }, + "render-020": { + "answer": "fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy", + "tokens": 22551, + "fixed_tokens": 1221, + "processed_tokens": 107867, + "tool_calls": 7, + "turns": 8 + }, + "render-021": { + "answer": "dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4", + "tokens": 16239, + "fixed_tokens": 1224, + "processed_tokens": 182460, + "tool_calls": 13, + "turns": 14 + }, + "render-022": { + "answer": "dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr", + "tokens": 17797, + "fixed_tokens": 1223, + "processed_tokens": 282187, + "tool_calls": 20, + "turns": 21 + }, + "render-023": { + "answer": "dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676", + "tokens": 39074, + "fixed_tokens": 1222, + "processed_tokens": 330227, + "tool_calls": 13, + "turns": 14 + }, + "render-024": { + "answer": "dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r", + "tokens": 13499, + "fixed_tokens": 1225, + "processed_tokens": 119804, + "tool_calls": 9, + "turns": 10 + }, + "render-025": { + "answer": "fnd-tern-cost-at-4k-output-on-meridian-after-fp16-pa--p4gcmzw2a4bvzjev", + "tokens": 36477, + "fixed_tokens": 1222, + "processed_tokens": 303246, + "tool_calls": 15, + "turns": 15 + }, + "render-026": { + "answer": "dec-ship-four-tern-quality-presets--vjw18d82dx5gath8", + "tokens": 52400, + "fixed_tokens": 1221, + "processed_tokens": 291490, + "tool_calls": 11, + "turns": 12 + }, + "render-027": { + "answer": "con-frame-budget--j6vneva1g2ywj86m", + "tokens": 14809, + "fixed_tokens": 1224, + "processed_tokens": 93944, + "tool_calls": 7, + "turns": 8 + }, + "render-028": { + "answer": "dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee", + "tokens": 25255, + "fixed_tokens": 1222, + "processed_tokens": 151165, + "tool_calls": 10, + "turns": 11 + }, + "render-029": { + "answer": "fnd-vsm-page-pool-overflows-during-spring-tides--m2p8e89hhdmh0z8a", + "tokens": 19611, + "fixed_tokens": 1228, + "processed_tokens": 184004, + "tool_calls": 11, + "turns": 12 + }, + "render-030": { + "answer": "dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6", + "tokens": 47672, + "fixed_tokens": 1224, + "processed_tokens": 439011, + "tool_calls": 15, + "turns": 16 + }, + "render-031": { + "answer": "Alpha-tested foliage cost 2.1 ms in the visibility buffer versus 0.8 ms in forward+, so it moved to a forward pass (dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9, citing fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb). Saltglass moved out because it refracts the scene behind it and so needs that image resolved first, which the buffer cannot provide.", + "tokens": 16359, + "fixed_tokens": 1227, + "processed_tokens": 203208, + "tool_calls": 14, + "turns": 15 + }, + "render-032": { + "answer": "The team chose Tern because Halcyon has no Skiff build, and shipping it on two platforms would break the one-upscaler constraint; owning Tern's code also lets them make saltglass refraction and caustics fixes the same week instead of filing closed-binary vendor tickets, with no license to negotiate. (dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e)", + "tokens": 14516, + "fixed_tokens": 1220, + "processed_tokens": 143235, + "tool_calls": 10, + "turns": 11 + }, + "render-033": { + "answer": "128 MB", + "tokens": 22069, + "fixed_tokens": 1227, + "processed_tokens": 217753, + "tool_calls": 12, + "turns": 13 + }, + "render-034": { + "answer": "PC workstation (Meridian clock profile)", + "tokens": 20775, + "fixed_tokens": 1224, + "processed_tokens": 355269, + "tool_calls": 21, + "turns": 22 + }, + "render-035": { + "answer": "5912 pages", + "tokens": 21576, + "fixed_tokens": 1224, + "processed_tokens": 259683, + "tool_calls": 14, + "turns": 15 + }, + "render-036": { + "answer": "HDR-07", + "tokens": 29762, + "fixed_tokens": 1224, + "processed_tokens": 451833, + "tool_calls": 20, + "turns": 21 + }, + "render-037": { + "answer": "0.33", + "tokens": 14974, + "fixed_tokens": 1225, + "processed_tokens": 191138, + "tool_calls": 13, + "turns": 14 + }, + "render-038": { + "answer": "unknown", + "tokens": 35507, + "fixed_tokens": 1227, + "processed_tokens": 373013, + "tool_calls": 15, + "turns": 16 + }, + "render-039": { + "answer": "unknown", + "tokens": 32117, + "fixed_tokens": 1226, + "processed_tokens": 253875, + "tool_calls": 15, + "turns": 12 + }, + "render-040": { + "answer": "fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c", + "tokens": 15772, + "fixed_tokens": 1224, + "processed_tokens": 160670, + "tool_calls": 11, + "turns": 12 + }, + "render-041": { + "answer": "4.7 ms", + "tokens": 18359, + "fixed_tokens": 1224, + "processed_tokens": 261874, + "tool_calls": 17, + "turns": 18 + }, + "render-042": { + "answer": "dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1", + "tokens": 12666, + "fixed_tokens": 1228, + "processed_tokens": 104162, + "tool_calls": 8, + "turns": 9 + }, + "render-043": { + "answer": "fnd-meshlet-cone-culling-rejects-9-percent-of-triang--t6e5x7trzedex105", + "tokens": 42913, + "fixed_tokens": 1222, + "processed_tokens": 279740, + "tool_calls": 12, + "turns": 12 + }, + "render-044": { + "answer": "dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r", + "tokens": 14064, + "fixed_tokens": 1224, + "processed_tokens": 140510, + "tool_calls": 10, + "turns": 11 + }, + "render-045": { + "answer": false, + "tokens": 10190, + "fixed_tokens": 1221, + "processed_tokens": 84889, + "tool_calls": 7, + "turns": 8 + }, + "render-046": { + "answer": "The cost Finding that had sunk virtual shadow maps was a capture error; with cached pages VSM costs 1.4 ms, less than four cascades, and cascade seams through saltglass remain unsolved under CSM (record dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4, reopened 2026-01-12 from its rejection by dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr).", + "tokens": 10462, + "fixed_tokens": 1228, + "processed_tokens": 85176, + "tool_calls": 7, + "turns": 8 + }, + "render-047": { + "answer": "It brought the visibility buffer back to Skiff because its release-build capture measured 7.4 ms against 8.1 ms for forward+ (6.3 ms with half-rate material resolve), so the forward+ fallback was no longer worth keeping, and maintaining two opaque paths cost about one engineer-week a month (dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1).", + "tokens": 13567, + "fixed_tokens": 1225, + "processed_tokens": 174865, + "tool_calls": 13, + "turns": 14 + }, + "render-048": { + "answer": "dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4", + "tokens": 39395, + "fixed_tokens": 1223, + "processed_tokens": 564355, + "tool_calls": 21, + "turns": 22 + }, + "render-049": { + "answer": "dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4", + "tokens": 17637, + "fixed_tokens": 1222, + "processed_tokens": 265164, + "tool_calls": 18, + "turns": 19 + }, + "render-050": { + "answer": "con-frame-budget--fzdrbxns6dmrrmy3", + "tokens": 14449, + "fixed_tokens": 1226, + "processed_tokens": 93500, + "tool_calls": 7, + "turns": 8 + }, + "render-051": { + "answer": "iss-tern-ghosting-on-moving-saltglass--2yr3q6zf476wajqp", + "tokens": 20629, + "fixed_tokens": 1226, + "processed_tokens": 229990, + "tool_calls": 14, + "turns": 14 + }, + "render-052": { + "answer": "61%", + "tokens": 35917, + "fixed_tokens": 1220, + "processed_tokens": 476871, + "tool_calls": 19, + "turns": 20 + }, + "render-053": { + "answer": "every frame", + "tokens": 16591, + "fixed_tokens": 1223, + "processed_tokens": 209276, + "tool_calls": 14, + "turns": 15 + }, + "render-054": { + "answer": "debug-gpu-validation", + "tokens": 25033, + "fixed_tokens": 1227, + "processed_tokens": 464388, + "tool_calls": 24, + "turns": 25 + }, + "render-055": { + "answer": "fnd-tern-cost-at-4k-output-on-meridian-with-the-reac--81tcpzvhwzcy6wyn", + "tokens": 29471, + "fixed_tokens": 1223, + "processed_tokens": 398143, + "tool_calls": 19, + "turns": 20 + }, + "render-056": { + "answer": "208,000 meshlets", + "tokens": 46830, + "fixed_tokens": 1225, + "processed_tokens": 813035, + "tool_calls": 22, + "turns": 23 + }, + "render-057": { + "answer": "dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1", + "tokens": 15104, + "fixed_tokens": 1228, + "processed_tokens": 144089, + "tool_calls": 10, + "turns": 11 + }, + "render-058": { + "answer": "iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v", + "tokens": 15580, + "fixed_tokens": 1228, + "processed_tokens": 179697, + "tool_calls": 12, + "turns": 13 + }, + "render-059": { + "answer": "fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr", + "tokens": 40435, + "fixed_tokens": 1223, + "processed_tokens": 535098, + "tool_calls": 18, + "turns": 19 + }, + "render-060": { + "answer": "0.31", + "tokens": 46470, + "fixed_tokens": 1224, + "processed_tokens": 472356, + "tool_calls": 16, + "turns": 16 + }, + "render-061": { + "answer": "con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s", + "tokens": 16484, + "fixed_tokens": 1221, + "processed_tokens": 232366, + "tool_calls": 15, + "turns": 16 + }, + "render-062": { + "answer": "con-frame-budget--j6vneva1g2ywj86m", + "tokens": 30698, + "fixed_tokens": 1228, + "processed_tokens": 394421, + "tool_calls": 18, + "turns": 19 + }, + "render-063": { + "answer": "dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r", + "tokens": 20200, + "fixed_tokens": 1223, + "processed_tokens": 182768, + "tool_calls": 14, + "turns": 13 + }, + "render-064": { + "answer": "dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j", + "tokens": 22078, + "fixed_tokens": 1225, + "processed_tokens": 369925, + "tool_calls": 21, + "turns": 22 + }, + "render-065": { + "answer": "dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e", + "tokens": 23216, + "fixed_tokens": 1227, + "processed_tokens": 303905, + "tool_calls": 17, + "turns": 18 + }, + "render-066": { + "answer": "dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr", + "tokens": 38899, + "fixed_tokens": 1219, + "processed_tokens": 488486, + "tool_calls": 20, + "turns": 21 + }, + "render-067": { + "answer": 4, + "tokens": 21601, + "fixed_tokens": 1223, + "processed_tokens": 132351, + "tool_calls": 8, + "turns": 9 + }, + "render-068": { + "answer": [ + "dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4", + "dec-lock-caustic-photon-jitter-to-the-tide-phase--85x10k4h11t8nx7c", + "dec-use-the-probe-grid-alone-in-120-hz-performance-m--6dzm1nt40pjfpyae", + "dec-trace-sdf-gi-at-quarter-resolution-in-performanc--06cqt3mqn3fg5h6e", + "dec-read-paper-white-from-the-meridian-system-settin--7crbx73gqw1hn7xq", + "dec-add-an-in-game-paper-white-slider-from-80-to-400--1phfvxby983z8tjf" + ], + "tokens": 21654, + "fixed_tokens": 1226, + "processed_tokens": 194781, + "tool_calls": 11, + "turns": 12 + }, + "render-069": { + "answer": "iss-shadow-pages-run-out-at-spring-low-tide--f4fgy6b44jbkrsmh", + "tokens": 18004, + "fixed_tokens": 1224, + "processed_tokens": 139084, + "tool_calls": 9, + "turns": 10 + }, + "render-070": { + "answer": [ + "dec-use-signed-distance-field-gi--yn366zmp3k7snd9w", + "dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2", + "dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k" + ], + "tokens": 101479, + "fixed_tokens": 1227, + "processed_tokens": 1107283, + "tool_calls": 20, + "turns": 21 + }, + "render-071": { + "answer": 3, + "tokens": 27591, + "fixed_tokens": 1228, + "processed_tokens": 193400, + "tool_calls": 12, + "turns": 11 + }, + "render-072": { + "answer": [ + "rsk-sdf-volumes-outgrow-the-render-target-memory-bud--xfd2pfztvskdcd2c", + "rsk-artists-cannot-match-concept-paintings-under-the--6cfh9vkamn0kbtcx" + ], + "tokens": 14193, + "fixed_tokens": 1224, + "processed_tokens": 92708, + "tool_calls": 7, + "turns": 8 + }, + "render-073": { + "answer": [ + "rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty", + "rsk-gi-cannot-fit-the-120-hz-performance-mode--tqt3fj839dqfq5s7", + "rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4" + ], + "tokens": 11924, + "fixed_tokens": 1230, + "processed_tokens": 103146, + "tool_calls": 8, + "turns": 9 + }, + "render-074": { + "answer": "unknown", + "tokens": 26006, + "fixed_tokens": 1227, + "processed_tokens": 156681, + "tool_calls": 9, + "turns": 10 + }, + "render-075": { + "answer": "3", + "tokens": 41849, + "fixed_tokens": 1231, + "processed_tokens": 292775, + "tool_calls": 11, + "turns": 12 + }, + "render-076": { + "answer": false, + "tokens": 18569, + "fixed_tokens": 1227, + "processed_tokens": 239704, + "tool_calls": 15, + "turns": 16 + }, + "render-077": { + "answer": true, + "tokens": 8253, + "fixed_tokens": 1220, + "processed_tokens": 55348, + "tool_calls": 5, + "turns": 6 + }, + "render-078": { + "answer": [ + "dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e", + "rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4" + ], + "tokens": 8809, + "fixed_tokens": 1221, + "processed_tokens": 56352, + "tool_calls": 5, + "turns": 6 + }, + "render-079": { + "answer": 6, + "tokens": 23777, + "fixed_tokens": 1225, + "processed_tokens": 127429, + "tool_calls": 8, + "turns": 9 + }, + "render-080": { + "answer": "6 versions", + "tokens": 28096, + "fixed_tokens": 1228, + "processed_tokens": 215316, + "tool_calls": 12, + "turns": 13 + }, + "render-081": { + "answer": "unknown", + "tokens": 35023, + "fixed_tokens": 1221, + "processed_tokens": 474744, + "tool_calls": 18, + "turns": 19 + }, + "render-082": { + "answer": "unknown", + "tokens": 11748, + "fixed_tokens": 1222, + "processed_tokens": 152371, + "tool_calls": 12, + "turns": 13 + }, + "render-083": { + "answer": 4, + "tokens": 55586, + "fixed_tokens": 1222, + "processed_tokens": 657557, + "tool_calls": 20, + "turns": 20 + }, + "tools-001": { + "answer": "completed", + "tokens": 10370, + "fixed_tokens": 1234, + "processed_tokens": 72187, + "tool_calls": 6, + "turns": 7 + }, + "tools-002": { + "answer": "47 minutes", + "tokens": 12110, + "fixed_tokens": 1216, + "processed_tokens": 88536, + "tool_calls": 9, + "turns": 8 + }, + "tools-003": { + "answer": "6 min 40 s", + "tokens": 7036, + "fixed_tokens": 1230, + "processed_tokens": 63061, + "tool_calls": 6, + "turns": 7 + }, + "tools-004": { + "answer": "unknown", + "tokens": 13964, + "fixed_tokens": 1231, + "processed_tokens": 79076, + "tool_calls": 6, + "turns": 7 + }, + "tools-005": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tokens": 16531, + "fixed_tokens": 1228, + "processed_tokens": 96541, + "tool_calls": 7, + "turns": 8 + }, + "tools-006": { + "answer": "dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh", + "tokens": 16328, + "fixed_tokens": 1226, + "processed_tokens": 96527, + "tool_calls": 7, + "turns": 8 + }, + "tools-007": { + "answer": "dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6", + "tokens": 19384, + "fixed_tokens": 1229, + "processed_tokens": 86834, + "tool_calls": 6, + "turns": 7 + }, + "tools-008": { + "answer": "dec-key-the-shader-cache-on-raw-source-text-and-comp--hp6awmx3gq5rn9nc", + "tokens": 16846, + "fixed_tokens": 1226, + "processed_tokens": 97914, + "tool_calls": 7, + "turns": 8 + }, + "tools-009": { + "answer": "92.4%", + "tokens": 17369, + "fixed_tokens": 1228, + "processed_tokens": 140005, + "tool_calls": 9, + "turns": 10 + }, + "tools-010": { + "answer": "dec-cap-each-farm-agent-at-6-parallel-shader-compile--q5w4sfjm73tsj8x8", + "tokens": 16160, + "fixed_tokens": 1226, + "processed_tokens": 127514, + "tool_calls": 11, + "turns": 10 + }, + "tools-011": { + "answer": "fnd-two-compiler-builds-with-the-same-version-string--gmgr4ha0ndxqmcn9", + "tokens": 19548, + "fixed_tokens": 1227, + "processed_tokens": 196662, + "tool_calls": 12, + "turns": 13 + }, + "tools-012": { + "answer": 3, + "tokens": 11337, + "fixed_tokens": 1230, + "processed_tokens": 87045, + "tool_calls": 7, + "turns": 8 + }, + "tools-013": { + "answer": 8, + "tokens": 10153, + "fixed_tokens": 1229, + "processed_tokens": 72068, + "tool_calls": 6, + "turns": 7 + }, + "tools-014": { + "answer": "false, fnd-flaky-nightly-builds-are-compiler-processes-runn--1sabnpb1s7004jkb", + "tokens": 12163, + "fixed_tokens": 1228, + "processed_tokens": 89391, + "tool_calls": 9, + "turns": 8 + }, + "tools-015": { + "answer": [ + "rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd" + ], + "tokens": 20463, + "fixed_tokens": 1231, + "processed_tokens": 183739, + "tool_calls": 11, + "turns": 12 + }, + "tools-016": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tokens": 26052, + "fixed_tokens": 1228, + "processed_tokens": 173663, + "tool_calls": 9, + "turns": 10 + }, + "world-001": { + "answer": "64 KB", + "tokens": 28772, + "fixed_tokens": 1221, + "processed_tokens": 232550, + "tool_calls": 12, + "turns": 13 + }, + "world-002": { + "answer": "5.1 ms", + "tokens": 10621, + "fixed_tokens": 1223, + "processed_tokens": 97548, + "tool_calls": 8, + "turns": 9 + }, + "world-003": { + "answer": "one crash per 900 script waits", + "tokens": 61439, + "fixed_tokens": 1223, + "processed_tokens": 486943, + "tool_calls": 14, + "turns": 15 + }, + "world-004": { + "answer": "unknown", + "tokens": 21925, + "fixed_tokens": 1223, + "processed_tokens": 199256, + "tool_calls": 13, + "turns": 12 + }, + "world-005": { + "answer": "11 m", + "tokens": 29046, + "fixed_tokens": 1227, + "processed_tokens": 466676, + "tool_calls": 22, + "turns": 23 + }, + "world-006": { + "answer": "3.4 direction reversals per minute", + "tokens": 34494, + "fixed_tokens": 1223, + "processed_tokens": 419244, + "tool_calls": 16, + "turns": 17 + }, + "world-007": { + "answer": "260 MB", + "tokens": 12810, + "fixed_tokens": 1222, + "processed_tokens": 135261, + "tool_calls": 10, + "turns": 11 + }, + "world-008": { + "answer": "10 Hz", + "tokens": 8305, + "fixed_tokens": 1222, + "processed_tokens": 77054, + "tool_calls": 7, + "turns": 8 + }, + "world-009": { + "answer": "unknown", + "tokens": 47675, + "fixed_tokens": 1220, + "processed_tokens": 486756, + "tool_calls": 15, + "turns": 16 + }, + "world-010": { + "answer": "unknown", + "tokens": 75460, + "fixed_tokens": 1227, + "processed_tokens": 1034314, + "tool_calls": 26, + "turns": 25 + }, + "world-011": { + "answer": "fnd-shipping-entity-names-costs-57-mb-at-full-popula--6w7gjvy7wdmdx9qx", + "tokens": 23426, + "fixed_tokens": 1224, + "processed_tokens": 180498, + "tool_calls": 10, + "turns": 11 + }, + "world-012": { + "answer": "dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3", + "tokens": 42784, + "fixed_tokens": 1219, + "processed_tokens": 299835, + "tool_calls": 14, + "turns": 13 + }, + "world-013": { + "answer": "unknown", + "tokens": 29448, + "fixed_tokens": 1221, + "processed_tokens": 244828, + "tool_calls": 11, + "turns": 12 + }, + "world-014": { + "answer": "unknown", + "tokens": 40395, + "fixed_tokens": 1223, + "processed_tokens": 727097, + "tool_calls": 23, + "turns": 24 + }, + "world-015": { + "answer": "3.0 ms per frame", + "tokens": 32533, + "fixed_tokens": 1222, + "processed_tokens": 296749, + "tool_calls": 14, + "turns": 15 + }, + "world-016": { + "answer": "unknown", + "tokens": 43855, + "fixed_tokens": 1223, + "processed_tokens": 762811, + "tool_calls": 24, + "turns": 25 + }, + "world-017": { + "answer": "dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw", + "tokens": 40469, + "fixed_tokens": 1224, + "processed_tokens": 287092, + "tool_calls": 12, + "turns": 13 + }, + "world-018": { + "answer": "dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x", + "tokens": 30139, + "fixed_tokens": 1225, + "processed_tokens": 448686, + "tool_calls": 21, + "turns": 22 + }, + "world-019": { + "answer": "fnd-tide-priority-reads-starve-player-proximity-load--by0d7b0bk39xz3rk", + "tokens": 30197, + "fixed_tokens": 1223, + "processed_tokens": 484805, + "tool_calls": 21, + "turns": 22 + }, + "world-020": { + "answer": "dec-schedule-streaming-reads-by-deadline-instead-of--q2x5aknabgcssdj2", + "tokens": 12252, + "fixed_tokens": 1222, + "processed_tokens": 120884, + "tool_calls": 10, + "turns": 11 + }, + "world-021": { + "answer": "dec-cut-navigation-tiles-to-64-m-so-three-fit-along--snvepk8ygeb3qsjs", + "tokens": 33088, + "fixed_tokens": 1226, + "processed_tokens": 342453, + "tool_calls": 14, + "turns": 15 + }, + "world-022": { + "answer": "fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m", + "tokens": 25899, + "fixed_tokens": 1223, + "processed_tokens": 251927, + "tool_calls": 13, + "turns": 14 + }, + "world-023": { + "answer": "dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m", + "tokens": 28894, + "fixed_tokens": 1223, + "processed_tokens": 202022, + "tool_calls": 10, + "turns": 11 + }, + "world-024": { + "answer": "dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew", + "tokens": 15858, + "fixed_tokens": 1225, + "processed_tokens": 166063, + "tool_calls": 11, + "turns": 12 + }, + "world-025": { + "answer": "con-streaming-pool-budget--kca88sgh2j6sxvd5", + "tokens": 11058, + "fixed_tokens": 1228, + "processed_tokens": 133065, + "tool_calls": 11, + "turns": 12 + }, + "world-026": { + "answer": "fnd-retail-skiff-units-sustain-only-190-mb-s-of-stre--485sdcmm3gweevvn", + "tokens": 65492, + "fixed_tokens": 1232, + "processed_tokens": 637447, + "tool_calls": 17, + "turns": 18 + }, + "world-027": { + "answer": "160 MB/s", + "tokens": 21383, + "fixed_tokens": 1223, + "processed_tokens": 145513, + "tool_calls": 10, + "turns": 10 + }, + "world-028": { + "answer": "unknown", + "tokens": 37944, + "fixed_tokens": 1222, + "processed_tokens": 447848, + "tool_calls": 19, + "turns": 19 + }, + "world-029": { + "answer": "unknown", + "tokens": 14925, + "fixed_tokens": 1220, + "processed_tokens": 147008, + "tool_calls": 11, + "turns": 11 + }, + "world-030": { + "answer": "fnd-world-core-state-at-alpha--tkbsm4867h65jqq8", + "tokens": 15832, + "fixed_tokens": 1230, + "processed_tokens": 179020, + "tool_calls": 12, + "turns": 13 + }, + "world-031": { + "answer": "1.5 GB/s", + "tokens": 10110, + "fixed_tokens": 1230, + "processed_tokens": 80972, + "tool_calls": 9, + "turns": 8 + }, + "world-032": { + "answer": "fnd-float-tide-heights-drift-apart-between-pc-and-me--7jb0fg4b5xzr7q5e", + "tokens": 26476, + "fixed_tokens": 1221, + "processed_tokens": 133234, + "tool_calls": 8, + "turns": 9 + }, + "world-033": { + "answer": "dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw", + "tokens": 32254, + "fixed_tokens": 1225, + "processed_tokens": 440293, + "tool_calls": 17, + "turns": 18 + }, + "world-034": { + "answer": "unknown", + "tokens": 36939, + "fixed_tokens": 1221, + "processed_tokens": 195418, + "tool_calls": 9, + "turns": 10 + }, + "world-035": { + "answer": false, + "tokens": 38738, + "fixed_tokens": 1227, + "processed_tokens": 219562, + "tool_calls": 10, + "turns": 11 + }, + "world-036": { + "answer": "Kestrel retired the fiber scheduler because 41% of alpha crash reports had no usable stack, which blocked crash triage for beta, and a continuation-wait thread pool kept workers 93% busy during tide turns, close to the 95% fibers gave (dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h).", + "tokens": 29249, + "fixed_tokens": 1226, + "processed_tokens": 283750, + "tool_calls": 13, + "turns": 13 + }, + "world-037": { + "answer": "fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws", + "tokens": 18168, + "fixed_tokens": 1220, + "processed_tokens": 257734, + "tool_calls": 16, + "turns": 17 + }, + "world-038": { + "answer": "3", + "tokens": 28568, + "fixed_tokens": 1222, + "processed_tokens": 259792, + "tool_calls": 12, + "turns": 13 + }, + "world-039": { + "answer": "1.2 GB/s", + "tokens": 28832, + "fixed_tokens": 1221, + "processed_tokens": 386106, + "tool_calls": 16, + "turns": 17 + }, + "world-040": { + "answer": "unknown", + "tokens": 38040, + "fixed_tokens": 1224, + "processed_tokens": 485479, + "tool_calls": 24, + "turns": 21 + }, + "world-041": { + "answer": "61%", + "tokens": 30710, + "fixed_tokens": 1220, + "processed_tokens": 239548, + "tool_calls": 11, + "turns": 12 + }, + "world-042": { + "answer": "5.4 s", + "tokens": 40281, + "fixed_tokens": 1230, + "processed_tokens": 630481, + "tool_calls": 21, + "turns": 22 + }, + "world-043": { + "answer": "5.8 minutes", + "tokens": 39197, + "fixed_tokens": 1225, + "processed_tokens": 530536, + "tool_calls": 19, + "turns": 20 + }, + "world-044": { + "answer": "dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq", + "tokens": 43724, + "fixed_tokens": 1219, + "processed_tokens": 406348, + "tool_calls": 14, + "turns": 15 + }, + "world-045": { + "answer": "dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te", + "tokens": 42256, + "fixed_tokens": 1223, + "processed_tokens": 314339, + "tool_calls": 12, + "turns": 13 + }, + "world-046": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tokens": 17472, + "fixed_tokens": 1221, + "processed_tokens": 138061, + "tool_calls": 9, + "turns": 10 + }, + "world-047": { + "answer": "fnd-world-core-state-at-alpha--tkbsm4867h65jqq8", + "tokens": 16123, + "fixed_tokens": 1225, + "processed_tokens": 200750, + "tool_calls": 13, + "turns": 14 + }, + "world-048": { + "answer": "dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3", + "tokens": 40634, + "fixed_tokens": 1229, + "processed_tokens": 311441, + "tool_calls": 12, + "turns": 13 + }, + "world-049": { + "answer": "22%", + "tokens": 51029, + "fixed_tokens": 1226, + "processed_tokens": 733913, + "tool_calls": 20, + "turns": 21 + }, + "world-050": { + "answer": "fnd-alpha-content-needs-6-2-ms-of-gull-time-per-fram--4mekgdpsdv5nk085", + "tokens": 54422, + "fixed_tokens": 1226, + "processed_tokens": 433805, + "tool_calls": 18, + "turns": 19 + }, + "world-051": { + "answer": "Float tides drifted apart between machines within 6 minutes, with PC against Skiff the worst pair, from fused multiply-add contraction and a Skiff sin() one ulp off (fnd-float-tides-drift-apart-between-machines-within--znd0wy18bfw2prss); fixed-point integer math gives identical bits on every CPU and compiler, with no platform math library, so the tide runs in 32.32 fixed point. Record: dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e", + "tokens": 14911, + "fixed_tokens": 1225, + "processed_tokens": 144530, + "tool_calls": 10, + "turns": 11 + }, + "world-052": { + "answer": "Dara Whitlock", + "tokens": 21434, + "fixed_tokens": 1226, + "processed_tokens": 219735, + "tool_calls": 13, + "turns": 14 + }, + "world-053": { + "answer": "1.9 ms", + "tokens": 74586, + "fixed_tokens": 1220, + "processed_tokens": 1374327, + "tool_calls": 30, + "turns": 27 + }, + "world-054": { + "answer": "Marta Lindqvist", + "tokens": 19406, + "fixed_tokens": 1223, + "processed_tokens": 273252, + "tool_calls": 16, + "turns": 17 + }, + "world-055": { + "answer": "Kelp stays because shrinking its dictionary to 1 MB made it beat Zstandard cold on Skiff (2.2 vs 1.3 GB/s, 1.7x), per dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew. After Skiff firmware 3.2, the 1 MB Kelp still wins (1.5 vs 1.2 GB/s), per fnd-kelp-with-a-1-mb-dictionary-decodes-at-1-5-gb-s--y9v8jrxgbv6abrx5.", + "tokens": 31240, + "fixed_tokens": 1221, + "processed_tokens": 328993, + "tool_calls": 14, + "turns": 15 + }, + "world-056": { + "answer": "dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x", + "tokens": 27702, + "fixed_tokens": 1222, + "processed_tokens": 150994, + "tool_calls": 9, + "turns": 10 + }, + "world-057": { + "answer": "tile [212, 87]", + "tokens": 19738, + "fixed_tokens": 1226, + "processed_tokens": 243127, + "tool_calls": 14, + "turns": 15 + }, + "world-058": { + "answer": "1.1 GB/s", + "tokens": 22588, + "fixed_tokens": 1225, + "processed_tokens": 378834, + "tool_calls": 20, + "turns": 21 + }, + "world-059": { + "answer": "dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw", + "tokens": 18956, + "fixed_tokens": 1223, + "processed_tokens": 190654, + "tool_calls": 14, + "turns": 13 + }, + "world-060": { + "answer": "dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc", + "tokens": 18217, + "fixed_tokens": 1222, + "processed_tokens": 250280, + "tool_calls": 15, + "turns": 16 + }, + "world-061": { + "answer": "236 MB", + "tokens": 24775, + "fixed_tokens": 1226, + "processed_tokens": 352853, + "tool_calls": 17, + "turns": 18 + }, + "world-062": { + "answer": "310 MB", + "tokens": 20406, + "fixed_tokens": 1234, + "processed_tokens": 271174, + "tool_calls": 17, + "turns": 18 + }, + "world-063": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tokens": 40545, + "fixed_tokens": 1223, + "processed_tokens": 374931, + "tool_calls": 17, + "turns": 17 + }, + "world-064": { + "answer": [ + "dec-force-strict-ieee-float-mode-for-the-tide-simula--ecwmqt7ncjngysqw", + "dec-have-the-host-stream-tide-heights-to-every-peer--a3rb1seedn2bj7k8" + ], + "tokens": 31811, + "fixed_tokens": 1223, + "processed_tokens": 384089, + "tool_calls": 18, + "turns": 19 + }, + "world-065": { + "answer": "3.1 ms", + "tokens": 56026, + "fixed_tokens": 1218, + "processed_tokens": 698922, + "tool_calls": 26, + "turns": 19 + }, + "world-066": { + "answer": "46 proximity reads", + "tokens": 17734, + "fixed_tokens": 1233, + "processed_tokens": 215929, + "tool_calls": 13, + "turns": 14 + }, + "world-067": { + "answer": "1.2 GB/s", + "tokens": 21824, + "fixed_tokens": 1221, + "processed_tokens": 278095, + "tool_calls": 15, + "turns": 16 + }, + "world-068": { + "answer": false, + "tokens": 4856, + "fixed_tokens": 1223, + "processed_tokens": 39721, + "tool_calls": 4, + "turns": 5 + }, + "world-069": { + "answer": 7, + "tokens": 8705, + "fixed_tokens": 1225, + "processed_tokens": 56209, + "tool_calls": 5, + "turns": 6 + }, + "world-070": { + "answer": 3, + "tokens": 19640, + "fixed_tokens": 1224, + "processed_tokens": 103873, + "tool_calls": 7, + "turns": 8 + }, + "world-071": { + "answer": [ + "dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m", + "dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9", + "dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg", + "dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42", + "dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w" + ], + "tokens": 111385, + "fixed_tokens": 1218, + "processed_tokens": 965104, + "tool_calls": 19, + "turns": 20 + }, + "world-072": { + "answer": [ + "dec-compress-streamed-assets-with-zstandard--bs1t15cygc51cpje", + "dec-compress-streamed-assets-with-lz4--v1pfsgfp0b3yjv4s" + ], + "tokens": 49577, + "fixed_tokens": 1227, + "processed_tokens": 496298, + "tool_calls": 17, + "turns": 17 + }, + "world-073": { + "answer": false, + "tokens": 32991, + "fixed_tokens": 1223, + "processed_tokens": 321186, + "tool_calls": 15, + "turns": 16 + }, + "world-074": { + "answer": "unknown", + "tokens": 41859, + "fixed_tokens": 1222, + "processed_tokens": 380430, + "tool_calls": 28, + "turns": 15 + }, + "world-075": { + "answer": "unknown", + "tokens": 43239, + "fixed_tokens": 1226, + "processed_tokens": 317526, + "tool_calls": 12, + "turns": 13 + }, + "world-076": { + "answer": "unknown", + "tokens": 53796, + "fixed_tokens": 1229, + "processed_tokens": 610310, + "tool_calls": 28, + "turns": 18 + }, + "world-077": { + "answer": 9, + "tokens": 30011, + "fixed_tokens": 1222, + "processed_tokens": 197383, + "tool_calls": 10, + "turns": 11 + }, + "world-078": { + "answer": [ + "rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew", + "rsk-reworking-the-read-scheduler-may-slip-the-coast--9jzvs7etvb5jxqtp" + ], + "tokens": 15315, + "fixed_tokens": 1224, + "processed_tokens": 94656, + "tool_calls": 7, + "turns": 8 + }, + "world-079": { + "answer": [ + "con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73", + "con-tide-state-must-be-bit-identical-on-every-peer--zrpnp8qjyxzkas7t", + "con-saves-from-beta-onward-must-load-in-every-later--v6z856sxtgc5sb09", + "con-streaming-pool-budget--8czwb4fjr5p5vpy7" + ], + "tokens": 15814, + "fixed_tokens": 1226, + "processed_tokens": 94909, + "tool_calls": 7, + "turns": 8 + }, + "world-080": { + "answer": [ + "iss-gull-hot-reload-rejects-struct-layout-changes--3v2w2f9hg2gwy6aj", + "iss-gull-hot-reload-drops-suspended-coroutines--z7j2gmyny6gdxd07", + "iss-cross-platform-cloud-saves-are-unplanned--5bk0k4wrgj42ztfy" + ], + "tokens": 20268, + "fixed_tokens": 1225, + "processed_tokens": 109494, + "tool_calls": 7, + "turns": 8 + }, + "world-081": { + "answer": "rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew", + "tokens": 64807, + "fixed_tokens": 1220, + "processed_tokens": 707258, + "tool_calls": 39, + "turns": 17 + } + } +} diff --git a/benchmarks/proof-recall/runs/full-haiku-nobrief.json b/benchmarks/proof-recall/runs/full-haiku-nobrief.json new file mode 100644 index 00000000..7b971333 --- /dev/null +++ b/benchmarks/proof-recall/runs/full-haiku-nobrief.json @@ -0,0 +1,2041 @@ +{ + "run": { + "name": "full-haiku-nobrief", + "protocol": "one fresh session per question", + "models": ["claude-haiku-5-5"] + }, + "answers": { + "cross-001": { + "answer": "con-frame-budget--br0qszfg8fys908n", + "tokens": 21392, + "fixed_tokens": 1232, + "processed_tokens": 172918, + "tool_calls": 9, + "turns": 10 + }, + "cross-002": { + "answer": 2, + "tokens": 30777, + "fixed_tokens": 1236, + "processed_tokens": 236651, + "tool_calls": 19, + "turns": 13 + }, + "cross-003": { + "answer": "unknown", + "tokens": 33904, + "fixed_tokens": 1230, + "processed_tokens": 551912, + "tool_calls": 24, + "turns": 22 + }, + "cross-004": { + "answer": "dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e", + "tokens": 28458, + "fixed_tokens": 1231, + "processed_tokens": 334977, + "tool_calls": 15, + "turns": 16 + }, + "cross-005": { + "answer": "Rhea Valdés", + "tokens": 16281, + "fixed_tokens": 1232, + "processed_tokens": 170522, + "tool_calls": 11, + "turns": 12 + }, + "cross-006": { + "answer": "19%", + "tokens": 27338, + "fixed_tokens": 1234, + "processed_tokens": 258416, + "tool_calls": 11, + "turns": 12 + }, + "cross-007": { + "answer": "8 GB", + "tokens": 31102, + "fixed_tokens": 1236, + "processed_tokens": 372271, + "tool_calls": 15, + "turns": 16 + }, + "cross-008": { + "answer": "unknown", + "tokens": 46525, + "fixed_tokens": 1234, + "processed_tokens": 490525, + "tool_calls": 15, + "turns": 16 + }, + "cross-009": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tokens": 44631, + "fixed_tokens": 1227, + "processed_tokens": 340959, + "tool_calls": 11, + "turns": 12 + }, + "cross-010": { + "answer": "dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7", + "tokens": 28999, + "fixed_tokens": 1231, + "processed_tokens": 203399, + "tool_calls": 10, + "turns": 11 + }, + "cross-011": { + "answer": false, + "tokens": 55593, + "fixed_tokens": 1234, + "processed_tokens": 368368, + "tool_calls": 12, + "turns": 13 + }, + "cross-012": { + "answer": "61 MB/s", + "tokens": 25820, + "fixed_tokens": 1236, + "processed_tokens": 208405, + "tool_calls": 10, + "turns": 11 + }, + "cross-013": { + "answer": "Skiff runs Tern at the Performance preset, not the lowest (Ultra Performance, which is offered only in Meridian's 120 Hz mode), and it saves 1.8 ms over Quality (2.1 ms vs 3.9 ms). See dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3, which is still accepted and was reaffirmed by dec-lower-the-skiff-dynamic-resolution-floor-to-504p--15esnt90gcn29enn; the timings come from fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0.", + "tokens": 71641, + "fixed_tokens": 1231, + "processed_tokens": 605100, + "tool_calls": 14, + "turns": 15 + }, + "cross-014": { + "answer": 3, + "tokens": 5860, + "fixed_tokens": 1229, + "processed_tokens": 41536, + "tool_calls": 4, + "turns": 5 + }, + "cross-015": { + "answer": "Two Efforts are no longer active. The Co-op rollback netcode prototype was abandoned: the Decision dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b stopped the prototype because tide re-simulation costs 4.8 ms on Skiff, so co-op will not ship with rollback. The Shader compile cache and build farm is completed: fnd-retrospective-on-the-shader-compile-cache--9rpv2a60ach04cx6 records that the cache has run on every farm build for five weeks, with a 94% steady-state hit rate and a warm clean rebuild of 6 min 40 s, down from 47 minutes.", + "tokens": 40225, + "fixed_tokens": 1230, + "processed_tokens": 322160, + "tool_calls": 13, + "turns": 13 + }, + "cross-016": { + "answer": "16.7 ms", + "tokens": 70349, + "fixed_tokens": 1235, + "processed_tokens": 673581, + "tool_calls": 15, + "turns": 16 + }, + "cross-017": { + "answer": "unknown", + "tokens": 30205, + "fixed_tokens": 1231, + "processed_tokens": 412778, + "tool_calls": 18, + "turns": 17 + }, + "netcode-001": { + "answer": "abandoned", + "tokens": 5852, + "fixed_tokens": 1233, + "processed_tokens": 41494, + "tool_calls": 4, + "turns": 5 + }, + "netcode-002": { + "answer": "netcode/rollback-archive", + "tokens": 25992, + "fixed_tokens": 1234, + "processed_tokens": 194968, + "tool_calls": 9, + "turns": 10 + }, + "netcode-003": { + "answer": "38 KB", + "tokens": 24757, + "fixed_tokens": 1233, + "processed_tokens": 97964, + "tool_calls": 7, + "turns": 7 + }, + "netcode-004": { + "answer": "The team abandoned rollback because co-op tides must stay bit-identical across peers, so every rolled-back frame must re-run the tide step, costing 4.8 ms on Skiff (about a fifth of the 25 ms frame), and the quarter-resolution workaround desynced within 90 seconds (dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b). The reason depends on the world Decision dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e.", + "tokens": 30184, + "fixed_tokens": 1238, + "processed_tokens": 287516, + "tool_calls": 12, + "turns": 13 + }, + "netcode-005": { + "answer": "unknown", + "tokens": 27646, + "fixed_tokens": 1240, + "processed_tokens": 186394, + "tool_calls": 10, + "turns": 11 + }, + "netcode-006": { + "answer": "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "tokens": 13950, + "fixed_tokens": 1234, + "processed_tokens": 119779, + "tool_calls": 9, + "turns": 10 + }, + "netcode-007": { + "answer": "dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b", + "tokens": 11895, + "fixed_tokens": 1235, + "processed_tokens": 82232, + "tool_calls": 7, + "turns": 8 + }, + "netcode-008": { + "answer": "dec-use-a-4-frame-rollback-window--pqe4hvbgmbp0dmh9", + "tokens": 27860, + "fixed_tokens": 1235, + "processed_tokens": 141095, + "tool_calls": 8, + "turns": 9 + }, + "netcode-009": { + "answer": "1.9 ms", + "tokens": 26340, + "fixed_tokens": 1238, + "processed_tokens": 265755, + "tool_calls": 12, + "turns": 13 + }, + "netcode-010": { + "answer": "dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk", + "tokens": 16173, + "fixed_tokens": 1240, + "processed_tokens": 124175, + "tool_calls": 11, + "turns": 10 + }, + "netcode-011": { + "answer": "con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g", + "tokens": 43474, + "fixed_tokens": 1232, + "processed_tokens": 312870, + "tool_calls": 11, + "turns": 12 + }, + "netcode-012": { + "answer": "dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f", + "tokens": 21606, + "fixed_tokens": 1237, + "processed_tokens": 128548, + "tool_calls": 7, + "turns": 8 + }, + "netcode-013": { + "answer": [ + "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf", + "rsk-re-simulation-cost-could-blow-the-skiff-frame-bu--sk2njsp170a3qwyf" + ], + "tokens": 28137, + "fixed_tokens": 1235, + "processed_tokens": 156894, + "tool_calls": 8, + "turns": 9 + }, + "netcode-014": { + "answer": [ + "iss-how-should-co-op-keep-up-to-four-players-in-sync--92t2zfsy3etfzr89", + "iss-late-join-during-a-tide-surge-desyncs-the-joinin--mya93va0n7s8g7cj" + ], + "tokens": 28766, + "fixed_tokens": 1236, + "processed_tokens": 253499, + "tool_calls": 12, + "turns": 13 + }, + "netcode-015": { + "answer": 2, + "tokens": 12505, + "fixed_tokens": 1234, + "processed_tokens": 75071, + "tool_calls": 6, + "turns": 7 + }, + "ports-001": { + "answer": "25 ms", + "tokens": 21132, + "fixed_tokens": 1234, + "processed_tokens": 125371, + "tool_calls": 9, + "turns": 8 + }, + "ports-002": { + "answer": "384 MB", + "tokens": 56930, + "fixed_tokens": 1234, + "processed_tokens": 434542, + "tool_calls": 13, + "turns": 14 + }, + "ports-003": { + "answer": "61 MB/s", + "tokens": 49351, + "fixed_tokens": 1234, + "processed_tokens": 358540, + "tool_calls": 11, + "turns": 12 + }, + "ports-004": { + "answer": "accepted", + "tokens": 37825, + "fixed_tokens": 1231, + "processed_tokens": 340632, + "tool_calls": 12, + "turns": 13 + }, + "ports-005": { + "answer": "unknown", + "tokens": 54524, + "fixed_tokens": 1232, + "processed_tokens": 370706, + "tool_calls": 11, + "turns": 12 + }, + "ports-034": { + "answer": "6 weeks", + "tokens": 37084, + "fixed_tokens": 1233, + "processed_tokens": 249141, + "tool_calls": 10, + "turns": 11 + }, + "ports-006": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tokens": 21279, + "fixed_tokens": 1233, + "processed_tokens": 141285, + "tool_calls": 8, + "turns": 9 + }, + "ports-007": { + "answer": "SKF-UI-031", + "tokens": 50012, + "fixed_tokens": 1235, + "processed_tokens": 465476, + "tool_calls": 13, + "turns": 14 + }, + "ports-008": { + "answer": "dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3", + "tokens": 20261, + "fixed_tokens": 1237, + "processed_tokens": 108858, + "tool_calls": 8, + "turns": 9 + }, + "ports-009": { + "answer": "dec-load-skiff-fast-travel-without-a-loading-screen--v4qft5znysjv5f24", + "tokens": 36912, + "fixed_tokens": 1233, + "processed_tokens": 251537, + "tool_calls": 10, + "turns": 11 + }, + "ports-010": { + "answer": "con-frame-budget--wt5rfqh5z444g2cg", + "tokens": 35068, + "fixed_tokens": 1235, + "processed_tokens": 200426, + "tool_calls": 9, + "turns": 10 + }, + "ports-011": { + "answer": "99.6%", + "tokens": 24357, + "fixed_tokens": 1235, + "processed_tokens": 233989, + "tool_calls": 11, + "turns": 12 + }, + "ports-012": { + "answer": "Caustics under saltglass shimmered badly at the 540p floor even with Tern (visible in 7 of 10 dune views; 2 of 10 at 576p), so the team raised the floor to 576p, per `dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb`, citing `fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q`. That 576p decision was later superseded by `dec-lower-the-skiff-dynamic-resolution-floor-to-504p--15esnt90gcn29enn`.", + "tokens": 23433, + "fixed_tokens": 1236, + "processed_tokens": 228833, + "tool_calls": 11, + "turns": 12 + }, + "ports-013": { + "answer": "Ship Tern as Lantern's only upscaler", + "tokens": 32041, + "fixed_tokens": 1229, + "processed_tokens": 184162, + "tool_calls": 9, + "turns": 10 + }, + "ports-014": { + "answer": "dec-scale-skiff-resolution-dynamically-between-540p--jtytvgh2erd32x68", + "tokens": 32735, + "fixed_tokens": 1240, + "processed_tokens": 170395, + "tool_calls": 8, + "turns": 9 + }, + "ports-015": { + "answer": "textures", + "tokens": 28822, + "fixed_tokens": 1234, + "processed_tokens": 297868, + "tool_calls": 13, + "turns": 14 + }, + "ports-016": { + "answer": "dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn", + "tokens": 25344, + "fixed_tokens": 1235, + "processed_tokens": 210089, + "tool_calls": 11, + "turns": 12 + }, + "ports-017": { + "answer": "fnd-skiff-microsd-slows-sharply-on-full-warm-cards--p1rgh36hat2egpz3", + "tokens": 39805, + "fixed_tokens": 1233, + "processed_tokens": 518213, + "tool_calls": 16, + "turns": 17 + }, + "ports-018": { + "answer": "504p", + "tokens": 37393, + "fixed_tokens": 1230, + "processed_tokens": 236655, + "tool_calls": 11, + "turns": 10 + }, + "ports-019": { + "answer": "4 MB per minute", + "tokens": 49162, + "fixed_tokens": 1231, + "processed_tokens": 361813, + "tool_calls": 11, + "turns": 12 + }, + "ports-020": { + "answer": "fnd-skiff-sdk-1-2-takes-1-gb-back-from-games--a0ybdgjzw64hwfqa", + "tokens": 20922, + "fixed_tokens": 1237, + "processed_tokens": 171956, + "tool_calls": 9, + "turns": 10 + }, + "ports-021": { + "answer": "SKF-DSP-004", + "tokens": 52769, + "fixed_tokens": 1233, + "processed_tokens": 504233, + "tool_calls": 14, + "turns": 15 + }, + "ports-022": { + "answer": "cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe", + "tokens": 25280, + "fixed_tokens": 1233, + "processed_tokens": 242255, + "tool_calls": 13, + "turns": 12 + }, + "ports-023": { + "answer": "fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0", + "tokens": 26093, + "fixed_tokens": 1236, + "processed_tokens": 223977, + "tool_calls": 12, + "turns": 12 + }, + "ports-024": { + "answer": "fnd-skiff-firmware-1-2-rejects-pipeline-blobs-built--pernvgb2he7m3z3y", + "tokens": 34998, + "fixed_tokens": 1233, + "processed_tokens": 228360, + "tool_calls": 9, + "turns": 10 + }, + "ports-025": { + "answer": "dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3", + "tokens": 22703, + "fixed_tokens": 1228, + "processed_tokens": 177249, + "tool_calls": 9, + "turns": 10 + }, + "ports-026": { + "answer": "912 MB", + "tokens": 24487, + "fixed_tokens": 1232, + "processed_tokens": 239788, + "tool_calls": 11, + "turns": 12 + }, + "ports-027": { + "answer": [ + "dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw", + "rsk-tide-streaming-outruns-skiff-storage--6q8s3b383z2tyeyb" + ], + "tokens": 60304, + "fixed_tokens": 1239, + "processed_tokens": 413700, + "tool_calls": 12, + "turns": 13 + }, + "ports-028": { + "answer": 2, + "tokens": 8618, + "fixed_tokens": 1229, + "processed_tokens": 67812, + "tool_calls": 6, + "turns": 7 + }, + "ports-029": { + "answer": 8, + "tokens": 73515, + "fixed_tokens": 1231, + "processed_tokens": 551938, + "tool_calls": 13, + "turns": 14 + }, + "ports-030": { + "answer": [ + "dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1", + "dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc" + ], + "tokens": 20513, + "fixed_tokens": 1227, + "processed_tokens": 123723, + "tool_calls": 7, + "turns": 8 + }, + "ports-031": { + "answer": [ + "iss-meridian-cert-activity-cards-missing-for-two-bio--k214cmfra7pyvvzq", + "iss-skiff-cert-docked-30-hz-judder-on-some-tvs--9nq2xg9mzash474g" + ], + "tokens": 55146, + "fixed_tokens": 1237, + "processed_tokens": 373415, + "tool_calls": 11, + "turns": 12 + }, + "ports-032": { + "answer": "unknown", + "tokens": 38582, + "fixed_tokens": 1237, + "processed_tokens": 510779, + "tool_calls": 18, + "turns": 19 + }, + "ports-033": { + "answer": "unknown", + "tokens": 56775, + "fixed_tokens": 1235, + "processed_tokens": 433488, + "tool_calls": 13, + "turns": 14 + }, + "render-001": { + "answer": "7.4 ms", + "tokens": 27234, + "fixed_tokens": 1230, + "processed_tokens": 237937, + "tool_calls": 11, + "turns": 12 + }, + "render-002": { + "answer": "3.4x", + "tokens": 25201, + "fixed_tokens": 1230, + "processed_tokens": 206783, + "tool_calls": 12, + "turns": 11 + }, + "render-003": { + "answer": "Tomasz Brandt", + "tokens": 21230, + "fixed_tokens": 1228, + "processed_tokens": 175484, + "tool_calls": 9, + "turns": 10 + }, + "render-004": { + "answer": "rejected", + "tokens": 37160, + "fixed_tokens": 1229, + "processed_tokens": 313730, + "tool_calls": 11, + "turns": 12 + }, + "render-005": { + "answer": true, + "tokens": 19509, + "fixed_tokens": 1231, + "processed_tokens": 153579, + "tool_calls": 9, + "turns": 10 + }, + "render-006": { + "answer": "unknown", + "tokens": 13585, + "fixed_tokens": 1230, + "processed_tokens": 132290, + "tool_calls": 10, + "turns": 11 + }, + "render-007": { + "answer": "2026-07-24", + "tokens": 49908, + "fixed_tokens": 1232, + "processed_tokens": 357277, + "tool_calls": 11, + "turns": 12 + }, + "render-008": { + "answer": "2 failures", + "tokens": 35693, + "fixed_tokens": 1230, + "processed_tokens": 633200, + "tool_calls": 22, + "turns": 23 + }, + "render-009": { + "answer": "32 steps", + "tokens": 23544, + "fixed_tokens": 1234, + "processed_tokens": 149477, + "tool_calls": 8, + "turns": 9 + }, + "render-010": { + "answer": "unknown", + "tokens": 20520, + "fixed_tokens": 1230, + "processed_tokens": 296385, + "tool_calls": 18, + "turns": 19 + }, + "render-011": { + "answer": "unknown", + "tokens": 32741, + "fixed_tokens": 1232, + "processed_tokens": 312968, + "tool_calls": 12, + "turns": 13 + }, + "render-012": { + "answer": "deferred", + "tokens": 44982, + "fixed_tokens": 1229, + "processed_tokens": 767841, + "tool_calls": 23, + "turns": 24 + }, + "render-013": { + "answer": "16-bit float per channel", + "tokens": 40934, + "fixed_tokens": 1231, + "processed_tokens": 851302, + "tool_calls": 26, + "turns": 27 + }, + "render-014": { + "answer": "52%", + "tokens": 26040, + "fixed_tokens": 1226, + "processed_tokens": 209250, + "tool_calls": 10, + "turns": 11 + }, + "render-015": { + "answer": "unknown", + "tokens": 105693, + "fixed_tokens": 1215, + "processed_tokens": 1257020, + "tool_calls": 21, + "turns": 22 + }, + "render-016": { + "answer": "1.2 km", + "tokens": 9942, + "fixed_tokens": 1226, + "processed_tokens": 107866, + "tool_calls": 9, + "turns": 10 + }, + "render-017": { + "answer": "unknown", + "tokens": 171286, + "fixed_tokens": 1233, + "processed_tokens": 2241915, + "tool_calls": 32, + "turns": 29 + }, + "render-018": { + "answer": "unknown", + "tokens": 63224, + "fixed_tokens": 1228, + "processed_tokens": 400121, + "tool_calls": 12, + "turns": 13 + }, + "render-019": { + "answer": "dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86", + "tokens": 24367, + "fixed_tokens": 1235, + "processed_tokens": 209968, + "tool_calls": 10, + "turns": 11 + }, + "render-020": { + "answer": "fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy", + "tokens": 36202, + "fixed_tokens": 1231, + "processed_tokens": 181682, + "tool_calls": 9, + "turns": 10 + }, + "render-021": { + "answer": "dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4", + "tokens": 21351, + "fixed_tokens": 1235, + "processed_tokens": 129480, + "tool_calls": 7, + "turns": 8 + }, + "render-022": { + "answer": "dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr", + "tokens": 37674, + "fixed_tokens": 1233, + "processed_tokens": 242336, + "tool_calls": 9, + "turns": 10 + }, + "render-023": { + "answer": "dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676", + "tokens": 8756, + "fixed_tokens": 1225, + "processed_tokens": 89919, + "tool_calls": 8, + "turns": 9 + }, + "render-024": { + "answer": "dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r", + "tokens": 25333, + "fixed_tokens": 1227, + "processed_tokens": 190187, + "tool_calls": 9, + "turns": 10 + }, + "render-025": { + "answer": "fnd-tern-cost-at-4k-output-on-meridian-after-fp16-pa--p4gcmzw2a4bvzjev", + "tokens": 51012, + "fixed_tokens": 1229, + "processed_tokens": 269228, + "tool_calls": 9, + "turns": 10 + }, + "render-026": { + "answer": "dec-ship-four-tern-quality-presets--vjw18d82dx5gath8", + "tokens": 37281, + "fixed_tokens": 1226, + "processed_tokens": 177240, + "tool_calls": 8, + "turns": 9 + }, + "render-027": { + "answer": "con-frame-budget--j6vneva1g2ywj86m", + "tokens": 13505, + "fixed_tokens": 1233, + "processed_tokens": 106634, + "tool_calls": 8, + "turns": 9 + }, + "render-028": { + "answer": "dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee", + "tokens": 9439, + "fixed_tokens": 1229, + "processed_tokens": 91788, + "tool_calls": 8, + "turns": 9 + }, + "render-029": { + "answer": "fnd-vsm-page-pool-overflows-during-spring-tides--m2p8e89hhdmh0z8a", + "tokens": 14788, + "fixed_tokens": 1229, + "processed_tokens": 127043, + "tool_calls": 9, + "turns": 10 + }, + "render-030": { + "answer": "unknown", + "tokens": 38151, + "fixed_tokens": 1227, + "processed_tokens": 465188, + "tool_calls": 21, + "turns": 18 + }, + "render-031": { + "answer": "Alpha-tested foliage cost 2.1 ms in the visibility buffer versus 0.8 ms in forward+, because the alpha test runs in the raster pass with a per-pixel texture fetch, and saltglass refracts what is behind it so it needs the resolved scene first. (dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9; based on fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb)", + "tokens": 25847, + "fixed_tokens": 1230, + "processed_tokens": 210340, + "tool_calls": 10, + "turns": 11 + }, + "render-032": { + "answer": "Tern was chosen as Lantern's only upscaler (dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e) because Halcyon has no Skiff build, so shipping it on two platforms would break the one-upscaler constraint, and because owning the upscaler code matters more for saltglass than raw quality, since refraction and per-frame caustics need upscaler changes the team can make itself rather than vendor tickets.", + "tokens": 22445, + "fixed_tokens": 1230, + "processed_tokens": 142471, + "tool_calls": 8, + "turns": 9 + }, + "render-033": { + "answer": "128 MB", + "tokens": 22895, + "fixed_tokens": 1228, + "processed_tokens": 226853, + "tool_calls": 12, + "turns": 13 + }, + "render-034": { + "answer": "PC workstation (Meridian clock profile)", + "tokens": 26757, + "fixed_tokens": 1223, + "processed_tokens": 348440, + "tool_calls": 15, + "turns": 16 + }, + "render-035": { + "answer": "5912 pages", + "tokens": 18488, + "fixed_tokens": 1236, + "processed_tokens": 234017, + "tool_calls": 14, + "turns": 15 + }, + "render-036": { + "answer": "HDR-07", + "tokens": 31356, + "fixed_tokens": 1235, + "processed_tokens": 680574, + "tool_calls": 31, + "turns": 32 + }, + "render-037": { + "answer": "unknown", + "tokens": 39615, + "fixed_tokens": 1227, + "processed_tokens": 343181, + "tool_calls": 12, + "turns": 13 + }, + "render-038": { + "answer": "dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9", + "tokens": 16440, + "fixed_tokens": 1228, + "processed_tokens": 208531, + "tool_calls": 14, + "turns": 15 + }, + "render-039": { + "answer": "dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e", + "tokens": 41210, + "fixed_tokens": 1231, + "processed_tokens": 353939, + "tool_calls": 12, + "turns": 13 + }, + "render-040": { + "answer": "fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c", + "tokens": 24941, + "fixed_tokens": 1234, + "processed_tokens": 135983, + "tool_calls": 7, + "turns": 8 + }, + "render-041": { + "answer": "4.7 ms", + "tokens": 26467, + "fixed_tokens": 1232, + "processed_tokens": 262517, + "tool_calls": 12, + "turns": 13 + }, + "render-042": { + "answer": "dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1", + "tokens": 26348, + "fixed_tokens": 1231, + "processed_tokens": 194976, + "tool_calls": 9, + "turns": 10 + }, + "render-043": { + "answer": "fnd-meshlet-cone-culling-rejects-9-percent-of-triang--t6e5x7trzedex105", + "tokens": 31936, + "fixed_tokens": 1236, + "processed_tokens": 418720, + "tool_calls": 20, + "turns": 21 + }, + "render-044": { + "answer": "dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r", + "tokens": 22668, + "fixed_tokens": 1231, + "processed_tokens": 143940, + "tool_calls": 8, + "turns": 9 + }, + "render-045": { + "answer": "false dec-brine-curve-with-an-hdr-shoulder-at-800-nits--fpznx0cnj4avsxk1", + "tokens": 34481, + "fixed_tokens": 1226, + "processed_tokens": 555453, + "tool_calls": 21, + "turns": 22 + }, + "render-046": { + "answer": "The cost Finding that had sunk virtual shadow maps was a capture error; with cached pages VSM costs 1.4 ms, less than four cascades, and cascade seams through saltglass remain unsolved under CSM (dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4, reopened 2026-01-12 after being rejected_by dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr).", + "tokens": 10386, + "fixed_tokens": 1231, + "processed_tokens": 94084, + "tool_calls": 8, + "turns": 9 + }, + "render-047": { + "answer": "dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1: a release-build capture put the visibility buffer on Skiff at 7.4 ms against 8.1 ms for forward+ (6.3 ms with half-rate material resolve), so the forward+ fallback was no longer worth keeping. The earlier 11.2 ms Skiff number came from a capture with GPU validation on and was invalidated by fnd-visibility-buffer-costs-7-4-ms-on-skiff-in-a-rel--fs86h16tm5hgempd.", + "tokens": 30407, + "fixed_tokens": 1225, + "processed_tokens": 371365, + "tool_calls": 15, + "turns": 16 + }, + "render-048": { + "answer": "dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4", + "tokens": 66623, + "fixed_tokens": 1234, + "processed_tokens": 633044, + "tool_calls": 21, + "turns": 19 + }, + "render-049": { + "answer": "dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4", + "tokens": 18405, + "fixed_tokens": 1233, + "processed_tokens": 75112, + "tool_calls": 5, + "turns": 6 + }, + "render-050": { + "answer": "con-frame-budget--fzdrbxns6dmrrmy3", + "tokens": 10540, + "fixed_tokens": 1229, + "processed_tokens": 73616, + "tool_calls": 6, + "turns": 7 + }, + "render-051": { + "answer": "iss-tern-ghosting-on-moving-saltglass--2yr3q6zf476wajqp", + "tokens": 38886, + "fixed_tokens": 1235, + "processed_tokens": 340872, + "tool_calls": 12, + "turns": 13 + }, + "render-052": { + "answer": "61 percent", + "tokens": 60584, + "fixed_tokens": 1228, + "processed_tokens": 1876394, + "tool_calls": 46, + "turns": 47 + }, + "render-053": { + "answer": "every frame", + "tokens": 25507, + "fixed_tokens": 1232, + "processed_tokens": 260274, + "tool_calls": 12, + "turns": 13 + }, + "render-054": { + "answer": "debug-gpu-validation", + "tokens": 41832, + "fixed_tokens": 1235, + "processed_tokens": 531370, + "tool_calls": 17, + "turns": 16 + }, + "render-055": { + "answer": "fnd-tern-cost-at-4k-output-on-meridian-with-the-reac--81tcpzvhwzcy6wyn", + "tokens": 29107, + "fixed_tokens": 1232, + "processed_tokens": 275119, + "tool_calls": 12, + "turns": 13 + }, + "render-056": { + "answer": "208,000 meshlets", + "tokens": 33679, + "fixed_tokens": 1226, + "processed_tokens": 619240, + "tool_calls": 22, + "turns": 23 + }, + "render-057": { + "answer": "dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1", + "tokens": 33461, + "fixed_tokens": 1226, + "processed_tokens": 452124, + "tool_calls": 17, + "turns": 18 + }, + "render-058": { + "answer": "iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v", + "tokens": 44410, + "fixed_tokens": 1234, + "processed_tokens": 639844, + "tool_calls": 18, + "turns": 19 + }, + "render-059": { + "answer": "fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr", + "tokens": 24624, + "fixed_tokens": 1228, + "processed_tokens": 214208, + "tool_calls": 11, + "turns": 12 + }, + "render-060": { + "answer": "0.31", + "tokens": 42339, + "fixed_tokens": 1233, + "processed_tokens": 525934, + "tool_calls": 16, + "turns": 17 + }, + "render-061": { + "answer": "con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s", + "tokens": 45464, + "fixed_tokens": 1234, + "processed_tokens": 699830, + "tool_calls": 21, + "turns": 22 + }, + "render-062": { + "answer": "con-frame-budget--j6vneva1g2ywj86m", + "tokens": 25350, + "fixed_tokens": 1227, + "processed_tokens": 158334, + "tool_calls": 8, + "turns": 9 + }, + "render-063": { + "answer": "dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r", + "tokens": 14689, + "fixed_tokens": 1237, + "processed_tokens": 108603, + "tool_calls": 10, + "turns": 9 + }, + "render-064": { + "answer": "dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j", + "tokens": 23698, + "fixed_tokens": 1227, + "processed_tokens": 208195, + "tool_calls": 10, + "turns": 11 + }, + "render-065": { + "answer": "dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e", + "tokens": 37255, + "fixed_tokens": 1230, + "processed_tokens": 252357, + "tool_calls": 10, + "turns": 11 + }, + "render-066": { + "answer": "dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr", + "tokens": 13979, + "fixed_tokens": 1231, + "processed_tokens": 178874, + "tool_calls": 14, + "turns": 15 + }, + "render-067": { + "answer": 4, + "tokens": 17402, + "fixed_tokens": 1231, + "processed_tokens": 92782, + "tool_calls": 6, + "turns": 7 + }, + "render-068": { + "answer": [ + "dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4", + "dec-lock-caustic-photon-jitter-to-the-tide-phase--85x10k4h11t8nx7c", + "dec-use-the-probe-grid-alone-in-120-hz-performance-m--6dzm1nt40pjfpyae", + "dec-trace-sdf-gi-at-quarter-resolution-in-performanc--06cqt3mqn3fg5h6e", + "dec-read-paper-white-from-the-meridian-system-settin--7crbx73gqw1hn7xq", + "dec-add-an-in-game-paper-white-slider-from-80-to-400--1phfvxby983z8tjf" + ], + "tokens": 30143, + "fixed_tokens": 1228, + "processed_tokens": 201208, + "tool_calls": 9, + "turns": 10 + }, + "render-069": { + "answer": "iss-shadow-pages-run-out-at-spring-low-tide--f4fgy6b44jbkrsmh", + "tokens": 37298, + "fixed_tokens": 1228, + "processed_tokens": 266398, + "tool_calls": 11, + "turns": 12 + }, + "render-070": { + "answer": [ + "dec-use-signed-distance-field-gi--yn366zmp3k7snd9w", + "dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2", + "dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k" + ], + "tokens": 63269, + "fixed_tokens": 1231, + "processed_tokens": 1021351, + "tool_calls": 24, + "turns": 25 + }, + "render-071": { + "answer": 3, + "tokens": 11610, + "fixed_tokens": 1231, + "processed_tokens": 75451, + "tool_calls": 8, + "turns": 7 + }, + "render-072": { + "answer": [ + "rsk-sdf-volumes-outgrow-the-render-target-memory-bud--xfd2pfztvskdcd2c", + "rsk-artists-cannot-match-concept-paintings-under-the--6cfh9vkamn0kbtcx" + ], + "tokens": 12937, + "fixed_tokens": 1229, + "processed_tokens": 93203, + "tool_calls": 9, + "turns": 8 + }, + "render-073": { + "answer": [ + "rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty", + "rsk-gi-cannot-fit-the-120-hz-performance-mode--tqt3fj839dqfq5s7", + "rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4" + ], + "tokens": 14687, + "fixed_tokens": 1228, + "processed_tokens": 96991, + "tool_calls": 11, + "turns": 8 + }, + "render-074": { + "answer": "unknown", + "tokens": 34705, + "fixed_tokens": 1227, + "processed_tokens": 433864, + "tool_calls": 16, + "turns": 17 + }, + "render-075": { + "answer": "3", + "tokens": 29524, + "fixed_tokens": 1227, + "processed_tokens": 248425, + "tool_calls": 12, + "turns": 13 + }, + "render-076": { + "answer": false, + "tokens": 36869, + "fixed_tokens": 1228, + "processed_tokens": 236489, + "tool_calls": 10, + "turns": 10 + }, + "render-077": { + "answer": true, + "tokens": 49481, + "fixed_tokens": 1230, + "processed_tokens": 484000, + "tool_calls": 16, + "turns": 17 + }, + "render-078": { + "answer": [ + "dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e", + "rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4" + ], + "tokens": 48412, + "fixed_tokens": 1229, + "processed_tokens": 715919, + "tool_calls": 23, + "turns": 23 + }, + "render-079": { + "answer": 6, + "tokens": 117317, + "fixed_tokens": 1231, + "processed_tokens": 1326194, + "tool_calls": 21, + "turns": 22 + }, + "render-080": { + "answer": "6 versions", + "tokens": 13519, + "fixed_tokens": 1230, + "processed_tokens": 162645, + "tool_calls": 12, + "turns": 13 + }, + "render-081": { + "answer": "unknown", + "tokens": 68090, + "fixed_tokens": 1226, + "processed_tokens": 1668663, + "tool_calls": 34, + "turns": 35 + }, + "render-082": { + "answer": false, + "tokens": 16543, + "fixed_tokens": 1230, + "processed_tokens": 262582, + "tool_calls": 19, + "turns": 20 + }, + "render-083": { + "answer": 6, + "tokens": 107237, + "fixed_tokens": 1234, + "processed_tokens": 1010533, + "tool_calls": 18, + "turns": 19 + }, + "tools-001": { + "answer": "completed", + "tokens": 20640, + "fixed_tokens": 1233, + "processed_tokens": 92633, + "tool_calls": 6, + "turns": 7 + }, + "tools-002": { + "answer": "47 minutes", + "tokens": 24965, + "fixed_tokens": 1231, + "processed_tokens": 135570, + "tool_calls": 7, + "turns": 8 + }, + "tools-003": { + "answer": "6 min 40 s", + "tokens": 20494, + "fixed_tokens": 1229, + "processed_tokens": 125953, + "tool_calls": 7, + "turns": 8 + }, + "tools-004": { + "answer": "unknown", + "tokens": 14461, + "fixed_tokens": 1244, + "processed_tokens": 100291, + "tool_calls": 7, + "turns": 8 + }, + "tools-005": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tokens": 18849, + "fixed_tokens": 1228, + "processed_tokens": 76354, + "tool_calls": 5, + "turns": 6 + }, + "tools-006": { + "answer": "dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh", + "tokens": 11713, + "fixed_tokens": 1237, + "processed_tokens": 61588, + "tool_calls": 5, + "turns": 6 + }, + "tools-007": { + "answer": "dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6", + "tokens": 21967, + "fixed_tokens": 1235, + "processed_tokens": 142648, + "tool_calls": 9, + "turns": 10 + }, + "tools-008": { + "answer": "dec-key-the-shader-cache-on-raw-source-text-and-comp--hp6awmx3gq5rn9nc", + "tokens": 13151, + "fixed_tokens": 1234, + "processed_tokens": 74073, + "tool_calls": 6, + "turns": 7 + }, + "tools-009": { + "answer": "92.4%", + "tokens": 21715, + "fixed_tokens": 1237, + "processed_tokens": 176854, + "tool_calls": 9, + "turns": 10 + }, + "tools-010": { + "answer": "dec-cap-each-farm-agent-at-6-parallel-shader-compile--q5w4sfjm73tsj8x8", + "tokens": 25201, + "fixed_tokens": 1231, + "processed_tokens": 134876, + "tool_calls": 7, + "turns": 8 + }, + "tools-011": { + "answer": "fnd-two-compiler-builds-with-the-same-version-string--gmgr4ha0ndxqmcn9", + "tokens": 15854, + "fixed_tokens": 1231, + "processed_tokens": 139529, + "tool_calls": 9, + "turns": 10 + }, + "tools-012": { + "answer": 3, + "tokens": 12315, + "fixed_tokens": 1236, + "processed_tokens": 62525, + "tool_calls": 5, + "turns": 6 + }, + "tools-013": { + "answer": 8, + "tokens": 30518, + "fixed_tokens": 1234, + "processed_tokens": 217832, + "tool_calls": 10, + "turns": 11 + }, + "tools-014": { + "answer": false, + "tokens": 17244, + "fixed_tokens": 1234, + "processed_tokens": 127513, + "tool_calls": 9, + "turns": 10 + }, + "tools-015": { + "answer": [ + "iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj", + "rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd" + ], + "tokens": 28992, + "fixed_tokens": 1233, + "processed_tokens": 199513, + "tool_calls": 10, + "turns": 11 + }, + "tools-016": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tokens": 22697, + "fixed_tokens": 1236, + "processed_tokens": 130711, + "tool_calls": 7, + "turns": 8 + }, + "world-001": { + "answer": "64 KB", + "tokens": 22802, + "fixed_tokens": 1229, + "processed_tokens": 159094, + "tool_calls": 9, + "turns": 10 + }, + "world-002": { + "answer": "5.1 ms", + "tokens": 20304, + "fixed_tokens": 1225, + "processed_tokens": 125418, + "tool_calls": 7, + "turns": 8 + }, + "world-003": { + "answer": "unknown", + "tokens": 108783, + "fixed_tokens": 1229, + "processed_tokens": 1321167, + "tool_calls": 23, + "turns": 24 + }, + "world-004": { + "answer": "4,100 file opens", + "tokens": 30518, + "fixed_tokens": 1235, + "processed_tokens": 337698, + "tool_calls": 14, + "turns": 15 + }, + "world-005": { + "answer": "11 m", + "tokens": 36327, + "fixed_tokens": 1231, + "processed_tokens": 323821, + "tool_calls": 12, + "turns": 13 + }, + "world-006": { + "answer": "unknown", + "tokens": 34126, + "fixed_tokens": 1223, + "processed_tokens": 339281, + "tool_calls": 16, + "turns": 14 + }, + "world-007": { + "answer": "260 MB", + "tokens": 58652, + "fixed_tokens": 1231, + "processed_tokens": 648767, + "tool_calls": 16, + "turns": 17 + }, + "world-008": { + "answer": "10 Hz", + "tokens": 38164, + "fixed_tokens": 1226, + "processed_tokens": 258720, + "tool_calls": 10, + "turns": 11 + }, + "world-009": { + "answer": "0.3 ms", + "tokens": 81531, + "fixed_tokens": 1233, + "processed_tokens": 803253, + "tool_calls": 17, + "turns": 17 + }, + "world-010": { + "answer": "unknown", + "tokens": 52096, + "fixed_tokens": 1227, + "processed_tokens": 1215956, + "tool_calls": 32, + "turns": 33 + }, + "world-011": { + "answer": "unknown", + "tokens": 39123, + "fixed_tokens": 1234, + "processed_tokens": 802384, + "tool_calls": 32, + "turns": 29 + }, + "world-012": { + "answer": "dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3", + "tokens": 35771, + "fixed_tokens": 1230, + "processed_tokens": 251564, + "tool_calls": 10, + "turns": 11 + }, + "world-013": { + "answer": "unknown", + "tokens": 27655, + "fixed_tokens": 1235, + "processed_tokens": 267664, + "tool_calls": 15, + "turns": 13 + }, + "world-014": { + "answer": "unknown", + "tokens": 130228, + "fixed_tokens": 1231, + "processed_tokens": 1717389, + "tool_calls": 26, + "turns": 25 + }, + "world-015": { + "answer": "3.0 ms per frame", + "tokens": 15687, + "fixed_tokens": 1225, + "processed_tokens": 201267, + "tool_calls": 14, + "turns": 15 + }, + "world-016": { + "answer": "unknown", + "tokens": 38048, + "fixed_tokens": 1231, + "processed_tokens": 362154, + "tool_calls": 15, + "turns": 15 + }, + "world-017": { + "answer": "dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw", + "tokens": 43704, + "fixed_tokens": 1231, + "processed_tokens": 634129, + "tool_calls": 20, + "turns": 21 + }, + "world-018": { + "answer": "dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x", + "tokens": 21683, + "fixed_tokens": 1226, + "processed_tokens": 93953, + "tool_calls": 6, + "turns": 7 + }, + "world-019": { + "answer": "fnd-tide-priority-reads-starve-player-proximity-load--by0d7b0bk39xz3rk", + "tokens": 86078, + "fixed_tokens": 1229, + "processed_tokens": 790168, + "tool_calls": 16, + "turns": 17 + }, + "world-020": { + "answer": "dec-schedule-streaming-reads-by-deadline-instead-of--q2x5aknabgcssdj2", + "tokens": 17730, + "fixed_tokens": 1239, + "processed_tokens": 124710, + "tool_calls": 8, + "turns": 9 + }, + "world-021": { + "answer": "dec-cut-navigation-tiles-to-64-m-so-three-fit-along--snvepk8ygeb3qsjs", + "tokens": 18934, + "fixed_tokens": 1231, + "processed_tokens": 268023, + "tool_calls": 17, + "turns": 18 + }, + "world-022": { + "answer": "fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m", + "tokens": 15075, + "fixed_tokens": 1229, + "processed_tokens": 148627, + "tool_calls": 10, + "turns": 11 + }, + "world-023": { + "answer": "dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m", + "tokens": 38091, + "fixed_tokens": 1229, + "processed_tokens": 259211, + "tool_calls": 10, + "turns": 11 + }, + "world-024": { + "answer": "dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew", + "tokens": 38142, + "fixed_tokens": 1234, + "processed_tokens": 259133, + "tool_calls": 10, + "turns": 11 + }, + "world-025": { + "answer": "con-streaming-pool-budget--kca88sgh2j6sxvd5", + "tokens": 20311, + "fixed_tokens": 1226, + "processed_tokens": 125006, + "tool_calls": 7, + "turns": 8 + }, + "world-026": { + "answer": "fnd-retail-skiff-units-sustain-only-190-mb-s-of-stre--485sdcmm3gweevvn", + "tokens": 26000, + "fixed_tokens": 1230, + "processed_tokens": 246701, + "tool_calls": 11, + "turns": 12 + }, + "world-027": { + "answer": "160 MB/s", + "tokens": 40008, + "fixed_tokens": 1232, + "processed_tokens": 323783, + "tool_calls": 11, + "turns": 12 + }, + "world-028": { + "answer": "fnd-streaming-tide-heights-costs-46-kb-s-per-peer--knxqtyqh6xcz1tp9", + "tokens": 48206, + "fixed_tokens": 1230, + "processed_tokens": 496846, + "tool_calls": 16, + "turns": 15 + }, + "world-029": { + "answer": "dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3", + "tokens": 20228, + "fixed_tokens": 1229, + "processed_tokens": 147931, + "tool_calls": 9, + "turns": 10 + }, + "world-030": { + "answer": "fnd-world-core-state-at-alpha--tkbsm4867h65jqq8", + "tokens": 41994, + "fixed_tokens": 1228, + "processed_tokens": 276575, + "tool_calls": 10, + "turns": 11 + }, + "world-031": { + "answer": "1.5 GB/s", + "tokens": 55057, + "fixed_tokens": 1228, + "processed_tokens": 595358, + "tool_calls": 17, + "turns": 16 + }, + "world-032": { + "answer": "fnd-float-tide-heights-drift-apart-between-pc-and-me--7jb0fg4b5xzr7q5e", + "tokens": 27768, + "fixed_tokens": 1229, + "processed_tokens": 240727, + "tool_calls": 11, + "turns": 12 + }, + "world-033": { + "answer": "dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw", + "tokens": 46639, + "fixed_tokens": 1239, + "processed_tokens": 490366, + "tool_calls": 15, + "turns": 16 + }, + "world-034": { + "answer": "unknown", + "tokens": 48445, + "fixed_tokens": 1230, + "processed_tokens": 695746, + "tool_calls": 19, + "turns": 20 + }, + "world-035": { + "answer": false, + "tokens": 35871, + "fixed_tokens": 1227, + "processed_tokens": 174595, + "tool_calls": 10, + "turns": 9 + }, + "world-036": { + "answer": "Kestrel retired the fiber scheduler because 41% of alpha crash reports had no usable stack, which blocked crash triage for beta, and the continuation-wait thread pool kept workers 93% busy during tide turns, close to the 95% fibers gave, so fibers' two points of utilisation did not justify unreadable crashes and the Gull thread-local bug. (dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h)", + "tokens": 34743, + "fixed_tokens": 1229, + "processed_tokens": 171744, + "tool_calls": 8, + "turns": 9 + }, + "world-037": { + "answer": "fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws", + "tokens": 31886, + "fixed_tokens": 1230, + "processed_tokens": 422517, + "tool_calls": 16, + "turns": 17 + }, + "world-038": { + "answer": "3 archetypes", + "tokens": 22525, + "fixed_tokens": 1228, + "processed_tokens": 180222, + "tool_calls": 9, + "turns": 10 + }, + "world-039": { + "answer": "1.2 GB/s", + "tokens": 33186, + "fixed_tokens": 1231, + "processed_tokens": 460392, + "tool_calls": 17, + "turns": 18 + }, + "world-040": { + "answer": "unknown", + "tokens": 69411, + "fixed_tokens": 1226, + "processed_tokens": 926389, + "tool_calls": 19, + "turns": 20 + }, + "world-041": { + "answer": "61%", + "tokens": 40503, + "fixed_tokens": 1230, + "processed_tokens": 373557, + "tool_calls": 13, + "turns": 13 + }, + "world-042": { + "answer": "5.4 s", + "tokens": 31537, + "fixed_tokens": 1225, + "processed_tokens": 361708, + "tool_calls": 14, + "turns": 15 + }, + "world-043": { + "answer": "5.8 minutes", + "tokens": 15157, + "fixed_tokens": 1227, + "processed_tokens": 159983, + "tool_calls": 11, + "turns": 12 + }, + "world-044": { + "answer": "dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq", + "tokens": 41561, + "fixed_tokens": 1226, + "processed_tokens": 515035, + "tool_calls": 16, + "turns": 17 + }, + "world-045": { + "answer": "dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te", + "tokens": 36986, + "fixed_tokens": 1229, + "processed_tokens": 254433, + "tool_calls": 10, + "turns": 11 + }, + "world-046": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tokens": 30223, + "fixed_tokens": 1230, + "processed_tokens": 278235, + "tool_calls": 12, + "turns": 13 + }, + "world-047": { + "answer": "fnd-world-core-state-at-alpha--tkbsm4867h65jqq8", + "tokens": 31857, + "fixed_tokens": 1230, + "processed_tokens": 271220, + "tool_calls": 15, + "turns": 14 + }, + "world-048": { + "answer": "dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3", + "tokens": 39552, + "fixed_tokens": 1229, + "processed_tokens": 646966, + "tool_calls": 21, + "turns": 22 + }, + "world-049": { + "answer": "22%", + "tokens": 40952, + "fixed_tokens": 1230, + "processed_tokens": 411083, + "tool_calls": 13, + "turns": 14 + }, + "world-050": { + "answer": "fnd-alpha-content-needs-6-2-ms-of-gull-time-per-fram--4mekgdpsdv5nk085", + "tokens": 68145, + "fixed_tokens": 1228, + "processed_tokens": 431845, + "tool_calls": 12, + "turns": 13 + }, + "world-051": { + "answer": "Integer adds and multiplies in 32.32 fixed point give the same bits on every CPU and compiler, so the drift that float tides showed between machines within 6 minutes cannot happen (dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e; the strict IEEE option, dec-force-strict-ieee-float-mode-for-the-tide-simula--ecwmqt7ncjngysqw, was rejected by it).", + "tokens": 63704, + "fixed_tokens": 1230, + "processed_tokens": 818486, + "tool_calls": 18, + "turns": 19 + }, + "world-052": { + "answer": "Dara Whitlock", + "tokens": 25945, + "fixed_tokens": 1231, + "processed_tokens": 296669, + "tool_calls": 13, + "turns": 14 + }, + "world-053": { + "answer": "1.9 ms", + "tokens": 46059, + "fixed_tokens": 1227, + "processed_tokens": 689155, + "tool_calls": 19, + "turns": 20 + }, + "world-054": { + "answer": "Marta Lindqvist", + "tokens": 30081, + "fixed_tokens": 1225, + "processed_tokens": 242314, + "tool_calls": 12, + "turns": 12 + }, + "world-055": { + "answer": "Kelp stays because the team kept it and shipped a 1 MB dictionary on every platform, which beats Zstandard by 1.7x with a cold cache on Skiff; this closes the reopened Zstandard option. Record: dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew", + "tokens": 59175, + "fixed_tokens": 1228, + "processed_tokens": 772677, + "tool_calls": 20, + "turns": 21 + }, + "world-056": { + "answer": "dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x", + "tokens": 34737, + "fixed_tokens": 1232, + "processed_tokens": 172774, + "tool_calls": 8, + "turns": 9 + }, + "world-057": { + "answer": "[212, 87]", + "tokens": 33792, + "fixed_tokens": 1227, + "processed_tokens": 499360, + "tool_calls": 18, + "turns": 19 + }, + "world-058": { + "answer": "0.8 GB/s", + "tokens": 34658, + "fixed_tokens": 1228, + "processed_tokens": 591060, + "tool_calls": 21, + "turns": 22 + }, + "world-059": { + "answer": "dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw", + "tokens": 19874, + "fixed_tokens": 1226, + "processed_tokens": 277748, + "tool_calls": 16, + "turns": 17 + }, + "world-060": { + "answer": "dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc", + "tokens": 19255, + "fixed_tokens": 1229, + "processed_tokens": 245021, + "tool_calls": 14, + "turns": 15 + }, + "world-061": { + "answer": "236 MB", + "tokens": 24793, + "fixed_tokens": 1233, + "processed_tokens": 205527, + "tool_calls": 10, + "turns": 11 + }, + "world-062": { + "answer": "310 MB", + "tokens": 32414, + "fixed_tokens": 1231, + "processed_tokens": 453020, + "tool_calls": 17, + "turns": 18 + }, + "world-063": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tokens": 22892, + "fixed_tokens": 1229, + "processed_tokens": 180149, + "tool_calls": 9, + "turns": 10 + }, + "world-064": { + "answer": [ + "dec-force-strict-ieee-float-mode-for-the-tide-simula--ecwmqt7ncjngysqw", + "dec-have-the-host-stream-tide-heights-to-every-peer--a3rb1seedn2bj7k8" + ], + "tokens": 40665, + "fixed_tokens": 1230, + "processed_tokens": 495363, + "tool_calls": 20, + "turns": 21 + }, + "world-065": { + "answer": "3.1 ms", + "tokens": 45886, + "fixed_tokens": 1232, + "processed_tokens": 729434, + "tool_calls": 23, + "turns": 24 + }, + "world-066": { + "answer": "46", + "tokens": 31255, + "fixed_tokens": 1227, + "processed_tokens": 385008, + "tool_calls": 15, + "turns": 16 + }, + "world-067": { + "answer": "1.2 GB/s", + "tokens": 54399, + "fixed_tokens": 1231, + "processed_tokens": 962266, + "tool_calls": 23, + "turns": 24 + }, + "world-068": { + "answer": false, + "tokens": 39118, + "fixed_tokens": 1227, + "processed_tokens": 532543, + "tool_calls": 23, + "turns": 19 + }, + "world-069": { + "answer": 6, + "tokens": 109197, + "fixed_tokens": 1229, + "processed_tokens": 979474, + "tool_calls": 19, + "turns": 20 + }, + "world-070": { + "answer": 3, + "tokens": 16049, + "fixed_tokens": 1228, + "processed_tokens": 80201, + "tool_calls": 6, + "turns": 7 + }, + "world-071": { + "answer": [ + "dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9", + "dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m", + "dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg", + "dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42", + "dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w" + ], + "tokens": 108156, + "fixed_tokens": 1230, + "processed_tokens": 911275, + "tool_calls": 17, + "turns": 18 + }, + "world-072": { + "answer": [ + "dec-compress-streamed-assets-with-zstandard--bs1t15cygc51cpje", + "dec-compress-streamed-assets-with-lz4--v1pfsgfp0b3yjv4s" + ], + "tokens": 49596, + "fixed_tokens": 1227, + "processed_tokens": 282308, + "tool_calls": 10, + "turns": 11 + }, + "world-073": { + "answer": false, + "tokens": 42584, + "fixed_tokens": 1228, + "processed_tokens": 343227, + "tool_calls": 14, + "turns": 13 + }, + "world-074": { + "answer": "unknown", + "tokens": 33185, + "fixed_tokens": 1231, + "processed_tokens": 425541, + "tool_calls": 17, + "turns": 18 + }, + "world-075": { + "answer": "unknown", + "tokens": 35428, + "fixed_tokens": 1231, + "processed_tokens": 194139, + "tool_calls": 8, + "turns": 9 + }, + "world-076": { + "answer": "unknown", + "tokens": 35994, + "fixed_tokens": 1228, + "processed_tokens": 399610, + "tool_calls": 31, + "turns": 20 + }, + "world-077": { + "answer": 9, + "tokens": 17785, + "fixed_tokens": 1228, + "processed_tokens": 85258, + "tool_calls": 6, + "turns": 7 + }, + "world-078": { + "answer": [ + "rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew", + "rsk-reworking-the-read-scheduler-may-slip-the-coast--9jzvs7etvb5jxqtp" + ], + "tokens": 10792, + "fixed_tokens": 1231, + "processed_tokens": 59448, + "tool_calls": 5, + "turns": 6 + }, + "world-079": { + "answer": [ + "con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73", + "con-tide-state-must-be-bit-identical-on-every-peer--zrpnp8qjyxzkas7t", + "con-saves-from-beta-onward-must-load-in-every-later--v6z856sxtgc5sb09", + "con-streaming-pool-budget--8czwb4fjr5p5vpy7" + ], + "tokens": 13628, + "fixed_tokens": 1228, + "processed_tokens": 93836, + "tool_calls": 7, + "turns": 8 + }, + "world-080": { + "answer": [ + "iss-gull-hot-reload-rejects-struct-layout-changes--3v2w2f9hg2gwy6aj", + "iss-gull-hot-reload-drops-suspended-coroutines--z7j2gmyny6gdxd07", + "iss-cross-platform-cloud-saves-are-unplanned--5bk0k4wrgj42ztfy" + ], + "tokens": 19140, + "fixed_tokens": 1231, + "processed_tokens": 109984, + "tool_calls": 9, + "turns": 8 + }, + "world-081": { + "answer": "rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew", + "tokens": 28011, + "fixed_tokens": 1230, + "processed_tokens": 498334, + "tool_calls": 23, + "turns": 24 + } + } +} diff --git a/benchmarks/proof-recall/runs/pilot-1-brief.json b/benchmarks/proof-recall/runs/pilot-1-brief.json new file mode 100644 index 00000000..91b5d7bc --- /dev/null +++ b/benchmarks/proof-recall/runs/pilot-1-brief.json @@ -0,0 +1,210 @@ +{ + "run": { + "name": "pilot-1-brief", + "strategy": "brief-first", + "protocol": "one session answers all 46 questions", + "sample": "stratified, seed pilot-1", + "harness": { + "total_tokens": 203004, + "total_tool_calls": 46, + "duration_ms": 436096 + }, + "note": "Per-answer tool_calls are the agent own tally; the harness totals are authoritative." + }, + "answers": { + "netcode-004": { + "answer": "Rollback must re-run the tide simulation for every rolled-back frame, which costs 4.8 ms on Skiff (a fifth of the 25 ms frame), and tides cannot be simplified or left out because co-op needs them bit-identical. That determinism rests on the world Decision \"Run the tide simulation in 32.32 fixed point\".", + "tool_calls": 3 + }, + "netcode-006": { + "answer": "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "tool_calls": 1 + }, + "netcode-010": { + "answer": "dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk", + "tool_calls": 1 + }, + "netcode-012": { + "answer": "dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f", + "tool_calls": 1 + }, + "netcode-015": { + "answer": 2, + "tool_calls": 1 + }, + "render-002": { + "answer": "3.4x", + "tool_calls": 4 + }, + "render-005": { + "answer": true, + "tool_calls": 3 + }, + "render-021": { + "answer": "dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4", + "tool_calls": 2 + }, + "render-033": { + "answer": "128 MB", + "tool_calls": 3 + }, + "render-040": { + "answer": "fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c", + "tool_calls": 2 + }, + "render-050": { + "answer": "con-frame-budget--fzdrbxns6dmrrmy3", + "tool_calls": 2 + }, + "render-056": { + "answer": "208,000 meshlets", + "tool_calls": 6 + }, + "render-059": { + "answer": "fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr", + "tool_calls": 4 + }, + "render-070": { + "answer": [ + "dec-use-signed-distance-field-gi--yn366zmp3k7snd9w", + "dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2", + "dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k" + ], + "tool_calls": 8 + }, + "render-075": { + "answer": "3", + "tool_calls": 6 + }, + "tools-002": { + "answer": "47 minutes", + "tool_calls": 2 + }, + "tools-006": { + "answer": "dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh", + "tool_calls": 1 + }, + "tools-014": { + "answer": false, + "tool_calls": 2 + }, + "tools-015": { + "answer": [ + "rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd", + "iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj" + ], + "tool_calls": 2 + }, + "tools-016": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tool_calls": 1 + }, + "ports-001": { + "answer": "25 ms", + "tool_calls": 2 + }, + "ports-034": { + "answer": "6 weeks", + "tool_calls": 2 + }, + "ports-012": { + "answer": "At the 540p floor, saltglass caustics shimmered badly in motion even after Tern (7 of 10 dune views); at 576p the shimmer dropped to 2 of 10, for 1.3 ms more on the worst view.", + "tool_calls": 1 + }, + "ports-013": { + "answer": "Ship Tern as Lantern's only upscaler", + "tool_calls": 2 + }, + "ports-015": { + "answer": "textures (3,184 MB)", + "tool_calls": 2 + }, + "ports-016": { + "answer": "dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn", + "tool_calls": 1 + }, + "ports-022": { + "answer": "cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe", + "tool_calls": 1 + }, + "ports-026": { + "answer": "912 MB", + "tool_calls": 2 + }, + "ports-030": { + "answer": [ + "dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1", + "dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc" + ], + "tool_calls": 2 + }, + "ports-033": { + "answer": "unknown", + "tool_calls": 1 + }, + "cross-011": { + "answer": false, + "tool_calls": 1 + }, + "cross-012": { + "answer": "61 MB/s", + "tool_calls": 2 + }, + "cross-013": { + "answer": "The Skiff port runs Tern at the Performance preset (2.1 ms), which saves 1.8 ms over Quality (3.9 ms).", + "tool_calls": 2 + }, + "cross-017": { + "answer": false, + "tool_calls": 2 + }, + "cross-009": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tool_calls": 2 + }, + "cross-015": { + "answer": "Two Efforts are no longer active. The co-op rollback netcode prototype was abandoned because re-running tides on every rolled-back frame cost 4.8 ms on Skiff, and co-op moved to host-authoritative sync; the shader compile cache and build farm Effort was completed once the cache was turned on for every farm build.", + "tool_calls": 4 + }, + "world-014": { + "answer": "unknown", + "tool_calls": 2 + }, + "world-016": { + "answer": "unknown", + "tool_calls": 3 + }, + "world-022": { + "answer": "fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m", + "tool_calls": 2 + }, + "world-035": { + "answer": false, + "tool_calls": 2 + }, + "world-046": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tool_calls": 2 + }, + "world-053": { + "answer": "1.9 ms (from 5.1 ms to 3.2 ms)", + "tool_calls": 3 + }, + "world-059": { + "answer": "dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw", + "tool_calls": 4 + }, + "world-066": { + "answer": "46", + "tool_calls": 3 + }, + "world-069": { + "answer": 7, + "tool_calls": 2 + }, + "world-077": { + "answer": 9, + "tool_calls": 2 + } + } +} diff --git a/benchmarks/proof-recall/runs/pilot-1-ids.txt b/benchmarks/proof-recall/runs/pilot-1-ids.txt new file mode 100644 index 00000000..cd9beb18 --- /dev/null +++ b/benchmarks/proof-recall/runs/pilot-1-ids.txt @@ -0,0 +1 @@ +cross-013,cross-017,cross-012,cross-011,cross-015,cross-009,netcode-004,netcode-006,netcode-010,netcode-012,netcode-015,ports-001,ports-034,ports-012,ports-013,ports-015,ports-016,ports-026,ports-022,ports-033,ports-030,render-002,render-005,render-033,render-021,render-040,render-050,render-059,render-056,render-075,render-070,tools-002,tools-006,tools-014,tools-016,tools-015,world-014,world-016,world-035,world-022,world-053,world-046,world-066,world-059,world-069,world-077 diff --git a/benchmarks/proof-recall/runs/pilot-1-nobrief.json b/benchmarks/proof-recall/runs/pilot-1-nobrief.json new file mode 100644 index 00000000..311907c0 --- /dev/null +++ b/benchmarks/proof-recall/runs/pilot-1-nobrief.json @@ -0,0 +1,210 @@ +{ + "run": { + "name": "pilot-1-nobrief", + "strategy": "no-brief", + "protocol": "one session answers all 46 questions", + "sample": "stratified, seed pilot-1", + "harness": { + "total_tokens": 239556, + "total_tool_calls": 27, + "duration_ms": 313576 + }, + "note": "Per-answer tool_calls are the agent own tally; the harness totals are authoritative." + }, + "answers": { + "netcode-004": { + "answer": "Rollback had to re-run the tide step on every rolled-back frame, costing 4.8 ms on Skiff (a fifth of the 25 ms frame), and the workarounds tried (smaller window, quarter-resolution tides, leaving tides out of the snapshot) failed. The reason depends on the world Decision \"Run the tide simulation in 32.32 fixed point\" (dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e), which keeps tides deterministic.", + "tool_calls": 4 + }, + "netcode-006": { + "answer": "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "tool_calls": 2 + }, + "netcode-010": { + "answer": "dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk", + "tool_calls": 2 + }, + "netcode-012": { + "answer": "dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f", + "tool_calls": 2 + }, + "netcode-015": { + "answer": 2, + "tool_calls": 2 + }, + "tools-002": { + "answer": "47 minutes", + "tool_calls": 2 + }, + "tools-006": { + "answer": "dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh", + "tool_calls": 2 + }, + "tools-014": { + "answer": false, + "tool_calls": 2 + }, + "tools-015": { + "answer": [ + "rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd", + "iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj" + ], + "tool_calls": 2 + }, + "tools-016": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tool_calls": 2 + }, + "ports-001": { + "answer": "25 ms", + "tool_calls": 2 + }, + "ports-034": { + "answer": "6 weeks", + "tool_calls": 3 + }, + "ports-012": { + "answer": "At the 540p floor the saltglass caustics shimmered badly in motion even after Tern (7 of 10 dune views); at 576p shimmer dropped to 2 of 10 for 1.3 ms more on the worst view.", + "tool_calls": 2 + }, + "ports-015": { + "answer": "textures (3,184 MB)", + "tool_calls": 4 + }, + "ports-016": { + "answer": "dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn", + "tool_calls": 2 + }, + "ports-022": { + "answer": "cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe", + "tool_calls": 2 + }, + "ports-026": { + "answer": "912 MB", + "tool_calls": 4 + }, + "ports-030": { + "answer": [ + "dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1", + "dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc" + ], + "tool_calls": 3 + }, + "ports-033": { + "answer": "unknown", + "tool_calls": 2 + }, + "cross-011": { + "answer": false, + "tool_calls": 3 + }, + "cross-012": { + "answer": "61 MB/s", + "tool_calls": 3 + }, + "ports-013": { + "answer": "Ship Tern as Lantern's only upscaler", + "tool_calls": 3 + }, + "cross-013": { + "answer": "The Skiff port runs Tern at the Performance preset (2.1 ms), which saves 1.8 ms over Quality (3.9 ms).", + "tool_calls": 3 + }, + "cross-017": { + "answer": false, + "tool_calls": 4 + }, + "render-002": { + "answer": "3.4x", + "tool_calls": 3 + }, + "render-005": { + "answer": true, + "tool_calls": 2 + }, + "render-021": { + "answer": "dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4", + "tool_calls": 2 + }, + "render-033": { + "answer": "128 MB", + "tool_calls": 3 + }, + "render-040": { + "answer": "fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c", + "tool_calls": 2 + }, + "render-050": { + "answer": "con-frame-budget--fzdrbxns6dmrrmy3", + "tool_calls": 2 + }, + "render-056": { + "answer": "208,000 meshlets", + "tool_calls": 3 + }, + "render-059": { + "answer": "fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr", + "tool_calls": 2 + }, + "render-070": { + "answer": [ + "dec-use-signed-distance-field-gi--yn366zmp3k7snd9w", + "dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2", + "dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k" + ], + "tool_calls": 3 + }, + "render-075": { + "answer": "3", + "tool_calls": 3 + }, + "cross-009": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tool_calls": 3 + }, + "cross-015": { + "answer": "Two Efforts are no longer active: \"Co-op rollback netcode prototype\" was abandoned, when the Decision \"Abandon rollback netcode for co-op\" stopped rollback (re-running tides cost 4.8 ms on Skiff) and co-op moved to host-authoritative sync; \"Shader compile cache and build farm\" was completed once the cache was turned on for every farm build.", + "tool_calls": 3 + }, + "world-014": { + "answer": "unknown", + "tool_calls": 3 + }, + "world-016": { + "answer": "unknown", + "tool_calls": 2 + }, + "world-022": { + "answer": "fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m", + "tool_calls": 2 + }, + "world-035": { + "answer": false, + "tool_calls": 2 + }, + "world-046": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tool_calls": 2 + }, + "world-053": { + "answer": "1.9 ms (from 5.1 ms to 3.2 ms)", + "tool_calls": 3 + }, + "world-059": { + "answer": "dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw", + "tool_calls": 2 + }, + "world-066": { + "answer": "46 player-proximity reads", + "tool_calls": 4 + }, + "world-069": { + "answer": 6, + "tool_calls": 5 + }, + "world-077": { + "answer": 9, + "tool_calls": 3 + } + } +} diff --git a/benchmarks/proof-recall/runs/pilot-2-brief.json b/benchmarks/proof-recall/runs/pilot-2-brief.json new file mode 100644 index 00000000..4a3038df --- /dev/null +++ b/benchmarks/proof-recall/runs/pilot-2-brief.json @@ -0,0 +1,350 @@ +{ + "run": { + "name": "pilot-2-brief", + "protocol": "one fresh session per question", + "models": ["claude-sonnet-5-5"] + }, + "answers": { + "cross-009": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tokens": 78005, + "processed_tokens": 1428923, + "tool_calls": 23, + "turns": 22 + }, + "cross-011": { + "answer": false, + "tokens": 64468, + "processed_tokens": 761883, + "tool_calls": 14, + "turns": 13 + }, + "cross-012": { + "answer": "61 MB/s", + "tokens": 63084, + "processed_tokens": 624523, + "tool_calls": 12, + "turns": 11 + }, + "cross-013": { + "answer": "The Skiff port runs Tern at the Performance preset (not the lowest preset, Ultra Performance, which is the Meridian 120 Hz mode's), saving 1.8 ms over Quality (2.1 ms vs 3.9 ms); see dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3.", + "tokens": 69961, + "processed_tokens": 838139, + "tool_calls": 15, + "turns": 14 + }, + "cross-015": { + "answer": "Two Efforts are no longer active. \"Shader compile cache and build farm\" (eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn) is completed: it ended when dec-turn-the-shader-compile-cache-on-for-every-farm--4rr3b12b4sasdmaj turned the cache on for every farm build, as its end condition required. \"Co-op rollback netcode prototype\" (eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49) is abandoned via dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b, because re-running tides on every rolled-back frame costs 4.8 ms on Skiff.", + "tokens": 65913, + "processed_tokens": 519987, + "tool_calls": 12, + "turns": 9 + }, + "cross-017": { + "answer": true, + "tokens": 62514, + "processed_tokens": 730932, + "tool_calls": 15, + "turns": 13 + }, + "netcode-004": { + "answer": "The team abandoned rollback because rollback must re-run the tide simulation on every rolled-back frame, which costs 4.8 ms on Skiff (a fifth of the 25 ms frame), while co-op needs tides to stay bit-for-bit deterministic (shrinking the window, quarter-resolution tides, and leaving tides out of the snapshot all failed); the reason depends on the world Decision dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e (accepted, not superseded), recorded in dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b.", + "tokens": 63674, + "processed_tokens": 683835, + "tool_calls": 13, + "turns": 12 + }, + "netcode-006": { + "answer": "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "tokens": 62147, + "processed_tokens": 443186, + "tool_calls": 8, + "turns": 8 + }, + "netcode-010": { + "answer": "dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk", + "tokens": 30084, + "processed_tokens": 570800, + "tool_calls": 10, + "turns": 10 + }, + "netcode-012": { + "answer": "dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f", + "tokens": 26026, + "processed_tokens": 499915, + "tool_calls": 10, + "turns": 9 + }, + "netcode-015": { + "answer": 2, + "tokens": 23038, + "processed_tokens": 375791, + "tool_calls": 7, + "turns": 7 + }, + "ports-001": { + "answer": "25 ms", + "tokens": 22026, + "processed_tokens": 377041, + "tool_calls": 8, + "turns": 7 + }, + "ports-012": { + "answer": "Because saltglass caustics shimmered badly at the 540p floor (visible in 7 of 10 dune views, versus 2 of 10 at 576p), recorded in fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q; this drove dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb (later superseded by the 504p-behind-Tern decision).", + "tokens": 23934, + "processed_tokens": 554646, + "tool_calls": 10, + "turns": 10 + }, + "ports-013": { + "answer": "dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e", + "tokens": 30118, + "processed_tokens": 800240, + "tool_calls": 15, + "turns": 14 + }, + "ports-015": { + "answer": "textures (3184 MB)", + "tokens": 29053, + "processed_tokens": 685342, + "tool_calls": 14, + "turns": 12 + }, + "ports-016": { + "answer": "dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn", + "tokens": 27760, + "processed_tokens": 625691, + "tool_calls": 12, + "turns": 11 + }, + "ports-022": { + "answer": "cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe", + "tokens": 29041, + "processed_tokens": 510431, + "tool_calls": 10, + "turns": 9 + }, + "ports-026": { + "answer": "912 MB", + "tokens": 27186, + "processed_tokens": 800013, + "tool_calls": 16, + "turns": 14 + }, + "ports-030": { + "answer": [ + "dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1", + "dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc" + ], + "tokens": 21654, + "processed_tokens": 486085, + "tool_calls": 10, + "turns": 9 + }, + "ports-033": { + "answer": "unknown", + "tokens": 26101, + "processed_tokens": 503027, + "tool_calls": 10, + "turns": 9 + }, + "ports-034": { + "answer": "6 weeks", + "tokens": 29367, + "processed_tokens": 750550, + "tool_calls": 16, + "turns": 13 + }, + "render-002": { + "answer": "3.4x", + "tokens": 26381, + "processed_tokens": 742238, + "tool_calls": 14, + "turns": 13 + }, + "render-005": { + "answer": true, + "tokens": 27454, + "processed_tokens": 738893, + "tool_calls": 14, + "turns": 13 + }, + "render-021": { + "answer": "dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4", + "tokens": 23035, + "processed_tokens": 542704, + "tool_calls": 11, + "turns": 10 + }, + "render-033": { + "answer": "128 MB", + "tokens": 23156, + "processed_tokens": 435847, + "tool_calls": 9, + "turns": 8 + }, + "render-040": { + "answer": "fnd-ports-status-after-alpha--yaqm024j41anp4vn", + "tokens": 32930, + "processed_tokens": 770236, + "tool_calls": 16, + "turns": 13 + }, + "render-050": { + "answer": "con-frame-budget--fzdrbxns6dmrrmy3", + "tokens": 24214, + "processed_tokens": 376611, + "tool_calls": 8, + "turns": 7 + }, + "render-056": { + "answer": "208,000 meshlets", + "tokens": 34182, + "processed_tokens": 1037159, + "tool_calls": 17, + "turns": 17 + }, + "render-059": { + "answer": "fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr", + "tokens": 33565, + "processed_tokens": 769680, + "tool_calls": 15, + "turns": 13 + }, + "render-070": { + "answer": [ + "dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9", + "dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m", + "dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg", + "dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42", + "dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w", + "dec-use-signed-distance-field-gi--yn366zmp3k7snd9w", + "dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2", + "dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k", + "dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6", + "dec-load-skiff-fast-travel-without-a-loading-screen--v4qft5znysjv5f24", + "dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw", + "dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk" + ], + "tokens": 51680, + "processed_tokens": 3033067, + "tool_calls": 44, + "turns": 43 + }, + "render-075": { + "answer": "unknown", + "tokens": 25394, + "processed_tokens": 668684, + "tool_calls": 15, + "turns": 12 + }, + "tools-002": { + "answer": "47 minutes", + "tokens": 24169, + "processed_tokens": 497705, + "tool_calls": 10, + "turns": 9 + }, + "tools-006": { + "answer": "dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh", + "tokens": 24434, + "processed_tokens": 498658, + "tool_calls": 10, + "turns": 9 + }, + "tools-014": { + "answer": false, + "tokens": 22348, + "processed_tokens": 377677, + "tool_calls": 8, + "turns": 7 + }, + "tools-015": { + "answer": [ + "iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj", + "rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd" + ], + "tokens": 27115, + "processed_tokens": 565858, + "tool_calls": 11, + "turns": 10 + }, + "tools-016": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tokens": 34231, + "processed_tokens": 522384, + "tool_calls": 10, + "turns": 9 + }, + "world-014": { + "answer": "25 ms", + "tokens": 24179, + "processed_tokens": 444866, + "tool_calls": 9, + "turns": 8 + }, + "world-016": { + "answer": "unknown", + "tokens": 22919, + "processed_tokens": 547532, + "tool_calls": 11, + "turns": 10 + }, + "world-022": { + "answer": "fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m", + "tokens": 21829, + "processed_tokens": 487734, + "tool_calls": 9, + "turns": 9 + }, + "world-035": { + "answer": false, + "tokens": 26342, + "processed_tokens": 562079, + "tool_calls": 11, + "turns": 10 + }, + "world-046": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tokens": 26578, + "processed_tokens": 510837, + "tool_calls": 10, + "turns": 9 + }, + "world-053": { + "answer": "1.9 ms", + "tokens": 29815, + "processed_tokens": 1057733, + "tool_calls": 19, + "turns": 18 + }, + "world-059": { + "answer": "dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw", + "tokens": 32019, + "processed_tokens": 892826, + "tool_calls": 15, + "turns": 15 + }, + "world-066": { + "answer": 46, + "tokens": 30732, + "processed_tokens": 884551, + "tool_calls": 16, + "turns": 15 + }, + "world-069": { + "answer": "unknown", + "tokens": 24033, + "processed_tokens": 440904, + "tool_calls": 9, + "turns": 8 + }, + "world-077": { + "answer": "unknown", + "tokens": 22028, + "processed_tokens": 432057, + "tool_calls": 11, + "turns": 8 + } + } +} diff --git a/benchmarks/proof-recall/runs/pilot-2-nobrief.json b/benchmarks/proof-recall/runs/pilot-2-nobrief.json new file mode 100644 index 00000000..607b22e7 --- /dev/null +++ b/benchmarks/proof-recall/runs/pilot-2-nobrief.json @@ -0,0 +1,349 @@ +{ + "run": { + "name": "pilot-2-nobrief", + "protocol": "one fresh session per question", + "models": ["claude-sonnet-5-5"] + }, + "answers": { + "cross-009": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tokens": 77227, + "processed_tokens": 1162939, + "tool_calls": 19, + "turns": 18 + }, + "cross-011": { + "answer": false, + "tokens": 76841, + "processed_tokens": 639901, + "tool_calls": 10, + "turns": 10 + }, + "cross-012": { + "answer": "61 MB/s", + "tokens": 62441, + "processed_tokens": 614580, + "tool_calls": 12, + "turns": 11 + }, + "cross-013": { + "answer": "The Skiff port runs Tern at the Performance preset (not Ultra Performance, which is the lowest preset and is offered only in Meridian's 120 Hz mode), saving 1.8 ms over Quality (2.1 ms vs 3.9 ms), per dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3.", + "tokens": 86491, + "processed_tokens": 1044331, + "tool_calls": 21, + "turns": 15 + }, + "cross-015": { + "answer": "Two Efforts are no longer active: \"Shader compile cache and build farm\" (eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn) is completed, ending with dec-turn-the-shader-compile-cache-on-for-every-farm--4rr3b12b4sasdmaj (cache on for every farm build); \"Co-op rollback netcode prototype\" (eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49) is abandoned, ending with dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b (re-running tides on rollback costs 4.8 ms on Skiff), after which dec-use-host-authoritative-sync-for-co-op--17hqrmtja7pn98d6 was adopted.", + "tokens": 71621, + "processed_tokens": 463202, + "tool_calls": 11, + "turns": 8 + }, + "cross-017": { + "answer": true, + "tokens": 71667, + "processed_tokens": 803167, + "tool_calls": 14, + "turns": 13 + }, + "netcode-004": { + "answer": "Rollback must re-run the tide simulation on every rolled-back frame, which costs 4.8 ms on Skiff (a fifth of the 25 ms frame), and quarter-resolution tides desynced and dropping tides from the snapshot breaks the bit-for-bit tide constraint (dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b); this depends on the world Decision dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e (\"Run the tide simulation in 32.32 fixed point\").", + "tokens": 74349, + "processed_tokens": 698301, + "tool_calls": 11, + "turns": 11 + }, + "netcode-006": { + "answer": "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "tokens": 59832, + "processed_tokens": 376788, + "tool_calls": 7, + "turns": 7 + }, + "netcode-010": { + "answer": "dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk", + "tokens": 34169, + "processed_tokens": 464611, + "tool_calls": 9, + "turns": 8 + }, + "netcode-012": { + "answer": "dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f", + "tokens": 33893, + "processed_tokens": 533190, + "tool_calls": 9, + "turns": 9 + }, + "netcode-015": { + "answer": 2, + "tokens": 23040, + "processed_tokens": 375610, + "tool_calls": 7, + "turns": 7 + }, + "ports-001": { + "answer": "25 ms", + "tokens": 30246, + "processed_tokens": 401496, + "tool_calls": 8, + "turns": 7 + }, + "ports-012": { + "answer": "Saltglass caustics shimmered badly in motion at the 540p floor (visible in 7 of 10 dune views, versus 2 of 10 at 576p), per fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q, so dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb raised the floor to 576p at a cost of 1.3 ms. (That decision was itself later superseded by dec-lower-the-skiff-dynamic-resolution-floor-to-504p--15esnt90gcn29enn.)", + "tokens": 32459, + "processed_tokens": 657905, + "tool_calls": 11, + "turns": 11 + }, + "ports-013": { + "answer": "Ship Tern as Lantern's only upscaler", + "tokens": 30171, + "processed_tokens": 573881, + "tool_calls": 11, + "turns": 10 + }, + "ports-015": { + "answer": "textures (3184 MB)", + "tokens": 30071, + "processed_tokens": 644728, + "tool_calls": 11, + "turns": 11 + }, + "ports-016": { + "answer": "dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn", + "tokens": 24375, + "processed_tokens": 547921, + "tool_calls": 11, + "turns": 10 + }, + "ports-022": { + "answer": "cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe", + "tokens": 33509, + "processed_tokens": 730467, + "tool_calls": 13, + "turns": 12 + }, + "ports-026": { + "answer": "912 MB", + "tokens": 25443, + "processed_tokens": 729499, + "tool_calls": 14, + "turns": 13 + }, + "ports-030": { + "answer": [ + "dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1", + "dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc" + ], + "tokens": 20451, + "processed_tokens": 372119, + "tool_calls": 8, + "turns": 7 + }, + "ports-033": { + "answer": "unknown", + "tokens": 43356, + "processed_tokens": 894350, + "tool_calls": 16, + "turns": 14 + }, + "ports-034": { + "answer": "6 weeks", + "tokens": 37624, + "processed_tokens": 737797, + "tool_calls": 15, + "turns": 12 + }, + "render-002": { + "answer": "3.4x", + "tokens": 25478, + "processed_tokens": 557462, + "tool_calls": 11, + "turns": 10 + }, + "render-005": { + "answer": true, + "tokens": 31116, + "processed_tokens": 951999, + "tool_calls": 17, + "turns": 16 + }, + "render-021": { + "answer": "dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4", + "tokens": 25242, + "processed_tokens": 555678, + "tool_calls": 11, + "turns": 10 + }, + "render-033": { + "answer": "128 MB", + "tokens": 21827, + "processed_tokens": 488460, + "tool_calls": 9, + "turns": 9 + }, + "render-040": { + "answer": "fnd-ports-status-after-alpha--yaqm024j41anp4vn", + "tokens": 32115, + "processed_tokens": 526909, + "tool_calls": 12, + "turns": 9 + }, + "render-050": { + "answer": "con-frame-budget--fzdrbxns6dmrrmy3", + "tokens": 25802, + "processed_tokens": 558963, + "tool_calls": 13, + "turns": 10 + }, + "render-056": { + "answer": "208,000 meshlets", + "tokens": 38557, + "processed_tokens": 1171290, + "tool_calls": 19, + "turns": 18 + }, + "render-059": { + "answer": "fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr", + "tokens": 29732, + "processed_tokens": 751749, + "tool_calls": 14, + "turns": 13 + }, + "render-070": { + "answer": [ + "dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m", + "dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2", + "dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg", + "dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k", + "dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42", + "dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6", + "dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w", + "dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9", + "dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw", + "dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk", + "dec-use-signed-distance-field-gi--yn366zmp3k7snd9w" + ], + "tokens": 50897, + "processed_tokens": 1878034, + "tool_calls": 42, + "turns": 28 + }, + "render-075": { + "answer": "unknown", + "tokens": 24705, + "processed_tokens": 496782, + "tool_calls": 9, + "turns": 9 + }, + "tools-002": { + "answer": "47 minutes", + "tokens": 32079, + "processed_tokens": 459412, + "tool_calls": 9, + "turns": 8 + }, + "tools-006": { + "answer": "dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh", + "tokens": 24693, + "processed_tokens": 325964, + "tool_calls": 6, + "turns": 6 + }, + "tools-014": { + "answer": false, + "tokens": 38250, + "processed_tokens": 541475, + "tool_calls": 9, + "turns": 9 + }, + "tools-015": { + "answer": [ + "rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd", + "iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj" + ], + "tokens": 25281, + "processed_tokens": 502456, + "tool_calls": 10, + "turns": 9 + }, + "tools-016": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tokens": 30790, + "processed_tokens": 391280, + "tool_calls": 8, + "turns": 7 + }, + "world-014": { + "answer": "25 ms", + "tokens": 24704, + "processed_tokens": 496265, + "tool_calls": 10, + "turns": 9 + }, + "world-016": { + "answer": "unknown", + "tokens": 26737, + "processed_tokens": 674012, + "tool_calls": 15, + "turns": 12 + }, + "world-022": { + "answer": "fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m", + "tokens": 21387, + "processed_tokens": 375532, + "tool_calls": 7, + "turns": 7 + }, + "world-035": { + "answer": false, + "tokens": 22455, + "processed_tokens": 432239, + "tool_calls": 9, + "turns": 8 + }, + "world-046": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tokens": 25584, + "processed_tokens": 505095, + "tool_calls": 10, + "turns": 9 + }, + "world-053": { + "answer": "1.9 ms", + "tokens": 41178, + "processed_tokens": 1483082, + "tool_calls": 26, + "turns": 23 + }, + "world-059": { + "answer": "dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw", + "tokens": 28396, + "processed_tokens": 858136, + "tool_calls": 16, + "turns": 15 + }, + "world-066": { + "answer": 46, + "tokens": 30499, + "processed_tokens": 961590, + "tool_calls": 17, + "turns": 16 + }, + "world-069": { + "answer": "unknown", + "tokens": 32547, + "processed_tokens": 465779, + "tool_calls": 11, + "turns": 8 + }, + "world-077": { + "answer": "unknown", + "tokens": 21812, + "processed_tokens": 374260, + "tool_calls": 11, + "turns": 7 + } + } +} diff --git a/benchmarks/proof-recall/runs/pilot-3-brief.json b/benchmarks/proof-recall/runs/pilot-3-brief.json new file mode 100644 index 00000000..ed5dee4b --- /dev/null +++ b/benchmarks/proof-recall/runs/pilot-3-brief.json @@ -0,0 +1,341 @@ +{ + "run": { + "name": "pilot-3-brief", + "protocol": "one fresh session per question", + "models": ["claude-haiku-5-5"] + }, + "answers": { + "cross-009": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tokens": 69093, + "processed_tokens": 844465, + "tool_calls": 14, + "turns": 14 + }, + "cross-011": { + "answer": false, + "tokens": 91395, + "processed_tokens": 1418625, + "tool_calls": 19, + "turns": 19 + }, + "cross-012": { + "answer": "61 MB/s", + "tokens": 81527, + "processed_tokens": 1084187, + "tool_calls": 16, + "turns": 16 + }, + "cross-013": { + "answer": "Skiff runs Tern at the Performance preset, which saves 1.8 ms over Quality (2.1 ms against 3.9 ms of GPU time on the Skiff dev kit). Records: dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3 and fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0.", + "tokens": 103676, + "processed_tokens": 1698341, + "tool_calls": 21, + "turns": 21 + }, + "cross-015": { + "answer": "The shader compile cache and build farm Effort is completed: the cache now runs on every farm build, as the retrospective fnd-retrospective-on-the-shader-compile-cache--9rpv2a60ach04cx6 records. The co-op rollback netcode prototype Effort is abandoned: decision dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b stopped it because re-running tides on every rolled-back frame costs 4.8 ms on Skiff.", + "tokens": 70657, + "processed_tokens": 791779, + "tool_calls": 13, + "turns": 13 + }, + "cross-017": { + "answer": true, + "tokens": 86776, + "processed_tokens": 1487784, + "tool_calls": 21, + "turns": 21 + }, + "netcode-004": { + "answer": "The team abandoned rollback netcode for co-op because rollback must re-run the tide simulation on every rolled-back frame, which costs 4.8 ms on Skiff, a fifth of the frame budget, while co-op needs tide state to stay bit-identical on all peers. The reason depends on the world Decision dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e (Run the tide simulation in 32.32 fixed point).", + "tokens": 67984, + "processed_tokens": 780519, + "tool_calls": 13, + "turns": 13 + }, + "netcode-006": { + "answer": "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "tokens": 70567, + "processed_tokens": 736662, + "tool_calls": 12, + "turns": 12 + }, + "netcode-010": { + "answer": "dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk", + "tokens": 69015, + "processed_tokens": 664940, + "tool_calls": 11, + "turns": 11 + }, + "netcode-012": { + "answer": "dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f", + "tokens": 85184, + "processed_tokens": 945972, + "tool_calls": 14, + "turns": 14 + }, + "netcode-015": { + "answer": 2, + "tokens": 31151, + "processed_tokens": 596833, + "tool_calls": 10, + "turns": 10 + }, + "ports-001": { + "answer": "25 ms", + "tokens": 23650, + "processed_tokens": 510111, + "tool_calls": 9, + "turns": 9 + }, + "ports-012": { + "answer": "The ports team raised the Skiff dynamic resolution floor to 576p because caustic patterns under saltglass shimmered badly at the 540p floor, even after Tern: visible shimmer appeared in 7 of 10 dune views, versus 2 of 10 at 576p (fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q). The 576p decision is dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb.", + "tokens": 26358, + "processed_tokens": 575082, + "tool_calls": 10, + "turns": 10 + }, + "ports-013": { + "answer": "Ship Tern as Lantern's only upscaler", + "tokens": 44721, + "processed_tokens": 951217, + "tool_calls": 14, + "turns": 14 + }, + "ports-015": { + "answer": "textures", + "tokens": 41250, + "processed_tokens": 942749, + "tool_calls": 14, + "turns": 14 + }, + "ports-016": { + "answer": "dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn", + "tokens": 37357, + "processed_tokens": 631409, + "tool_calls": 10, + "turns": 10 + }, + "ports-022": { + "answer": "cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe", + "tokens": 41181, + "processed_tokens": 834559, + "tool_calls": 13, + "turns": 13 + }, + "ports-026": { + "answer": "912 MB", + "tokens": 34172, + "processed_tokens": 1462955, + "tool_calls": 24, + "turns": 24 + }, + "ports-030": { + "answer": [ + "dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1", + "dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc" + ], + "tokens": 41924, + "processed_tokens": 988909, + "tool_calls": 15, + "turns": 15 + }, + "ports-033": { + "answer": "unknown", + "tokens": 44491, + "processed_tokens": 954771, + "tool_calls": 15, + "turns": 15 + }, + "ports-034": { + "answer": "6 weeks", + "tokens": 69958, + "processed_tokens": 1152216, + "tool_calls": 15, + "turns": 15 + }, + "render-002": { + "answer": "3.4x", + "tokens": 44882, + "processed_tokens": 1139911, + "tool_calls": 17, + "turns": 17 + }, + "render-005": { + "answer": true, + "tokens": 50550, + "processed_tokens": 969996, + "tool_calls": 14, + "turns": 14 + }, + "render-021": { + "answer": "dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4", + "tokens": 28155, + "processed_tokens": 877984, + "tool_calls": 15, + "turns": 15 + }, + "render-033": { + "answer": "128 MB", + "tokens": 35208, + "processed_tokens": 865499, + "tool_calls": 14, + "turns": 14 + }, + "render-040": { + "answer": "fnd-ports-status-after-alpha--yaqm024j41anp4vn", + "tokens": 46164, + "processed_tokens": 1141677, + "tool_calls": 17, + "turns": 17 + }, + "render-050": { + "answer": "con-frame-budget--fzdrbxns6dmrrmy3", + "tokens": 29760, + "processed_tokens": 656125, + "tool_calls": 11, + "turns": 11 + }, + "render-056": { + "answer": "208,000 meshlets", + "tokens": 48586, + "processed_tokens": 1751139, + "tool_calls": 24, + "turns": 24 + }, + "render-059": { + "answer": "fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr", + "tokens": 60800, + "processed_tokens": 1740873, + "tool_calls": 23, + "turns": 23 + }, + "render-070": { + "answer": [ + "dec-use-signed-distance-field-gi--yn366zmp3k7snd9w", + "dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k", + "dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2" + ], + "tokens": 118817, + "processed_tokens": 2449486, + "tool_calls": 25, + "turns": 25 + }, + "render-075": { + "answer": "3 decisions", + "tokens": 57129, + "processed_tokens": 937611, + "tool_calls": 13, + "turns": 13 + }, + "tools-002": { + "answer": "47 minutes", + "tokens": 48440, + "processed_tokens": 987762, + "tool_calls": 15, + "turns": 15 + }, + "tools-006": { + "answer": "dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh", + "tokens": 33610, + "processed_tokens": 674293, + "tool_calls": 11, + "turns": 11 + }, + "tools-014": { + "answer": false, + "tokens": 25754, + "processed_tokens": 636050, + "tool_calls": 11, + "turns": 11 + }, + "tools-015": { + "answer": [ + "rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd", + "iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj" + ], + "tokens": 52934, + "processed_tokens": 1250050, + "tool_calls": 17, + "turns": 17 + }, + "tools-016": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tokens": 41990, + "processed_tokens": 779287, + "tool_calls": 12, + "turns": 12 + }, + "world-014": { + "answer": "unknown", + "tokens": 63873, + "processed_tokens": 2442800, + "tool_calls": 30, + "turns": 30 + }, + "world-016": { + "answer": "unknown", + "tokens": 40444, + "processed_tokens": 698588, + "tool_calls": 11, + "turns": 11 + }, + "world-022": { + "answer": "fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m", + "tokens": 62092, + "processed_tokens": 2166025, + "tool_calls": 28, + "turns": 28 + }, + "world-035": { + "answer": false, + "tokens": 53145, + "processed_tokens": 786612, + "tool_calls": 12, + "turns": 12 + }, + "world-046": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tokens": 33325, + "processed_tokens": 735124, + "tool_calls": 12, + "turns": 12 + }, + "world-053": { + "answer": "1.9 ms", + "tokens": 60110, + "processed_tokens": 2439256, + "tool_calls": 31, + "turns": 31 + }, + "world-059": { + "answer": "dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw", + "tokens": 34925, + "processed_tokens": 874084, + "tool_calls": 14, + "turns": 14 + }, + "world-066": { + "answer": "46 proximity reads", + "tokens": 30505, + "processed_tokens": 973002, + "tool_calls": 16, + "turns": 16 + }, + "world-069": { + "answer": 7, + "tokens": 41794, + "processed_tokens": 634375, + "tool_calls": 10, + "turns": 10 + }, + "world-077": { + "answer": 9, + "tokens": 35325, + "processed_tokens": 675878, + "tool_calls": 11, + "turns": 11 + } + } +} diff --git a/benchmarks/proof-recall/runs/pilot-3-nobrief.json b/benchmarks/proof-recall/runs/pilot-3-nobrief.json new file mode 100644 index 00000000..c6fe9340 --- /dev/null +++ b/benchmarks/proof-recall/runs/pilot-3-nobrief.json @@ -0,0 +1,338 @@ +{ + "run": { + "name": "pilot-3-nobrief", + "protocol": "one fresh session per question", + "models": ["claude-haiku-5-5"] + }, + "answers": { + "cross-009": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tokens": 90550, + "processed_tokens": 1015081, + "tool_calls": 14, + "turns": 14 + }, + "cross-011": { + "answer": false, + "tokens": 98809, + "processed_tokens": 1420177, + "tool_calls": 20, + "turns": 18 + }, + "cross-012": { + "answer": "61 MB/s", + "tokens": 125443, + "processed_tokens": 1553161, + "tool_calls": 18, + "turns": 18 + }, + "cross-013": { + "answer": "Skiff runs Tern at the Performance preset, which saves 1.8 ms over Quality (2.1 ms against 3.9 ms of GPU time). See dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3 and fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0.", + "tokens": 158990, + "processed_tokens": 2763888, + "tool_calls": 25, + "turns": 25 + }, + "cross-015": { + "answer": "Two Efforts are no longer active. Shader compile cache and build farm is completed: its cache was turned on for every farm build (dec-turn-the-shader-compile-cache-on-for-every-farm--4rr3b12b4sasdmaj), which is the end point the Effort set for itself. Co-op rollback netcode prototype is abandoned: the team dropped rollback because re-running tides on each rolled-back frame costs 4.8 ms on Skiff (dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b).", + "tokens": 95476, + "processed_tokens": 632587, + "tool_calls": 13, + "turns": 9 + }, + "cross-017": { + "answer": true, + "tokens": 94864, + "processed_tokens": 1061459, + "tool_calls": 14, + "turns": 14 + }, + "netcode-004": { + "answer": "Rollback was dropped because every rolled-back frame must re-run the tide simulation, which costs 4.8 ms on Skiff (a fifth of the 25 ms frame), and co-op needs tides to match bit for bit on every peer (dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b). The reason depends on the world Decision \"Run the tide simulation in 32.32 fixed point\" (dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e), which keeps tides deterministic.", + "tokens": 102258, + "processed_tokens": 1495386, + "tool_calls": 19, + "turns": 19 + }, + "netcode-006": { + "answer": "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "tokens": 64076, + "processed_tokens": 524501, + "tool_calls": 9, + "turns": 9 + }, + "netcode-010": { + "answer": "dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk", + "tokens": 71914, + "processed_tokens": 660710, + "tool_calls": 11, + "turns": 11 + }, + "netcode-012": { + "answer": "dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f", + "tokens": 80525, + "processed_tokens": 807978, + "tool_calls": 12, + "turns": 12 + }, + "netcode-015": { + "answer": 2, + "tokens": 26041, + "processed_tokens": 514310, + "tool_calls": 9, + "turns": 9 + }, + "ports-001": { + "answer": "25 ms", + "tokens": 35449, + "processed_tokens": 703179, + "tool_calls": 11, + "turns": 11 + }, + "ports-012": { + "answer": "The ports team raised the floor to 576p because at 540p the saltglass caustics shimmered badly in motion: Yusuf Demir saw visible shimmer in 7 of 10 dune views at 540p, versus 2 of 10 at 576p, and 576p still fits the 33.3 ms frame (27.3 ms on the worst dune view). Record: dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb, based on fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q.", + "tokens": 37665, + "processed_tokens": 852968, + "tool_calls": 13, + "turns": 13 + }, + "ports-013": { + "answer": "Ship Tern as Lantern's only upscaler", + "tokens": 39852, + "processed_tokens": 837655, + "tool_calls": 13, + "turns": 13 + }, + "ports-015": { + "answer": "textures", + "tokens": 40299, + "processed_tokens": 801136, + "tool_calls": 12, + "turns": 12 + }, + "ports-016": { + "answer": "dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn", + "tokens": 39941, + "processed_tokens": 724851, + "tool_calls": 11, + "turns": 11 + }, + "ports-022": { + "answer": "cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe", + "tokens": 39690, + "processed_tokens": 1008196, + "tool_calls": 15, + "turns": 15 + }, + "ports-026": { + "answer": "912 MB", + "tokens": 39207, + "processed_tokens": 1004879, + "tool_calls": 15, + "turns": 15 + }, + "ports-030": { + "answer": [ + "dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1", + "dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc" + ], + "tokens": 35938, + "processed_tokens": 633866, + "tool_calls": 10, + "turns": 10 + }, + "ports-033": { + "answer": "unknown", + "tokens": 69527, + "processed_tokens": 1010667, + "tool_calls": 13, + "turns": 13 + }, + "ports-034": { + "answer": "6 weeks", + "tokens": 64188, + "processed_tokens": 1067534, + "tool_calls": 14, + "turns": 14 + }, + "render-002": { + "answer": "3.4x", + "tokens": 27090, + "processed_tokens": 701244, + "tool_calls": 12, + "turns": 12 + }, + "render-005": { + "answer": true, + "tokens": 42243, + "processed_tokens": 822270, + "tool_calls": 13, + "turns": 13 + }, + "render-021": { + "answer": "dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4", + "tokens": 39769, + "processed_tokens": 780307, + "tool_calls": 12, + "turns": 12 + }, + "render-033": { + "answer": "128 MB", + "tokens": 28203, + "processed_tokens": 762770, + "tool_calls": 13, + "turns": 13 + }, + "render-040": { + "answer": "fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c", + "tokens": 56104, + "processed_tokens": 1341489, + "tool_calls": 18, + "turns": 18 + }, + "render-050": { + "answer": "con-frame-budget--fzdrbxns6dmrrmy3", + "tokens": 42286, + "processed_tokens": 849116, + "tool_calls": 13, + "turns": 13 + }, + "render-056": { + "answer": "208,000 meshlets", + "tokens": 63997, + "processed_tokens": 1616052, + "tool_calls": 20, + "turns": 20 + }, + "render-059": { + "answer": "fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr", + "tokens": 49945, + "processed_tokens": 1454260, + "tool_calls": 20, + "turns": 20 + }, + "render-070": { + "answer": [ + "dec-use-signed-distance-field-gi--yn366zmp3k7snd9w", + "dec-enable-meshlet-cone-culling-on-all-platforms--cpyweprmzcqhqsv2", + "dec-feed-a-saltglass-reactive-mask-into-tern--xezjs7v3vq3r8e6k" + ], + "tokens": 121670, + "processed_tokens": 1821737, + "tool_calls": 18, + "turns": 18 + }, + "render-075": { + "answer": "3", + "tokens": 52826, + "processed_tokens": 757452, + "tool_calls": 11, + "turns": 11 + }, + "tools-002": { + "answer": "47 minutes", + "tokens": 42251, + "processed_tokens": 570153, + "tool_calls": 9, + "turns": 9 + }, + "tools-006": { + "answer": "dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh", + "tokens": 44958, + "processed_tokens": 877740, + "tool_calls": 13, + "turns": 13 + }, + "tools-014": { + "answer": false, + "tokens": 40335, + "processed_tokens": 558482, + "tool_calls": 9, + "turns": 9 + }, + "tools-015": { + "answer": "unknown", + "tokens": 20181, + "processed_tokens": 268987, + "tool_calls": 5, + "turns": 5 + }, + "tools-016": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tokens": 36156, + "processed_tokens": 568719, + "tool_calls": 9, + "turns": 9 + }, + "world-014": { + "answer": "unknown", + "tokens": 116165, + "processed_tokens": 1752462, + "tool_calls": 18, + "turns": 18 + }, + "world-016": { + "answer": "unknown", + "tokens": 120598, + "processed_tokens": 1915471, + "tool_calls": 19, + "turns": 19 + }, + "world-022": { + "answer": "fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m", + "tokens": 56797, + "processed_tokens": 1431136, + "tool_calls": 19, + "turns": 19 + }, + "world-035": { + "answer": false, + "tokens": 71572, + "processed_tokens": 1277519, + "tool_calls": 16, + "turns": 16 + }, + "world-046": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tokens": 61877, + "processed_tokens": 1146771, + "tool_calls": 16, + "turns": 16 + }, + "world-053": { + "answer": "unknown", + "tokens": 102662, + "processed_tokens": 3902221, + "tool_calls": 37, + "turns": 37 + }, + "world-059": { + "answer": "dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw", + "tokens": 31112, + "processed_tokens": 788663, + "tool_calls": 14, + "turns": 13 + }, + "world-066": { + "answer": "46 reads", + "tokens": 51025, + "processed_tokens": 1769239, + "tool_calls": 25, + "turns": 25 + }, + "world-069": { + "answer": 6, + "tokens": 131123, + "processed_tokens": 2468164, + "tool_calls": 24, + "turns": 24 + }, + "world-077": { + "answer": 9, + "tokens": 31555, + "processed_tokens": 404942, + "tool_calls": 7, + "turns": 7 + } + } +} diff --git a/benchmarks/proof-recall/runs/retracted-haiku-brief.json b/benchmarks/proof-recall/runs/retracted-haiku-brief.json new file mode 100644 index 00000000..353d0c75 --- /dev/null +++ b/benchmarks/proof-recall/runs/retracted-haiku-brief.json @@ -0,0 +1,77 @@ +{ + "run": { + "name": "retracted-haiku-brief", + "protocol": "one fresh session per question", + "models": ["claude-haiku-5-5"] + }, + "answers": { + "cross-003": { + "answer": 2, + "tokens": 22230, + "fixed_tokens": 1231, + "processed_tokens": 138666, + "tool_calls": 14, + "turns": 9 + }, + "cross-017": { + "answer": "unknown", + "tokens": 15972, + "fixed_tokens": 1238, + "processed_tokens": 159973, + "tool_calls": 11, + "turns": 12 + }, + "ports-032": { + "answer": 2, + "tokens": 11275, + "fixed_tokens": 5942, + "processed_tokens": 52120, + "tool_calls": 5, + "turns": 6 + }, + "render-011": { + "answer": "fnd-sdf-gi-costs-2-4-ms-on-meridian--2w6c2pc5zmcsyjre", + "tokens": 26429, + "fixed_tokens": 1234, + "processed_tokens": 134141, + "tool_calls": 8, + "turns": 9 + }, + "render-074": { + "answer": 5, + "tokens": 12261, + "fixed_tokens": 1231, + "processed_tokens": 89379, + "tool_calls": 7, + "turns": 8 + }, + "world-010": { + "answer": "29 GB/s", + "tokens": 14100, + "fixed_tokens": 1229, + "processed_tokens": 111091, + "tool_calls": 8, + "turns": 9 + }, + "world-074": { + "answer": 7, + "tokens": 14622, + "fixed_tokens": 5926, + "processed_tokens": 72668, + "tool_calls": 6, + "turns": 7 + }, + "world-075": { + "answer": [ + "dec-store-components-in-archetype-tables-and-volatil--8679sjn071ycsbpv", + "dec-partition-the-world-into-192-meter-cells--q62ddwdv2n8wxay6", + "dec-return-engine-jobs-to-the-thread-pool-with-conti--547qbweqvrp1j5g3" + ], + "tokens": 6930, + "fixed_tokens": 1230, + "processed_tokens": 52577, + "tool_calls": 5, + "turns": 6 + } + } +} diff --git a/benchmarks/proof-recall/runs/retracted-haiku-nobrief.json b/benchmarks/proof-recall/runs/retracted-haiku-nobrief.json new file mode 100644 index 00000000..aa303196 --- /dev/null +++ b/benchmarks/proof-recall/runs/retracted-haiku-nobrief.json @@ -0,0 +1,77 @@ +{ + "run": { + "name": "retracted-haiku-nobrief", + "protocol": "one fresh session per question", + "models": ["claude-haiku-5-5"] + }, + "answers": { + "cross-003": { + "answer": 2, + "tokens": 26399, + "fixed_tokens": 5947, + "processed_tokens": 85472, + "tool_calls": 14, + "turns": 6 + }, + "cross-017": { + "answer": false, + "tokens": 34035, + "fixed_tokens": 1239, + "processed_tokens": 151933, + "tool_calls": 7, + "turns": 8 + }, + "ports-032": { + "answer": 2, + "tokens": 6873, + "fixed_tokens": 1237, + "processed_tokens": 52431, + "tool_calls": 5, + "turns": 6 + }, + "render-011": { + "answer": "fnd-sdf-gi-costs-2-4-ms-on-meridian--2w6c2pc5zmcsyjre", + "tokens": 15995, + "fixed_tokens": 1233, + "processed_tokens": 141605, + "tool_calls": 11, + "turns": 12 + }, + "render-074": { + "answer": 5, + "tokens": 12739, + "fixed_tokens": 5954, + "processed_tokens": 55193, + "tool_calls": 5, + "turns": 6 + }, + "world-010": { + "answer": "unknown", + "tokens": 32115, + "fixed_tokens": 5945, + "processed_tokens": 213268, + "tool_calls": 12, + "turns": 11 + }, + "world-074": { + "answer": 7, + "tokens": 10065, + "fixed_tokens": 1236, + "processed_tokens": 72217, + "tool_calls": 6, + "turns": 7 + }, + "world-075": { + "answer": [ + "dec-store-components-in-archetype-tables-and-volatil--8679sjn071ycsbpv", + "dec-partition-the-world-into-192-meter-cells--q62ddwdv2n8wxay6", + "dec-return-engine-jobs-to-the-thread-pool-with-conti--547qbweqvrp1j5g3" + ], + "tokens": 12428, + "fixed_tokens": 5950, + "processed_tokens": 63849, + "tool_calls": 6, + "turns": 7 + } + } +} diff --git a/benchmarks/proof-recall/runs/x10-haiku-brief.json b/benchmarks/proof-recall/runs/x10-haiku-brief.json new file mode 100644 index 00000000..0806bff1 --- /dev/null +++ b/benchmarks/proof-recall/runs/x10-haiku-brief.json @@ -0,0 +1,2046 @@ +{ + "run": { + "name": "x10-haiku-brief", + "protocol": "one fresh session per question", + "models": ["claude-haiku-5-5"] + }, + "answers": { + "cross-001": { + "answer": "con-frame-budget--br0qszfg8fys908n", + "tokens": 14574, + "fixed_tokens": 1232, + "processed_tokens": 122631, + "tool_calls": 9, + "turns": 10 + }, + "cross-002": { + "answer": 2, + "tokens": 25644, + "fixed_tokens": 1228, + "processed_tokens": 186012, + "tool_calls": 13, + "turns": 10 + }, + "cross-003": { + "answer": 2, + "tokens": 20101, + "fixed_tokens": 1230, + "processed_tokens": 82459, + "tool_calls": 14, + "turns": 6 + }, + "cross-004": { + "answer": "dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e", + "tokens": 40117, + "fixed_tokens": 1230, + "processed_tokens": 565336, + "tool_calls": 20, + "turns": 21 + }, + "cross-005": { + "answer": "unknown", + "tokens": 13814, + "fixed_tokens": 1236, + "processed_tokens": 121171, + "tool_calls": 9, + "turns": 10 + }, + "cross-006": { + "answer": "~19% (4.8 ms of the 25 ms frame)", + "tokens": 11838, + "fixed_tokens": 1232, + "processed_tokens": 118487, + "tool_calls": 9, + "turns": 10 + }, + "cross-007": { + "answer": "8 GB", + "tokens": 19929, + "fixed_tokens": 1229, + "processed_tokens": 225561, + "tool_calls": 14, + "turns": 15 + }, + "cross-008": { + "answer": "unknown", + "tokens": 27357, + "fixed_tokens": 1236, + "processed_tokens": 323827, + "tool_calls": 17, + "turns": 18 + }, + "cross-009": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tokens": 31792, + "fixed_tokens": 1235, + "processed_tokens": 363453, + "tool_calls": 15, + "turns": 16 + }, + "cross-010": { + "answer": "unknown", + "tokens": 14849, + "fixed_tokens": 1227, + "processed_tokens": 160970, + "tool_calls": 11, + "turns": 12 + }, + "cross-011": { + "answer": "unknown", + "tokens": 41588, + "fixed_tokens": 1227, + "processed_tokens": 361964, + "tool_calls": 15, + "turns": 14 + }, + "cross-012": { + "answer": "61 MB/s", + "tokens": 30295, + "fixed_tokens": 1235, + "processed_tokens": 357685, + "tool_calls": 15, + "turns": 16 + }, + "cross-013": { + "answer": "unknown", + "tokens": 29925, + "fixed_tokens": 1230, + "processed_tokens": 331998, + "tool_calls": 14, + "turns": 15 + }, + "cross-014": { + "answer": 3, + "tokens": 5857, + "fixed_tokens": 1238, + "processed_tokens": 41859, + "tool_calls": 4, + "turns": 5 + }, + "cross-015": { + "answer": "Two Efforts are no longer active. The shader compile cache and build farm Effort (eff-shader-compile-cache-and-build-farm--6xeac11zxvwwarkn) is completed: its retrospective, fnd-retrospective-on-the-shader-compile-cache--9rpv2a60ach04cx6, says the cache has run on every farm build for five weeks, which meets the Effort's stated end condition. The co-op rollback netcode prototype (eff-co-op-rollback-netcode-prototype--n5ejm416kfcfap49) is abandoned: dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b stops it because re-running tides every rollback frame costs 4.8 ms on Skiff, so co-op will not ship with rollback.", + "tokens": 19637, + "fixed_tokens": 1232, + "processed_tokens": 130359, + "tool_calls": 12, + "turns": 9 + }, + "cross-016": { + "answer": "16.7 ms", + "tokens": 31710, + "fixed_tokens": 1228, + "processed_tokens": 289870, + "tool_calls": 14, + "turns": 15 + }, + "cross-017": { + "answer": false, + "tokens": 19741, + "fixed_tokens": 692, + "processed_tokens": 267768, + "tool_calls": 16, + "turns": 17 + }, + "netcode-001": { + "answer": "abandoned", + "tokens": 9699, + "fixed_tokens": 699, + "processed_tokens": 71958, + "tool_calls": 6, + "turns": 7 + }, + "netcode-002": { + "answer": "netcode/rollback-archive", + "tokens": 9570, + "fixed_tokens": 699, + "processed_tokens": 84544, + "tool_calls": 7, + "turns": 8 + }, + "netcode-003": { + "answer": "38 KB", + "tokens": 9450, + "fixed_tokens": 697, + "processed_tokens": 84348, + "tool_calls": 7, + "turns": 8 + }, + "netcode-004": { + "answer": "The team abandoned rollback because co-op peers must agree on tide state bit for bit, and rollback re-runs tides every rolled-back frame, costing 4.8 ms on Skiff (a fifth of the 25 ms frame), while shrinking the window and quarter-resolution tides both failed. The reason depends on the world Decision dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e.", + "tokens": 28833, + "fixed_tokens": 697, + "processed_tokens": 643747, + "tool_calls": 29, + "turns": 30 + }, + "netcode-005": { + "answer": "unknown", + "tokens": 24213, + "fixed_tokens": 696, + "processed_tokens": 171103, + "tool_calls": 10, + "turns": 11 + }, + "netcode-006": { + "answer": "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "tokens": 22131, + "fixed_tokens": 696, + "processed_tokens": 110626, + "tool_calls": 7, + "turns": 8 + }, + "netcode-007": { + "answer": "dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b", + "tokens": 11816, + "fixed_tokens": 696, + "processed_tokens": 89574, + "tool_calls": 7, + "turns": 8 + }, + "netcode-008": { + "answer": "dec-use-a-4-frame-rollback-window--pqe4hvbgmbp0dmh9", + "tokens": 27385, + "fixed_tokens": 706, + "processed_tokens": 291935, + "tool_calls": 13, + "turns": 14 + }, + "netcode-009": { + "answer": "1.9 ms", + "tokens": 16770, + "fixed_tokens": 694, + "processed_tokens": 227804, + "tool_calls": 14, + "turns": 15 + }, + "netcode-010": { + "answer": "dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk", + "tokens": 63342, + "fixed_tokens": 699, + "processed_tokens": 996008, + "tool_calls": 27, + "turns": 28 + }, + "netcode-011": { + "answer": "con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g", + "tokens": 54321, + "fixed_tokens": 699, + "processed_tokens": 997566, + "tool_calls": 27, + "turns": 28 + }, + "netcode-012": { + "answer": "dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f", + "tokens": 20800, + "fixed_tokens": 1238, + "processed_tokens": 250342, + "tool_calls": 15, + "turns": 16 + }, + "netcode-013": { + "answer": [ + "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf", + "rsk-re-simulation-cost-could-blow-the-skiff-frame-bu--sk2njsp170a3qwyf" + ], + "tokens": 8917, + "fixed_tokens": 1234, + "processed_tokens": 56306, + "tool_calls": 5, + "turns": 6 + }, + "netcode-014": { + "answer": [ + "iss-how-should-co-op-keep-up-to-four-players-in-sync--92t2zfsy3etfzr89", + "iss-late-join-during-a-tide-surge-desyncs-the-joinin--mya93va0n7s8g7cj" + ], + "tokens": 65290, + "fixed_tokens": 1235, + "processed_tokens": 699781, + "tool_calls": 24, + "turns": 21 + }, + "netcode-015": { + "answer": 2, + "tokens": 32515, + "fixed_tokens": 1234, + "processed_tokens": 283057, + "tool_calls": 13, + "turns": 14 + }, + "ports-001": { + "answer": "25 ms", + "tokens": 9841, + "fixed_tokens": 1228, + "processed_tokens": 84936, + "tool_calls": 7, + "turns": 8 + }, + "ports-002": { + "answer": "384 MB", + "tokens": 29188, + "fixed_tokens": 1230, + "processed_tokens": 272422, + "tool_calls": 13, + "turns": 14 + }, + "ports-003": { + "answer": "61 MB/s", + "tokens": 42617, + "fixed_tokens": 1235, + "processed_tokens": 739407, + "tool_calls": 22, + "turns": 23 + }, + "ports-004": { + "answer": "accepted", + "tokens": 12320, + "fixed_tokens": 1224, + "processed_tokens": 89608, + "tool_calls": 7, + "turns": 8 + }, + "ports-005": { + "answer": "unknown", + "tokens": 34373, + "fixed_tokens": 1228, + "processed_tokens": 295431, + "tool_calls": 15, + "turns": 13 + }, + "ports-034": { + "answer": "unknown", + "tokens": 35952, + "fixed_tokens": 1228, + "processed_tokens": 720217, + "tool_calls": 29, + "turns": 30 + }, + "ports-006": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tokens": 9972, + "fixed_tokens": 1231, + "processed_tokens": 84588, + "tool_calls": 7, + "turns": 8 + }, + "ports-007": { + "answer": "unknown", + "tokens": 30409, + "fixed_tokens": 1236, + "processed_tokens": 404331, + "tool_calls": 17, + "turns": 18 + }, + "ports-008": { + "answer": "dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3", + "tokens": 28406, + "fixed_tokens": 1229, + "processed_tokens": 278263, + "tool_calls": 13, + "turns": 14 + }, + "ports-009": { + "answer": "dec-load-skiff-fast-travel-without-a-loading-screen--v4qft5znysjv5f24", + "tokens": 60977, + "fixed_tokens": 1229, + "processed_tokens": 811012, + "tool_calls": 25, + "turns": 23 + }, + "ports-010": { + "answer": "unknown", + "tokens": 39494, + "fixed_tokens": 1236, + "processed_tokens": 688548, + "tool_calls": 24, + "turns": 25 + }, + "ports-011": { + "answer": "unknown", + "tokens": 26220, + "fixed_tokens": 1230, + "processed_tokens": 256492, + "tool_calls": 13, + "turns": 14 + }, + "ports-012": { + "answer": "The team raised the Skiff dynamic resolution floor to 576p because saltglass caustics shimmered badly in motion at the 540p floor, even after Tern (7 of 10 dune views, versus 2 of 10 at 576p), per `dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb` citing `fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q`. That 576p decision is now superseded by a 504p floor (`dec-lower-the-skiff-dynamic-resolution-floor-to-504p--15esnt90gcn29enn`).", + "tokens": 12424, + "fixed_tokens": 1227, + "processed_tokens": 118724, + "tool_calls": 9, + "turns": 10 + }, + "ports-013": { + "answer": "Ship Tern as Lantern's only upscaler", + "tokens": 27707, + "fixed_tokens": 1230, + "processed_tokens": 346160, + "tool_calls": 15, + "turns": 16 + }, + "ports-014": { + "answer": "unknown", + "tokens": 39947, + "fixed_tokens": 1234, + "processed_tokens": 634030, + "tool_calls": 23, + "turns": 22 + }, + "ports-015": { + "answer": "unknown", + "tokens": 55523, + "fixed_tokens": 1236, + "processed_tokens": 2336661, + "tool_calls": 66, + "turns": 67 + }, + "ports-016": { + "answer": "dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn", + "tokens": 14376, + "fixed_tokens": 1231, + "processed_tokens": 243098, + "tool_calls": 18, + "turns": 19 + }, + "ports-017": { + "answer": "unknown", + "tokens": 49825, + "fixed_tokens": 1228, + "processed_tokens": 668022, + "tool_calls": 20, + "turns": 21 + }, + "ports-018": { + "answer": "504p", + "tokens": 10920, + "fixed_tokens": 1233, + "processed_tokens": 100792, + "tool_calls": 8, + "turns": 9 + }, + "ports-019": { + "answer": "unknown", + "tokens": 37569, + "fixed_tokens": 1228, + "processed_tokens": 422186, + "tool_calls": 16, + "turns": 17 + }, + "ports-020": { + "answer": "fnd-skiff-sdk-1-2-takes-1-gb-back-from-games--a0ybdgjzw64hwfqa", + "tokens": 24160, + "fixed_tokens": 1231, + "processed_tokens": 164325, + "tool_calls": 9, + "turns": 10 + }, + "ports-021": { + "answer": "SKF-DSP-004", + "tokens": 64711, + "fixed_tokens": 1227, + "processed_tokens": 1358951, + "tool_calls": 33, + "turns": 34 + }, + "ports-022": { + "answer": "cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe", + "tokens": 18365, + "fixed_tokens": 1232, + "processed_tokens": 245406, + "tool_calls": 17, + "turns": 16 + }, + "ports-023": { + "answer": "fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0", + "tokens": 15176, + "fixed_tokens": 1238, + "processed_tokens": 175256, + "tool_calls": 12, + "turns": 13 + }, + "ports-024": { + "answer": "fnd-skiff-firmware-1-2-rejects-pipeline-blobs-built--pernvgb2he7m3z3y", + "tokens": 39843, + "fixed_tokens": 1233, + "processed_tokens": 962728, + "tool_calls": 36, + "turns": 37 + }, + "ports-025": { + "answer": "dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3", + "tokens": 12024, + "fixed_tokens": 1230, + "processed_tokens": 118050, + "tool_calls": 9, + "turns": 10 + }, + "ports-026": { + "answer": "unknown", + "tokens": 45194, + "fixed_tokens": 1230, + "processed_tokens": 1090578, + "tool_calls": 33, + "turns": 34 + }, + "ports-027": { + "answer": [ + "dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw", + "rsk-tide-streaming-outruns-skiff-storage--6q8s3b383z2tyeyb" + ], + "tokens": 43692, + "fixed_tokens": 1232, + "processed_tokens": 581159, + "tool_calls": 33, + "turns": 20 + }, + "ports-028": { + "answer": 2, + "tokens": 8848, + "fixed_tokens": 1228, + "processed_tokens": 66719, + "tool_calls": 6, + "turns": 7 + }, + "ports-029": { + "answer": 8, + "tokens": 21504, + "fixed_tokens": 1234, + "processed_tokens": 120581, + "tool_calls": 8, + "turns": 9 + }, + "ports-030": { + "answer": [ + "dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1", + "dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc" + ], + "tokens": 11968, + "fixed_tokens": 1231, + "processed_tokens": 102989, + "tool_calls": 8, + "turns": 9 + }, + "ports-031": { + "answer": [ + "iss-meridian-cert-activity-cards-missing-for-two-bio--k214cmfra7pyvvzq", + "iss-skiff-cert-docked-30-hz-judder-on-some-tvs--9nq2xg9mzash474g" + ], + "tokens": 29372, + "fixed_tokens": 1227, + "processed_tokens": 274555, + "tool_calls": 13, + "turns": 14 + }, + "ports-032": { + "answer": 2, + "tokens": 7216, + "fixed_tokens": 1232, + "processed_tokens": 64363, + "tool_calls": 6, + "turns": 7 + }, + "ports-033": { + "answer": "unknown", + "tokens": 22882, + "fixed_tokens": 1234, + "processed_tokens": 161834, + "tool_calls": 9, + "turns": 10 + }, + "render-001": { + "answer": "7.4 ms", + "tokens": 10391, + "fixed_tokens": 1233, + "processed_tokens": 85958, + "tool_calls": 7, + "turns": 8 + }, + "render-002": { + "answer": "3.4x", + "tokens": 25089, + "fixed_tokens": 1233, + "processed_tokens": 187257, + "tool_calls": 10, + "turns": 11 + }, + "render-003": { + "answer": "Tomasz Brandt", + "tokens": 26298, + "fixed_tokens": 1228, + "processed_tokens": 192599, + "tool_calls": 10, + "turns": 11 + }, + "render-004": { + "answer": "unknown", + "tokens": 17215, + "fixed_tokens": 1231, + "processed_tokens": 198339, + "tool_calls": 15, + "turns": 14 + }, + "render-005": { + "answer": true, + "tokens": 16380, + "fixed_tokens": 1229, + "processed_tokens": 169297, + "tool_calls": 11, + "turns": 12 + }, + "render-006": { + "answer": "unknown", + "tokens": 22299, + "fixed_tokens": 1234, + "processed_tokens": 330662, + "tool_calls": 21, + "turns": 20 + }, + "render-007": { + "answer": "unknown", + "tokens": 28065, + "fixed_tokens": 1228, + "processed_tokens": 641015, + "tool_calls": 30, + "turns": 31 + }, + "render-008": { + "answer": "2 failures", + "tokens": 35048, + "fixed_tokens": 1225, + "processed_tokens": 328604, + "tool_calls": 14, + "turns": 14 + }, + "render-009": { + "answer": "32 steps", + "tokens": 31177, + "fixed_tokens": 1234, + "processed_tokens": 339911, + "tool_calls": 14, + "turns": 15 + }, + "render-010": { + "answer": "unknown", + "tokens": 25280, + "fixed_tokens": 1228, + "processed_tokens": 189135, + "tool_calls": 10, + "turns": 11 + }, + "render-011": { + "answer": "fnd-sdf-gi-costs-2-4-ms-on-meridian--2w6c2pc5zmcsyjre", + "tokens": 21711, + "fixed_tokens": 1231, + "processed_tokens": 304969, + "tool_calls": 20, + "turns": 19 + }, + "render-012": { + "answer": "unknown", + "tokens": 32484, + "fixed_tokens": 1228, + "processed_tokens": 676254, + "tool_calls": 29, + "turns": 30 + }, + "render-013": { + "answer": "16-bit float per channel", + "tokens": 26423, + "fixed_tokens": 1227, + "processed_tokens": 191494, + "tool_calls": 10, + "turns": 11 + }, + "render-014": { + "answer": "unknown", + "tokens": 36207, + "fixed_tokens": 1227, + "processed_tokens": 555462, + "tool_calls": 24, + "turns": 25 + }, + "render-015": { + "answer": "unknown", + "tokens": 51327, + "fixed_tokens": 1226, + "processed_tokens": 712201, + "tool_calls": 22, + "turns": 23 + }, + "render-016": { + "answer": "1.2 km", + "tokens": 10056, + "fixed_tokens": 1226, + "processed_tokens": 117736, + "tool_calls": 10, + "turns": 11 + }, + "render-017": { + "answer": "unknown", + "tokens": 57046, + "fixed_tokens": 1228, + "processed_tokens": 2079672, + "tool_calls": 62, + "turns": 63 + }, + "render-018": { + "answer": "unknown", + "tokens": 31060, + "fixed_tokens": 1235, + "processed_tokens": 315078, + "tool_calls": 15, + "turns": 16 + }, + "render-019": { + "answer": "dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86", + "tokens": 29157, + "fixed_tokens": 1225, + "processed_tokens": 324278, + "tool_calls": 14, + "turns": 15 + }, + "render-020": { + "answer": "fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy", + "tokens": 26233, + "fixed_tokens": 1226, + "processed_tokens": 605587, + "tool_calls": 30, + "turns": 31 + }, + "render-021": { + "answer": "dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4", + "tokens": 10610, + "fixed_tokens": 1226, + "processed_tokens": 104259, + "tool_calls": 9, + "turns": 10 + }, + "render-022": { + "answer": "dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr", + "tokens": 10738, + "fixed_tokens": 1232, + "processed_tokens": 105721, + "tool_calls": 9, + "turns": 10 + }, + "render-023": { + "answer": "dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676", + "tokens": 24126, + "fixed_tokens": 1232, + "processed_tokens": 370002, + "tool_calls": 20, + "turns": 21 + }, + "render-024": { + "answer": "dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r", + "tokens": 13324, + "fixed_tokens": 1224, + "processed_tokens": 118599, + "tool_calls": 9, + "turns": 10 + }, + "render-025": { + "answer": "unknown", + "tokens": 39153, + "fixed_tokens": 1232, + "processed_tokens": 1077283, + "tool_calls": 40, + "turns": 41 + }, + "render-026": { + "answer": "dec-ship-four-tern-quality-presets--vjw18d82dx5gath8", + "tokens": 31485, + "fixed_tokens": 1224, + "processed_tokens": 346924, + "tool_calls": 15, + "turns": 16 + }, + "render-027": { + "answer": "con-frame-budget--j6vneva1g2ywj86m", + "tokens": 15284, + "fixed_tokens": 1231, + "processed_tokens": 95038, + "tool_calls": 7, + "turns": 8 + }, + "render-028": { + "answer": "dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee", + "tokens": 33703, + "fixed_tokens": 1232, + "processed_tokens": 560430, + "tool_calls": 21, + "turns": 22 + }, + "render-029": { + "answer": "fnd-vsm-page-pool-overflows-during-spring-tides--m2p8e89hhdmh0z8a", + "tokens": 14133, + "fixed_tokens": 1227, + "processed_tokens": 111977, + "tool_calls": 8, + "turns": 9 + }, + "render-030": { + "answer": "dec-use-screen-space-refraction-for-saltglass--vknzksgdrgr7zkg6", + "tokens": 30417, + "fixed_tokens": 1226, + "processed_tokens": 327284, + "tool_calls": 14, + "turns": 15 + }, + "render-031": { + "answer": "Alpha-tested foliage cost 2.1 ms in the visibility buffer, and a forward pass brought it to 0.8 ms; saltglass moved to a forward pass after the resolve so it could refract the resolved scene behind it. Record: dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9", + "tokens": 33594, + "fixed_tokens": 1227, + "processed_tokens": 422650, + "tool_calls": 17, + "turns": 18 + }, + "render-032": { + "answer": "Tern was chosen because Halcyon has no Skiff build, and shipping a second upscaler on two platforms would break the one-upscaler constraint; the team also wanted to own the upscaler code, since saltglass refraction and caustics need upscaler changes they can make the same week rather than vendor tickets (dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e).", + "tokens": 12485, + "fixed_tokens": 1226, + "processed_tokens": 106021, + "tool_calls": 8, + "turns": 9 + }, + "render-033": { + "answer": "128 MB", + "tokens": 22566, + "fixed_tokens": 1227, + "processed_tokens": 216728, + "tool_calls": 12, + "turns": 13 + }, + "render-034": { + "answer": "PC workstation (Meridian clock profile)", + "tokens": 37095, + "fixed_tokens": 1232, + "processed_tokens": 591424, + "tool_calls": 23, + "turns": 22 + }, + "render-035": { + "answer": "5912 pages", + "tokens": 21193, + "fixed_tokens": 1228, + "processed_tokens": 258687, + "tool_calls": 14, + "turns": 15 + }, + "render-036": { + "answer": "HDR-07", + "tokens": 28222, + "fixed_tokens": 1225, + "processed_tokens": 443862, + "tool_calls": 19, + "turns": 20 + }, + "render-037": { + "answer": "unknown", + "tokens": 43279, + "fixed_tokens": 1230, + "processed_tokens": 1148301, + "tool_calls": 40, + "turns": 41 + }, + "render-038": { + "answer": "dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9", + "tokens": 35739, + "fixed_tokens": 1232, + "processed_tokens": 480211, + "tool_calls": 18, + "turns": 19 + }, + "render-039": { + "answer": "dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e", + "tokens": 30080, + "fixed_tokens": 1227, + "processed_tokens": 304133, + "tool_calls": 15, + "turns": 14 + }, + "render-040": { + "answer": "fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c", + "tokens": 12553, + "fixed_tokens": 1226, + "processed_tokens": 88898, + "tool_calls": 7, + "turns": 8 + }, + "render-041": { + "answer": "4.7 ms", + "tokens": 37017, + "fixed_tokens": 1228, + "processed_tokens": 696495, + "tool_calls": 26, + "turns": 27 + }, + "render-042": { + "answer": "dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1", + "tokens": 16859, + "fixed_tokens": 1228, + "processed_tokens": 158696, + "tool_calls": 11, + "turns": 12 + }, + "render-043": { + "answer": "unknown", + "tokens": 31597, + "fixed_tokens": 1229, + "processed_tokens": 660905, + "tool_calls": 31, + "turns": 30 + }, + "render-044": { + "answer": "dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r", + "tokens": 24341, + "fixed_tokens": 1230, + "processed_tokens": 436838, + "tool_calls": 25, + "turns": 26 + }, + "render-045": { + "answer": "false dec-brine-curve-with-an-hdr-shoulder-at-800-nits--fpznx0cnj4avsxk1", + "tokens": 10540, + "fixed_tokens": 1231, + "processed_tokens": 85583, + "tool_calls": 7, + "turns": 8 + }, + "render-046": { + "answer": "Because the cost Finding that had sunk virtual shadow maps was a capture error: with cached pages, VSM costs 1.4 ms, less than four cascades (1.6 ms), and cascade seams through saltglass remained unsolved under CSM. (dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4)", + "tokens": 16292, + "fixed_tokens": 1232, + "processed_tokens": 171883, + "tool_calls": 12, + "turns": 12 + }, + "render-047": { + "answer": "Because the release-build capture showed the visibility buffer at 7.4 ms on Skiff versus 8.1 ms for forward+ (6.3 ms with material resolve at half rate), so the forward+ fallback was no longer worth keeping, and maintaining two opaque paths cost about one engineer-week a month in fixes. Record: dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1.", + "tokens": 35471, + "fixed_tokens": 1224, + "processed_tokens": 705633, + "tool_calls": 28, + "turns": 29 + }, + "render-048": { + "answer": "unknown", + "tokens": 37819, + "fixed_tokens": 1229, + "processed_tokens": 719600, + "tool_calls": 30, + "turns": 31 + }, + "render-049": { + "answer": "dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4", + "tokens": 29619, + "fixed_tokens": 1228, + "processed_tokens": 565307, + "tool_calls": 28, + "turns": 29 + }, + "render-050": { + "answer": "con-frame-budget--fzdrbxns6dmrrmy3", + "tokens": 15037, + "fixed_tokens": 1229, + "processed_tokens": 94525, + "tool_calls": 7, + "turns": 8 + }, + "render-051": { + "answer": "iss-tern-ghosting-on-moving-saltglass--2yr3q6zf476wajqp", + "tokens": 32983, + "fixed_tokens": 1231, + "processed_tokens": 319226, + "tool_calls": 13, + "turns": 14 + }, + "render-052": { + "answer": "61 percent", + "tokens": 21179, + "fixed_tokens": 1227, + "processed_tokens": 344989, + "tool_calls": 20, + "turns": 21 + }, + "render-053": { + "answer": "every frame", + "tokens": 21442, + "fixed_tokens": 1228, + "processed_tokens": 364374, + "tool_calls": 21, + "turns": 22 + }, + "render-054": { + "answer": "debug-gpu-validation", + "tokens": 21685, + "fixed_tokens": 1231, + "processed_tokens": 335689, + "tool_calls": 20, + "turns": 20 + }, + "render-055": { + "answer": "fnd-tern-cost-at-4k-output-on-meridian-with-the-reac--81tcpzvhwzcy6wyn", + "tokens": 41724, + "fixed_tokens": 1227, + "processed_tokens": 555432, + "tool_calls": 19, + "turns": 20 + }, + "render-056": { + "answer": "208,000 meshlets", + "tokens": 37471, + "fixed_tokens": 1226, + "processed_tokens": 764487, + "tool_calls": 26, + "turns": 27 + }, + "render-057": { + "answer": "dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1", + "tokens": 15401, + "fixed_tokens": 1224, + "processed_tokens": 146671, + "tool_calls": 10, + "turns": 11 + }, + "render-058": { + "answer": "iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v", + "tokens": 35016, + "fixed_tokens": 1234, + "processed_tokens": 597339, + "tool_calls": 21, + "turns": 22 + }, + "render-059": { + "answer": "fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr", + "tokens": 34731, + "fixed_tokens": 1232, + "processed_tokens": 600079, + "tool_calls": 24, + "turns": 25 + }, + "render-060": { + "answer": "0.31", + "tokens": 48732, + "fixed_tokens": 1226, + "processed_tokens": 1647095, + "tool_calls": 50, + "turns": 51 + }, + "render-061": { + "answer": "con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s", + "tokens": 16596, + "fixed_tokens": 1224, + "processed_tokens": 233923, + "tool_calls": 15, + "turns": 16 + }, + "render-062": { + "answer": "con-frame-budget--j6vneva1g2ywj86m", + "tokens": 15420, + "fixed_tokens": 1229, + "processed_tokens": 95428, + "tool_calls": 7, + "turns": 8 + }, + "render-063": { + "answer": "dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r", + "tokens": 42266, + "fixed_tokens": 1228, + "processed_tokens": 544624, + "tool_calls": 19, + "turns": 20 + }, + "render-064": { + "answer": "dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j", + "tokens": 40150, + "fixed_tokens": 1225, + "processed_tokens": 579974, + "tool_calls": 22, + "turns": 22 + }, + "render-065": { + "answer": "dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e", + "tokens": 34997, + "fixed_tokens": 1222, + "processed_tokens": 587368, + "tool_calls": 22, + "turns": 23 + }, + "render-066": { + "answer": "dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr", + "tokens": 23569, + "fixed_tokens": 1237, + "processed_tokens": 367088, + "tool_calls": 20, + "turns": 21 + }, + "render-067": { + "answer": 4, + "tokens": 25564, + "fixed_tokens": 1226, + "processed_tokens": 193695, + "tool_calls": 10, + "turns": 11 + }, + "render-068": { + "answer": [ + "dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4", + "dec-lock-caustic-photon-jitter-to-the-tide-phase--85x10k4h11t8nx7c", + "dec-use-the-probe-grid-alone-in-120-hz-performance-m--6dzm1nt40pjfpyae", + "dec-trace-sdf-gi-at-quarter-resolution-in-performanc--06cqt3mqn3fg5h6e", + "dec-read-paper-white-from-the-meridian-system-settin--7crbx73gqw1hn7xq", + "dec-add-an-in-game-paper-white-slider-from-80-to-400--1phfvxby983z8tjf" + ], + "tokens": 15182, + "fixed_tokens": 1229, + "processed_tokens": 94429, + "tool_calls": 7, + "turns": 8 + }, + "render-069": { + "answer": "iss-shadow-pages-run-out-at-spring-low-tide--f4fgy6b44jbkrsmh", + "tokens": 31008, + "fixed_tokens": 1212, + "processed_tokens": 231734, + "tool_calls": 11, + "turns": 12 + }, + "render-070": { + "answer": "unknown", + "tokens": 46614, + "fixed_tokens": 1229, + "processed_tokens": 880340, + "tool_calls": 40, + "turns": 31 + }, + "render-071": { + "answer": 3, + "tokens": 14084, + "fixed_tokens": 1226, + "processed_tokens": 92568, + "tool_calls": 7, + "turns": 8 + }, + "render-072": { + "answer": [ + "rsk-sdf-volumes-outgrow-the-render-target-memory-bud--xfd2pfztvskdcd2c", + "rsk-artists-cannot-match-concept-paintings-under-the--6cfh9vkamn0kbtcx" + ], + "tokens": 14149, + "fixed_tokens": 1225, + "processed_tokens": 92382, + "tool_calls": 7, + "turns": 8 + }, + "render-073": { + "answer": [ + "rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty", + "rsk-gi-cannot-fit-the-120-hz-performance-mode--tqt3fj839dqfq5s7", + "rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4" + ], + "tokens": 14733, + "fixed_tokens": 1228, + "processed_tokens": 93993, + "tool_calls": 7, + "turns": 8 + }, + "render-074": { + "answer": 5, + "tokens": 9129, + "fixed_tokens": 1228, + "processed_tokens": 67540, + "tool_calls": 6, + "turns": 7 + }, + "render-075": { + "answer": "3 decisions", + "tokens": 47908, + "fixed_tokens": 1227, + "processed_tokens": 990718, + "tool_calls": 32, + "turns": 33 + }, + "render-076": { + "answer": "false", + "tokens": 35671, + "fixed_tokens": 1225, + "processed_tokens": 503720, + "tool_calls": 19, + "turns": 20 + }, + "render-077": { + "answer": true, + "tokens": 4915, + "fixed_tokens": 1227, + "processed_tokens": 39706, + "tool_calls": 4, + "turns": 5 + }, + "render-078": { + "answer": [ + "dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e", + "rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4" + ], + "tokens": 8716, + "fixed_tokens": 1232, + "processed_tokens": 56378, + "tool_calls": 5, + "turns": 6 + }, + "render-079": { + "answer": 6, + "tokens": 11344, + "fixed_tokens": 1229, + "processed_tokens": 87978, + "tool_calls": 7, + "turns": 8 + }, + "render-080": { + "answer": "6", + "tokens": 11451, + "fixed_tokens": 1223, + "processed_tokens": 108334, + "tool_calls": 9, + "turns": 10 + }, + "render-081": { + "answer": "unknown", + "tokens": 31926, + "fixed_tokens": 1228, + "processed_tokens": 754903, + "tool_calls": 32, + "turns": 33 + }, + "render-082": { + "answer": false, + "tokens": 16600, + "fixed_tokens": 1226, + "processed_tokens": 226510, + "tool_calls": 15, + "turns": 16 + }, + "render-083": { + "answer": 6, + "tokens": 153096, + "fixed_tokens": 1227, + "processed_tokens": 8079168, + "tool_calls": 94, + "turns": 94 + }, + "tools-001": { + "answer": "completed", + "tokens": 10518, + "fixed_tokens": 1234, + "processed_tokens": 72863, + "tool_calls": 6, + "turns": 7 + }, + "tools-002": { + "answer": "47 minutes", + "tokens": 11850, + "fixed_tokens": 1233, + "processed_tokens": 117074, + "tool_calls": 9, + "turns": 10 + }, + "tools-003": { + "answer": "6 min 40 s", + "tokens": 6869, + "fixed_tokens": 1231, + "processed_tokens": 62585, + "tool_calls": 6, + "turns": 7 + }, + "tools-004": { + "answer": "unknown", + "tokens": 17143, + "fixed_tokens": 1236, + "processed_tokens": 190787, + "tool_calls": 12, + "turns": 13 + }, + "tools-005": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tokens": 25717, + "fixed_tokens": 1227, + "processed_tokens": 250920, + "tool_calls": 12, + "turns": 13 + }, + "tools-006": { + "answer": "dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh", + "tokens": 11644, + "fixed_tokens": 1233, + "processed_tokens": 137144, + "tool_calls": 11, + "turns": 12 + }, + "tools-007": { + "answer": "dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6", + "tokens": 41647, + "fixed_tokens": 1231, + "processed_tokens": 344665, + "tool_calls": 21, + "turns": 14 + }, + "tools-008": { + "answer": "dec-key-the-shader-cache-on-raw-source-text-and-comp--hp6awmx3gq5rn9nc", + "tokens": 25108, + "fixed_tokens": 1230, + "processed_tokens": 168622, + "tool_calls": 9, + "turns": 10 + }, + "tools-009": { + "answer": "92.4%", + "tokens": 26070, + "fixed_tokens": 1224, + "processed_tokens": 281067, + "tool_calls": 13, + "turns": 14 + }, + "tools-010": { + "answer": "dec-cap-each-farm-agent-at-6-parallel-shader-compile--q5w4sfjm73tsj8x8", + "tokens": 28939, + "fixed_tokens": 1231, + "processed_tokens": 193392, + "tool_calls": 12, + "turns": 11 + }, + "tools-011": { + "answer": "fnd-two-compiler-builds-with-the-same-version-string--gmgr4ha0ndxqmcn9", + "tokens": 24073, + "fixed_tokens": 1229, + "processed_tokens": 221395, + "tool_calls": 12, + "turns": 13 + }, + "tools-012": { + "answer": 3, + "tokens": 12693, + "fixed_tokens": 1229, + "processed_tokens": 119192, + "tool_calls": 9, + "turns": 10 + }, + "tools-013": { + "answer": 8, + "tokens": 10017, + "fixed_tokens": 1234, + "processed_tokens": 71922, + "tool_calls": 6, + "turns": 7 + }, + "tools-014": { + "answer": false, + "tokens": 12122, + "fixed_tokens": 1234, + "processed_tokens": 89296, + "tool_calls": 9, + "turns": 8 + }, + "tools-015": { + "answer": [ + "rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd", + "iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj", + "iss-whether-the-artist-sandbox-should-load-on-a-work--73j819anqct8etfn", + "iss-whether-the-artist-sandbox-should-be-split-into--ek47ca2vgmrjanp8", + "iss-whether-the-level-editor-autosave-needs-its-own--rkvmnbqe7w644zkr", + "iss-whether-the-level-editor-autosave-should-be-cach--radcjs4hyvh7p55q", + "iss-whether-the-review-bot-should-load-on-a-worker-t--rtsjwvsksjdq15v1", + "iss-whether-the-crash-symbol-server-should-load-on-a--qvyphhgnsnm2cvqb", + "iss-whether-the-doc-site-should-load-on-a-worker-thr--qxswe0pg52ekky0z", + "iss-whether-the-asset-search-should-load-on-a-worker--f9gpv3z522x6p6h4", + "iss-whether-the-license-scanner-should-be-cached-bet--nqhd89czbfat9rya", + "iss-whether-the-audio-bank-packer-should-load-on-a-w--sqzp2rwp6s01w3b0" + ], + "tokens": 50797, + "fixed_tokens": 1228, + "processed_tokens": 515432, + "tool_calls": 26, + "turns": 18 + }, + "tools-016": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tokens": 37768, + "fixed_tokens": 1230, + "processed_tokens": 586266, + "tool_calls": 22, + "turns": 23 + }, + "world-001": { + "answer": "64 KB", + "tokens": 29379, + "fixed_tokens": 1229, + "processed_tokens": 262491, + "tool_calls": 12, + "turns": 13 + }, + "world-002": { + "answer": "5.1 ms", + "tokens": 11213, + "fixed_tokens": 1231, + "processed_tokens": 135038, + "tool_calls": 11, + "turns": 12 + }, + "world-003": { + "answer": "1 crash per 900 script waits", + "tokens": 37699, + "fixed_tokens": 1229, + "processed_tokens": 566787, + "tool_calls": 20, + "turns": 21 + }, + "world-004": { + "answer": "4,100 file opens", + "tokens": 35215, + "fixed_tokens": 1225, + "processed_tokens": 431739, + "tool_calls": 17, + "turns": 18 + }, + "world-005": { + "answer": "unknown", + "tokens": 37661, + "fixed_tokens": 1235, + "processed_tokens": 352753, + "tool_calls": 14, + "turns": 15 + }, + "world-006": { + "answer": "unknown", + "tokens": 19925, + "fixed_tokens": 1231, + "processed_tokens": 316536, + "tool_calls": 18, + "turns": 19 + }, + "world-007": { + "answer": "260 MB", + "tokens": 14711, + "fixed_tokens": 1227, + "processed_tokens": 206482, + "tool_calls": 15, + "turns": 16 + }, + "world-008": { + "answer": "10 Hz", + "tokens": 12554, + "fixed_tokens": 1222, + "processed_tokens": 106470, + "tool_calls": 8, + "turns": 9 + }, + "world-009": { + "answer": "unknown", + "tokens": 52706, + "fixed_tokens": 1229, + "processed_tokens": 843764, + "tool_calls": 23, + "turns": 24 + }, + "world-010": { + "answer": "unknown", + "tokens": 12970, + "fixed_tokens": 1229, + "processed_tokens": 89294, + "tool_calls": 7, + "turns": 8 + }, + "world-011": { + "answer": "unknown", + "tokens": 43677, + "fixed_tokens": 1226, + "processed_tokens": 756959, + "tool_calls": 26, + "turns": 25 + }, + "world-012": { + "answer": "dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3", + "tokens": 11894, + "fixed_tokens": 1223, + "processed_tokens": 104554, + "tool_calls": 8, + "turns": 9 + }, + "world-013": { + "answer": "unknown", + "tokens": 24356, + "fixed_tokens": 1230, + "processed_tokens": 391408, + "tool_calls": 23, + "turns": 21 + }, + "world-014": { + "answer": "unknown", + "tokens": 29386, + "fixed_tokens": 1227, + "processed_tokens": 317611, + "tool_calls": 14, + "turns": 15 + }, + "world-015": { + "answer": "3.0 ms per frame", + "tokens": 35175, + "fixed_tokens": 1232, + "processed_tokens": 386807, + "tool_calls": 16, + "turns": 16 + }, + "world-016": { + "answer": "unknown", + "tokens": 23993, + "fixed_tokens": 1230, + "processed_tokens": 139319, + "tool_calls": 8, + "turns": 9 + }, + "world-017": { + "answer": "dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw", + "tokens": 30976, + "fixed_tokens": 1226, + "processed_tokens": 330481, + "tool_calls": 14, + "turns": 15 + }, + "world-018": { + "answer": "dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x", + "tokens": 24944, + "fixed_tokens": 1225, + "processed_tokens": 131570, + "tool_calls": 8, + "turns": 9 + }, + "world-019": { + "answer": "fnd-tide-priority-reads-starve-player-proximity-load--by0d7b0bk39xz3rk", + "tokens": 30901, + "fixed_tokens": 1230, + "processed_tokens": 361807, + "tool_calls": 15, + "turns": 16 + }, + "world-020": { + "answer": "dec-schedule-streaming-reads-by-deadline-instead-of--q2x5aknabgcssdj2", + "tokens": 17399, + "fixed_tokens": 1226, + "processed_tokens": 273962, + "tool_calls": 18, + "turns": 19 + }, + "world-021": { + "answer": "dec-cut-navigation-tiles-to-64-m-so-three-fit-along--snvepk8ygeb3qsjs", + "tokens": 18889, + "fixed_tokens": 1227, + "processed_tokens": 162961, + "tool_calls": 10, + "turns": 11 + }, + "world-022": { + "answer": "fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m", + "tokens": 20475, + "fixed_tokens": 1224, + "processed_tokens": 166607, + "tool_calls": 12, + "turns": 11 + }, + "world-023": { + "answer": "dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m", + "tokens": 37251, + "fixed_tokens": 1230, + "processed_tokens": 412119, + "tool_calls": 16, + "turns": 17 + }, + "world-024": { + "answer": "dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew", + "tokens": 38027, + "fixed_tokens": 1225, + "processed_tokens": 440477, + "tool_calls": 18, + "turns": 19 + }, + "world-025": { + "answer": "con-streaming-pool-budget--kca88sgh2j6sxvd5", + "tokens": 11490, + "fixed_tokens": 1231, + "processed_tokens": 71363, + "tool_calls": 6, + "turns": 7 + }, + "world-026": { + "answer": "fnd-retail-skiff-units-sustain-only-190-mb-s-of-stre--485sdcmm3gweevvn", + "tokens": 61620, + "fixed_tokens": 1226, + "processed_tokens": 1635792, + "tool_calls": 43, + "turns": 44 + }, + "world-027": { + "answer": "160 MB/s", + "tokens": 30954, + "fixed_tokens": 1228, + "processed_tokens": 235575, + "tool_calls": 12, + "turns": 13 + }, + "world-028": { + "answer": "unknown", + "tokens": 43961, + "fixed_tokens": 1231, + "processed_tokens": 753029, + "tool_calls": 25, + "turns": 26 + }, + "world-029": { + "answer": "dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h", + "tokens": 29797, + "fixed_tokens": 1226, + "processed_tokens": 323920, + "tool_calls": 15, + "turns": 16 + }, + "world-030": { + "answer": "fnd-world-core-state-at-alpha--tkbsm4867h65jqq8", + "tokens": 11386, + "fixed_tokens": 1224, + "processed_tokens": 131612, + "tool_calls": 11, + "turns": 12 + }, + "world-031": { + "answer": "1.5 GB/s", + "tokens": 12413, + "fixed_tokens": 1230, + "processed_tokens": 115518, + "tool_calls": 11, + "turns": 10 + }, + "world-032": { + "answer": "unknown", + "tokens": 37503, + "fixed_tokens": 1229, + "processed_tokens": 404056, + "tool_calls": 17, + "turns": 18 + }, + "world-033": { + "answer": "dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw", + "tokens": 34507, + "fixed_tokens": 1232, + "processed_tokens": 478817, + "tool_calls": 18, + "turns": 19 + }, + "world-034": { + "answer": "unknown", + "tokens": 55002, + "fixed_tokens": 1225, + "processed_tokens": 1294605, + "tool_calls": 30, + "turns": 31 + }, + "world-035": { + "answer": "false, dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3", + "tokens": 13310, + "fixed_tokens": 1232, + "processed_tokens": 124233, + "tool_calls": 9, + "turns": 10 + }, + "world-036": { + "answer": "Kestrel retired fibers for engine jobs on 2026-04-14 because 41% of alpha crash reports had no usable stack, which blocked crash triage for beta. The fiber scheduler bought only about two points of utilisation (95% vs 93% for continuations), not enough to outweigh the unreadable crashes and the Gull thread-local bug. See dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h.", + "tokens": 15432, + "fixed_tokens": 1228, + "processed_tokens": 142569, + "tool_calls": 12, + "turns": 11 + }, + "world-037": { + "answer": "fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws", + "tokens": 28700, + "fixed_tokens": 1228, + "processed_tokens": 599577, + "tool_calls": 27, + "turns": 28 + }, + "world-038": { + "answer": "3 archetypes", + "tokens": 32278, + "fixed_tokens": 1227, + "processed_tokens": 462511, + "tool_calls": 18, + "turns": 19 + }, + "world-039": { + "answer": "unknown", + "tokens": 36641, + "fixed_tokens": 1232, + "processed_tokens": 625202, + "tool_calls": 29, + "turns": 25 + }, + "world-040": { + "answer": "unknown", + "tokens": 16572, + "fixed_tokens": 1229, + "processed_tokens": 212743, + "tool_calls": 16, + "turns": 15 + }, + "world-041": { + "answer": "61%", + "tokens": 45212, + "fixed_tokens": 1227, + "processed_tokens": 761624, + "tool_calls": 22, + "turns": 23 + }, + "world-042": { + "answer": "5.4 s", + "tokens": 21412, + "fixed_tokens": 1233, + "processed_tokens": 311533, + "tool_calls": 18, + "turns": 19 + }, + "world-043": { + "answer": "unknown", + "tokens": 26208, + "fixed_tokens": 1224, + "processed_tokens": 450195, + "tool_calls": 23, + "turns": 24 + }, + "world-044": { + "answer": "dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq", + "tokens": 30571, + "fixed_tokens": 1230, + "processed_tokens": 326932, + "tool_calls": 14, + "turns": 15 + }, + "world-045": { + "answer": "dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te", + "tokens": 29815, + "fixed_tokens": 1234, + "processed_tokens": 262312, + "tool_calls": 12, + "turns": 13 + }, + "world-046": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tokens": 14642, + "fixed_tokens": 1223, + "processed_tokens": 174333, + "tool_calls": 12, + "turns": 13 + }, + "world-047": { + "answer": "fnd-world-core-state-at-alpha--tkbsm4867h65jqq8", + "tokens": 11252, + "fixed_tokens": 1227, + "processed_tokens": 87974, + "tool_calls": 7, + "turns": 8 + }, + "world-048": { + "answer": "unknown", + "tokens": 48735, + "fixed_tokens": 1224, + "processed_tokens": 1018933, + "tool_calls": 34, + "turns": 35 + }, + "world-049": { + "answer": "22%", + "tokens": 38734, + "fixed_tokens": 1228, + "processed_tokens": 824541, + "tool_calls": 27, + "turns": 28 + }, + "world-050": { + "answer": "unknown", + "tokens": 30519, + "fixed_tokens": 1230, + "processed_tokens": 394004, + "tool_calls": 19, + "turns": 20 + }, + "world-051": { + "answer": "Float tides drifted apart between machines within 6 minutes, from FMA contraction and a Skiff sin() that differed by one ulp, and integer fixed point gives identical bits on every CPU and compiler with no platform math library; the graph does not record a strict IEEE mode comparison. dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e", + "tokens": 13268, + "fixed_tokens": 1225, + "processed_tokens": 120584, + "tool_calls": 9, + "turns": 10 + }, + "world-052": { + "answer": "Dara Whitlock", + "tokens": 15254, + "fixed_tokens": 1224, + "processed_tokens": 193996, + "tool_calls": 13, + "turns": 14 + }, + "world-053": { + "answer": "1.9 ms", + "tokens": 28873, + "fixed_tokens": 1225, + "processed_tokens": 299354, + "tool_calls": 14, + "turns": 14 + }, + "world-054": { + "answer": "Marta Lindqvist", + "tokens": 19683, + "fixed_tokens": 1225, + "processed_tokens": 276307, + "tool_calls": 16, + "turns": 17 + }, + "world-055": { + "answer": "unknown", + "tokens": 27116, + "fixed_tokens": 1222, + "processed_tokens": 191319, + "tool_calls": 12, + "turns": 11 + }, + "world-056": { + "answer": "dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x", + "tokens": 29502, + "fixed_tokens": 1229, + "processed_tokens": 198553, + "tool_calls": 12, + "turns": 11 + }, + "world-057": { + "answer": "[212, 87]", + "tokens": 20353, + "fixed_tokens": 1231, + "processed_tokens": 319048, + "tool_calls": 18, + "turns": 19 + }, + "world-058": { + "answer": "0.8 GB/s", + "tokens": 21195, + "fixed_tokens": 1232, + "processed_tokens": 329211, + "tool_calls": 18, + "turns": 19 + }, + "world-059": { + "answer": "dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw", + "tokens": 16331, + "fixed_tokens": 1227, + "processed_tokens": 184900, + "tool_calls": 12, + "turns": 13 + }, + "world-060": { + "answer": "dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc", + "tokens": 20518, + "fixed_tokens": 1224, + "processed_tokens": 254234, + "tool_calls": 14, + "turns": 15 + }, + "world-061": { + "answer": "236 MB", + "tokens": 38558, + "fixed_tokens": 1224, + "processed_tokens": 616285, + "tool_calls": 24, + "turns": 25 + }, + "world-062": { + "answer": "310 MB", + "tokens": 16647, + "fixed_tokens": 1231, + "processed_tokens": 225628, + "tool_calls": 16, + "turns": 16 + }, + "world-063": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tokens": 20550, + "fixed_tokens": 1227, + "processed_tokens": 333850, + "tool_calls": 19, + "turns": 20 + }, + "world-064": { + "answer": [ + "dec-force-strict-ieee-float-mode-for-the-tide-simula--ecwmqt7ncjngysqw", + "dec-have-the-host-stream-tide-heights-to-every-peer--a3rb1seedn2bj7k8" + ], + "tokens": 44350, + "fixed_tokens": 1228, + "processed_tokens": 620527, + "tool_calls": 23, + "turns": 24 + }, + "world-065": { + "answer": "3.1 ms", + "tokens": 45268, + "fixed_tokens": 1225, + "processed_tokens": 1216788, + "tool_calls": 39, + "turns": 39 + }, + "world-066": { + "answer": "46", + "tokens": 18135, + "fixed_tokens": 1230, + "processed_tokens": 219991, + "tool_calls": 13, + "turns": 14 + }, + "world-067": { + "answer": "1.2 GB/s", + "tokens": 22471, + "fixed_tokens": 1225, + "processed_tokens": 302638, + "tool_calls": 16, + "turns": 17 + }, + "world-068": { + "answer": false, + "tokens": 9013, + "fixed_tokens": 1232, + "processed_tokens": 56505, + "tool_calls": 5, + "turns": 6 + }, + "world-069": { + "answer": 7, + "tokens": 10147, + "fixed_tokens": 1226, + "processed_tokens": 72143, + "tool_calls": 6, + "turns": 7 + }, + "world-070": { + "answer": 3, + "tokens": 13075, + "fixed_tokens": 1233, + "processed_tokens": 121323, + "tool_calls": 9, + "turns": 10 + }, + "world-071": { + "answer": [ + "dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w" + ], + "tokens": 59297, + "fixed_tokens": 1227, + "processed_tokens": 543819, + "tool_calls": 47, + "turns": 17 + }, + "world-072": { + "answer": [ + "dec-compress-streamed-assets-with-zstandard--bs1t15cygc51cpje", + "dec-compress-streamed-assets-with-lz4--v1pfsgfp0b3yjv4s" + ], + "tokens": 48008, + "fixed_tokens": 1225, + "processed_tokens": 702454, + "tool_calls": 21, + "turns": 22 + }, + "world-073": { + "answer": false, + "tokens": 41421, + "fixed_tokens": 1226, + "processed_tokens": 641285, + "tool_calls": 21, + "turns": 22 + }, + "world-074": { + "answer": 7, + "tokens": 10411, + "fixed_tokens": 1224, + "processed_tokens": 73585, + "tool_calls": 6, + "turns": 7 + }, + "world-075": { + "answer": [ + "dec-store-components-in-archetype-tables-and-volatil--8679sjn071ycsbpv", + "dec-partition-the-world-into-192-meter-cells--q62ddwdv2n8wxay6", + "dec-return-engine-jobs-to-the-thread-pool-with-conti--547qbweqvrp1j5g3" + ], + "tokens": 28428, + "fixed_tokens": 1231, + "processed_tokens": 445505, + "tool_calls": 23, + "turns": 22 + }, + "world-076": { + "answer": "dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3", + "tokens": 25180, + "fixed_tokens": 1230, + "processed_tokens": 446372, + "tool_calls": 23, + "turns": 24 + }, + "world-077": { + "answer": 251, + "tokens": 146053, + "fixed_tokens": 1222, + "processed_tokens": 1974084, + "tool_calls": 26, + "turns": 27 + }, + "world-078": { + "answer": [ + "rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew", + "rsk-reworking-the-read-scheduler-may-slip-the-coast--9jzvs7etvb5jxqtp" + ], + "tokens": 11814, + "fixed_tokens": 1225, + "processed_tokens": 72232, + "tool_calls": 6, + "turns": 7 + }, + "world-079": { + "answer": [ + "con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73", + "con-saves-from-beta-onward-must-load-in-every-later--v6z856sxtgc5sb09", + "con-streaming-pool-budget--8czwb4fjr5p5vpy7" + ], + "tokens": 14890, + "fixed_tokens": 1227, + "processed_tokens": 93946, + "tool_calls": 7, + "turns": 8 + }, + "world-080": { + "answer": [ + "iss-gull-hot-reload-rejects-struct-layout-changes--3v2w2f9hg2gwy6aj", + "iss-gull-hot-reload-drops-suspended-coroutines--z7j2gmyny6gdxd07", + "iss-cross-platform-cloud-saves-are-unplanned--5bk0k4wrgj42ztfy" + ], + "tokens": 12468, + "fixed_tokens": 1236, + "processed_tokens": 104374, + "tool_calls": 8, + "turns": 9 + }, + "world-081": { + "answer": "rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew", + "tokens": 48088, + "fixed_tokens": 1231, + "processed_tokens": 635583, + "tool_calls": 32, + "turns": 20 + } + } +} diff --git a/benchmarks/proof-recall/runs/x10-haiku-nobrief.json b/benchmarks/proof-recall/runs/x10-haiku-nobrief.json new file mode 100644 index 00000000..4a02a83e --- /dev/null +++ b/benchmarks/proof-recall/runs/x10-haiku-nobrief.json @@ -0,0 +1,2041 @@ +{ + "run": { + "name": "x10-haiku-nobrief", + "protocol": "one fresh session per question", + "models": ["claude-haiku-5-5"] + }, + "answers": { + "cross-001": { + "answer": "con-frame-budget--br0qszfg8fys908n", + "tokens": 38635, + "fixed_tokens": 1240, + "processed_tokens": 407687, + "tool_calls": 14, + "turns": 15 + }, + "cross-002": { + "answer": 2, + "tokens": 26265, + "fixed_tokens": 1230, + "processed_tokens": 105536, + "tool_calls": 14, + "turns": 7 + }, + "cross-003": { + "answer": 2, + "tokens": 22003, + "fixed_tokens": 1236, + "processed_tokens": 167581, + "tool_calls": 14, + "turns": 11 + }, + "cross-004": { + "answer": "dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e", + "tokens": 25503, + "fixed_tokens": 1238, + "processed_tokens": 361831, + "tool_calls": 16, + "turns": 17 + }, + "cross-005": { + "answer": "Rhea Valdés", + "tokens": 41121, + "fixed_tokens": 1237, + "processed_tokens": 636540, + "tool_calls": 20, + "turns": 21 + }, + "cross-006": { + "answer": "about 19% (4.8 ms of the 25 ms frame at 40 Hz)", + "tokens": 29206, + "fixed_tokens": 1234, + "processed_tokens": 357400, + "tool_calls": 15, + "turns": 16 + }, + "cross-007": { + "answer": "8 GB", + "tokens": 65784, + "fixed_tokens": 1240, + "processed_tokens": 1915572, + "tool_calls": 46, + "turns": 46 + }, + "cross-008": { + "answer": "unknown", + "tokens": 41367, + "fixed_tokens": 1237, + "processed_tokens": 771014, + "tool_calls": 25, + "turns": 26 + }, + "cross-009": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tokens": 46147, + "fixed_tokens": 1240, + "processed_tokens": 466009, + "tool_calls": 15, + "turns": 16 + }, + "cross-010": { + "answer": "dec-build-an-on-device-pipeline-cache-for-skiff--726r9mtk76qndeh7", + "tokens": 49186, + "fixed_tokens": 1231, + "processed_tokens": 372396, + "tool_calls": 12, + "turns": 13 + }, + "cross-011": { + "answer": false, + "tokens": 40601, + "fixed_tokens": 1237, + "processed_tokens": 515170, + "tool_calls": 16, + "turns": 17 + }, + "cross-012": { + "answer": "unknown", + "tokens": 49725, + "fixed_tokens": 702, + "processed_tokens": 1187396, + "tool_calls": 35, + "turns": 36 + }, + "cross-013": { + "answer": "unknown", + "tokens": 56606, + "fixed_tokens": 698, + "processed_tokens": 1535087, + "tool_calls": 39, + "turns": 39 + }, + "cross-014": { + "answer": 3, + "tokens": 5883, + "fixed_tokens": 1236, + "processed_tokens": 41807, + "tool_calls": 4, + "turns": 5 + }, + "cross-015": { + "answer": "Two Efforts are no longer active. Shader compile cache and build farm is completed: its end condition (every farm build reads from the cache) was met when dec-turn-the-shader-compile-cache-on-for-every-farm--4rr3b12b4sasdmaj was accepted on 2026-03-20. Co-op rollback netcode prototype is abandoned: dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b was accepted on 2026-04-01, stopping rollback because re-running tides on every rolled-back frame costs 4.8 ms on Skiff.", + "tokens": 37116, + "fixed_tokens": 1236, + "processed_tokens": 315164, + "tool_calls": 13, + "turns": 12 + }, + "cross-016": { + "answer": "16.7 ms", + "tokens": 27282, + "fixed_tokens": 696, + "processed_tokens": 186981, + "tool_calls": 9, + "turns": 10 + }, + "cross-017": { + "answer": "false", + "tokens": 23668, + "fixed_tokens": 697, + "processed_tokens": 254307, + "tool_calls": 15, + "turns": 15 + }, + "netcode-001": { + "answer": "abandoned", + "tokens": 5415, + "fixed_tokens": 706, + "processed_tokens": 41932, + "tool_calls": 4, + "turns": 5 + }, + "netcode-002": { + "answer": "netcode/rollback-archive", + "tokens": 17981, + "fixed_tokens": 697, + "processed_tokens": 118006, + "tool_calls": 7, + "turns": 8 + }, + "netcode-003": { + "answer": "unknown", + "tokens": 51215, + "fixed_tokens": 705, + "processed_tokens": 575805, + "tool_calls": 17, + "turns": 18 + }, + "netcode-004": { + "answer": "Rollback was abandoned because re-running the tide simulation on every rolled-back frame costs 4.8 ms on Skiff, about a fifth of the 25 ms frame, and the tide state must stay bit-for-bit deterministic (dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b). The reason depends on the world Decision \"Run the tide simulation in 32.32 fixed point\" (dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e), which keeps tides deterministic and so forces the re-simulation.", + "tokens": 28984, + "fixed_tokens": 705, + "processed_tokens": 497750, + "tool_calls": 20, + "turns": 21 + }, + "netcode-005": { + "answer": "unknown", + "tokens": 26666, + "fixed_tokens": 701, + "processed_tokens": 289572, + "tool_calls": 13, + "turns": 14 + }, + "netcode-006": { + "answer": "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "tokens": 10949, + "fixed_tokens": 700, + "processed_tokens": 112732, + "tool_calls": 9, + "turns": 10 + }, + "netcode-007": { + "answer": "dec-abandon-rollback-netcode-for-co-op--46envrg0v4pdwv7b", + "tokens": 9410, + "fixed_tokens": 697, + "processed_tokens": 83856, + "tool_calls": 7, + "turns": 8 + }, + "netcode-008": { + "answer": "dec-use-a-4-frame-rollback-window--pqe4hvbgmbp0dmh9", + "tokens": 23268, + "fixed_tokens": 700, + "processed_tokens": 197406, + "tool_calls": 10, + "turns": 11 + }, + "netcode-009": { + "answer": "1.9 ms", + "tokens": 27066, + "fixed_tokens": 701, + "processed_tokens": 320120, + "tool_calls": 14, + "turns": 15 + }, + "netcode-010": { + "answer": "dec-use-a-6-frame-rollback-window-with-1-frame-of-in--s53944zhkw103frk", + "tokens": 65902, + "fixed_tokens": 704, + "processed_tokens": 757920, + "tool_calls": 19, + "turns": 20 + }, + "netcode-011": { + "answer": "con-co-op-peers-must-agree-on-tide-state-bit-for-bit--4v0sdbc3t4ywzr3g", + "tokens": 41750, + "fixed_tokens": 1243, + "processed_tokens": 711765, + "tool_calls": 22, + "turns": 23 + }, + "netcode-012": { + "answer": "dec-re-simulate-tides-at-quarter-resolution-during-r--7ah25p0r0xt9719f", + "tokens": 37923, + "fixed_tokens": 1235, + "processed_tokens": 710257, + "tool_calls": 24, + "turns": 25 + }, + "netcode-013": { + "answer": [ + "dec-prototype-rollback-netcode-for-co-op--2tx2s2p3sfbwj8x4", + "fnd-rollback-re-simulates-a-4-frame-window-in-1-1-ms--xa30a1cez2brphyf", + "rsk-re-simulation-cost-could-blow-the-skiff-frame-bu--sk2njsp170a3qwyf" + ], + "tokens": 37530, + "fixed_tokens": 1241, + "processed_tokens": 306863, + "tool_calls": 27, + "turns": 13 + }, + "netcode-014": { + "answer": [ + "iss-how-should-co-op-keep-up-to-four-players-in-sync--92t2zfsy3etfzr89", + "iss-late-join-during-a-tide-surge-desyncs-the-joinin--mya93va0n7s8g7cj" + ], + "tokens": 76914, + "fixed_tokens": 1242, + "processed_tokens": 1173964, + "tool_calls": 24, + "turns": 25 + }, + "netcode-015": { + "answer": 2, + "tokens": 14054, + "fixed_tokens": 1241, + "processed_tokens": 100007, + "tool_calls": 8, + "turns": 9 + }, + "ports-001": { + "answer": "25 ms", + "tokens": 19672, + "fixed_tokens": 1235, + "processed_tokens": 165455, + "tool_calls": 9, + "turns": 10 + }, + "ports-002": { + "answer": "unknown", + "tokens": 77514, + "fixed_tokens": 1238, + "processed_tokens": 846971, + "tool_calls": 18, + "turns": 19 + }, + "ports-003": { + "answer": "61 MB/s", + "tokens": 46157, + "fixed_tokens": 1244, + "processed_tokens": 1358208, + "tool_calls": 40, + "turns": 41 + }, + "ports-004": { + "answer": "accepted", + "tokens": 20583, + "fixed_tokens": 1238, + "processed_tokens": 130973, + "tool_calls": 8, + "turns": 9 + }, + "ports-005": { + "answer": "unknown", + "tokens": 60236, + "fixed_tokens": 1237, + "processed_tokens": 2369663, + "tool_calls": 63, + "turns": 64 + }, + "ports-034": { + "answer": "unknown", + "tokens": 36647, + "fixed_tokens": 1241, + "processed_tokens": 585983, + "tool_calls": 21, + "turns": 22 + }, + "ports-006": { + "answer": "con-skiff-memory-budget--nf7qbhsnmcn6v479", + "tokens": 17804, + "fixed_tokens": 1235, + "processed_tokens": 115459, + "tool_calls": 7, + "turns": 8 + }, + "ports-007": { + "answer": "SKF-UI-031", + "tokens": 47551, + "fixed_tokens": 1233, + "processed_tokens": 1599027, + "tool_calls": 52, + "turns": 53 + }, + "ports-008": { + "answer": "dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3", + "tokens": 7714, + "fixed_tokens": 1237, + "processed_tokens": 63942, + "tool_calls": 6, + "turns": 7 + }, + "ports-009": { + "answer": "unknown", + "tokens": 29030, + "fixed_tokens": 1239, + "processed_tokens": 641806, + "tool_calls": 26, + "turns": 27 + }, + "ports-010": { + "answer": "unknown", + "tokens": 41526, + "fixed_tokens": 1240, + "processed_tokens": 1003126, + "tool_calls": 31, + "turns": 32 + }, + "ports-011": { + "answer": "unknown", + "tokens": 96646, + "fixed_tokens": 1238, + "processed_tokens": 1432198, + "tool_calls": 23, + "turns": 24 + }, + "ports-012": { + "answer": "Saltglass caustic patterns shimmered badly in motion at the 540p floor (7 of 10 dune views, versus 2 of 10 at 576p), so the floor was raised to 576p in dec-raise-the-skiff-dynamic-resolution-floor-to-576p--fep9q7m08pp9f0bb, based on fnd-saltglass-caustics-shimmer-at-the-540p-floor--0aa8sts89vhq1s6q. The 576p decision has since been superseded by a later decision to lower the floor to 504p.", + "tokens": 24667, + "fixed_tokens": 1232, + "processed_tokens": 233966, + "tool_calls": 11, + "turns": 12 + }, + "ports-013": { + "answer": "Ship Tern as Lantern's only upscaler", + "tokens": 47165, + "fixed_tokens": 1241, + "processed_tokens": 551621, + "tool_calls": 17, + "turns": 18 + }, + "ports-014": { + "answer": "dec-scale-skiff-resolution-dynamically-between-540p--jtytvgh2erd32x68", + "tokens": 69415, + "fixed_tokens": 1239, + "processed_tokens": 1860573, + "tool_calls": 38, + "turns": 38 + }, + "ports-015": { + "answer": "textures", + "tokens": 19581, + "fixed_tokens": 1241, + "processed_tokens": 306245, + "tool_calls": 18, + "turns": 19 + }, + "ports-016": { + "answer": "dec-ship-prebuilt-pipeline-blobs-in-the-skiff-packag--3vjysjgy9qkvzebn", + "tokens": 33408, + "fixed_tokens": 1239, + "processed_tokens": 602664, + "tool_calls": 23, + "turns": 24 + }, + "ports-017": { + "answer": "unknown", + "tokens": 46717, + "fixed_tokens": 1232, + "processed_tokens": 994919, + "tool_calls": 29, + "turns": 30 + }, + "ports-018": { + "answer": "504p", + "tokens": 21467, + "fixed_tokens": 1236, + "processed_tokens": 171141, + "tool_calls": 9, + "turns": 10 + }, + "ports-019": { + "answer": "4 MB per minute", + "tokens": 40606, + "fixed_tokens": 1232, + "processed_tokens": 993288, + "tool_calls": 32, + "turns": 33 + }, + "ports-020": { + "answer": "fnd-skiff-sdk-1-2-takes-1-gb-back-from-games--a0ybdgjzw64hwfqa", + "tokens": 20125, + "fixed_tokens": 1233, + "processed_tokens": 164740, + "tool_calls": 9, + "turns": 10 + }, + "ports-021": { + "answer": "SKF-DSP-004", + "tokens": 88916, + "fixed_tokens": 1237, + "processed_tokens": 2571301, + "tool_calls": 42, + "turns": 42 + }, + "ports-022": { + "answer": "cit-skiff-sdk-1-2-release-notes--7gwwn8xxffrx6npe", + "tokens": 26501, + "fixed_tokens": 1237, + "processed_tokens": 350686, + "tool_calls": 15, + "turns": 16 + }, + "ports-023": { + "answer": "fnd-tern-costs-3-9-ms-at-quality-and-2-1-ms-at-perfo--dkbskbqfgfwtryq0", + "tokens": 17575, + "fixed_tokens": 1243, + "processed_tokens": 247257, + "tool_calls": 17, + "turns": 17 + }, + "ports-024": { + "answer": "fnd-skiff-firmware-1-2-rejects-pipeline-blobs-built--pernvgb2he7m3z3y", + "tokens": 36600, + "fixed_tokens": 1241, + "processed_tokens": 706598, + "tool_calls": 25, + "turns": 26 + }, + "ports-025": { + "answer": "dec-run-tern-on-skiff-at-the-performance-preset--74eqayfa83ybqpe3", + "tokens": 69570, + "fixed_tokens": 1239, + "processed_tokens": 771309, + "tool_calls": 18, + "turns": 19 + }, + "ports-026": { + "answer": "unknown", + "tokens": 31675, + "fixed_tokens": 1233, + "processed_tokens": 401886, + "tool_calls": 17, + "turns": 17 + }, + "ports-027": { + "answer": [ + "rsk-tide-streaming-outruns-skiff-storage--6q8s3b383z2tyeyb", + "dec-stream-skiff-world-tiles-in-2-mb-reads--3jz9w9gvhhc7eppw" + ], + "tokens": 72711, + "fixed_tokens": 1237, + "processed_tokens": 1707118, + "tool_calls": 35, + "turns": 36 + }, + "ports-028": { + "answer": 2, + "tokens": 9357, + "fixed_tokens": 1240, + "processed_tokens": 69703, + "tool_calls": 7, + "turns": 7 + }, + "ports-029": { + "answer": 8, + "tokens": 51170, + "fixed_tokens": 1240, + "processed_tokens": 579581, + "tool_calls": 18, + "turns": 19 + }, + "ports-030": { + "answer": [ + "dec-cap-tide-storm-particles-at-6-000-on-skiff--resze52afjxyxys1", + "dec-drop-skiff-to-30-hz-while-a-tide-storm-is-on-scr--72vx1c8s4jrs6axc" + ], + "tokens": 6883, + "fixed_tokens": 1244, + "processed_tokens": 52414, + "tool_calls": 5, + "turns": 6 + }, + "ports-031": { + "answer": [ + "iss-skiff-cert-docked-30-hz-judder-on-some-tvs--9nq2xg9mzash474g", + "iss-meridian-cert-activity-cards-missing-for-two-bio--k214cmfra7pyvvzq" + ], + "tokens": 24969, + "fixed_tokens": 1232, + "processed_tokens": 272953, + "tool_calls": 13, + "turns": 14 + }, + "ports-032": { + "answer": 2, + "tokens": 6679, + "fixed_tokens": 1236, + "processed_tokens": 52285, + "tool_calls": 5, + "turns": 6 + }, + "ports-033": { + "answer": "unknown", + "tokens": 31817, + "fixed_tokens": 1239, + "processed_tokens": 234109, + "tool_calls": 10, + "turns": 11 + }, + "render-001": { + "answer": "7.4 ms", + "tokens": 26160, + "fixed_tokens": 1232, + "processed_tokens": 226039, + "tool_calls": 11, + "turns": 12 + }, + "render-002": { + "answer": "3.4x", + "tokens": 13831, + "fixed_tokens": 1235, + "processed_tokens": 188968, + "tool_calls": 14, + "turns": 15 + }, + "render-003": { + "answer": "Tomasz Brandt", + "tokens": 9205, + "fixed_tokens": 1232, + "processed_tokens": 92232, + "tool_calls": 8, + "turns": 9 + }, + "render-004": { + "answer": "rejected", + "tokens": 35221, + "fixed_tokens": 1228, + "processed_tokens": 394586, + "tool_calls": 15, + "turns": 16 + }, + "render-005": { + "answer": true, + "tokens": 31281, + "fixed_tokens": 1233, + "processed_tokens": 283976, + "tool_calls": 12, + "turns": 13 + }, + "render-006": { + "answer": "unknown", + "tokens": 28251, + "fixed_tokens": 1238, + "processed_tokens": 435935, + "tool_calls": 18, + "turns": 19 + }, + "render-007": { + "answer": "2026-07-24", + "tokens": 31814, + "fixed_tokens": 1233, + "processed_tokens": 210802, + "tool_calls": 9, + "turns": 10 + }, + "render-008": { + "answer": "2 failures", + "tokens": 24577, + "fixed_tokens": 1238, + "processed_tokens": 206047, + "tool_calls": 10, + "turns": 11 + }, + "render-009": { + "answer": "32 steps", + "tokens": 25181, + "fixed_tokens": 1228, + "processed_tokens": 240322, + "tool_calls": 11, + "turns": 12 + }, + "render-010": { + "answer": "unknown", + "tokens": 20354, + "fixed_tokens": 1236, + "processed_tokens": 138826, + "tool_calls": 8, + "turns": 9 + }, + "render-011": { + "answer": "fnd-sdf-gi-costs-2-4-ms-on-meridian--2w6c2pc5zmcsyjre", + "tokens": 11293, + "fixed_tokens": 1233, + "processed_tokens": 147447, + "tool_calls": 12, + "turns": 13 + }, + "render-012": { + "answer": "unknown", + "tokens": 40708, + "fixed_tokens": 1233, + "processed_tokens": 945327, + "tool_calls": 31, + "turns": 32 + }, + "render-013": { + "answer": "16-bit float per channel", + "tokens": 52557, + "fixed_tokens": 1241, + "processed_tokens": 945872, + "tool_calls": 24, + "turns": 25 + }, + "render-014": { + "answer": "52%", + "tokens": 35764, + "fixed_tokens": 1231, + "processed_tokens": 564989, + "tool_calls": 27, + "turns": 27 + }, + "render-015": { + "answer": "unknown", + "tokens": 41414, + "fixed_tokens": 1239, + "processed_tokens": 1031970, + "tool_calls": 33, + "turns": 34 + }, + "render-016": { + "answer": "1.2 km", + "tokens": 20919, + "fixed_tokens": 1233, + "processed_tokens": 191793, + "tool_calls": 10, + "turns": 11 + }, + "render-017": { + "answer": "unknown", + "tokens": 72192, + "fixed_tokens": 1229, + "processed_tokens": 2309087, + "tool_calls": 48, + "turns": 49 + }, + "render-018": { + "answer": "unknown", + "tokens": 47932, + "fixed_tokens": 1238, + "processed_tokens": 470279, + "tool_calls": 14, + "turns": 15 + }, + "render-019": { + "answer": "dec-use-the-custom-brine-curve-for-tonemapping--p735g6wf2njare86", + "tokens": 12454, + "fixed_tokens": 1232, + "processed_tokens": 139258, + "tool_calls": 11, + "turns": 12 + }, + "render-020": { + "answer": "fnd-screen-space-refraction-loses-off-screen-content--k8zvmmdee7wg2fjy", + "tokens": 28369, + "fixed_tokens": 1234, + "processed_tokens": 383708, + "tool_calls": 17, + "turns": 18 + }, + "render-021": { + "answer": "dec-adopt-a-visibility-buffer-for-all-opaque-geometr--68vchzqgd1avw8q4", + "tokens": 18585, + "fixed_tokens": 1235, + "processed_tokens": 167815, + "tool_calls": 11, + "turns": 12 + }, + "render-022": { + "answer": "dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr", + "tokens": 11174, + "fixed_tokens": 1231, + "processed_tokens": 118372, + "tool_calls": 10, + "turns": 11 + }, + "render-023": { + "answer": "dec-capture-the-cliffs-and-dunes-benchmarks-on-every--3pqyr66yh4v6q676", + "tokens": 43502, + "fixed_tokens": 1237, + "processed_tokens": 812125, + "tool_calls": 23, + "turns": 24 + }, + "render-024": { + "answer": "dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r", + "tokens": 27265, + "fixed_tokens": 1227, + "processed_tokens": 289431, + "tool_calls": 13, + "turns": 14 + }, + "render-025": { + "answer": "fnd-tern-cost-at-4k-output-on-meridian-after-fp16-pa--p4gcmzw2a4bvzjev", + "tokens": 44615, + "fixed_tokens": 1234, + "processed_tokens": 1057480, + "tool_calls": 33, + "turns": 32 + }, + "render-026": { + "answer": "unknown", + "tokens": 35674, + "fixed_tokens": 1233, + "processed_tokens": 599931, + "tool_calls": 26, + "turns": 27 + }, + "render-027": { + "answer": "con-frame-budget--j6vneva1g2ywj86m", + "tokens": 14426, + "fixed_tokens": 1234, + "processed_tokens": 119448, + "tool_calls": 9, + "turns": 10 + }, + "render-028": { + "answer": "dec-move-to-gpu-driven-two-phase-occlusion-culling--6dre481mabxsw6ee", + "tokens": 40164, + "fixed_tokens": 1230, + "processed_tokens": 409291, + "tool_calls": 15, + "turns": 16 + }, + "render-029": { + "answer": "fnd-vsm-page-pool-overflows-during-spring-tides--m2p8e89hhdmh0z8a", + "tokens": 32022, + "fixed_tokens": 1232, + "processed_tokens": 285663, + "tool_calls": 13, + "turns": 14 + }, + "render-030": { + "answer": "unknown", + "tokens": 47284, + "fixed_tokens": 1234, + "processed_tokens": 1268353, + "tool_calls": 35, + "turns": 36 + }, + "render-031": { + "answer": "Alpha-tested foliage cost 2.1 ms in the visibility buffer (its alpha test runs in the raster pass with a per-pixel texture fetch) versus 0.8 ms in forward+, and saltglass refracts the resolved scene so it cannot live in the buffer; see dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9, derived from fnd-alpha-tested-foliage-costs-2-1-ms-in-the-visibil--f3g34x2k6fs367eb.", + "tokens": 23986, + "fixed_tokens": 1230, + "processed_tokens": 276112, + "tool_calls": 13, + "turns": 14 + }, + "render-032": { + "answer": "Halcyon has no Skiff build, so shipping it would break the one-upscaler constraint, and the team wanted to own the upscaler code for saltglass rather than depend on vendor tickets and a license (Tern costs 0.7 ms more than Halcyon on Meridian). See dec-ship-tern-as-lantern-s-only-upscaler--fmreq35nzyjc7k4e.", + "tokens": 30443, + "fixed_tokens": 1235, + "processed_tokens": 483701, + "tool_calls": 21, + "turns": 22 + }, + "render-033": { + "answer": "unknown", + "tokens": 29176, + "fixed_tokens": 1238, + "processed_tokens": 404400, + "tool_calls": 18, + "turns": 18 + }, + "render-034": { + "answer": "PC workstation (Meridian clock profile)", + "tokens": 42399, + "fixed_tokens": 1231, + "processed_tokens": 1172274, + "tool_calls": 37, + "turns": 38 + }, + "render-035": { + "answer": "5912 pages", + "tokens": 16368, + "fixed_tokens": 1232, + "processed_tokens": 189255, + "tool_calls": 12, + "turns": 13 + }, + "render-036": { + "answer": "unknown", + "tokens": 55100, + "fixed_tokens": 1231, + "processed_tokens": 888170, + "tool_calls": 21, + "turns": 22 + }, + "render-037": { + "answer": "unknown", + "tokens": 27903, + "fixed_tokens": 1233, + "processed_tokens": 300795, + "tool_calls": 13, + "turns": 14 + }, + "render-038": { + "answer": "dec-visibility-buffer-for-opaque-geometry-foliage-an--gvnvp04jgm7kbfh9", + "tokens": 26465, + "fixed_tokens": 1235, + "processed_tokens": 287397, + "tool_calls": 13, + "turns": 14 + }, + "render-039": { + "answer": "dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e", + "tokens": 38470, + "fixed_tokens": 1234, + "processed_tokens": 357651, + "tool_calls": 13, + "turns": 13 + }, + "render-040": { + "answer": "fnd-lantern-at-alpha--ckpd9ecvdjqbcr7c", + "tokens": 26154, + "fixed_tokens": 1231, + "processed_tokens": 191247, + "tool_calls": 10, + "turns": 11 + }, + "render-041": { + "answer": "4.7 ms", + "tokens": 42605, + "fixed_tokens": 1237, + "processed_tokens": 625427, + "tool_calls": 20, + "turns": 21 + }, + "render-042": { + "answer": "dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1", + "tokens": 32134, + "fixed_tokens": 1233, + "processed_tokens": 215923, + "tool_calls": 13, + "turns": 10 + }, + "render-043": { + "answer": "fnd-meshlet-cone-culling-rejects-9-percent-of-triang--t6e5x7trzedex105", + "tokens": 44911, + "fixed_tokens": 1230, + "processed_tokens": 1488092, + "tool_calls": 49, + "turns": 50 + }, + "render-044": { + "answer": "dec-screen-space-refraction-with-a-ray-marched-fallb--2639xtpyrfrvbx1r", + "tokens": 32240, + "fixed_tokens": 1230, + "processed_tokens": 299188, + "tool_calls": 12, + "turns": 13 + }, + "render-045": { + "answer": false, + "tokens": 35375, + "fixed_tokens": 1236, + "processed_tokens": 461894, + "tool_calls": 21, + "turns": 22 + }, + "render-046": { + "answer": "The cost finding that sank virtual shadow maps (3.1 ms) was a capture error; with cached pages VSM costs 1.4 ms, less than four cascaded shadow maps, and cascade seams through saltglass remained unsolved under CSM. (dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4)", + "tokens": 30101, + "fixed_tokens": 1231, + "processed_tokens": 478258, + "tool_calls": 25, + "turns": 26 + }, + "render-047": { + "answer": "Because the release-build capture put the visibility buffer at 7.4 ms on Skiff against 8.1 ms for forward+ (6.3 ms with half-rate material resolve), so the forward+ fallback was no longer worth keeping, and maintaining two opaque paths cost about one engineer-week a month. Record: dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1", + "tokens": 19037, + "fixed_tokens": 1232, + "processed_tokens": 237291, + "tool_calls": 15, + "turns": 16 + }, + "render-048": { + "answer": "dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4", + "tokens": 103872, + "fixed_tokens": 1230, + "processed_tokens": 6842523, + "tool_calls": 100, + "turns": 100 + }, + "render-049": { + "answer": "dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4", + "tokens": 19649, + "fixed_tokens": 1233, + "processed_tokens": 279681, + "tool_calls": 17, + "turns": 18 + }, + "render-050": { + "answer": "con-frame-budget--fzdrbxns6dmrrmy3", + "tokens": 11808, + "fixed_tokens": 1230, + "processed_tokens": 91723, + "tool_calls": 7, + "turns": 8 + }, + "render-051": { + "answer": "iss-tern-ghosting-on-moving-saltglass--2yr3q6zf476wajqp", + "tokens": 32164, + "fixed_tokens": 1233, + "processed_tokens": 300986, + "tool_calls": 12, + "turns": 13 + }, + "render-052": { + "answer": "unknown", + "tokens": 61899, + "fixed_tokens": 1234, + "processed_tokens": 1224695, + "tool_calls": 29, + "turns": 26 + }, + "render-053": { + "answer": "every frame", + "tokens": 24442, + "fixed_tokens": 1233, + "processed_tokens": 456385, + "tool_calls": 24, + "turns": 25 + }, + "render-054": { + "answer": "debug-gpu-validation", + "tokens": 31539, + "fixed_tokens": 1232, + "processed_tokens": 553203, + "tool_calls": 21, + "turns": 22 + }, + "render-055": { + "answer": "fnd-tern-cost-at-4k-output-on-meridian-with-the-reac--81tcpzvhwzcy6wyn", + "tokens": 86169, + "fixed_tokens": 1232, + "processed_tokens": 1425701, + "tool_calls": 25, + "turns": 26 + }, + "render-056": { + "answer": "208,000 meshlets", + "tokens": 29867, + "fixed_tokens": 1238, + "processed_tokens": 432485, + "tool_calls": 17, + "turns": 18 + }, + "render-057": { + "answer": "dec-visibility-buffer-on-all-platforms-skiff-resolve--k1ackk3c3275r5y1", + "tokens": 26669, + "fixed_tokens": 1236, + "processed_tokens": 208466, + "tool_calls": 10, + "turns": 11 + }, + "render-058": { + "answer": "iss-which-upscaler-should-lantern-ship--g8c2y9tsr856tn2v", + "tokens": 39164, + "fixed_tokens": 1231, + "processed_tokens": 923303, + "tool_calls": 31, + "turns": 32 + }, + "render-059": { + "answer": "fnd-sdf-gi-costs-4-7-ms-on-meridian--sm19rt2f274ajsvr", + "tokens": 34952, + "fixed_tokens": 1233, + "processed_tokens": 556514, + "tool_calls": 21, + "turns": 22 + }, + "render-060": { + "answer": "unknown", + "tokens": 39664, + "fixed_tokens": 1243, + "processed_tokens": 905282, + "tool_calls": 35, + "turns": 36 + }, + "render-061": { + "answer": "con-ui-composites-at-a-fixed-203-nits-in-hdr--de6aft7cvhdezn5s", + "tokens": 35305, + "fixed_tokens": 1234, + "processed_tokens": 697291, + "tool_calls": 25, + "turns": 26 + }, + "render-062": { + "answer": "con-frame-budget--j6vneva1g2ywj86m", + "tokens": 23181, + "fixed_tokens": 1242, + "processed_tokens": 126612, + "tool_calls": 7, + "turns": 8 + }, + "render-063": { + "answer": "dec-resolve-materials-with-one-uber-shader-over-bind--s9nbq2qn05mk5j6r", + "tokens": 31923, + "fixed_tokens": 1235, + "processed_tokens": 452449, + "tool_calls": 19, + "turns": 19 + }, + "render-064": { + "answer": "dec-use-a-cached-shadow-atlas-for-local-lights--8p6f2v774he38t5j", + "tokens": 46282, + "fixed_tokens": 1231, + "processed_tokens": 621012, + "tool_calls": 21, + "turns": 19 + }, + "render-065": { + "answer": "unknown", + "tokens": 42617, + "fixed_tokens": 1235, + "processed_tokens": 741182, + "tool_calls": 27, + "turns": 24 + }, + "render-066": { + "answer": "dec-use-cascaded-shadow-maps-with-four-cascades--s5c1y9jaf275afzr", + "tokens": 29461, + "fixed_tokens": 1231, + "processed_tokens": 424260, + "tool_calls": 18, + "turns": 19 + }, + "render-067": { + "answer": 4, + "tokens": 22287, + "fixed_tokens": 1240, + "processed_tokens": 141874, + "tool_calls": 9, + "turns": 9 + }, + "render-068": { + "answer": [ + "dec-exclude-caustic-luminance-from-tern-s-history-cl--xhxjn26ss343v2k4", + "dec-lock-caustic-photon-jitter-to-the-tide-phase--85x10k4h11t8nx7c", + "dec-use-the-probe-grid-alone-in-120-hz-performance-m--6dzm1nt40pjfpyae", + "dec-trace-sdf-gi-at-quarter-resolution-in-performanc--06cqt3mqn3fg5h6e", + "dec-read-paper-white-from-the-meridian-system-settin--7crbx73gqw1hn7xq", + "dec-add-an-in-game-paper-white-slider-from-80-to-400--1phfvxby983z8tjf" + ], + "tokens": 23640, + "fixed_tokens": 1232, + "processed_tokens": 127620, + "tool_calls": 7, + "turns": 8 + }, + "render-069": { + "answer": "iss-shadow-pages-run-out-at-spring-low-tide--f4fgy6b44jbkrsmh", + "tokens": 26156, + "fixed_tokens": 1234, + "processed_tokens": 169958, + "tool_calls": 9, + "turns": 10 + }, + "render-070": { + "answer": "unknown", + "tokens": 70422, + "fixed_tokens": 1233, + "processed_tokens": 1991543, + "tool_calls": 40, + "turns": 41 + }, + "render-071": { + "answer": 3, + "tokens": 10013, + "fixed_tokens": 1236, + "processed_tokens": 58522, + "tool_calls": 5, + "turns": 6 + }, + "render-072": { + "answer": [ + "rsk-sdf-volumes-outgrow-the-render-target-memory-bud--xfd2pfztvskdcd2c", + "rsk-artists-cannot-match-concept-paintings-under-the--6cfh9vkamn0kbtcx" + ], + "tokens": 10040, + "fixed_tokens": 1233, + "processed_tokens": 58388, + "tool_calls": 5, + "turns": 6 + }, + "render-073": { + "answer": [ + "rsk-vsm-page-pool-overflows-when-tides-expose-the-fl--x1r161nrdngra4ty", + "rsk-gi-cannot-fit-the-120-hz-performance-mode--tqt3fj839dqfq5s7", + "rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4" + ], + "tokens": 10271, + "fixed_tokens": 1231, + "processed_tokens": 58859, + "tool_calls": 5, + "turns": 6 + }, + "render-074": { + "answer": 5, + "tokens": 8736, + "fixed_tokens": 1240, + "processed_tokens": 69023, + "tool_calls": 6, + "turns": 7 + }, + "render-075": { + "answer": "3", + "tokens": 35185, + "fixed_tokens": 1232, + "processed_tokens": 931166, + "tool_calls": 32, + "turns": 33 + }, + "render-076": { + "answer": true, + "tokens": 32428, + "fixed_tokens": 1230, + "processed_tokens": 463456, + "tool_calls": 18, + "turns": 19 + }, + "render-077": { + "answer": true, + "tokens": 38070, + "fixed_tokens": 1235, + "processed_tokens": 691235, + "tool_calls": 23, + "turns": 24 + }, + "render-078": { + "answer": [ + "dec-brine-curve-with-a-separate-hdr-shoulder-at-1-00--be68yywg78dysm2e", + "rsk-hdr-certification-slips-the-release-candidate--49t4xjbzmkgc22a4" + ], + "tokens": 44505, + "fixed_tokens": 1235, + "processed_tokens": 435380, + "tool_calls": 33, + "turns": 16 + }, + "render-079": { + "answer": 5, + "tokens": 70696, + "fixed_tokens": 1232, + "processed_tokens": 1432241, + "tool_calls": 35, + "turns": 36 + }, + "render-080": { + "answer": "6 versions", + "tokens": 30454, + "fixed_tokens": 1236, + "processed_tokens": 404017, + "tool_calls": 16, + "turns": 17 + }, + "render-081": { + "answer": "unknown", + "tokens": 49869, + "fixed_tokens": 1232, + "processed_tokens": 1481028, + "tool_calls": 42, + "turns": 43 + }, + "render-082": { + "answer": "false", + "tokens": 28639, + "fixed_tokens": 1230, + "processed_tokens": 334647, + "tool_calls": 15, + "turns": 16 + }, + "render-083": { + "answer": 6, + "tokens": 281594, + "fixed_tokens": 1233, + "processed_tokens": 22947838, + "tool_calls": 150, + "turns": 151 + }, + "tools-001": { + "answer": "completed", + "tokens": 18829, + "fixed_tokens": 1241, + "processed_tokens": 89021, + "tool_calls": 6, + "turns": 7 + }, + "tools-002": { + "answer": "47 minutes", + "tokens": 35098, + "fixed_tokens": 1234, + "processed_tokens": 297750, + "tool_calls": 12, + "turns": 13 + }, + "tools-003": { + "answer": "6 min 40 s", + "tokens": 34043, + "fixed_tokens": 1243, + "processed_tokens": 503218, + "tool_calls": 21, + "turns": 22 + }, + "tools-004": { + "answer": "unknown", + "tokens": 39688, + "fixed_tokens": 1240, + "processed_tokens": 235630, + "tool_calls": 9, + "turns": 10 + }, + "tools-005": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tokens": 24973, + "fixed_tokens": 1236, + "processed_tokens": 288003, + "tool_calls": 14, + "turns": 14 + }, + "tools-006": { + "answer": "dec-build-a-content-addressed-shader-compile-cache-s--e65rq9439k7xz5zh", + "tokens": 18788, + "fixed_tokens": 1237, + "processed_tokens": 98645, + "tool_calls": 6, + "turns": 7 + }, + "tools-007": { + "answer": "dec-raise-the-shader-cache-fetch-timeout-from-5-seco--4sgdf42ajyct6gt6", + "tokens": 66140, + "fixed_tokens": 1241, + "processed_tokens": 1007512, + "tool_calls": 29, + "turns": 26 + }, + "tools-008": { + "answer": "dec-key-the-shader-cache-on-raw-source-text-and-comp--hp6awmx3gq5rn9nc", + "tokens": 27128, + "fixed_tokens": 1240, + "processed_tokens": 216428, + "tool_calls": 10, + "turns": 11 + }, + "tools-009": { + "answer": "92.4%", + "tokens": 51055, + "fixed_tokens": 1237, + "processed_tokens": 664487, + "tool_calls": 18, + "turns": 18 + }, + "tools-010": { + "answer": "dec-cap-each-farm-agent-at-6-parallel-shader-compile--q5w4sfjm73tsj8x8", + "tokens": 51240, + "fixed_tokens": 1233, + "processed_tokens": 955694, + "tool_calls": 25, + "turns": 26 + }, + "tools-011": { + "answer": "fnd-two-compiler-builds-with-the-same-version-string--gmgr4ha0ndxqmcn9", + "tokens": 16894, + "fixed_tokens": 1233, + "processed_tokens": 200844, + "tool_calls": 13, + "turns": 14 + }, + "tools-012": { + "answer": 3, + "tokens": 8356, + "fixed_tokens": 1244, + "processed_tokens": 75763, + "tool_calls": 7, + "turns": 8 + }, + "tools-013": { + "answer": 7, + "tokens": 85899, + "fixed_tokens": 1239, + "processed_tokens": 1930216, + "tool_calls": 39, + "turns": 40 + }, + "tools-014": { + "answer": false, + "tokens": 32179, + "fixed_tokens": 1244, + "processed_tokens": 521536, + "tool_calls": 20, + "turns": 21 + }, + "tools-015": { + "answer": [ + "iss-developer-workstations-cannot-read-the-farm-shad--q2xw0f7fze6z55nj", + "rsk-shader-cache-storage-could-outgrow-the-4-tb-farm--76y9649mwrx7aavd" + ], + "tokens": 55528, + "fixed_tokens": 1240, + "processed_tokens": 559909, + "tool_calls": 18, + "turns": 16 + }, + "tools-016": { + "answer": "dec-key-the-shader-cache-on-preprocessed-source-defi--qx2da8e4cbkx0drp", + "tokens": 61425, + "fixed_tokens": 1236, + "processed_tokens": 1344384, + "tool_calls": 32, + "turns": 33 + }, + "world-001": { + "answer": "64 KB", + "tokens": 24238, + "fixed_tokens": 1231, + "processed_tokens": 201576, + "tool_calls": 10, + "turns": 11 + }, + "world-002": { + "answer": "5.1 ms", + "tokens": 19420, + "fixed_tokens": 1231, + "processed_tokens": 256595, + "tool_calls": 15, + "turns": 16 + }, + "world-003": { + "answer": "one crash per 900 script waits", + "tokens": 39031, + "fixed_tokens": 1235, + "processed_tokens": 465381, + "tool_calls": 22, + "turns": 17 + }, + "world-004": { + "answer": "4100 file opens", + "tokens": 40839, + "fixed_tokens": 1229, + "processed_tokens": 858370, + "tool_calls": 28, + "turns": 29 + }, + "world-005": { + "answer": "11 m", + "tokens": 31031, + "fixed_tokens": 1232, + "processed_tokens": 483663, + "tool_calls": 19, + "turns": 20 + }, + "world-006": { + "answer": "unknown", + "tokens": 34869, + "fixed_tokens": 1231, + "processed_tokens": 618277, + "tool_calls": 22, + "turns": 23 + }, + "world-007": { + "answer": "260 MB", + "tokens": 48725, + "fixed_tokens": 1237, + "processed_tokens": 1015088, + "tool_calls": 27, + "turns": 28 + }, + "world-008": { + "answer": "10 Hz", + "tokens": 53757, + "fixed_tokens": 1234, + "processed_tokens": 991701, + "tool_calls": 25, + "turns": 26 + }, + "world-009": { + "answer": "unknown", + "tokens": 41099, + "fixed_tokens": 1231, + "processed_tokens": 550854, + "tool_calls": 17, + "turns": 18 + }, + "world-010": { + "answer": "29 GB/s per core", + "tokens": 21430, + "fixed_tokens": 1238, + "processed_tokens": 141148, + "tool_calls": 8, + "turns": 9 + }, + "world-011": { + "answer": "fnd-shipping-entity-names-costs-57-mb-at-full-popula--6w7gjvy7wdmdx9qx", + "tokens": 56001, + "fixed_tokens": 1233, + "processed_tokens": 1250766, + "tool_calls": 30, + "turns": 31 + }, + "world-012": { + "answer": "dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3", + "tokens": 24634, + "fixed_tokens": 1235, + "processed_tokens": 202175, + "tool_calls": 10, + "turns": 11 + }, + "world-013": { + "answer": "unknown", + "tokens": 61988, + "fixed_tokens": 1228, + "processed_tokens": 1410144, + "tool_calls": 42, + "turns": 37 + }, + "world-014": { + "answer": "unknown", + "tokens": 55763, + "fixed_tokens": 1233, + "processed_tokens": 1047791, + "tool_calls": 25, + "turns": 26 + }, + "world-015": { + "answer": "3.0 ms", + "tokens": 24949, + "fixed_tokens": 1232, + "processed_tokens": 382929, + "tool_calls": 17, + "turns": 18 + }, + "world-016": { + "answer": "unknown", + "tokens": 48983, + "fixed_tokens": 1237, + "processed_tokens": 428367, + "tool_calls": 14, + "turns": 15 + }, + "world-017": { + "answer": "dec-partition-the-world-into-128-m-cells--372b6czbjf29ymaw", + "tokens": 39852, + "fixed_tokens": 1235, + "processed_tokens": 772773, + "tool_calls": 25, + "turns": 26 + }, + "world-018": { + "answer": "dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x", + "tokens": 18247, + "fixed_tokens": 1232, + "processed_tokens": 74900, + "tool_calls": 5, + "turns": 6 + }, + "world-019": { + "answer": "fnd-tide-priority-reads-starve-player-proximity-load--by0d7b0bk39xz3rk", + "tokens": 43083, + "fixed_tokens": 1230, + "processed_tokens": 900464, + "tool_calls": 28, + "turns": 29 + }, + "world-020": { + "answer": "dec-schedule-streaming-reads-by-deadline-instead-of--q2x5aknabgcssdj2", + "tokens": 11520, + "fixed_tokens": 1227, + "processed_tokens": 73837, + "tool_calls": 7, + "turns": 7 + }, + "world-021": { + "answer": "dec-cut-navigation-tiles-to-64-m-so-three-fit-along--snvepk8ygeb3qsjs", + "tokens": 38276, + "fixed_tokens": 1234, + "processed_tokens": 452043, + "tool_calls": 16, + "turns": 17 + }, + "world-022": { + "answer": "fnd-41-of-alpha-crash-reports-have-no-usable-stack--35a50b07ferhf13m", + "tokens": 29799, + "fixed_tokens": 1238, + "processed_tokens": 298884, + "tool_calls": 13, + "turns": 14 + }, + "world-023": { + "answer": "dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m", + "tokens": 33142, + "fixed_tokens": 1230, + "processed_tokens": 371647, + "tool_calls": 15, + "turns": 16 + }, + "world-024": { + "answer": "dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew", + "tokens": 62791, + "fixed_tokens": 1240, + "processed_tokens": 1031238, + "tool_calls": 24, + "turns": 25 + }, + "world-025": { + "answer": "con-streaming-pool-budget--kca88sgh2j6sxvd5", + "tokens": 25874, + "fixed_tokens": 1229, + "processed_tokens": 191166, + "tool_calls": 9, + "turns": 10 + }, + "world-026": { + "answer": "unknown", + "tokens": 30830, + "fixed_tokens": 1234, + "processed_tokens": 534430, + "tool_calls": 25, + "turns": 26 + }, + "world-027": { + "answer": "160 MB/s", + "tokens": 39355, + "fixed_tokens": 1231, + "processed_tokens": 299114, + "tool_calls": 12, + "turns": 12 + }, + "world-028": { + "answer": "unknown", + "tokens": 71080, + "fixed_tokens": 1242, + "processed_tokens": 2088116, + "tool_calls": 51, + "turns": 52 + }, + "world-029": { + "answer": "dec-run-engine-jobs-and-gull-scripts-on-one-thread-p--07pbzvqg00pmnrr3", + "tokens": 50876, + "fixed_tokens": 1235, + "processed_tokens": 810451, + "tool_calls": 23, + "turns": 24 + }, + "world-030": { + "answer": "fnd-world-core-state-at-alpha--tkbsm4867h65jqq8", + "tokens": 28112, + "fixed_tokens": 1236, + "processed_tokens": 230020, + "tool_calls": 11, + "turns": 12 + }, + "world-031": { + "answer": "unknown", + "tokens": 41208, + "fixed_tokens": 1233, + "processed_tokens": 673332, + "tool_calls": 20, + "turns": 21 + }, + "world-032": { + "answer": "fnd-float-tide-heights-drift-apart-between-pc-and-me--7jb0fg4b5xzr7q5e", + "tokens": 41741, + "fixed_tokens": 1233, + "processed_tokens": 832219, + "tool_calls": 26, + "turns": 27 + }, + "world-033": { + "answer": "dec-save-player-changes-as-deltas-against-the-tide-f--n38scy1yaarsr8cw", + "tokens": 43066, + "fixed_tokens": 1229, + "processed_tokens": 746101, + "tool_calls": 23, + "turns": 24 + }, + "world-034": { + "answer": "unknown", + "tokens": 39808, + "fixed_tokens": 1235, + "processed_tokens": 882978, + "tool_calls": 33, + "turns": 34 + }, + "world-035": { + "answer": "false, dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3", + "tokens": 29240, + "fixed_tokens": 1233, + "processed_tokens": 383755, + "tool_calls": 16, + "turns": 17 + }, + "world-036": { + "answer": "Kestrel retired the fiber scheduler because 41% of alpha crash reports had no usable stack, which blocked crash triage for beta, and a thread-pool prototype with continuation waits kept workers 93% busy during tide turns, close to the 95% fibers gave (dec-return-engine-jobs-to-a-thread-pool-with-continu--1zkc1v2x97taf50h).", + "tokens": 42612, + "fixed_tokens": 1234, + "processed_tokens": 601208, + "tool_calls": 18, + "turns": 19 + }, + "world-037": { + "answer": "fnd-hot-reload-drops-suspended-gull-coroutines--va0fn0svryzwbzws", + "tokens": 46187, + "fixed_tokens": 1237, + "processed_tokens": 1140776, + "tool_calls": 34, + "turns": 35 + }, + "world-038": { + "answer": "3 archetypes", + "tokens": 28106, + "fixed_tokens": 1233, + "processed_tokens": 381424, + "tool_calls": 16, + "turns": 17 + }, + "world-039": { + "answer": "1.2 GB/s", + "tokens": 41936, + "fixed_tokens": 1236, + "processed_tokens": 582617, + "tool_calls": 19, + "turns": 20 + }, + "world-040": { + "answer": "unknown", + "tokens": 42730, + "fixed_tokens": 1235, + "processed_tokens": 1125156, + "tool_calls": 34, + "turns": 35 + }, + "world-041": { + "answer": "61%", + "tokens": 39096, + "fixed_tokens": 1228, + "processed_tokens": 334598, + "tool_calls": 12, + "turns": 13 + }, + "world-042": { + "answer": "5.4 s", + "tokens": 29933, + "fixed_tokens": 1233, + "processed_tokens": 346803, + "tool_calls": 14, + "turns": 15 + }, + "world-043": { + "answer": "unknown", + "tokens": 49726, + "fixed_tokens": 1230, + "processed_tokens": 1465581, + "tool_calls": 41, + "turns": 42 + }, + "world-044": { + "answer": "dec-move-engine-jobs-to-fibers--qjkgnm8cex8ydzfq", + "tokens": 43794, + "fixed_tokens": 1233, + "processed_tokens": 928809, + "tool_calls": 29, + "turns": 30 + }, + "world-045": { + "answer": "dec-run-engine-jobs-on-fibers-and-pin-gull-scripts-t--rw28cbqfd07rd9te", + "tokens": 30599, + "fixed_tokens": 1239, + "processed_tokens": 398337, + "tool_calls": 16, + "turns": 17 + }, + "world-046": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tokens": 11874, + "fixed_tokens": 1238, + "processed_tokens": 92924, + "tool_calls": 7, + "turns": 8 + }, + "world-047": { + "answer": "fnd-world-core-state-at-alpha--tkbsm4867h65jqq8", + "tokens": 17990, + "fixed_tokens": 1232, + "processed_tokens": 157943, + "tool_calls": 10, + "turns": 11 + }, + "world-048": { + "answer": "dec-compile-gull-to-bytecode-for-a-register-vm--jrqje646fpevp5f3", + "tokens": 18767, + "fixed_tokens": 1235, + "processed_tokens": 151702, + "tool_calls": 12, + "turns": 11 + }, + "world-049": { + "answer": "22%", + "tokens": 57950, + "fixed_tokens": 1236, + "processed_tokens": 1372957, + "tool_calls": 33, + "turns": 33 + }, + "world-050": { + "answer": "fnd-alpha-content-needs-6-2-ms-of-gull-time-per-fram--4mekgdpsdv5nk085", + "tokens": 34180, + "fixed_tokens": 1232, + "processed_tokens": 372039, + "tool_calls": 14, + "turns": 15 + }, + "world-051": { + "answer": "Float tides drifted apart between machines within 6 minutes, and integer adds and multiplies in 32.32 fixed point give the same bits on every CPU and compiler, so that drift cannot happen (record dec-run-the-tide-simulation-in-32-32-fixed-point--c5rjfcnmhne4h05e). The strict IEEE mode decision (dec-force-strict-ieee-float-mode-for-the-tide-simula--ecwmqt7ncjngysqw) was rejected in favor of it.", + "tokens": 35372, + "fixed_tokens": 1234, + "processed_tokens": 599485, + "tool_calls": 22, + "turns": 23 + }, + "world-052": { + "answer": "Dara Whitlock", + "tokens": 26825, + "fixed_tokens": 1231, + "processed_tokens": 250700, + "tool_calls": 11, + "turns": 12 + }, + "world-053": { + "answer": "unknown", + "tokens": 70744, + "fixed_tokens": 1232, + "processed_tokens": 2359524, + "tool_calls": 48, + "turns": 48 + }, + "world-054": { + "answer": "Marta Lindqvist", + "tokens": 45268, + "fixed_tokens": 1236, + "processed_tokens": 931337, + "tool_calls": 28, + "turns": 29 + }, + "world-055": { + "answer": "Kelp stays because the decision `dec-shrink-kelp-s-dictionary-to-1-mb-for-streamed-as--yh8hktfqnyqhepew` ships a 1 MB Kelp dictionary and closes the reopened Zstandard option, since cold on Skiff Kelp still beats Zstandard, now by 1.25x after firmware 3.2 (`fnd-kelp-with-a-1-mb-dictionary-decodes-at-1-5-gb-s--y9v8jrxgbv6abrx5`).", + "tokens": 40660, + "fixed_tokens": 1230, + "processed_tokens": 741483, + "tool_calls": 25, + "turns": 26 + }, + "world-056": { + "answer": "dec-run-engine-jobs-on-a-work-stealing-thread-pool--1pd72x1pxpgwy21x", + "tokens": 24421, + "fixed_tokens": 1239, + "processed_tokens": 202184, + "tool_calls": 10, + "turns": 11 + }, + "world-057": { + "answer": "tile [212, 87]", + "tokens": 20371, + "fixed_tokens": 1233, + "processed_tokens": 241482, + "tool_calls": 14, + "turns": 15 + }, + "world-058": { + "answer": "0.8 GB/s", + "tokens": 38979, + "fixed_tokens": 1234, + "processed_tokens": 575165, + "tool_calls": 20, + "turns": 21 + }, + "world-059": { + "answer": "dec-derive-the-missing-harmonic-phase-from-each-save--gbqrvvgyq2gy2gnw", + "tokens": 14146, + "fixed_tokens": 1231, + "processed_tokens": 142614, + "tool_calls": 10, + "turns": 11 + }, + "world-060": { + "answer": "dec-partition-the-world-into-192-m-cells--bk9r1c5jwb6fh8tc", + "tokens": 18414, + "fixed_tokens": 1234, + "processed_tokens": 174821, + "tool_calls": 11, + "turns": 12 + }, + "world-061": { + "answer": "236 MB", + "tokens": 19471, + "fixed_tokens": 1233, + "processed_tokens": 248693, + "tool_calls": 14, + "turns": 15 + }, + "world-062": { + "answer": "310 MB", + "tokens": 27554, + "fixed_tokens": 1228, + "processed_tokens": 378362, + "tool_calls": 17, + "turns": 18 + }, + "world-063": { + "answer": "con-streaming-pool-budget--632bkbs79bwj4cr5", + "tokens": 52226, + "fixed_tokens": 1232, + "processed_tokens": 823735, + "tool_calls": 22, + "turns": 23 + }, + "world-064": { + "answer": [ + "dec-force-strict-ieee-float-mode-for-the-tide-simula--ecwmqt7ncjngysqw", + "dec-have-the-host-stream-tide-heights-to-every-peer--a3rb1seedn2bj7k8" + ], + "tokens": 32836, + "fixed_tokens": 1232, + "processed_tokens": 389969, + "tool_calls": 18, + "turns": 19 + }, + "world-065": { + "answer": "3.1 ms", + "tokens": 32609, + "fixed_tokens": 1235, + "processed_tokens": 734548, + "tool_calls": 31, + "turns": 32 + }, + "world-066": { + "answer": "46 reads", + "tokens": 32155, + "fixed_tokens": 1232, + "processed_tokens": 389529, + "tool_calls": 16, + "turns": 17 + }, + "world-067": { + "answer": "1.2 GB/s", + "tokens": 23483, + "fixed_tokens": 1235, + "processed_tokens": 309937, + "tool_calls": 16, + "turns": 17 + }, + "world-068": { + "answer": false, + "tokens": 34635, + "fixed_tokens": 1234, + "processed_tokens": 486835, + "tool_calls": 18, + "turns": 19 + }, + "world-069": { + "answer": 2, + "tokens": 82598, + "fixed_tokens": 1232, + "processed_tokens": 1215406, + "tool_calls": 48, + "turns": 28 + }, + "world-070": { + "answer": 3, + "tokens": 22254, + "fixed_tokens": 1238, + "processed_tokens": 154943, + "tool_calls": 9, + "turns": 10 + }, + "world-071": { + "answer": [ + "dec-store-components-in-archetype-tables-and-volatil--yxsjd26wcaz6fgx9", + "dec-evict-cells-by-distance-and-tide-forecast--fyp1jp366pjjzxcg", + "dec-compress-streamed-assets-with-kelp--ezwc5p1tgsgm7v8m", + "dec-hot-reload-gull-functions-by-swapping-bytecode-a--8dxnkg6h8vmcsr42", + "dec-stamp-each-save-with-a-schema-version-and-upgrad--nbg1h8g1bhn2ks8w" + ], + "tokens": 148654, + "fixed_tokens": 1234, + "processed_tokens": 9622531, + "tool_calls": 107, + "turns": 108 + }, + "world-072": { + "answer": [ + "dec-compress-streamed-assets-with-zstandard--bs1t15cygc51cpje", + "dec-compress-streamed-assets-with-lz4--v1pfsgfp0b3yjv4s" + ], + "tokens": 38906, + "fixed_tokens": 1236, + "processed_tokens": 260711, + "tool_calls": 12, + "turns": 11 + }, + "world-073": { + "answer": false, + "tokens": 34409, + "fixed_tokens": 1237, + "processed_tokens": 425332, + "tool_calls": 16, + "turns": 17 + }, + "world-074": { + "answer": 7, + "tokens": 9923, + "fixed_tokens": 1234, + "processed_tokens": 72413, + "tool_calls": 6, + "turns": 7 + }, + "world-075": { + "answer": [ + "dec-store-components-in-archetype-tables-and-volatil--8679sjn071ycsbpv", + "dec-partition-the-world-into-192-meter-cells--q62ddwdv2n8wxay6", + "dec-return-engine-jobs-to-the-thread-pool-with-conti--547qbweqvrp1j5g3" + ], + "tokens": 6789, + "fixed_tokens": 1230, + "processed_tokens": 52225, + "tool_calls": 5, + "turns": 6 + }, + "world-076": { + "answer": "dec-use-virtual-shadow-maps-for-the-sun--x8nqkn9q7eaf1ap4", + "tokens": 35678, + "fixed_tokens": 1239, + "processed_tokens": 185727, + "tool_calls": 11, + "turns": 8 + }, + "world-077": { + "answer": 251, + "tokens": 31664, + "fixed_tokens": 1235, + "processed_tokens": 437591, + "tool_calls": 18, + "turns": 19 + }, + "world-078": { + "answer": [ + "rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew", + "rsk-reworking-the-read-scheduler-may-slip-the-coast--9jzvs7etvb5jxqtp" + ], + "tokens": 16355, + "fixed_tokens": 1235, + "processed_tokens": 135240, + "tool_calls": 11, + "turns": 10 + }, + "world-079": { + "answer": [ + "con-streaming-pool-budget--8czwb4fjr5p5vpy7", + "con-no-runtime-code-generation-on-consoles--6cf25zqmsvqkdd73", + "con-tide-state-must-be-bit-identical-on-every-peer--zrpnp8qjyxzkas7t", + "con-saves-from-beta-onward-must-load-in-every-later--v6z856sxtgc5sb09" + ], + "tokens": 13418, + "fixed_tokens": 1232, + "processed_tokens": 93292, + "tool_calls": 7, + "turns": 8 + }, + "world-080": { + "answer": [ + "iss-gull-hot-reload-rejects-struct-layout-changes--3v2w2f9hg2gwy6aj", + "iss-gull-hot-reload-drops-suspended-coroutines--z7j2gmyny6gdxd07", + "iss-cross-platform-cloud-saves-are-unplanned--5bk0k4wrgj42ztfy" + ], + "tokens": 36752, + "fixed_tokens": 1232, + "processed_tokens": 266768, + "tool_calls": 11, + "turns": 12 + }, + "world-081": { + "answer": "rsk-hot-reload-may-corrupt-live-script-state--ec2ht2r1sq6h56ew", + "tokens": 20901, + "fixed_tokens": 1230, + "processed_tokens": 250246, + "tool_calls": 15, + "turns": 15 + } + } +} diff --git a/benchmarks/proof-recall/scripts/build.mjs b/benchmarks/proof-recall/scripts/build.mjs new file mode 100644 index 00000000..dd96663e --- /dev/null +++ b/benchmarks/proof-recall/scripts/build.mjs @@ -0,0 +1,236 @@ +#!/usr/bin/env node +// Builds the benchmark graph by replaying each Effort's event script through +// the real Proof writer. Every record is therefore valid by construction, and +// fixed ids and timestamps make the output identical on every run. +// +// node scripts/build.mjs build every Effort into .flatbread-proof/ +// node scripts/build.mjs --only render build one Effort (for authoring) +// node scripts/build.mjs --out /tmp/x write somewhere else +// node scripts/build.mjs --scale 10 --out /tmp/x10 +// add filler until each Effort is +// about 10 times its size; every +// question keeps its answer +import { createHash } from 'node:crypto'; +import { existsSync } from 'node:fs'; +import { cp, mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { + createProofWriter, + generateArtifactId, + ProofMutationSchema, +} from '@flatbread/proof'; +import { fillerEvents, fillerTerms, mergeEvents } from '../spec/_filler.mjs'; + +const BENCH = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +const SPEC_DIR = join(BENCH, 'spec'); + +const KIND_BY_TYPE = { + CreateEffort: 'effort', + WriteIssue: 'issue', + WriteFinding: 'finding', + WriteCompaction: 'finding', + WriteDecision: 'decision', + WriteConstraint: 'constraint', + WriteRisk: 'risk', + WriteCitation: 'citation', + WriteBlob: 'blob', +}; +// Fields whose values name other records. Authors write local keys; the +// builder swaps in real ids. +const REF_FIELDS = [ + 'derives_from', + 'supersedes', + 'invalidates', + 'cites', + 'blob', + 'supersederId', + 'targetId', + 'findingId', + 'issueId', + 'resolvedBy', + 'decisionId', + 'rejects', + 'riskId', + 'evidence', + 'recordId', + 'effortId', +]; +const GRAPH_DIRS = [ + 'efforts', + 'issues', + 'findings', + 'decisions', + 'constraints', + 'risks', + 'citations', + 'blobs', + '.journal', +]; + +function args(argv) { + const out = { only: [], out: join(BENCH, '.flatbread-proof'), scale: 1 }; + for (let i = 0; i < argv.length; i++) { + if (argv[i] === '--only') out.only.push(...argv[++i].split(',')); + else if (argv[i] === '--out') out.out = resolve(argv[++i]); + else if (argv[i] === '--scale') out.scale = Number(argv[++i]); + else throw new Error(`Unknown argument ${argv[i]}`); + } + if (!(out.scale >= 1)) throw new Error('--scale must be 1 or more'); + // The committed graph is the unscaled one. + if (out.scale > 1 && out.out === join(BENCH, '.flatbread-proof')) + throw new Error('A scaled build needs --out'); + return out; +} + +/** Filler may never name a subsystem a spec or question talks about. */ +async function assertFillerIsDisjoint(specs) { + const questions = await readdir(join(BENCH, 'questions')); + const text = [ + ...specs.map((spec) => JSON.stringify(spec)), + ...(await Promise.all( + questions.map((name) => readFile(join(BENCH, 'questions', name), 'utf8')) + )), + ] + .join('\n') + .toLowerCase(); + for (const spec of specs) + for (const term of fillerTerms(spec.key)) + if (text.includes(term.toLowerCase())) + throw new Error(`Filler subsystem "${term}" appears in real content`); +} + +/** Fixed id: the writer's own format, with a suffix hashed from the key. */ +export function benchId(kind, title, qualifiedKey) { + const bytes = createHash('sha256').update(qualifiedKey).digest(); + return generateArtifactId(kind, title, (n) => bytes.subarray(0, n)); +} + +export async function loadSpecs(only = []) { + const names = (await readdir(SPEC_DIR)).filter( + (name) => !name.startsWith('_') && !name.startsWith('.') + ); + const specs = []; + for (const name of names.sort()) { + const path = join(SPEC_DIR, name); + const file = name.endsWith('.mjs') ? path : join(path, 'index.mjs'); + if (!existsSync(file)) continue; + const spec = (await import(pathToFileURL(file).href)).default; + if (only.length && !only.includes(spec.key)) continue; + specs.push(spec); + } + return specs; +} + +function fail(spec, event, message) { + const where = event?.key ?? event?.type ?? 'effort'; + throw new Error(`[${spec.key}] ${where}: ${message}`); +} + +async function buildEffort(spec, rootDir, keymap) { + if (!/^[a-z][a-z0-9-]*$/.test(spec.key)) + throw new Error(`Bad Effort key ${spec.key}`); + let now = new Date(spec.effort.created_at); + const writer = createProofWriter({ rootDir, clock: () => now }); + const local = new Map(); + const resolveRef = (event, key) => { + const id = local.get(key); + if (!id) fail(spec, event, `unknown key "${key}"`); + return id; + }; + const effortId = benchId('effort', spec.effort.title, `${spec.key}.effort`); + local.set('effort', effortId); + keymap[`${spec.key}.effort`] = effortId; + await writer.mutate( + ProofMutationSchema.parse({ + type: 'CreateEffort', + id: effortId, + title: spec.effort.title, + body: spec.effort.body, + created_at: spec.effort.created_at, + }) + ); + let last = now.getTime(); + for (const event of spec.events) { + const { at, key, ...rest } = event; + if (!at) fail(spec, event, 'every event needs `at`'); + now = new Date(at); + if (Number.isNaN(now.getTime())) fail(spec, event, `bad time ${at}`); + if (now.getTime() < last) fail(spec, event, 'events must be in time order'); + last = now.getTime(); + const payload = { ...rest }; + const kind = KIND_BY_TYPE[payload.type]; + if (kind && kind !== 'effort') { + if (!key) fail(spec, event, 'create events need a `key`'); + if (local.has(key)) fail(spec, event, 'duplicate key'); + payload.effort = effortId; + payload.created_at = at; + } + if (payload.type === 'SetEffortStatus') payload.effortId ??= 'effort'; + for (const field of REF_FIELDS) { + if (payload[field] === undefined || field === 'effort') continue; + payload[field] = Array.isArray(payload[field]) + ? payload[field].map((ref) => resolveRef(event, ref)) + : resolveRef(event, payload[field]); + } + if (kind && kind !== 'effort') { + payload.id = benchId(kind, payload.title, `${spec.key}.${key}`); + local.set(key, payload.id); + keymap[`${spec.key}.${key}`] = payload.id; + } else if (key) fail(spec, event, '`key` is only for create events'); + try { + await writer.mutate(ProofMutationSchema.parse(payload)); + } catch (error) { + fail(spec, event, error instanceof Error ? error.message : String(error)); + } + } + return spec.events.length + 1; +} + +async function main() { + const options = args(process.argv.slice(2)); + const specs = await loadSpecs(options.only); + if (!specs.length) throw new Error('No specs matched'); + if (options.scale > 1) { + await assertFillerIsDisjoint(specs); + for (const spec of specs) + spec.events = mergeEvents(spec.events, fillerEvents(spec, options.scale)); + } + await mkdir(options.out, { recursive: true }); + for (const dir of GRAPH_DIRS) + await rm(join(options.out, dir), { recursive: true, force: true }); + const keymap = {}; + // Each Effort builds in a folder of its own, then moves into place. The + // writer reads every record under its root on each mutation, so a shared + // root would make every Effort pay for the ones built before it. + const parts = join(options.out, '.parts'); + await rm(parts, { recursive: true, force: true }); + for (const spec of specs) { + const started = Date.now(); + const root = join(parts, spec.key); + const events = await buildEffort(spec, root, keymap); + for (const dir of GRAPH_DIRS.filter((d) => d !== '.journal')) + if (existsSync(join(root, dir))) + await cp(join(root, dir), join(options.out, dir), { recursive: true }); + console.log( + `${spec.key}: ${events} mutations in ${Date.now() - started} ms` + ); + } + // The journal is writer state, not benchmark content. + await rm(parts, { recursive: true, force: true }); + await rm(join(options.out, '.journal'), { recursive: true, force: true }); + const sorted = Object.fromEntries( + Object.entries(keymap).sort(([a], [b]) => a.localeCompare(b)) + ); + // Maps each `<effort>.<key>` to its record id, for checking and grading. + await writeFile( + join(options.out, 'keymap.json'), + `${JSON.stringify(sorted, null, 2)}\n` + ); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) + main().catch((error) => { + console.error(error.message); + process.exitCode = 1; + }); diff --git a/benchmarks/proof-recall/scripts/check.mjs b/benchmarks/proof-recall/scripts/check.mjs new file mode 100644 index 00000000..247842d5 --- /dev/null +++ b/benchmarks/proof-recall/scripts/check.mjs @@ -0,0 +1,346 @@ +#!/usr/bin/env node +// Validates the question set against the built graph, then prints coverage. +// Exits 1 on any error, so authors can loop on it. +// +// node scripts/check.mjs all question files +// node scripts/check.mjs --only render one Effort's questions +// node scripts/check.mjs --graph /tmp/x a graph built elsewhere +import { readdir, readFile } from 'node:fs/promises'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { isCompaction } from '@flatbread/proof'; +import { + hasEdge, + idFor, + loadGraph, + qualify, + runCheck, + sameAnswer, + shortestHops, + standing, +} from './graph.mjs'; + +const BENCH = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +export const CATEGORIES = [ + 'current-state', // what holds now + 'lookup', // a fact stated in one record + 'supersession', // follow a replacement chain + 'invalidation', // evidence or a choice shown wrong + 'rejected-alternative', // why an option lost, or which options lost + 'reopened', // a rejected option brought back + 'retraction', // noise removed from browse reads + 'dead-evidence', // live records resting on dead support + 'lifecycle', // Issue, Risk, and Effort transitions + 'blocker', // open blockers and the choices they gate + 'temporal', // what held at a past moment + 'aggregate', // sets and counts across the Effort + 'blob', // facts only in attached payloads + 'truncation', // facts past the browse excerpt + 'compaction', // trusting or doubting the summary + 'negative', // the graph does not say, or the premise is false + 'distractor', // a similar record in another Effort or thread + 'cross-effort', // needs records from two Efforts + 'rationale', // explain why, scored by rubric +]; +const ANSWER_KINDS = ['record', 'records', 'value', 'boolean', 'count', 'text']; +const NEEDS_CHECK = new Set(['record', 'records', 'count']); + +function args(argv) { + const out = { only: [], graph: join(BENCH, '.flatbread-proof') }; + for (let i = 0; i < argv.length; i++) { + if (argv[i] === '--only') out.only.push(...argv[++i].split(',')); + else if (argv[i] === '--graph') out.graph = resolve(argv[++i]); + else throw new Error(`Unknown argument ${argv[i]}`); + } + return out; +} + +export async function loadQuestions(only = []) { + const dir = join(BENCH, 'questions'); + const files = (await readdir(dir)) + .filter((name) => name.endsWith('.json')) + .sort(); + const sets = []; + for (const file of files) { + const set = JSON.parse(await readFile(join(dir, file), 'utf8')); + if (only.length && !only.includes(set.effort)) continue; + sets.push({ file, ...set }); + } + return sets; +} + +function validate(graph, set, q, errors, seen, warnings = []) { + const err = (message) => + errors.push(`${set.file} ${q.id ?? '?'}: ${message}`); + if (!q.id || seen.has(q.id)) return err('missing or duplicate id'); + seen.add(q.id); + if (!Number.isInteger(q.tier) || q.tier < 0 || q.tier > 4) + err('tier must be 0-4'); + if (!Number.isInteger(q.hops) || q.hops < 0) + err('hops must be a whole number'); + if (!q.question?.trim()) err('empty question'); + // Runs show each question alone, so it must name its Effort. + if (/\bthis Effort\b/i.test(q.question ?? '')) + err( + 'says "this Effort"; name the Effort, since runs show a question alone' + ); + for (const c of q.categories ?? []) + if (!CATEGORIES.includes(c)) err(`unknown category ${c}`); + if (!q.categories?.length) err('needs categories'); + const answer = q.answer ?? {}; + if (!ANSWER_KINDS.includes(answer.kind)) + err(`bad answer kind ${answer.kind}`); + if (answer.kind === 'text' && !answer.rubric?.length) + err('text answers need a rubric'); + if (answer.kind !== 'text' && answer.value === undefined) + err('answer needs a value'); + const keysOk = (keys, label) => { + for (const key of keys ?? []) { + try { + idFor(graph, set.effort, key); + } catch (error) { + err(`${label}: ${error.message}`); + } + } + }; + if (!q.evidence?.length) err('needs evidence keys'); + keysOk(q.evidence, 'evidence'); + if (answer.kind === 'record') keysOk([answer.value], 'answer'); + if (answer.kind === 'records') keysOk(answer.value, 'answer'); + const path = q.path ?? []; + if (q.tier >= 1 && q.tier <= 3) { + if (!path.length) err('tiers 1-3 need a path'); + else if (path.length !== q.hops) + err(`hops ${q.hops} but path has ${path.length} edges`); + } + if (q.tier === 0 && q.hops !== 0) err('tier 0 means 0 hops'); + // Runs show a question alone. If an Effort-wide check would also find + // answers in another Effort, the question must name its own, or carry + // `"scoped": true` once an author confirms the wording pins it down. + if (set.effort !== 'cross' && !q.scoped) { + const title = graph.records.get(graph.keymap[`${set.effort}.effort`]) + ?.frontmatter.title; + const named = + title && q.question.toLowerCase().includes(title.toLowerCase()); + const others = Object.keys(graph.keymap) + .filter((key) => key.endsWith('.effort')) + .map((key) => key.split('.')[0]) + .filter((name) => name !== set.effort); + const answers = (r) => + Array.isArray(r) ? r.length > 0 : r !== null && r !== 0 && r !== false; + const wide = (q.checks ?? []).filter( + (c) => (c.type === 'select' || c.type === 'compaction') && !c.effort + ); + // A check that starts from one record is ambiguous when another Effort + // holds a record a reader could take for it: same kind and title, or + // another compaction. Run the check again from each such record. + const single = (q.checks ?? []).filter((c) => + ['asof', 'head', 'chain'].includes(c.type) + ); + const analogs = (c, name) => { + let start; + try { + start = graph.records.get(idFor(graph, set.effort, c.start)); + } catch { + return []; + } + const effortId = graph.keymap[`${name}.effort`]; + return [...graph.records.values()].filter( + (rec) => + rec.frontmatter.effort === effortId && + rec.kind === start.kind && + (rec.frontmatter.title === start.frontmatter.title || + (isCompaction(start) && isCompaction(rec))) + ); + }; + const elsewhere = others.filter( + (name) => + wide.some((c) => { + try { + return answers(runCheck(graph, name, { ...c, effort: name })); + } catch { + return false; + } + }) || + single.some((c) => + analogs(c, name).some((rec) => { + try { + const start = graph.keyById.get(rec.id); + return answers(runCheck(graph, name, { ...c, start })); + } catch { + return false; + } + }) + ) + ); + if (!named && elsewhere.length) + warnings.push( + `${set.file} ${q.id}: its check also answers in ${elsewhere.join( + ', ' + )}; name the Effort, or set "scoped": true if the wording pins it down` + ); + } + // A shortcut makes the question easier than its tier says. Joined + // branches have no single start and end, so this is a warning only. + if (q.tier >= 1 && q.tier <= 3 && path.length > 1) { + const [start] = path[0]; + // Measure to the answer itself when there is one; a reversed last edge + // would otherwise end on the record before it. + const end = answer.kind === 'record' ? answer.value : path.at(-1)[2]; + try { + const shortest = shortestHops(graph, set.effort, start, end); + if (start !== end && shortest < q.hops) + warnings.push( + `${set.file} ${q.id}: a ${shortest}-edge route joins ${start} and ${end}; the path has ${q.hops}` + ); + } catch { + // Unknown keys are already reported as errors. + } + } + for (const edge of path) { + try { + if (!hasEdge(graph, set.effort, edge)) err(`no edge ${edge.join(' ')}`); + } catch (error) { + err(`edge ${edge.join(' ')}: ${error.message}`); + } + } + const evidence = new Set( + (q.evidence ?? []).map((k) => qualify(set.effort, k)) + ); + for (const [from, , to] of path) + for (const key of [from, to]) + if (!evidence.has(qualify(set.effort, key))) + err(`path key ${key} missing from evidence`); + const checks = q.checks ?? []; + if (NEEDS_CHECK.has(answer.kind) && !checks.some((c) => !('expect' in c))) + err(`${answer.kind} answers need a check that computes the answer`); + for (const check of checks) { + try { + const actual = runCheck(graph, set.effort, check); + const ok = + 'expect' in check + ? JSON.stringify(actual) === JSON.stringify(check.expect) + : sameAnswer(answer.kind, answer.value, actual, set.effort); + if (!ok) + err( + `check ${check.type} gave ${JSON.stringify( + actual + )}, expected ${JSON.stringify( + 'expect' in check ? check.expect : answer.value + )}` + ); + } catch (error) { + err(`check ${check.type}: ${error.message}`); + } + } +} + +function histogram(values) { + const out = {}; + for (const v of values) out[v] = (out[v] ?? 0) + 1; + return out; +} + +function chainLengths(graph, recs) { + const lengths = []; + for (const rec of recs) { + if ((rec.frontmatter.supersedes ?? []).length) continue; + let n = 1; + let cur = rec; + while ((cur.frontmatter.superseded_by ?? []).length) { + cur = graph.records.get(cur.frontmatter.superseded_by[0]); + n++; + } + if (n > 1) lengths.push(n); + } + return lengths.sort((a, b) => b - a); +} + +export function graphStats(graph, effortKey) { + const effortId = graph.keymap[`${effortKey}.effort`]; + const recs = [...graph.records.values()].filter( + (r) => r.frontmatter.effort === effortId + ); + const fm = (r) => r.frontmatter; + return { + status: graph.records.get(effortId)?.frontmatter.status, + records: recs.length, + byKind: histogram( + recs.map((r) => (fm(r).kind === 'compaction' ? 'compaction' : r.kind)) + ), + standings: histogram(recs.map((r) => `${r.kind}:${standing(r)}`)), + supersessionChains: chainLengths(graph, recs), + invalidated: recs.filter((r) => (fm(r).invalidated_by ?? []).length).length, + retracted: recs.filter((r) => fm(r).retracted === true).length, + reopened: recs.filter((r) => (fm(r).reopen_history ?? []).length).length, + restingOnDead: recs.filter( + (r) => + !['retracted', 'superseded', 'invalidated', 'rejected'].includes( + standing(r) + ) && + (fm(r).derives_from ?? []).some((id) => { + const s = graph.records.get(id); + return ( + s && + ['invalidated', 'superseded', 'retracted', 'rejected'].includes( + standing(s) + ) + ); + }) + ).length, + longBodies: recs.filter( + (r) => r.body.length > 600 || r.body.split('\n').length > 12 + ).length, + }; +} + +async function main() { + const options = args(process.argv.slice(2)); + const graph = await loadGraph(options.graph); + const sets = await loadQuestions(options.only); + const errors = []; + const warnings = []; + const seen = new Set(); + const all = []; + for (const set of sets) + for (const q of set.questions ?? []) { + validate(graph, set, q, errors, seen, warnings); + all.push({ ...q, effort: set.effort }); + } + const efforts = [ + ...new Set(Object.keys(graph.keymap).map((key) => key.split('.')[0])), + ].sort(); + for (const effort of efforts) { + if (options.only.length && !options.only.includes(effort)) continue; + const qs = all.filter((q) => q.effort === effort); + console.log( + JSON.stringify({ + effort, + ...graphStats(graph, effort), + questions: qs.length, + tiers: histogram(qs.map((q) => q.tier)), + hops: histogram(qs.map((q) => q.hops)), + categories: histogram(qs.flatMap((q) => q.categories ?? [])), + }) + ); + } + const other = all.filter((q) => !efforts.includes(q.effort)); + if (other.length) + console.log(JSON.stringify({ effort: 'cross', questions: other.length })); + if (warnings.length) { + console.warn(warnings.join('\n')); + console.warn(`${warnings.length} warning(s)`); + } + if (errors.length) { + console.error(errors.join('\n')); + console.error(`${errors.length} error(s)`); + process.exitCode = 1; + } else + console.log(`ok: ${all.length} questions, ${graph.records.size} records`); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) + main().catch((error) => { + console.error(error.stack ?? error.message); + process.exitCode = 1; + }); diff --git a/benchmarks/proof-recall/scripts/collect.mjs b/benchmarks/proof-recall/scripts/collect.mjs new file mode 100644 index 00000000..ab26011e --- /dev/null +++ b/benchmarks/proof-recall/scripts/collect.mjs @@ -0,0 +1,112 @@ +#!/usr/bin/env node +// Builds a run file from one-question-per-session runs, taking cost from each +// session's transcript rather than from the agent's own tally. +// +// node scripts/collect.mjs <manifest.json> <run-name> <out.json> +// +// The manifest lists one entry per session: +// [{ "id": "render-001", "folder": "/tmp/.../render-001", "transcript": "/tmp/.../<agent>.output" }] +// Each folder holds the agent's `answer.json`: { "answer": ... }. Transcripts +// are Claude Code agent logs or `claude -p --output-format stream-json` +// output (JSON lines); each assistant turn carries usage. +import { readFile, writeFile } from 'node:fs/promises'; +import { join, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; + +/** + * `context_tokens` counts what entered the context once (new input, cache + * writes, output): how much the agent had to read. `processed_tokens` adds + * cache reads, which grow with every turn the context is re-read. + * `fixed_tokens` is the first turn alone: the system prompt and task, paid + * before any graph read. + */ +export async function sessionCost(transcriptPath) { + const lines = (await readFile(transcriptPath, 'utf8')).split('\n'); + const seen = new Set(); + const models = new Set(); + const cost = { + turns: 0, + tool_calls: 0, + context_tokens: 0, + processed_tokens: 0, + fixed_tokens: 0, + }; + for (const line of lines) { + let entry; + try { + entry = JSON.parse(line); + } catch { + continue; + } + const message = entry.type === 'assistant' ? entry.message : null; + if (!message) continue; + if (message.model) models.add(message.model); + for (const part of message.content ?? []) + if (part.type === 'tool_use') cost.tool_calls++; + // One assistant message can span several log lines; count usage once. + if (!message.usage || seen.has(message.id)) continue; + seen.add(message.id); + const u = message.usage; + const fresh = + (u.input_tokens ?? 0) + + (u.cache_creation_input_tokens ?? 0) + + (u.output_tokens ?? 0); + if (cost.turns === 0) cost.fixed_tokens = fresh; + cost.turns++; + cost.context_tokens += fresh; + cost.processed_tokens += fresh + (u.cache_read_input_tokens ?? 0); + } + return { ...cost, models: [...models] }; +} + +/** Reads each session's answer and cost, and writes one run file. */ +export async function collect(manifest, name, outPath) { + const answers = {}; + const models = new Set(); + for (const session of manifest) { + let answer = null; + try { + answer = JSON.parse( + await readFile(join(session.folder, 'answer.json'), 'utf8') + ).answer; + } catch { + // A missing or broken answer file scores zero. + } + const cost = await sessionCost(session.transcript); + cost.models.forEach((m) => models.add(m)); + answers[session.id] = { + answer, + tokens: cost.context_tokens, + fixed_tokens: cost.fixed_tokens, + processed_tokens: cost.processed_tokens, + tool_calls: cost.tool_calls, + turns: cost.turns, + }; + } + const run = { + run: { + name, + protocol: 'one fresh session per question', + models: [...models], + }, + answers, + }; + await writeFile(resolve(outPath), `${JSON.stringify(run, null, 2)}\n`); + console.log( + `${Object.keys(answers).length} sessions collected into ${outPath}` + ); +} + +async function main() { + const [manifestPath, name, outPath] = process.argv.slice(2); + if (!outPath) + throw new Error('usage: collect.mjs <manifest.json> <run-name> <out.json>'); + const manifest = JSON.parse(await readFile(resolve(manifestPath), 'utf8')); + await collect(manifest, name, outPath); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) + main().catch((error) => { + console.error(error.message); + process.exitCode = 1; + }); diff --git a/benchmarks/proof-recall/scripts/compare.mjs b/benchmarks/proof-recall/scripts/compare.mjs new file mode 100644 index 00000000..ada71d5b --- /dev/null +++ b/benchmarks/proof-recall/scripts/compare.mjs @@ -0,0 +1,115 @@ +#!/usr/bin/env node +// Compares two runs over the questions both answered, pair by pair. +// +// node scripts/compare.mjs runs/<a>.json runs/<b>.json [--skip id1,id2] +// +// Read tokens leave out each session's first turn (`fixed_tokens`), which is +// the same task and system prompt in both runs. A sign test on the questions +// that only one run got right says how likely the accuracy gap is by chance. +import { readFile } from 'node:fs/promises'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { loadQuestions } from './check.mjs'; +import { score } from './grade.mjs'; +import { loadGraph } from './graph.mjs'; + +const BENCH = resolve(dirname(fileURLToPath(import.meta.url)), '..'); + +function summary(values) { + const sorted = [...values].sort((a, b) => a - b); + const mid = sorted.length / 2; + const median = + sorted.length % 2 + ? sorted[Math.floor(mid)] + : (sorted[mid - 1] + sorted[mid]) / 2; + const mean = values.reduce((a, b) => a + b, 0) / values.length; + return { mean: Math.round(mean), median: Math.round(median) }; +} + +/** Two-sided exact sign test: P(a split at least this uneven | p = 0.5). */ +export function signTest(wins, losses) { + const n = wins + losses; + if (!n) return 1; + const k = Math.min(wins, losses); + let tail = 0; + for (let i = 0, c = 1; i <= k; i++, c = (c * (n - i + 1)) / i) + tail += c / 2 ** n; + return Math.min(1, 2 * tail); +} + +async function main() { + const argv = process.argv.slice(2); + const at = argv.indexOf('--skip'); + const skip = new Set(at >= 0 ? argv.splice(at, 2)[1].split(',') : []); + const [pathA, pathB] = argv; + if (!pathB) + throw new Error( + 'usage: compare.mjs <run-a.json> <run-b.json> [--skip ids]' + ); + const [a, b] = await Promise.all( + [pathA, pathB].map(async (p) => + JSON.parse(await readFile(resolve(p), 'utf8')) + ) + ); + const graph = await loadGraph(join(BENCH, '.flatbread-proof')); + const rows = []; + for (const set of await loadQuestions()) + for (const q of set.questions) { + const x = a.answers?.[q.id]; + const y = b.answers?.[q.id]; + if (!x || !y || skip.has(q.id)) continue; + rows.push({ + id: q.id, + tier: q.tier, + a: score(graph, q, set.effort, x.answer), + b: score(graph, q, set.effort, y.answer), + readA: x.tokens - (x.fixed_tokens ?? 0), + readB: y.tokens - (y.fixed_tokens ?? 0), + toolsA: x.tool_calls, + toolsB: y.tool_calls, + }); + } + if (!rows.length) throw new Error('The runs share no questions'); + const onlyA = rows.filter((r) => r.a === 1 && r.b < 1).map((r) => r.id); + const onlyB = rows.filter((r) => r.b === 1 && r.a < 1).map((r) => r.id); + const total = (key) => +rows.reduce((n, r) => n + r[key], 0).toFixed(2); + const byTier = {}; + for (const r of rows) { + const t = (byTier[`tier-${r.tier}`] ??= { n: 0, a: 0, b: 0 }); + t.n++; + t.a += r.a; + t.b += r.b; + } + console.log( + JSON.stringify( + { + a: a.run?.name ?? pathA, + b: b.run?.name ?? pathB, + questions: rows.length, + correct: { a: total('a'), b: total('b') }, + byTier, + onlyA, + onlyB, + signTestP: +signTest(onlyA.length, onlyB.length).toFixed(4), + readTokens: { + a: summary(rows.map((r) => r.readA)), + b: summary(rows.map((r) => r.readB)), + diff: summary(rows.map((r) => r.readA - r.readB)), + aCheaper: rows.filter((r) => r.readA < r.readB).length, + }, + toolCalls: { + a: summary(rows.map((r) => r.toolsA)), + b: summary(rows.map((r) => r.toolsB)), + }, + }, + null, + 2 + ) + ); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) + main().catch((error) => { + console.error(error.message); + process.exitCode = 1; + }); diff --git a/benchmarks/proof-recall/scripts/grade.mjs b/benchmarks/proof-recall/scripts/grade.mjs new file mode 100644 index 00000000..b929907c --- /dev/null +++ b/benchmarks/proof-recall/scripts/grade.mjs @@ -0,0 +1,158 @@ +#!/usr/bin/env node +// Scores one benchmark run. +// +// node scripts/grade.mjs runs/<name>.json +// +// A run file holds one entry per question id: +// { "run": { "strategy": "brief", "model": "..." }, +// "answers": { "<question id>": { "answer": ..., "tokens": 1234, "tool_calls": 5 } } } +// Record answers may be Proof ids or benchmark keys. Text answers are scored +// against the question's rubric: each rubric item lists phrases, and the item +// counts when the answer contains any one of them. +import { readFile } from 'node:fs/promises'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { loadQuestions } from './check.mjs'; +import { loadGraph, qualify, sameAnswer } from './graph.mjs'; + +const BENCH = resolve(dirname(fileURLToPath(import.meta.url)), '..'); + +function toKey(graph, effort, value) { + if (typeof value !== 'string') return value; + const key = graph.keyById.get(value.trim()); + return key ?? qualify(effort, value.trim()); +} + +export function score(graph, q, effort, given) { + if (given === undefined || given === null) return 0; + const { kind, value, rubric, accept } = q.answer; + if (kind === 'text') { + const text = String(given).toLowerCase(); + const hits = rubric.filter((item) => + (Array.isArray(item) ? item : [item]).some((p) => + text.includes(p.toLowerCase()) + ) + ); + return hits.length / rubric.length; + } + if (kind === 'record') + return sameAnswer(kind, value, toKey(graph, effort, given), effort) ? 1 : 0; + if (kind === 'records') + return sameAnswer( + kind, + value, + (Array.isArray(given) ? given : [given]).map((v) => + toKey(graph, effort, v) + ), + effort + ) + ? 1 + : 0; + if (kind === 'boolean') { + // Agents add evidence after the verdict: "false, fnd-...". Read the + // leading word. + const parsed = + typeof given === 'string' + ? /^(true|false)\b/.exec(given.trim().toLowerCase())?.[1] + : given; + if (parsed === 'true' || parsed === true) return value === true ? 1 : 0; + if (parsed === 'false' || parsed === false) return value === false ? 1 : 0; + return 0; + } + if (kind === 'count') + return firstNumber(String(given)) === Number(value) ? 1 : 0; + return [value, ...(accept ?? [])].some((gold) => looseValue(gold, given)) + ? 1 + : 0; +} + +function firstNumber(text) { + const match = /-?\d[\d,]*(?:\.\d+)?/.exec(text); + return match ? Number(match[0].replace(/,/g, '')) : NaN; +} + +/** + * Agents add detail to short answers: "46 player-proximity reads" for "46", + * "textures (3,184 MB)" for "textures". Accept an answer that equals the gold + * value, starts with it, or carries the same leading number and unit. + */ +function looseValue(gold, given) { + const want = String(gold).trim().toLowerCase(); + const got = String(given).trim().toLowerCase(); + if (got === want) return true; + if (got.startsWith(want) && !/[a-z0-9.]/.test(got[want.length] ?? '')) + return true; + const number = firstNumber(want); + if (Number.isNaN(number) || firstNumber(got) !== number) return false; + const unit = (text) => + /-?\d[\d,]*(?:\.\d+)?\s*([a-z%/]+)?/.exec(text)?.[1] ?? ''; + return !unit(want) || unit(want) === unit(got); +} + +function summarize(rows, by) { + const groups = {}; + for (const row of rows) + for (const key of [].concat(by(row))) { + const g = (groups[key] ??= { n: 0, score: 0, tokens: 0, tool_calls: 0 }); + g.n++; + g.score += row.score; + g.tokens += row.tokens ?? 0; + g.tool_calls += row.tool_calls ?? 0; + } + return Object.fromEntries( + Object.entries(groups) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([key, g]) => [ + key, + { + n: g.n, + accuracy: +(g.score / g.n).toFixed(3), + mean_tokens: Math.round(g.tokens / g.n), + mean_tool_calls: +(g.tool_calls / g.n).toFixed(1), + }, + ]) + ); +} + +async function main() { + const runPath = process.argv[2]; + if (!runPath) throw new Error('usage: grade.mjs <run.json>'); + const run = JSON.parse(await readFile(resolve(runPath), 'utf8')); + const graph = await loadGraph(join(BENCH, '.flatbread-proof')); + const rows = []; + for (const set of await loadQuestions()) + for (const q of set.questions) { + const entry = run.answers?.[q.id]; + if (!entry) continue; + rows.push({ + id: q.id, + effort: set.effort, + tier: q.tier, + categories: q.categories, + score: score(graph, q, set.effort, entry.answer), + tokens: entry.tokens, + tool_calls: entry.tool_calls, + }); + } + console.log( + JSON.stringify( + { + run: run.run ?? {}, + answered: rows.length, + overall: summarize(rows, () => 'all').all, + byTier: summarize(rows, (r) => `tier-${r.tier}`), + byEffort: summarize(rows, (r) => r.effort), + byCategory: summarize(rows, (r) => r.categories), + misses: rows.filter((r) => r.score < 1).map((r) => r.id), + }, + null, + 2 + ) + ); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) + main().catch((error) => { + console.error(error.message); + process.exitCode = 1; + }); diff --git a/benchmarks/proof-recall/scripts/graph.mjs b/benchmarks/proof-recall/scripts/graph.mjs new file mode 100644 index 00000000..4d27b758 --- /dev/null +++ b/benchmarks/proof-recall/scripts/graph.mjs @@ -0,0 +1,362 @@ +// Loads a built benchmark graph and evaluates question checks against it. +// Shared by check.mjs (authoring) and grade.mjs (scoring runs). +import { readdir, readFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { + compactionChanges, + compactionHeads, + isCompaction, + isLiveStanding, + KIND_DIRECTORY, + parseCovers, + parseDocument, + recordStanding, + staleDerivations, +} from '@flatbread/proof'; + +const EXCERPT_CHARS = 600; +const EXCERPT_LINES = 12; + +export async function loadGraph(root) { + const keymap = JSON.parse(await readFile(join(root, 'keymap.json'), 'utf8')); + const keyById = new Map(Object.entries(keymap).map(([k, id]) => [id, k])); + const records = new Map(); + for (const [kind, dir] of Object.entries(KIND_DIRECTORY)) { + let files = []; + try { + files = await readdir(join(root, dir)); + } catch { + continue; + } + for (const file of files.filter((name) => name.endsWith('.md'))) { + const bytes = await readFile(join(root, dir, file)); + const { frontmatter, body } = parseDocument(bytes, kind); + records.set(frontmatter.id, { + id: frontmatter.id, + kind, + frontmatter, + body, + }); + } + } + return { root, keymap, keyById, records }; +} + +/** A question's local keys belong to its file's Effort; `effort.key` is global. */ +export function qualify(effort, key) { + return key.includes('.') ? key : `${effort}.${key}`; +} + +export function idFor(graph, effort, key) { + const id = graph.keymap[qualify(effort, key)]; + if (!id) throw new Error(`unknown key "${qualify(effort, key)}"`); + return id; +} + +function record(graph, effort, key) { + return graph.records.get(idFor(graph, effort, key)); +} + +function list(value) { + return Array.isArray(value) ? value : value === undefined ? [] : [value]; +} + +export function standing(rec) { + return recordStanding(rec); +} + +function effortRecords(graph, effortId) { + return [...graph.records.values()].filter( + (rec) => rec.frontmatter.effort === effortId + ); +} + +const PATH_RELATIONS = new Set([ + 'derives_from', + 'supersedes', + 'superseded_by', + 'invalidates', + 'invalidated_by', + 'resolved_by', + 'rejected_by', + 'mitigated_by', + 'evidence', + 'cites', + 'blob', + 'effort', + // Reverse readings of stored forward edges: + 'supports', // to.derives_from contains from + 'cited_by', // to.cites contains from + 'reopen_history', // from.reopen_history[].rejected_by contains to +]); + +/** True when the stored graph holds this edge. */ +const LINK_FIELDS = [ + 'derives_from', + 'supersedes', + 'superseded_by', + 'invalidates', + 'invalidated_by', + 'resolved_by', + 'rejected_by', + 'mitigated_by', + 'evidence', + 'cites', + 'blob', +]; + +/** + * Fewest edges between two records, following only links stored on the + * record being read (what a reader can see), and never the Effort link every + * record shares. A route shorter than a question's `hops` means the question + * is easier than its tier claims. + */ +export function shortestHops(graph, effort, fromKey, toKey, max = 8) { + if (!graph.adjacency) { + graph.adjacency = new Map(); + const link = (a, b) => { + if (!graph.adjacency.has(a)) graph.adjacency.set(a, new Set()); + graph.adjacency.get(a).add(b); + }; + for (const rec of graph.records.values()) { + const targets = LINK_FIELDS.flatMap((field) => + list(rec.frontmatter[field]) + ); + for (const entry of list(rec.frontmatter.reopen_history)) + targets.push(...list(entry?.rejected_by)); + for (const target of targets) link(rec.id, target); + } + } + const start = idFor(graph, effort, fromKey); + const goal = idFor(graph, effort, toKey); + let frontier = [start]; + const seen = new Set(frontier); + for (let hops = 0; hops <= max; hops++) { + if (frontier.includes(goal)) return hops; + const next = []; + for (const id of frontier) + for (const neighbor of graph.adjacency.get(id) ?? []) + if (!seen.has(neighbor)) { + seen.add(neighbor); + next.push(neighbor); + } + frontier = next; + } + return Infinity; +} + +export function hasEdge(graph, effort, [fromKey, relation, toKey]) { + if (!PATH_RELATIONS.has(relation)) + throw new Error(`bad relation ${relation}`); + const from = record(graph, effort, fromKey); + const to = record(graph, effort, toKey); + if (!from || !to) return false; + if (relation === 'supports') + return list(to.frontmatter.derives_from).includes(from.id); + if (relation === 'cited_by') + return list(to.frontmatter.cites).includes(from.id); + if (relation === 'reopen_history') + return list(from.frontmatter.reopen_history).some((entry) => + list(entry?.rejected_by).includes(to.id) + ); + return list(from.frontmatter[relation]).includes(to.id); +} + +function head(graph, rec) { + const seen = new Set(); + let current = rec; + while (current && list(current.frontmatter.superseded_by).length) { + if (seen.has(current.id)) + throw new Error(`supersession cycle at ${current.id}`); + seen.add(current.id); + current = graph.records.get(list(current.frontmatter.superseded_by)[0]); + } + return current; +} + +function chain(graph, rec) { + let first = rec; + while (list(first.frontmatter.supersedes).length) + first = graph.records.get(list(first.frontmatter.supersedes)[0]); + const out = [first]; + while (list(out.at(-1).frontmatter.superseded_by).length) + out.push(graph.records.get(list(out.at(-1).frontmatter.superseded_by)[0])); + return out; +} + +function matches(rec, where = {}) { + return Object.entries(where).every(([field, want]) => { + const value = field === 'standing' ? standing(rec) : rec.frontmatter[field]; + return list(want).map(String).includes(String(value)); + }); +} + +function compactionState(graph, effortId) { + const recs = effortRecords(graph, effortId); + const heads = compactionHeads(recs).sort((a, b) => + `${a.frontmatter.created_at}\0${a.id}`.localeCompare( + `${b.frontmatter.created_at}\0${b.id}` + ) + ); + const top = heads.at(-1); + if (!top) + return { + head: null, + heads: 0, + stale: false, + changes: [], + staleTargets: [], + }; + const covers = parseCovers(top.frontmatter.covers); + const changes = compactionChanges(covers, recs); + const staleTargets = staleDerivations( + covers, + list(top.frontmatter.derives_from), + recs + ); + const invalidated = list(top.frontmatter.invalidated_by).length > 0; + return { + head: top.id, + heads: heads.length, + stale: staleTargets.length > 0 || invalidated, + changes, + staleTargets, + }; +} + +/** + * Runs one check. Value checks return the answer they compute; assertion + * checks (`body`, `edge`) return booleans. + */ +export function runCheck(graph, effort, check) { + const keyOf = (rec) => graph.keyById.get(rec.id); + // Only Effort-wide checks need it; cross-Effort files name `check.effort`. + const effortId = () => idFor(graph, check.effort ?? effort, 'effort'); + switch (check.type) { + case 'field': { + const rec = record(graph, effort, check.record); + if (check.field === 'standing') return standing(rec); + return rec.frontmatter[check.field] ?? null; + } + case 'head': + return keyOf(head(graph, record(graph, effort, check.start))); + case 'chain': + return chain(graph, record(graph, effort, check.start)).map(keyOf); + case 'asof': { + // The version of a supersession chain that was current at a moment. + const at = new Date(check.at).getTime(); + const versions = chain(graph, record(graph, effort, check.start)).filter( + (rec) => new Date(rec.frontmatter.created_at).getTime() <= at + ); + return versions.length ? keyOf(versions.at(-1)) : null; + } + case 'select': { + // `effort` may list several Efforts, or be "*" for all of them. + const scope = + check.effort === '*' + ? Object.keys(graph.keymap) + .filter((key) => key.endsWith('.effort')) + .map((key) => key.split('.')[0]) + : Array.isArray(check.effort) + ? check.effort + : null; + let recs = scope + ? scope.flatMap((name) => + effortRecords(graph, idFor(graph, name, 'effort')) + ) + : effortRecords(graph, effortId()); + if (check.kinds) + recs = recs.filter((rec) => check.kinds.includes(rec.kind)); + const retracted = check.retracted ?? 'exclude'; + if (retracted === 'exclude') + recs = recs.filter((rec) => rec.frontmatter.retracted !== true); + if (retracted === 'only') + recs = recs.filter((rec) => rec.frontmatter.retracted === true); + if (check.compactions !== true) + recs = recs.filter((rec) => !isCompaction(rec)); + if (check.where) recs = recs.filter((rec) => matches(rec, check.where)); + if (check.live !== undefined) + recs = recs.filter( + (rec) => isLiveStanding(rec.kind, standing(rec)) === check.live + ); + if (check.derivesFrom) { + const target = idFor(graph, effort, check.derivesFrom); + recs = recs.filter((rec) => + list(rec.frontmatter.derives_from).includes(target) + ); + } + if (check.restsOn) + recs = recs.filter((rec) => + list(rec.frontmatter.derives_from).some((id) => { + const support = graph.records.get(id); + return support && list(check.restsOn).includes(standing(support)); + }) + ); + if (check.bodyIncludes) + recs = recs.filter((rec) => + rec.body.toLowerCase().includes(check.bodyIncludes.toLowerCase()) + ); + const keys = recs.map(keyOf).sort(); + return check.count ? keys.length : keys; + } + case 'efforts': { + // Efforts themselves, filtered by frontmatter such as `status`. + const efforts = [...graph.records.values()].filter( + (rec) => rec.kind === 'effort' && matches(rec, check.where) + ); + const keys = efforts.map(keyOf).sort(); + return check.count ? keys.length : keys; + } + case 'compaction': { + const state = compactionState(graph, effortId()); + if (check.field === 'head') + return state.head ? keyOf(graph.records.get(state.head)) : null; + if (check.field === 'heads') return state.heads; + if (check.field === 'stale') return state.stale; + if (check.field === 'changes') return state.changes.length; + if (check.field === 'changed') + return state.changes.map((c) => graph.keyById.get(c.id)).sort(); + if (check.field === 'staleTargets') + return state.staleTargets.map((c) => graph.keyById.get(c.id)).sort(); + throw new Error(`bad compaction field ${check.field}`); + } + case 'body': { + const rec = record(graph, effort, check.record); + const body = rec.body.replace(/\r\n?/g, '\n'); + return list(check.includes).every((text) => { + const at = body.indexOf(text); + if (at < 0) return false; + if (!check.afterExcerpt) return true; + // The fact must sit past what browse digests show. + return ( + at >= EXCERPT_CHARS || + body.slice(0, at).split('\n').length > EXCERPT_LINES + ); + }); + } + case 'edge': + return hasEdge(graph, effort, check.edge); + default: + throw new Error(`bad check type ${check.type}`); + } +} + +export function sameAnswer(kind, expected, actual, effort) { + const norm = (key) => (typeof key === 'string' ? qualify(effort, key) : key); + if (kind === 'record') { + const one = + Array.isArray(actual) && actual.length === 1 ? actual[0] : actual; + return norm(expected) === norm(one); + } + if (kind === 'records') { + const a = [...list(expected)].map(norm).sort(); + const b = [...list(actual)].map(norm).sort(); + return a.length === b.length && a.every((value, i) => value === b[i]); + } + if (kind === 'count') return Number(expected) === Number(actual); + if (kind === 'boolean') return Boolean(expected) === Boolean(actual); + return ( + String(expected).trim().toLowerCase() === + String(actual).trim().toLowerCase() + ); +} diff --git a/benchmarks/proof-recall/scripts/prepare-run.mjs b/benchmarks/proof-recall/scripts/prepare-run.mjs new file mode 100644 index 00000000..40a68886 --- /dev/null +++ b/benchmarks/proof-recall/scripts/prepare-run.mjs @@ -0,0 +1,119 @@ +#!/usr/bin/env node +// Prepares a clean folder for one benchmark run: the built graph, the config, +// and the question text, with no answers, specs, or key map. +// +// node scripts/prepare-run.mjs <out-dir> [--only render,world] [--ids a,b] +// [--graph <built-graph-dir>] +// +// The answering agent works only inside <out-dir>, running +// `./flatbread proof …` there. +import { cp, mkdir, rm, symlink, writeFile } from 'node:fs/promises'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { loadQuestions } from './check.mjs'; + +const BENCH = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +// The form an answer takes, never its content. +export const FORMATS = { + record: 'one Proof record id', + records: 'a list of Proof record ids', + value: 'a short value, such as a number with its unit or a name', + boolean: 'true or false', + count: 'a whole number', + text: 'one or two sentences', +}; +const REPO = resolve(BENCH, '..', '..'); + +/** Questions as an agent may see them: text and answer form only. */ +export async function publicQuestions({ only = [], ids = [] } = {}) { + const wanted = new Set(ids); + return (await loadQuestions(only)) + .flatMap((set) => set.questions) + .filter((q) => !wanted.size || wanted.has(q.id)) + .map((q) => ({ + id: q.id, + question: q.question, + format: FORMATS[q.answer.kind], + })); +} + +/** Copies a built graph without its key map, which holds the answers. */ +export async function copyPublicGraph( + to, + graph = join(BENCH, '.flatbread-proof') +) { + await cp(graph, to, { + recursive: true, + filter: (src) => !src.endsWith('keymap.json'), + }); +} + +/** + * Empties `out` and fills it with a graph, the config, and the questions. + * The graph is the committed one unless `graph` names another build. With + * `linkTo`, the folder links to a public graph copy instead of copying one. + * With `server`, its `./flatbread` sends reads to that `proof serve` socket. + */ +export async function prepareFolder( + out, + questions, + graph = join(BENCH, '.flatbread-proof'), + { linkTo, server } = {} +) { + await rm(out, { recursive: true, force: true }); + await mkdir(out, { recursive: true }); + if (linkTo) await symlink(linkTo, join(out, '.flatbread-proof'), 'junction'); + else await copyPublicGraph(join(out, '.flatbread-proof'), graph); + await cp( + join(BENCH, 'flatbread.config.js'), + join(out, 'flatbread.config.js') + ); + await symlink( + join(REPO, 'node_modules'), + join(out, 'node_modules'), + 'junction' + ); + await writeFile( + join(out, 'flatbread'), + `#!/bin/sh\n${ + server ? `export FLATBREAD_PROOF_SERVER="${server}"\n` : '' + }exec node "${join( + REPO, + 'packages', + 'flatbread', + 'bin', + 'flatbread.js' + )}" "$@"\n`, + { mode: 0o755 } + ); + await writeFile( + join(out, 'questions.json'), + `${JSON.stringify(questions, null, 2)}\n` + ); +} + +async function main() { + const argv = process.argv.slice(2); + const out = argv[0] && !argv[0].startsWith('--') ? resolve(argv[0]) : null; + if (!out) + throw new Error( + 'usage: prepare-run.mjs <out-dir> [--only e1,e2] [--ids q1,q2]' + ); + const pick = (flag) => { + const at = argv.indexOf(flag); + return at >= 0 ? argv[at + 1].split(',') : []; + }; + const questions = await publicQuestions({ + only: pick('--only'), + ids: pick('--ids'), + }); + const graph = pick('--graph')[0]; + await prepareFolder(out, questions, graph ? resolve(graph) : undefined); + console.log(`${questions.length} questions ready in ${out}`); +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) + main().catch((error) => { + console.error(error.message); + process.exitCode = 1; + }); diff --git a/benchmarks/proof-recall/scripts/run.mjs b/benchmarks/proof-recall/scripts/run.mjs new file mode 100644 index 00000000..428936c2 --- /dev/null +++ b/benchmarks/proof-recall/scripts/run.mjs @@ -0,0 +1,380 @@ +#!/usr/bin/env node +// Runs the benchmark: one fresh, headless Claude Code session per question +// and per strategy, then collects answers and cost into run files. +// +// node scripts/run.mjs <work-dir> --name <run> [--model haiku] +// [--strategies brief,nobrief] [--only render] [--ids a,b] +// [--jobs 8] [--timeout 600] [--graph <built-graph-dir>] +// [--server <socket>] [--no-serve] +// node scripts/run.mjs --stop-server [--server <socket>] +// +// Each session works in <work-dir>/<strategy>/<id>/, which holds a link to +// the shared copy of the graph, TASK.md, the agent's answer.json, and +// transcript.jsonl. A rerun skips sessions that already have both an answer +// and a transcript, so an interrupted run picks up where it stopped. Keep +// <work-dir> outside the repository, so no CLAUDE.md or AGENTS.md reaches the +// agent. +// +// Runs share two things, kept under <tmp>/flatbread-proof-recall/: +// +// - graphs/<hash>/: one read-only copy of each built graph, without its key +// map, named by a hash of its contents. Every run on the same build reads +// the same files. +// - proof.sock: one `flatbread proof serve` process that keeps each graph +// loaded and answers every session's reads, so no read rebuilds the graph. +// It serves reads only. The first run that finds no server starts one and +// leaves it running for later runs, including runs in parallel; stop it +// with --stop-server, or restart it after rebuilding the CLI so it runs +// the new code. --no-serve makes every read run locally instead. +// +// Sessions get only the Bash, Read, and Write tools, no MCP servers, and no +// settings files, so an agent cannot reach other sessions or services. +import { spawn } from 'node:child_process'; +import { createHash, randomUUID } from 'node:crypto'; +import { createWriteStream, existsSync, openSync } from 'node:fs'; +import { + chmod, + mkdir, + readdir, + readFile, + rename, + rm, + stat, + writeFile, +} from 'node:fs/promises'; +import { request } from 'node:http'; +import { tmpdir } from 'node:os'; +import { dirname, join, relative, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { collect } from './collect.mjs'; +import { + copyPublicGraph, + prepareFolder, + publicQuestions, +} from './prepare-run.mjs'; +import { STRATEGIES, taskText } from './task.mjs'; + +const BENCH = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +// What runs share: graph copies and the read server. +const SHARED = join(tmpdir(), 'flatbread-proof-recall'); +const TOOLS = 'Bash,Read,Write'; +const FLATBREAD_BIN = resolve( + BENCH, + '..', + '..', + 'packages', + 'flatbread', + 'bin', + 'flatbread.js' +); +// Variables that tie a process to the Claude Code session that launched it. +// A benchmark session inheriting them could report into that session. +const SESSION_VARS = [ + 'CLAUDE_CODE_SESSION_ID', + 'CLAUDE_CODE_REMOTE_SESSION_ID', + 'CLAUDE_CODE_REMOTE_SDK_URL', + 'CLAUDE_CODE_MESSAGING_SOCKET', + 'CLAUDE_CODE_MESSAGING_TOKEN', + 'CLAUDE_SESSION_INGRESS_TOKEN_FILE', + 'CLAUDE_CODE_CHILD_SESSION', + 'CLAUDE_CODE_SESSION_ATTENDED', + 'CLAUDE_CODE_SYNC_SESSION_REFS', + 'CLAUDE_CODE_TEE_SDK_STDOUT', + 'CLAUDE_PID', +]; + +function args(argv) { + const out = { + dir: null, + name: null, + model: 'haiku', + strategies: STRATEGIES, + only: [], + ids: [], + jobs: 8, + timeout: 600, + graph: undefined, + serve: true, + server: join(SHARED, 'proof.sock'), + stopServer: false, + }; + for (let i = 0; i < argv.length; i++) { + const flag = argv[i]; + const next = () => argv[++i]; + if (flag === '--name') out.name = next(); + else if (flag === '--model') out.model = next(); + else if (flag === '--strategies') out.strategies = next().split(','); + else if (flag === '--only') out.only = next().split(','); + else if (flag === '--ids') out.ids = next().split(','); + else if (flag === '--jobs') out.jobs = Number(next()); + else if (flag === '--timeout') out.timeout = Number(next()); + else if (flag === '--graph') out.graph = resolve(next()); + else if (flag === '--no-serve') out.serve = false; + else if (flag === '--server') out.server = resolve(next()); + else if (flag === '--stop-server') out.stopServer = true; + else if (!flag.startsWith('--') && !out.dir) out.dir = resolve(flag); + else throw new Error(`Unknown argument ${flag}`); + } + if (out.stopServer) return out; + if (!out.dir || !out.name) + throw new Error('usage: run.mjs <work-dir> --name <run> [options]'); + if (out.dir.startsWith(resolve(BENCH, '..', '..') + '/')) + throw new Error('Keep <work-dir> outside the repository'); + return out; +} + +const sleep = (ms) => new Promise((done) => setTimeout(done, ms)); + +/** True when something answers HTTP on `socket`: a running `proof serve`. */ +function serverAnswers(socket) { + return new Promise((answer) => { + const req = request( + { socketPath: socket, path: '/', method: 'GET' }, + (res) => { + res.resume(); + answer(true); + } + ); + req.on('error', () => answer(false)); + req.setTimeout(2000, () => { + req.destroy(); + answer(false); + }); + req.end(); + }); +} + +/** + * Reuses the read server on `socket`, or starts one that outlives this run. + * A lock folder makes sure that runs starting together start one server. + */ +async function ensureServer(socket) { + if (await serverAnswers(socket)) return 'reused'; + const dir = dirname(socket); + await mkdir(dir, { recursive: true }); + const lock = `${socket}.lock`; + for (let i = 0; ; i++) { + try { + await mkdir(lock); + break; + } catch { + if (await serverAnswers(socket)) return 'reused'; + // A run that died mid-start leaves its lock; take it after a minute. + const age = Date.now() - (await stat(lock).catch(() => null))?.mtimeMs; + if (age > 60e3) await rm(lock, { recursive: true, force: true }); + else if (i > 600) throw new Error(`Gave up waiting for ${lock}`); + await sleep(200); + } + } + try { + if (await serverAnswers(socket)) return 'reused'; + const log = openSync(join(dir, 'serve.log'), 'a'); + const child = spawn( + process.execPath, + [FLATBREAD_BIN, 'proof', 'serve', '--socket', socket], + { cwd: dir, detached: true, stdio: ['ignore', log, log] } + ); + child.unref(); + await writeFile(`${socket}.pid`, `${child.pid}\n`); + for (let i = 0; i < 300; i++) { + if (await serverAnswers(socket)) return 'started'; + await sleep(200); + } + throw new Error(`proof serve did not start; see ${join(dir, 'serve.log')}`); + } finally { + await rm(lock, { recursive: true, force: true }); + } +} + +/** Stops the server that `ensureServer` started on `socket`. */ +async function stopServer(socket) { + const pid = Number(await readFile(`${socket}.pid`, 'utf8').catch(() => NaN)); + if (pid) { + try { + process.kill(pid); + console.log(`Stopped proof serve (pid ${pid})`); + } catch { + console.log(`No proof serve running as pid ${pid}`); + } + } else console.log(`No proof serve recorded for ${socket}`); + await rm(`${socket}.pid`, { force: true }); + await rm(socket, { force: true }); +} + +/** + * One hash over every file under `dir` but the key map: its path relative to + * `dir` and its bytes. A graph and its public copy hash the same. + */ +async function treeHash(dir) { + const hash = createHash('sha256'); + const walk = async (path) => { + const entries = (await readdir(path, { withFileTypes: true })).sort( + (a, b) => a.name.localeCompare(b.name) + ); + for (const entry of entries) { + const child = join(path, entry.name); + if (entry.isDirectory()) await walk(child); + else if (entry.name !== 'keymap.json') + hash + .update(relative(dir, child)) + .update('\0') + .update(await readFile(child)); + } + }; + await walk(dir); + return hash.digest('hex'); +} + +/** + * The shared public copy of `graph`, made once per build. A copy whose files + * no longer match its name was changed after the fact, so it is made again. + */ +async function sharedGraph(graph = join(BENCH, '.flatbread-proof')) { + const hash = await treeHash(graph); + const dir = join(SHARED, 'graphs', hash.slice(0, 16)); + if (existsSync(dir) && (await treeHash(dir)) === hash) return { dir, hash }; + await rm(dir, { recursive: true, force: true }); + const temporary = `${dir}.tmp-${randomUUID()}`; + await copyPublicGraph(temporary, graph); + await chmodTree(temporary); + try { + await rename(temporary, dir); + } catch { + // Another run made the same copy first. + await rm(temporary, { recursive: true, force: true }); + } + return { dir, hash }; +} + +/** Makes a folder tree read-only, so no session can change what others read. */ +async function chmodTree(dir) { + for (const entry of await readdir(dir, { withFileTypes: true })) { + const path = join(dir, entry.name); + if (entry.isDirectory()) await chmodTree(path); + else await chmod(path, 0o444); + } + await chmod(dir, 0o555); +} + +function sessionEnv() { + const env = { ...process.env }; + for (const key of SESSION_VARS) delete env[key]; + return env; +} + +/** Runs one session; resolves with its exit code, or "timeout". */ +function runSession(folder, model, timeoutSeconds) { + return new Promise((resolveRun) => { + const transcript = createWriteStream(join(folder, 'transcript.jsonl')); + const child = spawn( + 'claude', + [ + '-p', + `Read ${join(folder, 'TASK.md')} and follow it exactly.`, + '--model', + model, + '--session-id', + randomUUID(), + '--no-session-persistence', + '--strict-mcp-config', + '--mcp-config', + '{"mcpServers":{}}', + '--tools', + TOOLS, + '--allowedTools', + TOOLS, + '--setting-sources', + '', + '--output-format', + 'stream-json', + '--verbose', + ], + { cwd: folder, env: sessionEnv(), stdio: ['ignore', 'pipe', 'pipe'] } + ); + child.stdout.pipe(transcript); + let stderr = ''; + child.stderr.on('data', (chunk) => (stderr += chunk)); + const timer = setTimeout( + () => child.kill('SIGTERM'), + timeoutSeconds * 1000 + ); + child.on('close', async (code, signal) => { + clearTimeout(timer); + transcript.end(); + if (stderr) await writeFile(join(folder, 'stderr.txt'), stderr); + resolveRun(signal ? 'timeout' : code); + }); + }); +} + +async function main() { + const options = args(process.argv.slice(2)); + if (options.stopServer) return stopServer(options.server); + const questions = await publicQuestions(options); + // Alternate strategies question by question, so a change in API speed or + // load over the run falls on both strategies alike. + const sessions = []; + for (const q of questions) + for (const strategy of options.strategies) + sessions.push({ + id: q.id, + strategy, + q, + folder: join(options.dir, strategy, q.id), + }); + const todo = sessions.filter( + (s) => + !existsSync(join(s.folder, 'answer.json')) || + !existsSync(join(s.folder, 'transcript.jsonl')) + ); + console.log( + `${sessions.length} sessions, ${todo.length} to run, ${options.jobs} at a time` + ); + // Copying a large graph per session would fill the disk, so every session + // links to one read-only copy. + const { dir: shared, hash } = await sharedGraph(options.graph); + const socket = options.serve ? options.server : undefined; + if (socket) + console.log(`proof serve on ${socket}: ${await ensureServer(socket)}`); + let done = 0; + const failures = []; + const worker = async () => { + for (let s = todo.shift(); s; s = todo.shift()) { + await prepareFolder(s.folder, [s.q], options.graph, { + linkTo: shared, + server: socket, + }); + await writeFile( + join(s.folder, 'TASK.md'), + taskText({ folder: s.folder, strategy: s.strategy, ...s.q }) + ); + const result = await runSession(s.folder, options.model, options.timeout); + done++; + if (result !== 0) failures.push(`${s.strategy}/${s.id}: ${result}`); + console.log(`[${done}] ${s.strategy}/${s.id}: ${result}`); + } + }; + await Promise.all(Array.from({ length: options.jobs }, worker)); + if (failures.length) console.warn(`Failed:\n${failures.join('\n')}`); + // Root ignores file modes, so check that no session changed the graph. + if ((await treeHash(shared)) !== hash) + console.warn(`The shared graph in ${shared} changed during the run`); + await mkdir(join(BENCH, 'runs'), { recursive: true }); + for (const strategy of options.strategies) + await collect( + sessions + .filter((s) => s.strategy === strategy) + .map((s) => ({ + id: s.id, + folder: s.folder, + transcript: join(s.folder, 'transcript.jsonl'), + })), + `${options.name}-${strategy}`, + join(BENCH, 'runs', `${options.name}-${strategy}.json`) + ); +} + +main().catch((error) => { + console.error(error.message); + process.exitCode = 1; +}); diff --git a/benchmarks/proof-recall/scripts/task.mjs b/benchmarks/proof-recall/scripts/task.mjs new file mode 100644 index 00000000..41854ca4 --- /dev/null +++ b/benchmarks/proof-recall/scripts/task.mjs @@ -0,0 +1,50 @@ +// The instructions one benchmark session receives: its rules, the read +// commands its strategy allows, and one question. Never the answer. +import { join } from 'node:path'; + +export const STRATEGIES = ['brief', 'nobrief']; + +const BRIEF_LINE = + '- `./flatbread proof brief <effortId>`: an Effort\'s latest summary (a "compaction") in full, plus every record that changed since. Its envelope\'s `compaction.stale` is true when a record the summary relies on has changed. Start each Effort you need here.'; + +/** Markdown for TASK.md in `folder`, for one question and one strategy. */ +export function taskText({ folder, question, format, strategy }) { + if (!STRATEGIES.includes(strategy)) + throw new Error(`Unknown strategy ${strategy}`); + const brief = strategy === 'brief'; + return `# One-question recall test + +Answer one question about a project-memory graph, using only its read commands. Every command you run is counted, so be efficient, but a right answer matters most. + +## Rules +- Work only inside this folder: \`${folder}\`. Never read, list, or search anything outside it. Never open files under \`.flatbread-proof/\` directly. +- Run one graph command per tool call. No shell loops, scripts, or chains (\`&&\`, \`;\`, \`|\` into another graph command) that run several graph commands at once. + +## Read commands +Run from the folder. Each prints a JSON envelope; its \`artifact_path\` names a Markdown digest. Read or grep that digest for evidence. +- \`./flatbread proof list --status active,paused,completed,abandoned\` lists Efforts (the default shows only active ones). +${ + brief ? BRIEF_LINE + '\n' : '' +}- \`./flatbread proof records <effortId> [--kinds issue,finding,decision,constraint,risk,citation,blob] [--state s] [--status s] [--kind k] [--retracted include|only] [--limit 25] [--cursor c]\` browses records. Bodies are cut at 600 characters or 12 lines; Blob bodies are left out. Retracted records are left out unless you pass \`--retracted\`, and are marked RETRACTED when shown. +- \`./flatbread proof get <id> [--resolve head]\` shows one record in full, Blob payloads included. \`--resolve head\` follows replacements to the newest version. +- \`./flatbread proof relations <effortId> <fromId> --relations derives_from,supersedes,superseded_by,invalidates,invalidated_by,resolved_by,rejected_by,mitigated_by,evidence,cites\` follows one hop of links. +- \`./flatbread proof blocking-decisions <effortId>\`. +${ + brief + ? '' + : '\nDo not use `proof brief`. Findings with `kind: compaction` are summaries; check what they claim.\n' +} +Records can be superseded (replaced), invalidated (shown wrong), rejected, reopened, or retracted (noise, hidden from browse reads unless asked; \`get\` still shows them). Titles repeat on purpose. Efforts never link to each other; one may name another's record by title in prose. A summary can be out of date; check its claims against the records. + +## The question +${question} + +Answer format: ${format}. For a record, give its id (such as \`dec-...--...\`). If the graph does not answer the question, or its premise is false, answer the string "unknown". + +## When done +Write \`${join( + folder, + 'answer.json' + )}\` as \`{"answer": <your answer>}\`, then reply with only the answer. +`; +} diff --git a/benchmarks/proof-recall/spec/_filler.mjs b/benchmarks/proof-recall/spec/_filler.mjs new file mode 100644 index 00000000..96e76ec3 --- /dev/null +++ b/benchmarks/proof-recall/spec/_filler.mjs @@ -0,0 +1,320 @@ +// Filler: routine records that make an Effort larger without changing what +// any question asks about. `build.mjs --scale N` merges them into each +// Effort's events, so the Effort ends with about N times its own records. +// +// Filler is plausible project noise: measurements, captures, and small +// question-to-decision threads about subsystems no spec or question names. +// It never links to a real record, never retracts, and is all written before +// the Effort's head compaction, which therefore covers it. A seeded random +// generator makes the output identical on every build. +// +// The leading underscore keeps `loadSpecs` from reading this file as a spec. + +const PEOPLE = { + render: ['Ines Okafor', 'Tomasz Brandt', 'Yusuf Demir', 'Dara Whitlock'], + world: ['Rhea Valdés', 'Kenji Arakawa', 'Marta Lindqvist', 'Dara Whitlock'], + ports: ['Priya Natarajan', 'Dara Whitlock', 'Tomasz Brandt'], + tools: ['Liam O’Connell', 'Dara Whitlock', 'Kenji Arakawa'], + netcode: ['Sofia Marchetti', 'Dara Whitlock', 'Marta Lindqvist'], +}; + +// Subsystems per Effort. `build.mjs --scale` refuses any whose name +// appears in a spec or question, so filler cannot shadow a real topic. +const SUBSYSTEMS = { + render: [ + 'font atlas', + 'menu blur', + 'decal pool', + 'minimap renderer', + 'photo mode', + 'title card', + 'subtitle renderer', + 'crowd impostors', + 'lens flare', + 'credits roll', + 'map fog', + 'damage numbers', + 'tooltip renderer', + 'splash video', + 'item preview', + ], + world: [ + 'quest log', + 'fishing minigame', + 'bird flocks', + 'lighthouse scheduler', + 'market stalls', + 'weather vane props', + 'ambient chatter', + 'dock cranes', + 'bell tower clock', + 'kite physics', + 'lantern festival', + 'shell collection', + 'tavern doors', + 'rope bridges', + 'merchant carts', + ], + ports: [ + 'controller rumble', + 'achievement service', + 'cloud save sync', + 'suspend and resume', + 'user switching', + 'parental controls', + 'store overlay', + 'screenshot button', + 'trophy icons', + 'keyboard prompts', + 'battery indicator', + 'region settings', + 'capture gallery', + 'friend invites', + 'sleep mode', + ], + tools: [ + 'level editor autosave', + 'localization import', + 'audio bank packer', + 'texture viewer', + 'crash symbol server', + 'build dashboard', + 'test runner', + 'nightly installer', + 'asset search', + 'changelog bot', + 'license scanner', + 'artist sandbox', + 'patch differ', + 'doc site', + 'review bot', + ], + netcode: [ + 'lobby browser', + 'text chat', + 'friend presence', + 'party invites', + 'NAT probe', + 'chat filter', + 'emote wheel', + 'ping display', + 'matchmaking queue', + 'region picker', + 'spectator list', + 'kick vote', + 'host migration banner', + 'join codes', + 'session timeout', + ], +}; + +const PLATFORMS = ['PC', 'Meridian', 'Skiff']; +const METRICS = [ + ['load time', 'ms', 20, 900], + ['memory', 'MB', 2, 180], + ['CPU time', 'ms', 0.1, 3.5], + ['draw calls', '', 4, 400], + ['disk reads', '', 3, 600], + ['allocations per minute', '', 10, 5000], + ['startup time', 'ms', 40, 1500], +]; +const VERDICTS = [ + 'well inside what the team allows for it', + 'about the same as last month', + 'slightly worse than the previous build', + 'better than the previous build after a cleanup', + 'within noise of the last capture', +]; +const FOLLOWUPS = [ + 'No action needed.', + 'Recheck after the next content drop.', + 'Logged for the monthly performance review.', + 'The owner will look again if it doubles.', + 'Nobody is assigned; it stays on the watch list.', +]; +const QUESTIONS = [ + 'should be cached between sessions', + 'should load on a worker thread', + 'needs its own memory pool', + 'should ship in the first patch', + 'should be split into two assets', + 'should skip work when hidden', +]; + +/** Small seeded generator, so the same Effort always gets the same filler. */ +function random(seedText) { + let seed = 2166136261; + for (const ch of seedText) + seed = Math.imul(seed ^ ch.charCodeAt(0), 16777619); + return () => { + seed = (seed + 0x6d2b79f5) | 0; + let t = Math.imul(seed ^ (seed >>> 15), 1 | seed); + t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + }; +} + +const CREATES = new Set([ + 'WriteIssue', + 'WriteFinding', + 'WriteDecision', + 'WriteConstraint', + 'WriteRisk', + 'WriteCitation', + 'WriteBlob', + 'WriteCompaction', +]); + +function capitalize(text) { + return text[0].toUpperCase() + text.slice(1); +} + +/** Every subsystem name filler may use, for the collision check. */ +export function fillerTerms(effortKey) { + return SUBSYSTEMS[effortKey] ?? []; +} + +/** + * Filler events for one spec, so the Effort ends with about `scale` times + * its own records. Returns events with `at` and `key` like a spec's own. + */ +export function fillerEvents(spec, scale) { + if (scale <= 1) return []; + const subsystems = SUBSYSTEMS[spec.key]; + const people = PEOPLE[spec.key]; + if (!subsystems || !people) + throw new Error(`No filler vocabulary for ${spec.key}`); + const own = spec.events.filter((e) => CREATES.has(e.type)).length + 1; + let budget = Math.round(own * (scale - 1)); + const compactions = spec.events.filter((e) => e.type === 'WriteCompaction'); + const start = new Date(spec.effort.created_at).getTime() + 3600e3; + const end = + new Date((compactions.at(-1) ?? spec.events.at(-1)).at).getTime() - + 6 * 3600e3; + const rand = random(`filler:${spec.key}`); + const pick = (list) => list[Math.floor(rand() * list.length)]; + const at = (ms) => new Date(Math.floor(ms / 60e3) * 60e3).toISOString(); + const events = []; + let n = 0; + while (budget > 0) { + n++; + const id = String(n).padStart(4, '0'); + const sub = pick(subsystems); + const platform = pick(PLATFORMS); + const person = pick(people); + const build = 3000 + Math.floor(rand() * 6000); + const time = start + rand() * (end - start - 4 * 3600e3); + const roll = rand(); + if (roll < 0.25 && budget >= 3) { + // A small thread: a question, the measurement that answers it, and the + // accepted Decision that closes it. Its links stay inside the thread. + const question = pick(QUESTIONS); + const issue = `fill-iss-${id}`; + const finding = `fill-fnd-${id}`; + const decision = `fill-dec-${id}`; + const [metric, unit, lo, hi] = pick(METRICS); + const value = +(lo + rand() * (hi - lo)).toFixed(lo < 1 ? 1 : 0); + events.push( + { + at: at(time), + key: issue, + type: 'WriteIssue', + kind: 'question', + title: `Whether the ${sub} ${question} (${id})`, + body: `${person} asked whether the ${sub} ${question}. It came up while looking at build ${build} on ${platform}.`, + created_by: person, + }, + { + at: at(time + 3600e3), + key: finding, + type: 'WriteFinding', + kind: 'measurement', + title: `${capitalize(sub)} ${metric} is ${value}${ + unit ? ` ${unit}` : '' + } on ${platform} (${id})`, + body: `${person} measured the ${sub} ${metric} on ${platform}, build ${build}: ${value}${ + unit ? ` ${unit}` : '' + }. That is ${pick(VERDICTS)}.`, + derives_from: [issue], + created_by: person, + }, + { + at: at(time + 2 * 3600e3), + key: decision, + type: 'WriteDecision', + title: `${capitalize(sub)}: ${ + rand() < 0.5 ? 'do it' : 'leave it as is' + } (${id})`, + body: `The ${sub} ${metric} is ${value}${ + unit ? ` ${unit}` : '' + } on ${platform}, so the change is ${ + rand() < 0.5 + ? 'cheap enough to make now' + : 'not worth making this year' + }. ${pick(FOLLOWUPS)}`, + derives_from: [issue, finding], + created_by: person, + }, + { + at: at(time + 3 * 3600e3), + type: 'AcceptDecision', + decisionId: decision, + }, + { + at: at(time + 3 * 3600e3), + type: 'ResolveIssue', + issueId: issue, + resolution: 'resolved', + resolvedBy: [decision], + } + ); + budget -= 3; + } else if (roll < 0.4) { + events.push({ + at: at(time), + key: `fill-cit-${id}`, + type: 'WriteCitation', + title: `${capitalize(sub)} capture, build ${build} (${id})`, + body: `https://perf.tidewater.example/${spec.key}/${sub.replace( + /\W+/g, + '-' + )}/${build}`, + role: 'evidence', + created_by: person, + }); + budget -= 1; + } else { + const [metric, unit, lo, hi] = pick(METRICS); + const value = +(lo + rand() * (hi - lo)).toFixed(lo < 1 ? 1 : 0); + const runs = 3 + Math.floor(rand() * 8); + events.push({ + at: at(time), + key: `fill-fnd-${id}`, + type: 'WriteFinding', + kind: 'measurement', + title: `${capitalize( + sub + )} ${metric} on ${platform}, build ${build} (${id})`, + body: `${person} measured the ${sub} ${metric} on ${platform}, build ${build}, over ${runs} runs: ${value}${ + unit ? ` ${unit}` : '' + }. That is ${pick(VERDICTS)}. ${pick(FOLLOWUPS)}`, + created_by: person, + }); + budget -= 1; + } + } + return events; +} + +/** A spec's events and filler, in time order; spec events win ties. */ +export function mergeEvents(specEvents, filler) { + const tagged = [ + ...specEvents.map((e, i) => ({ e, i, filler: 0 })), + ...filler.map((e, i) => ({ e, i, filler: 1 })), + ]; + tagged.sort( + (a, b) => + new Date(a.e.at) - new Date(b.e.at) || a.filler - b.filler || a.i - b.i + ); + return tagged.map((t) => t.e); +} diff --git a/benchmarks/proof-recall/spec/netcode.mjs b/benchmarks/proof-recall/spec/netcode.mjs new file mode 100644 index 00000000..007304fb --- /dev/null +++ b/benchmarks/proof-recall/spec/netcode.mjs @@ -0,0 +1,532 @@ +// The co-op rollback netcode prototype. A small Effort that is abandoned: +// rollback cannot afford to re-run the fixed-point tides every frame on Skiff. +const SOFIA = 'Sofia Marchetti'; +const RHEA = 'Rhea Valdés'; +const MARTA = 'Marta Lindqvist'; +const PRIYA = 'Priya Natarajan'; +const DARA = 'Dara Whitlock'; +const KENJI = 'Kenji Arakawa'; + +export default { + key: 'netcode', + effort: { + title: 'Co-op rollback netcode prototype', + body: + 'Sofia Marchetti owns this Effort. It prototypes rollback netcode for Saltglass Reach co-op (one to four players) ' + + 'and decides whether rollback can ship. The tide simulation reshapes walkable terrain, so every sync model must keep tide state identical on all peers.', + created_at: '2025-11-03T09:00:00Z', + }, + events: [ + { + at: '2025-11-04T10:00:00Z', + key: 'iss-sync', + type: 'WriteIssue', + kind: 'question', + title: 'How should co-op keep up to four players in sync?', + body: + 'Co-op needs a sync model before the vertical slice. Players fight, climb and ride the same tide surges, ' + + 'so any lag in shared state is visible. Candidates: rollback, deterministic lockstep, or a host-authoritative model.', + created_by: SOFIA, + }, + { + at: '2025-11-05T10:00:00Z', + key: 'con-determinism', + type: 'WriteConstraint', + kind: 'hard', + title: 'Co-op peers must agree on tide state bit for bit', + body: + 'Tides decide which saltglass paths are walkable. If two peers disagree on the water line by a single cell, ' + + 'one player walks on sand that another sees as sea. Rhea Valdés requires tide state to match exactly on every peer, ' + + 'whatever sync model co-op uses.', + created_by: RHEA, + }, + { + at: '2025-11-06T10:00:00Z', + key: 'con-rtt', + type: 'WriteConstraint', + kind: 'soft', + title: 'Co-op must stay playable at 150 ms round trip', + body: + 'Dara Whitlock set the target: co-op between two continents must feel playable at 150 ms round trip. ' + + 'Above 250 ms we may show a warning.', + created_by: DARA, + }, + { + at: '2025-11-07T10:00:00Z', + key: 'dec-rollback', + type: 'WriteDecision', + title: 'Prototype rollback netcode for co-op', + body: + 'Each peer predicts remote inputs and simulates ahead. When a late input arrives, the peer restores a snapshot and re-simulates the frames since. ' + + 'Local input never waits on the network, which suits traversal and combat at 150 ms. ' + + 'The cost is re-simulation: everything in the snapshot must run again for every rolled-back frame.', + created_by: SOFIA, + derives_from: ['iss-sync', 'con-rtt', 'con-determinism'], + }, + { + at: '2025-11-07T11:00:00Z', + key: 'dec-lockstep', + type: 'WriteDecision', + title: 'Use deterministic lockstep for co-op', + body: + "Every peer waits for every other peer's input for a frame before simulating it. " + + 'Simple and cheap on CPU, and determinism is already required for tides. ' + + 'The cost is input delay equal to half the round trip, and the slowest peer gates everyone.', + created_by: SOFIA, + derives_from: ['iss-sync', 'con-determinism'], + }, + { + at: '2025-11-12T15:00:00Z', + key: 'fnd-lockstep-test', + type: 'WriteFinding', + kind: 'measurement', + title: 'Lockstep playtest at 150 ms round trip', + body: [ + 'Sofia Marchetti and Marta Lindqvist ran a four-player lockstep build on the Shoal-01 test map with 150 ms of injected round trip.', + '', + 'Setup:', + '- Two PC peers at 60 Hz, one Meridian devkit at 60 Hz, one Skiff devkit at 30 Hz.', + '- Ten minutes of traversal and one tide surge.', + '- Input delay fixed at 5 frames (75 ms at 60 Hz), the minimum that kept every peer fed.', + '', + 'What we saw:', + '- Marta Lindqvist rated traversal "mushy" from the first minute. Jumps across saltglass gaps landed late.', + '- Every peer ran at the speed of the slowest one. The Skiff devkit dropped frames during the tide surge and the whole session waited for it.', + '- Network traffic was tiny: 1.2 KB/s per peer.', + '', + 'The Skiff devkit stalled the whole session 41 times in 10 minutes. With a handheld in the group, lockstep would feel broken for all four players.', + ].join('\n'), + created_by: SOFIA, + derives_from: ['dec-lockstep', 'con-rtt'], + }, + { + at: '2025-11-14T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-rollback', + }, + { + at: '2025-11-18T14:00:00Z', + key: 'fnd-prototype-cost', + type: 'WriteFinding', + kind: 'measurement', + title: 'Rollback re-simulates a 4-frame window in 1.1 ms on PC', + body: + 'First rollback prototype on Shoal-01, PC, four players. Restoring a snapshot and re-simulating 4 frames takes 1.1 ms in total. ' + + 'Sofia Marchetti calls this cheap enough to grow the window later. ' + + 'Caveat: the tide simulation was frozen for this run, because it was not yet in the snapshot.', + created_by: SOFIA, + derives_from: ['dec-rollback'], + }, + { + at: '2025-11-20T10:00:00Z', + key: 'dec-window-v1', + type: 'WriteDecision', + title: 'Use a 4-frame rollback window', + body: + 'Roll back at most 4 frames (67 ms at 60 Hz). Inputs later than that stall the peer. ' + + 'At 1.1 ms per full rollback this costs almost nothing, and covers same-region play.', + created_by: SOFIA, + derives_from: ['dec-rollback', 'fnd-prototype-cost'], + }, + { + at: '2025-11-21T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-window-v1', + }, + { + at: '2025-12-05T10:00:00Z', + key: 'cit-primer', + type: 'WriteCitation', + role: 'context', + title: 'Studio wiki primer on rollback netcode', + body: 'https://wiki.tidewater-forge.example/netcode/rollback-primer', + created_by: SOFIA, + }, + { + at: '2025-12-09T11:00:00Z', + key: 'fnd-snapshot', + type: 'WriteFinding', + kind: 'measurement', + title: 'A rollback snapshot is 38 KB per player per frame', + body: + "With player physics, Gull script state and the local tide cells included, one player's rollback snapshot is 38 KB per frame. " + + 'A 4-frame ring for four players needs about 600 KB, which is fine on every platform.', + created_by: SOFIA, + derives_from: ['dec-rollback'], + cites: ['cit-primer'], + }, + { + at: '2025-12-10T09:00:00Z', + key: 'fnd-noise', + type: 'WriteFinding', + kind: 'measurement', + title: 'Player snapshot is 14 KB per player', + body: + 'Serialized player state, including Gull script variables and inventory, comes to 14 KB per player. ' + + 'Measured on the coast save slot.', + created_by: MARTA, + }, + { + at: '2025-12-12T09:00:00Z', + type: 'Retract', + recordId: 'fnd-noise', + reason: + 'Filed here by mistake. This measures save-game snapshots for the world Effort, not rollback snapshots.', + }, + { + at: '2025-12-16T10:00:00Z', + key: 'fnd-slice', + type: 'WriteFinding', + kind: 'playtest', + title: + 'Two-player rollback co-op ran the vertical slice demo without a visible desync', + body: + 'The vertical slice demo on 2025-12-15 ran two-player co-op on PC with rollback for 25 minutes. ' + + 'No visible desync and no stalls. Tides were still frozen in co-op builds.', + created_by: SOFIA, + derives_from: ['dec-window-v1'], + }, + { + at: '2026-01-08T10:00:00Z', + key: 'fnd-wifi-rtt', + type: 'WriteFinding', + kind: 'measurement', + title: 'Skiff co-op sessions over Wi-Fi see 180 ms round trips at p95', + body: + 'Priya Natarajan logged 340 Skiff sessions on home Wi-Fi. Median round trip was 95 ms; p95 was 180 ms. ' + + 'A 4-frame window covers only about half of those sessions without stalls.', + created_by: PRIYA, + derives_from: ['dec-window-v1'], + }, + { + at: '2026-01-12T10:00:00Z', + key: 'dec-window-v2', + type: 'WriteDecision', + title: 'Use a 7-frame rollback window', + body: + 'Grow the window to 7 frames (117 ms at 60 Hz) to cover p95 Skiff Wi-Fi. ' + + 'The snapshot ring grows to about 1 MB for four players.', + created_by: SOFIA, + derives_from: ['fnd-wifi-rtt'], + supersedes: ['dec-window-v1'], + }, + { + at: '2026-01-12T15:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-window-v2', + }, + { + at: '2026-01-20T10:00:00Z', + key: 'rsk-resim', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'high', + title: + 'Re-simulation cost could blow the Skiff frame budget once tides join the snapshot', + body: + 'Every prototype number so far ran with tides frozen. Once tides are in the snapshot, every rolled-back frame re-runs the tide step too. ' + + 'Sofia Marchetti does not yet know what one tide step costs on Skiff.', + created_by: SOFIA, + derives_from: ['dec-window-v2', 'fnd-prototype-cost'], + }, + { + at: '2026-01-26T10:00:00Z', + key: 'iss-late-join', + type: 'WriteIssue', + kind: 'defect', + title: 'Late join during a tide surge desyncs the joining player', + body: + 'A player who joins while a surge is rising receives tide cells from a snapshot that is up to 7 frames old. ' + + 'In 6 of 20 tries the joiner saw a dry path the others saw flooded. Kenji Arakawa suspects the join snapshot skips cells that are still streaming in.', + created_by: KENJI, + derives_from: ['dec-rollback', 'con-determinism'], + }, + { + at: '2026-01-28T10:00:00Z', + key: 'fnd-input-delay', + type: 'WriteFinding', + kind: 'playtest', + title: 'One frame of input delay is invisible in playtests', + body: + 'Marta Lindqvist ran blind tests with 0, 1 and 2 frames of local input delay. ' + + 'Nobody of eight testers noticed 1 frame; five of eight noticed 2 frames.', + created_by: MARTA, + }, + { + at: '2026-02-02T10:00:00Z', + key: 'dec-window-v3', + type: 'WriteDecision', + title: 'Use a 6-frame rollback window with 1 frame of input delay', + body: + 'Add 1 frame of local input delay, which playtesters cannot see, and shrink the window to 6 frames. ' + + 'Together they still cover p95 Skiff Wi-Fi. Scaling the 1.1 ms measurement, a 6-frame rollback should cost under 2 ms.', + created_by: SOFIA, + derives_from: ['fnd-input-delay', 'fnd-wifi-rtt', 'fnd-prototype-cost'], + supersedes: ['dec-window-v2'], + }, + { + at: '2026-02-03T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-window-v3', + }, + { + at: '2026-02-09T10:00:00Z', + key: 'iss-desync-debug', + type: 'WriteIssue', + kind: 'gap', + title: 'Nothing shows which system caused a desync', + body: 'When peers drift we only see the symptom, usually minutes later. We need to know whether tides, physics or Gull diverged first.', + created_by: SOFIA, + }, + { + at: '2026-02-11T10:00:00Z', + key: 'dec-checksum', + type: 'WriteDecision', + title: + 'Hash tide, physics and Gull state every 30 frames and compare across peers', + body: + 'Each peer hashes the three state blocks separately every 30 frames and sends 12 bytes to the others. ' + + 'A mismatch names the block that diverged and the frame window it happened in.', + created_by: SOFIA, + derives_from: ['iss-desync-debug'], + }, + { + at: '2026-02-11T15:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-checksum', + }, + { + at: '2026-02-16T10:00:00Z', + key: 'fnd-desync-hash', + type: 'WriteFinding', + kind: 'diagnosis', + title: 'The first checksum mismatch came from Gull random number calls', + body: + 'The checksums caught a Gull script that seeded its random generator from wall-clock time. ' + + 'Fixed in a day. Tide and physics hashes have matched in every session since.', + created_by: MARTA, + derives_from: ['dec-checksum'], + }, + { + at: '2026-02-16T11:00:00Z', + type: 'ResolveIssue', + issueId: 'iss-desync-debug', + resolution: 'resolved', + resolvedBy: ['dec-checksum', 'fnd-desync-hash'], + }, + { + at: '2026-02-18T16:00:00Z', + key: 'cmp-feb', + type: 'WriteCompaction', + title: 'Co-op netcode: where things stand in February', + body: + 'Rollback is the chosen co-op sync model; lockstep was rejected after the 150 ms playtest. ' + + 'The window is 6 frames with 1 frame of input delay, which covers p95 Skiff Wi-Fi. ' + + 'Measured rollback cost is 1.1 ms for 4 frames on PC, so a 6-frame rollback should stay under 2 ms. ' + + 'Desync checksums work. Open: late join during a tide surge, and the Risk that tide re-simulation costs more once tides join the snapshot. ' + + 'Next: profile on Skiff with tides running, then plan for alpha.', + created_by: SOFIA, + derives_from: [ + 'dec-rollback', + 'dec-window-v3', + 'fnd-prototype-cost', + 'fnd-snapshot', + 'fnd-slice', + 'dec-checksum', + 'iss-late-join', + 'rsk-resim', + ], + }, + { + at: '2026-03-10T10:00:00Z', + key: 'iss-skiff-profile', + type: 'WriteIssue', + kind: 'gap', + title: 'Rollback has not been profiled on Skiff with tides running', + body: 'Alpha builds now include tides in the rollback snapshot. Every cost number we have is from PC with tides frozen.', + created_by: SOFIA, + derives_from: ['rsk-resim'], + }, + { + at: '2026-03-18T10:00:00Z', + key: 'blb-capture', + type: 'WriteBlob', + kind: 'json', + title: 'Skiff rollback profile capture, 6-frame window, tides on', + body: JSON.stringify( + { + capture: 'skiff-devkit-04, Shoal-01, four players, 40 Hz mode', + window_frames: 6, + per_rollback_ms: { + tide_resim: 4.8, + physics_resim: 1.9, + gull_resim: 0.7, + snapshot_restore: 0.3, + total: 7.7, + }, + tide_step_ms: 0.8, + frame_budget_ms: 25, + rollbacks_per_second_p50: 22, + }, + null, + 2 + ), + created_by: PRIYA, + }, + { + at: '2026-03-18T10:10:00Z', + key: 'cit-capture', + type: 'WriteCitation', + role: 'evidence', + title: 'Skiff rollback profile capture', + body: 'Per-system rollback timings from a Skiff devkit with tides in the snapshot. Full numbers in the attached capture.', + blob: 'blb-capture', + created_by: PRIYA, + }, + { + at: '2026-03-19T10:00:00Z', + key: 'fnd-tide-cost', + type: 'WriteFinding', + kind: 'measurement', + title: 'Re-running tides every rollback frame costs 4.8 ms on Skiff', + body: + 'With tides in the snapshot, every rolled-back frame must re-run the tide step. One 32.32 fixed-point tide step costs 0.8 ms on Skiff, ' + + 'so a full 6-frame rollback re-runs tides for 4.8 ms, before physics and Gull. ' + + 'Rollbacks happen on most frames at Wi-Fi latency. Against the 25 ms Skiff frame at 40 Hz that is far too much. ' + + 'The 1.1 ms PC figure was measured with tides frozen and does not describe the real cost.', + created_by: SOFIA, + derives_from: ['iss-skiff-profile', 'rsk-resim'], + cites: ['cit-capture'], + }, + { + at: '2026-03-19T10:10:00Z', + type: 'Invalidate', + findingId: 'fnd-tide-cost', + targetId: 'fnd-prototype-cost', + }, + { + at: '2026-03-19T10:20:00Z', + type: 'SetRiskState', + riskId: 'rsk-resim', + state: 'realized', + evidence: ['fnd-tide-cost'], + }, + { + at: '2026-03-19T10:30:00Z', + type: 'ResolveIssue', + issueId: 'iss-skiff-profile', + resolution: 'resolved', + resolvedBy: ['fnd-tide-cost'], + }, + { + at: '2026-03-24T10:00:00Z', + key: 'dec-tide-lod', + type: 'WriteDecision', + title: 'Re-simulate tides at quarter resolution during rollback', + body: + 'Keep rollback, but re-run tides on a quarter-resolution grid for rolled-back frames and correct to full resolution afterwards. ' + + 'This would cut tide re-simulation to about 1.2 ms. Rhea Valdés doubts the correction step can stay bit-exact.', + created_by: SOFIA, + derives_from: ['fnd-tide-cost'], + }, + { + at: '2026-03-27T10:00:00Z', + key: 'fnd-lod-desync', + type: 'WriteFinding', + kind: 'measurement', + title: + 'Quarter-resolution tide re-simulation desyncs peers within 90 seconds', + body: + 'In the quarter-resolution prototype the tide checksum diverged between peers within 90 seconds in all 10 runs. ' + + 'The correction step rounds differently depending on how many frames were rolled back.', + created_by: RHEA, + derives_from: ['dec-tide-lod', 'con-determinism'], + }, + { + at: '2026-03-31T10:00:00Z', + key: 'fnd-host-spike', + type: 'WriteFinding', + kind: 'measurement', + title: 'Host-authoritative spike keeps tides off the client CPU', + body: + 'Marta Lindqvist built a two-day host-authoritative spike on Shoal-01 with one PC host and one Skiff client. ' + + 'The Skiff client never runs the tide step, so its simulation cost fell from 7.7 ms to 1.4 ms per frame. ' + + 'At 150 ms round trip the client sees tide edges correct by up to half a cell; Marta Lindqvist thinks blending can hide it.', + created_by: MARTA, + derives_from: ['fnd-tide-cost', 'con-determinism'], + }, + { + at: '2026-04-01T10:00:00Z', + key: 'dec-abandon', + type: 'WriteDecision', + title: 'Abandon rollback netcode for co-op', + body: [ + 'We stop the rollback prototype. Co-op will not ship with rollback.', + '', + 'The reason is the tides. The world Effort\'s Decision "Run the tide simulation in 32.32 fixed point" keeps tides deterministic, ' + + 'and co-op needs that. But rollback must re-run tides every frame it rolls back, which costs 4.8 ms on Skiff. ' + + 'That is a fifth of the 25 ms frame before physics, Gull and rendering.', + '', + 'What we tried before giving up:', + '- Shrinking the window: below 6 frames, p95 Skiff Wi-Fi stalls.', + '- Re-simulating tides at quarter resolution: desynced within 90 seconds.', + '- Leaving tides out of the snapshot: breaks the bit-for-bit tide Constraint.', + '', + 'The checksum tooling and the 1-frame input delay result carry over to whatever replaces rollback.', + 'The rollback code is archived on branch netcode/rollback-archive and will not be maintained.', + ].join('\n'), + created_by: SOFIA, + derives_from: ['fnd-tide-cost', 'fnd-lod-desync', 'con-determinism'], + supersedes: ['dec-rollback'], + }, + { + at: '2026-04-01T14:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-abandon', + rejects: ['dec-tide-lod'], + }, + { + at: '2026-04-02T10:00:00Z', + key: 'dec-host', + type: 'WriteDecision', + title: 'Use host-authoritative sync for co-op', + body: + "The host runs the only tide simulation and the only physics for shared objects. Clients send inputs and render the host's state with local prediction for their own player. " + + 'Nothing re-runs tides, so the 4.8 ms cost disappears. ' + + 'Clients see corrections on tide edges at their round trip; Marta Lindqvist will tune how those corrections blend. ' + + 'The snapshot send rate is not chosen yet.', + created_by: SOFIA, + derives_from: ['iss-sync', 'dec-abandon', 'fnd-host-spike', 'con-rtt'], + }, + { + at: '2026-04-02T15:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-host', + }, + { + at: '2026-04-02T15:10:00Z', + type: 'ResolveIssue', + issueId: 'iss-sync', + resolution: 'resolved', + resolvedBy: ['dec-host'], + }, + { + at: '2026-04-03T10:00:00Z', + key: 'rsk-host-upload', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'medium', + title: 'A Skiff host may lack the upload bandwidth for three clients', + body: + 'With host-authoritative sync the host sends world state to every client. Priya Natarajan has not yet measured Skiff upload on home Wi-Fi, ' + + 'and a Skiff hosting three clients may not keep up. Nobody owns this now that the netcode Effort is stopping.', + created_by: PRIYA, + derives_from: ['dec-host'], + }, + { + at: '2026-04-06T09:00:00Z', + type: 'SetEffortStatus', + status: 'abandoned', + }, + ], +}; diff --git a/benchmarks/proof-recall/spec/ports.mjs b/benchmarks/proof-recall/spec/ports.mjs new file mode 100644 index 00000000..5d66d16b --- /dev/null +++ b/benchmarks/proof-recall/spec/ports.mjs @@ -0,0 +1,1237 @@ +// The `ports` Effort: Saltglass Reach on Meridian and Skiff. +// Threads: Skiff memory, Skiff frame budget and 40 Hz mode, the on-device +// pipeline cache ("shader cache"), Tern on Skiff, dynamic resolution, +// storage speed, and certification defects on both consoles. +const p = (...parts) => parts.join('\n\n'); + +const PRIYA = 'Priya Natarajan'; +const DARA = 'Dara Whitlock'; +const TOMASZ = 'Tomasz Brandt'; +const YUSUF = 'Yusuf Demir'; +const KENJI = 'Kenji Arakawa'; +const LIAM = "Liam O'Connell"; +const SOFIA = 'Sofia Marchetti'; + +const memCapture = { + capture: 'harbor-district-peak', + platform: 'Skiff', + firmware: '1.2', + build: 4127, + captured_on: '2026-02-17', + route: + 'Fast travel to the harbor at low tide, then walk the fish market to the lighthouse', + budget_mb: 8192, + peak_mb: 8806, + over_budget_mb: 614, + categories_mb: { + textures: 3184, + streaming_pool: 2048, + meshes: 1106, + render_targets: 1012, + audio_banks: 912, + tide_sim: 330, + gull_heap: 214, + }, + growth_since_slice_mb: { + audio_banks: 388, + tide_sim: 214, + textures: 96, + meshes: 41, + }, + notes: 'Peak lasts about 4 seconds while two tide cells are double buffered.', +}; + +const psoStats = { + capture: 'first-visit-pipeline-compiles', + platform: 'Skiff', + firmware: '1.0', + build: 3810, + districts: { + harbor: { unique_pipelines: 1460, first_visit_hitches_over_33ms: 212 }, + dunes: { unique_pipelines: 820, first_visit_hitches_over_33ms: 96 }, + ruins: { unique_pipelines: 1110, first_visit_hitches_over_33ms: 147 }, + }, + compile_ms: { p50: 72, p90: 141, p99: 190, min: 45 }, +}; + +const certReport = p( + '# Skiff pre-certification report: Saltglass Reach build 5530', + 'Submitted 2026-05-11. Reviewed by the platform holder lot check team on 2026-05-15.', + [ + '| Code | Area | Result | Detail |', + '| --- | --- | --- | --- |', + '| SKF-ST-012 | Storage | Fail | Autosave writes 11.2 MB per minute; the limit is 4 MB per minute. |', + '| SKF-UI-031 | Interface | Fail | HUD stamina and tide labels are 6 px tall at 720p; the minimum is 9 px. |', + '| SKF-DSP-004 | Display | Advisory | Docked 30 Hz mode shows judder on some 50 Hz TVs. |', + ].join('\n'), + 'Fails must be fixed before a full submission. Advisories may be waived on request.' +); + +export default { + key: 'ports', + effort: { + title: 'Meridian and Skiff ports', + body: p( + 'Bring Saltglass Reach to the Meridian home console and the Skiff handheld. Meridian targets 60 Hz; Skiff targets 30 Hz with a 40 Hz mode.', + 'This Effort owns the Skiff numbers: memory, frame budget, the on-device pipeline cache, the Tern preset on Skiff, dynamic resolution, storage, and certification on both consoles. Priya Natarajan leads it.' + ), + created_at: '2025-10-15T09:00:00Z', + }, + events: [ + // --- Skiff memory, first pass ----------------------------------------- + { + at: '2025-10-16T10:00:00Z', + key: 'cit-skiff-sdk-09', + type: 'WriteCitation', + title: 'Skiff SDK 0.9 memory map', + body: 'https://devportal.skiff.example/sdk/0.9/memory-map', + role: 'evidence', + created_by: PRIYA, + }, + { + at: '2025-10-16T10:30:00Z', + key: 'iss-skiff-mem', + type: 'WriteIssue', + kind: 'gap', + title: 'Skiff memory limits for the game are unknown', + body: 'Nobody has measured how much memory Skiff gives a title. The SDK docs mention a system reserve but no title figure. Priya Natarajan will read the memory map on the dev kit before the team sizes any pools.', + created_by: PRIYA, + }, + { + at: '2025-10-20T14:00:00Z', + key: 'fnd-skiff-mem-map', + type: 'WriteFinding', + kind: 'measurement', + title: 'Skiff dev kit gives the game 9 GB', + body: 'The SDK 0.9 memory map on dev kit 0412 reserves 3 GB of the 12 GB for the system and hands 9 GB to the title. A test app allocated 9.0 GB and was killed at 9.02 GB. The figure holds in handheld and docked mode.', + derives_from: ['iss-skiff-mem'], + cites: ['cit-skiff-sdk-09'], + created_by: PRIYA, + }, + { + at: '2025-10-22T09:00:00Z', + key: 'con-skiff-mem-9', + type: 'WriteConstraint', + kind: 'hard', + title: 'Skiff memory budget', + body: 'Saltglass Reach may use at most 9 GB on Skiff, CPU and GPU combined. Every pool size on Skiff is set against this number. Keep 300 MB of it free as a safety margin.', + derives_from: ['fnd-skiff-mem-map'], + created_by: PRIYA, + }, + { + at: '2025-10-22T09:10:00Z', + type: 'ResolveIssue', + issueId: 'iss-skiff-mem', + resolution: 'resolved', + resolvedBy: ['fnd-skiff-mem-map'], + }, + { + at: '2025-10-24T11:00:00Z', + key: 'cit-meridian-trc', + type: 'WriteCitation', + title: 'Meridian technical requirements checklist 2.4', + body: 'https://partners.meridian.example/trc/2.4', + role: 'context', + created_by: PRIYA, + }, + { + at: '2025-10-24T11:20:00Z', + key: 'con-meridian-mem', + type: 'WriteConstraint', + kind: 'hard', + title: 'Meridian memory budget', + body: 'Meridian gives the game 13.5 GB. That is enough headroom that Meridian shares PC memory settings at the High preset. The checklist also requires the game to survive a suspend of 8 hours or more.', + cites: ['cit-meridian-trc'], + created_by: PRIYA, + }, + // --- Frame budget, first version -------------------------------------- + { + at: '2025-10-28T10:00:00Z', + key: 'con-frame-1', + type: 'WriteConstraint', + kind: 'hard', + title: 'Frame budget', + body: 'Skiff runs at 30 Hz, so each frame gets 33.3 ms of CPU and of GPU time. Meridian runs at 60 Hz and gets 16.6 ms. Captures that miss these numbers on the harbor route block a merge to the console branch.', + created_by: PRIYA, + }, + // --- Dynamic resolution question --------------------------------------- + { + at: '2025-11-03T09:30:00Z', + key: 'iss-dynres-q', + type: 'WriteIssue', + kind: 'question', + title: + 'How should Skiff hold its frame budget when the GPU is overloaded?', + body: 'Saltglass refraction spikes GPU time when a dune ridge fills the screen. On Skiff the spike reaches 38 ms on the dune route. We need one standing answer for what gives way: resolution or effects.', + derives_from: ['con-frame-1'], + created_by: PRIYA, + }, + { + at: '2025-11-05T10:00:00Z', + key: 'dec-dynres-1', + type: 'WriteDecision', + title: 'Scale Skiff resolution dynamically between 540p and 720p', + body: 'Lantern already has a dynamic resolution path for PC. On Skiff it will drop the internal resolution from 720p to as low as 540p when the GPU frame runs over. The HUD stays at native 720p. Tomasz Brandt measured the 540p floor at 26 ms on the worst dune view, inside 33.3 ms.', + derives_from: ['iss-dynres-q', 'con-frame-1'], + created_by: TOMASZ, + }, + { + at: '2025-11-05T10:20:00Z', + key: 'dec-dynres-tiers', + type: 'WriteDecision', + title: 'Drop effect quality tiers on Skiff instead of resolution', + body: 'Keep 720p and step caustics, fog, and foam down one tier when the GPU runs over. Yusuf Demir prefers this because the saltglass look depends on a sharp image. The tier changes pop visibly, though, and need art sign-off for every biome.', + derives_from: ['iss-dynres-q'], + created_by: YUSUF, + }, + { + at: '2025-11-10T15:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-dynres-1', + }, + { + at: '2025-11-10T15:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-dynres-q', + resolution: 'resolved', + resolvedBy: ['dec-dynres-1'], + }, + { + at: '2025-11-12T16:00:00Z', + key: 'fnd-mem-early', + type: 'WriteFinding', + kind: 'measurement', + title: 'Skiff slice build peaks at 6.9 GB', + body: 'Kenji Arakawa captured the vertical slice build on Skiff: peak 6.9 GB on the harbor route, 2.1 GB under the 9 GB budget. The capture ran with one tide cell loaded at a time.', + created_by: KENJI, + }, + { + at: '2025-11-14T10:00:00Z', + key: 'rsk-skiff-oom', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'high', + title: 'Skiff runs out of memory in dense districts', + body: 'The harbor and the ruins stack audio, tide state, and saltglass textures in one place. If the peak passes the Skiff memory budget, Skiff kills the game with no warning. Cert treats that as a crash.', + derives_from: ['con-skiff-mem-9'], + created_by: PRIYA, + }, + // --- Tern on Skiff ------------------------------------------------------- + { + at: '2025-11-18T09:00:00Z', + key: 'iss-upscale-q', + type: 'WriteIssue', + kind: 'question', + title: 'Which upscaler should Skiff use?', + body: 'Skiff renders below 720p most of the time, so the image needs an upscaler. Options on the table: Tern, a cheap spatial filter, or no upscaling at native 720p.', + created_by: PRIYA, + }, + { + at: '2025-11-20T13:00:00Z', + key: 'fnd-tern-cost', + type: 'WriteFinding', + kind: 'measurement', + title: 'Tern costs 3.9 ms at Quality and 2.1 ms at Performance on Skiff', + body: 'Tomasz Brandt profiled Tern on the Skiff dev kit, 540p in, 720p out, harbor route. Quality preset: 3.9 ms of GPU time. Performance preset: 2.1 ms. Performance shows a little more ghosting on foam but keeps saltglass edges stable. A bilinear upscale with sharpening costs 0.4 ms and crawls on every glass edge.', + derives_from: ['iss-upscale-q'], + created_by: TOMASZ, + }, + { + at: '2025-11-20T13:30:00Z', + key: 'rsk-tern-cost', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'medium', + title: 'Tern takes too much of the Skiff frame', + body: 'At 3.9 ms, Tern Quality eats 12 percent of the 33.3 ms Skiff frame. If Skiff ever runs faster than 30 Hz, that share grows and something else must give.', + derives_from: ['fnd-tern-cost', 'con-frame-1'], + created_by: TOMASZ, + }, + { + at: '2025-11-24T10:00:00Z', + key: 'dec-tern-skiff', + type: 'WriteDecision', + title: 'Run Tern on Skiff at the Performance preset', + body: p( + 'Skiff uses Tern, the temporal upscaler the render Effort owns. The render Decision "Ship Tern as Lantern\'s only upscaler" makes Tern the only upscaler Lantern supports, so Skiff cannot ship a second one without the render team taking it on.', + 'Skiff runs Tern at the Performance preset, a lower quality preset than other platforms use: 2.1 ms against 3.9 ms for Quality. The 1.8 ms saved pays for tide foam on Skiff. Yusuf Demir signed off on the extra foam ghosting after a side-by-side on the handheld screen, where it is hard to see.' + ), + derives_from: ['iss-upscale-q', 'fnd-tern-cost'], + created_by: PRIYA, + }, + { + at: '2025-11-24T10:30:00Z', + key: 'dec-skiff-spatial', + type: 'WriteDecision', + title: 'Use a spatial upscaler with sharpening on Skiff', + body: 'Bilinear upscale plus a sharpening pass. It costs 0.4 ms and needs no motion vectors. Yusuf Demir raised it as the cheap fallback.', + derives_from: ['iss-upscale-q'], + created_by: YUSUF, + }, + { + at: '2025-11-24T10:40:00Z', + key: 'dec-skiff-native', + type: 'WriteDecision', + title: 'Render Skiff at native 720p without upscaling', + body: 'Skip upscaling and render 720p always. Tomasz Brandt notes this only works if saltglass refraction drops to half resolution on Skiff, which the art team dislikes.', + derives_from: ['iss-upscale-q'], + created_by: TOMASZ, + }, + { + at: '2025-11-28T14:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-tern-skiff', + }, + { + at: '2025-11-28T14:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-upscale-q', + resolution: 'resolved', + resolvedBy: ['dec-tern-skiff'], + }, + { + at: '2025-11-28T14:10:00Z', + type: 'MitigateRisk', + riskId: 'rsk-tern-cost', + decisionId: 'dec-tern-skiff', + }, + // --- 40 Hz question opens ------------------------------------------------ + { + at: '2025-12-01T09:00:00Z', + key: 'iss-frame-modes', + type: 'WriteIssue', + kind: 'question', + title: 'Should Skiff offer a 40 Hz mode?', + body: 'The Skiff screen runs at 120 Hz, so 40 Hz divides evenly and paces cleanly. Other Skiff games offer 40 Hz as an option. Dara Whitlock wants a call before the slice review.', + created_by: DARA, + }, + { + at: '2025-12-03T10:00:00Z', + key: 'dec-skiff-30', + type: 'WriteDecision', + title: 'Lock Skiff to 30 Hz', + body: 'Ship one mode. Every Skiff capture, every cert run, and every performance fix then targets one number, 33.3 ms. Priya Natarajan worries a second mode doubles the test matrix.', + derives_from: ['iss-frame-modes', 'con-frame-1'], + created_by: PRIYA, + }, + { + at: '2025-12-03T10:15:00Z', + key: 'dec-skiff-40', + type: 'WriteDecision', + title: 'Offer a 40 Hz mode on Skiff alongside 30 Hz', + body: 'Add a 40 Hz option in the Skiff display menu, off by default. 30 Hz stays the default and the cert target. The 40 Hz mode leans on dynamic resolution to fit its shorter frame.', + derives_from: ['iss-frame-modes'], + created_by: DARA, + }, + // --- Pipeline compiles and the on-device cache --------------------------- + { + at: '2025-12-08T11:00:00Z', + key: 'iss-hitches', + type: 'WriteIssue', + kind: 'defect', + title: 'First-visit hitches of 45 to 190 ms on Skiff', + body: 'Walking into a district for the first time on Skiff stalls the game for 45 to 190 ms at a time. The stalls vanish on a second visit in the same session and come back after a restart. Skiff compiles each graphics pipeline the first time it is drawn.', + created_by: PRIYA, + }, + { + at: '2025-12-09T10:00:00Z', + key: 'blb-pso-stats', + type: 'WriteBlob', + kind: 'json', + title: 'Skiff first-visit pipeline compile capture, build 3810', + body: JSON.stringify(psoStats, null, 2), + created_by: PRIYA, + }, + { + at: '2025-12-09T10:05:00Z', + key: 'cit-pso-capture', + type: 'WriteCitation', + title: 'Skiff pipeline compile capture, build 3810', + body: 'Capture of first-visit pipeline compiles in three districts on Skiff firmware 1.0.', + role: 'evidence', + blob: 'blb-pso-stats', + created_by: PRIYA, + }, + { + at: '2025-12-09T10:30:00Z', + key: 'fnd-pso-count', + type: 'WriteFinding', + kind: 'measurement', + title: 'Harbor district needs 1,460 pipelines on Skiff', + body: 'The harbor district draws 1,460 unique graphics pipelines. Each first compile on Skiff takes 45 to 190 ms, median 72 ms. The capture covers the harbor, the dunes, and the ruins.', + derives_from: ['iss-hitches'], + cites: ['cit-pso-capture'], + created_by: PRIYA, + }, + { + at: '2025-12-10T09:00:00Z', + key: 'rsk-pso-hitch', + type: 'WriteRisk', + likelihood: 'high', + severity: 'medium', + title: 'Pipeline compiles hitch Skiff on first visits', + body: 'If first-visit compiles stay, every new player meets hitches in the first hour. Reviewers play the first hour.', + derives_from: ['fnd-pso-count'], + created_by: PRIYA, + }, + { + at: '2025-12-11T09:00:00Z', + key: 'iss-pso-q', + type: 'WriteIssue', + kind: 'question', + title: 'How should Skiff avoid first-use pipeline compiles?', + body: 'Three options: ship pipelines prebuilt in the package, build and keep them on the device, or draw with ubershaders until the real pipelines compile in the background.', + derives_from: ['iss-hitches'], + created_by: PRIYA, + }, + { + at: '2025-12-11T15:00:00Z', + key: 'fnd-blob-portable', + type: 'WriteFinding', + kind: 'measurement', + title: 'Prebuilt pipeline blobs load on Skiff dev firmware', + body: "Liam O'Connell built pipeline blobs on the build farm and loaded them on a Skiff dev kit running firmware 1.0. All 1,460 harbor pipelines loaded with no compile and no hitch. Only one firmware version was tested.", + derives_from: ['iss-pso-q'], + created_by: LIAM, + }, + { + at: '2025-12-12T10:00:00Z', + key: 'dec-pso-ship', + type: 'WriteDecision', + title: 'Ship prebuilt pipeline blobs in the Skiff package', + body: 'The build farm compiles every Skiff pipeline at package time and ships the blobs, about 140 MB. Players never compile. This adds 9 minutes to a Skiff package build.', + derives_from: ['iss-pso-q', 'fnd-blob-portable'], + created_by: LIAM, + }, + { + at: '2025-12-12T10:20:00Z', + key: 'dec-pso-ondevice', + type: 'WriteDecision', + title: 'Build an on-device pipeline cache for Skiff', + body: p( + "Keep compiled graphics pipelines on the Skiff itself. The first time the game needs a pipeline, it compiles it and writes the result to a cache file in the save partition. The next session reads it back instead of compiling. Everyone on the team calls this the shader cache. It is not the build farm's shader compile cache, which speeds up our own builds and never ships to players.", + 'To hide the first compile, the game warms the cache during load screens and fast travel. Each district has a list of the pipelines it drew in our playtests. While a load screen is up, the game compiles any pipeline on that list that is not in the cache yet. Priya Natarajan estimates that covers 95 percent of first visits.', + 'The cache is keyed by pipeline hash plus the Skiff driver version. A firmware update that changes the driver throws the cache away and the game rebuilds it from the district lists over the next few load screens.', + 'Size: the cache is capped at 384 MB on the Skiff storage. When it fills, the game drops the least recently used district first.' + ), + derives_from: ['iss-pso-q', 'fnd-pso-count'], + created_by: PRIYA, + }, + { + at: '2025-12-12T10:40:00Z', + key: 'dec-pso-uber', + type: 'WriteDecision', + title: 'Use ubershaders while Skiff pipelines compile', + body: 'Draw with a slow general shader until the specialized pipeline finishes compiling on a worker thread. Tomasz Brandt measured the ubershader at 2.4 times the GPU cost of the specialized saltglass shader, which Skiff cannot afford at 33.3 ms.', + derives_from: ['iss-pso-q'], + created_by: TOMASZ, + }, + { + at: '2025-12-15T11:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-pso-ship', + }, + { + at: '2025-12-15T11:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-pso-q', + resolution: 'resolved', + resolvedBy: ['dec-pso-ship'], + }, + // --- After the vertical slice: 40 Hz and the new Frame budget ------------- + { + at: '2026-01-12T16:00:00Z', + key: 'fnd-40hz-test', + type: 'WriteFinding', + kind: 'survey', + title: 'Skiff 40 Hz playtest: 9 of 12 testers preferred 40 Hz', + body: 'Dara Whitlock ran 12 testers through the dune route on Skiff at 30 Hz and at 40 Hz, in random order. 9 preferred 40 Hz, 2 saw no difference, 1 preferred 30 Hz for battery life. Battery drain rose from 11 to 13 percent an hour.', + derives_from: ['iss-frame-modes'], + created_by: DARA, + }, + { + at: '2026-01-14T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-skiff-40', + }, + { + at: '2026-01-14T10:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-frame-modes', + resolution: 'resolved', + resolvedBy: ['dec-skiff-40', 'fnd-40hz-test'], + }, + { + at: '2026-01-15T09:00:00Z', + key: 'con-frame-2', + type: 'WriteConstraint', + kind: 'hard', + title: 'Frame budget', + body: 'Skiff 40 Hz mode: 25 ms per frame, CPU and GPU. Skiff 30 Hz mode keeps 33.3 ms and stays the cert target. Meridian keeps 60 Hz at 16.6 ms. The Meridian 120 Hz performance mode and its budget belong to the render Effort, not here.', + supersedes: ['con-frame-1'], + derives_from: ['dec-skiff-40'], + created_by: PRIYA, + }, + { + at: '2026-01-20T14:00:00Z', + key: 'fnd-dynres-540', + type: 'WriteFinding', + kind: 'measurement', + title: 'Saltglass caustics shimmer at the 540p floor', + body: 'At 540p internal resolution the caustic patterns under saltglass shimmer badly in motion, even after Tern. Yusuf Demir counted visible shimmer in 7 of 10 dune views. At 576p it drops to 2 of 10. The 576p floor costs 1.3 ms more on the worst view.', + derives_from: ['dec-dynres-1'], + created_by: YUSUF, + }, + { + at: '2026-01-22T10:00:00Z', + key: 'dec-dynres-2', + type: 'WriteDecision', + title: 'Raise the Skiff dynamic resolution floor to 576p', + body: 'Dynamic resolution on Skiff now ranges from 576p to 720p. The worst dune view at the 576p floor costs 27.3 ms, still inside 33.3 ms at 30 Hz. In 40 Hz mode the floor leaves little room.', + supersedes: ['dec-dynres-1'], + derives_from: ['iss-dynres-q', 'fnd-dynres-540'], + created_by: TOMASZ, + }, + { + at: '2026-01-22T10:10:00Z', + type: 'AcceptDecision', + decisionId: 'dec-dynres-2', + }, + { + at: '2026-01-26T09:00:00Z', + key: 'rsk-thermal', + type: 'WriteRisk', + likelihood: 'low', + severity: 'medium', + title: 'Skiff throttles the GPU in long handheld sessions', + body: 'Skiff lowers clocks when the handheld runs hot. A big drop would push the frame past budget after an hour of play.', + created_by: PRIYA, + }, + // --- Skiff memory, second pass ----------------------------------------- + { + at: '2026-02-02T09:00:00Z', + key: 'iss-blk-devkits', + type: 'WriteIssue', + kind: 'blocker', + title: 'No Skiff dev kits on firmware 1.2', + body: 'Skiff firmware 1.2 ships to players at launch, but all four of our dev kits run 1.0. Memory and pipeline work on 1.2 cannot start until new kits arrive.', + created_by: PRIYA, + }, + { + at: '2026-02-10T11:00:00Z', + key: 'cit-skiff-sdk-12', + type: 'WriteCitation', + title: 'Skiff SDK 1.2 release notes', + body: 'https://devportal.skiff.example/sdk/1.2/release-notes', + role: 'evidence', + created_by: PRIYA, + }, + { + at: '2026-02-10T11:30:00Z', + key: 'fnd-sdk12', + type: 'WriteFinding', + kind: 'survey', + title: 'Skiff SDK 1.2 takes 1 GB back from games', + body: 'The SDK 1.2 release notes move the system overlay and the new voice chat service into title memory. Games now get 8 GB, down from 9 GB. The change applies to every title from firmware 1.2, with no opt-out.', + derives_from: ['con-skiff-mem-9'], + cites: ['cit-skiff-sdk-12'], + created_by: PRIYA, + }, + { + at: '2026-02-12T09:00:00Z', + key: 'con-skiff-mem-8', + type: 'WriteConstraint', + kind: 'hard', + title: 'Skiff memory budget', + body: 'Saltglass Reach may use at most 8 GB on Skiff, CPU and GPU combined, from firmware 1.2 on. Keep 300 MB of it free as a safety margin. Pools sized against the old 9 GB figure must be cut.', + supersedes: ['con-skiff-mem-9'], + derives_from: ['fnd-sdk12'], + created_by: PRIYA, + }, + { + at: '2026-02-16T10:00:00Z', + key: 'blb-mem-capture', + type: 'WriteBlob', + kind: 'json', + title: 'Skiff harbor district memory capture, build 4127', + body: JSON.stringify(memCapture, null, 2), + created_by: KENJI, + }, + { + at: '2026-02-16T10:05:00Z', + key: 'cit-mem-capture', + type: 'WriteCitation', + title: 'Skiff harbor memory capture, build 4127', + body: 'Per-category memory capture at the harbor district peak, Skiff firmware 1.2 emulation.', + role: 'evidence', + blob: 'blb-mem-capture', + created_by: KENJI, + }, + { + at: '2026-02-18T15:00:00Z', + key: 'fnd-mem-capture', + type: 'WriteFinding', + kind: 'measurement', + title: 'Harbor district peaks at 8.6 GB on Skiff', + body: p( + 'Kenji Arakawa and Priya Natarajan captured build 4127 on the harbor route with firmware 1.2 memory limits emulated. Peak use was 8.6 GB, 614 MB over the 8 GB Skiff memory budget, before counting the 300 MB safety margin.', + 'Most of the growth since the vertical slice came from audio banks, which grew by 388 MB when the harbor ambience was split per tide state, and from the tide simulation, which now double buffers two tide cells while the tide turns. The slice capture missed that second tide cell entirely because it ran with one cell loaded at a time.', + 'The peak lasts about 4 seconds, during the tide turn. Outside it the harbor sits near 7.9 GB, which is still too close to the budget to ship.', + 'Next step: the largest single category is the place to cut, not the fastest-growing one. The full per-category numbers are in the attached capture.' + ), + derives_from: ['con-skiff-mem-8', 'rsk-skiff-oom'], + invalidates: ['fnd-mem-early'], + cites: ['cit-mem-capture'], + created_by: KENJI, + }, + { + at: '2026-02-18T15:30:00Z', + type: 'SetRiskState', + riskId: 'rsk-skiff-oom', + state: 'realized', + evidence: ['fnd-mem-capture'], + }, + { + at: '2026-02-20T10:00:00Z', + key: 'dec-kelp-skiff', + type: 'WriteDecision', + title: "Use Kelp's high-ratio mode for Skiff textures", + body: "Encode Skiff textures with Kelp's high-ratio mode instead of the default mode. Priya Natarajan expects it to save about 900 MB on the harbor route. Decode costs 0.3 ms more per streamed tile on Skiff's CPU, and Yusuf Demir sees slight banding on saltglass gradients at handheld size only.", + derives_from: ['rsk-skiff-oom', 'con-skiff-mem-8'], + created_by: PRIYA, + }, + { + at: '2026-02-23T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-kelp-skiff', + }, + { + at: '2026-02-27T16:00:00Z', + key: 'fnd-mem-kelp', + type: 'WriteFinding', + kind: 'measurement', + title: 'Kelp high-ratio textures bring the Skiff harbor peak to 7.7 GB', + body: 'With Kelp high-ratio textures the harbor peak falls from 8.6 GB to 7.7 GB on build 4211. That leaves 300 MB, exactly the safety margin. Any new harbor content now needs a matching cut.', + derives_from: ['dec-kelp-skiff'], + created_by: KENJI, + }, + // --- Storage speed and fast travel -------------------------------------- + { + at: '2026-03-04T10:00:00Z', + key: 'cit-sd-bench', + type: 'WriteCitation', + title: 'Skiff storage benchmark sheet', + body: 'https://docs.tidewaterforge.example/ports/skiff-storage-bench', + role: 'evidence', + created_by: KENJI, + }, + { + at: '2026-03-04T10:30:00Z', + key: 'fnd-sd-speed', + type: 'WriteFinding', + kind: 'measurement', + title: 'Skiff microSD sustains 92 MB/s', + body: 'Kenji Arakawa read 4 GB of packed world tiles from three new microSD cards on a cold Skiff. Sustained read was 92 MB/s on all three. Internal storage reads at about 200 MB/s, but most players will install to microSD.', + cites: ['cit-sd-bench'], + created_by: KENJI, + }, + { + at: '2026-03-05T09:00:00Z', + key: 'iss-ft', + type: 'WriteIssue', + kind: 'gap', + title: 'Skiff fast travel has no load-time plan', + body: 'Fast travel on Meridian takes 3 seconds and hides behind a camera move. Nobody has said what Skiff does.', + created_by: DARA, + }, + { + at: '2026-03-06T10:00:00Z', + key: 'dec-seamless-ft', + type: 'WriteDecision', + title: 'Load Skiff fast travel without a loading screen', + body: 'At 92 MB/s a fast travel destination loads in 4.1 seconds on Skiff. That fits behind the same camera move Meridian uses, stretched to 4.5 seconds. No loading screen on Skiff.', + derives_from: ['iss-ft', 'fnd-sd-speed'], + created_by: PRIYA, + }, + { + at: '2026-03-06T10:30:00Z', + key: 'dec-stream-block', + type: 'WriteDecision', + title: 'Stream Skiff world tiles in 2 MB reads', + body: 'Read world tiles from storage in 2 MB blocks on Skiff. At 92 MB/s a 2 MB read takes about 22 ms, so streaming keeps up with a sprint across the dunes. Smaller reads waste time on per-read overhead on microSD.', + derives_from: ['fnd-sd-speed'], + created_by: KENJI, + }, + { + at: '2026-03-06T11:00:00Z', + key: 'rsk-skiff-stream', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'high', + title: 'Tide streaming outruns Skiff storage', + body: 'When the tide turns, the world swaps tide cells while the player moves. If storage falls behind, players see low-detail saltglass or fall through a newly exposed path. The margin on Skiff assumes the 92 MB/s read rate.', + derives_from: ['fnd-sd-speed'], + created_by: KENJI, + }, + { + at: '2026-03-09T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-seamless-ft', + }, + { + at: '2026-03-09T10:05:00Z', + type: 'AcceptDecision', + decisionId: 'dec-stream-block', + }, + { + at: '2026-03-10T17:00:00Z', + key: 'cmp-1', + type: 'WriteCompaction', + title: 'Ports status after alpha', + body: p( + 'Skiff memory budget is 8 GB from firmware 1.2. The harbor district overran it at 8.6 GB; Kelp high-ratio textures brought it to 7.7 GB. The out-of-memory risk is marked realized.', + 'Frame budget: Skiff 30 Hz at 33.3 ms, plus an optional 40 Hz mode at 25 ms. Dynamic resolution floor is 576p. Tern runs at the Performance preset on Skiff.', + 'Pipeline compiles are handled by shipping prebuilt blobs in the package. Fast travel on Skiff loads with no loading screen. Waiting on firmware 1.2 dev kits.' + ), + derives_from: [ + 'con-skiff-mem-8', + 'con-frame-2', + 'dec-dynres-2', + 'dec-tern-skiff', + 'dec-pso-ship', + 'dec-kelp-skiff', + 'rsk-skiff-oom', + 'dec-seamless-ft', + 'dec-skiff-40', + 'iss-blk-devkits', + ], + created_by: PRIYA, + }, + { + at: '2026-03-16T14:00:00Z', + key: 'fnd-devkits', + type: 'WriteFinding', + kind: 'survey', + title: 'Firmware 1.2 Skiff dev kits arrived', + body: 'Four dev kits on firmware 1.2 arrived on 2026-03-16. Two go to ports, one to render, one to QA.', + derives_from: ['iss-blk-devkits'], + created_by: DARA, + }, + { + at: '2026-03-16T14:10:00Z', + type: 'ResolveIssue', + issueId: 'iss-blk-devkits', + resolution: 'resolved', + resolvedBy: ['fnd-devkits'], + }, + { + at: '2026-03-20T11:00:00Z', + key: 'fnd-driver-keyed', + type: 'WriteFinding', + kind: 'measurement', + title: 'Skiff firmware 1.2 rejects pipeline blobs built for firmware 1.0', + body: 'On the new firmware 1.2 kits, all 1,460 prebuilt harbor pipelines failed to load and recompiled on the device. Skiff checks a driver hash in every blob and rejects any blob built for another driver. The platform holder plans driver updates every two to three months, so shipped blobs would go stale after the first update. The December test passed only because it used the same firmware the blobs were built for.', + derives_from: ['fnd-devkits'], + invalidates: ['fnd-blob-portable'], + created_by: PRIYA, + }, + { + at: '2026-03-23T10:00:00Z', + type: 'ReopenDecision', + decisionId: 'dec-pso-ondevice', + reason: + 'Prebuilt blobs go stale on every Skiff driver update; a cache on the device survives updates by rebuilding.', + }, + { + at: '2026-03-23T10:05:00Z', + type: 'Supersede', + supersederId: 'dec-pso-ondevice', + targetId: 'dec-pso-ship', + }, + { + at: '2026-03-24T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-pso-ondevice', + }, + { + at: '2026-03-24T09:05:00Z', + type: 'MitigateRisk', + riskId: 'rsk-pso-hitch', + decisionId: 'dec-pso-ondevice', + }, + { + at: '2026-04-14T15:00:00Z', + key: 'fnd-cache-warm', + type: 'WriteFinding', + kind: 'measurement', + title: 'Skiff pipeline cache removes second-visit hitches', + body: 'With the on-device pipeline cache, second visits to the harbor compiled nothing: 99.6 percent of pipeline lookups hit the cache, and the misses were all photo-mode filters. First visits after load-screen warming still hitched 6 times on the harbor route, down from 212. After a full playthrough the cache held 212 MB.', + derives_from: ['dec-pso-ondevice'], + created_by: PRIYA, + }, + { + at: '2026-04-14T15:10:00Z', + type: 'ResolveIssue', + issueId: 'iss-hitches', + resolution: 'resolved', + resolvedBy: ['dec-pso-ondevice', 'fnd-cache-warm'], + }, + { + at: '2026-04-20T16:00:00Z', + key: 'fnd-sd-speed-2', + type: 'WriteFinding', + kind: 'measurement', + title: 'Skiff microSD slows sharply on full, warm cards', + body: p( + 'Kenji Arakawa repeated the March storage benchmark under player conditions: cards filled past 80 percent, a Skiff that had run the game for 40 minutes, and the cheapest cards on sale in our three launch regions. The March test used three new, empty cards on a cold Skiff, which no player will have after a week.', + 'Results by card: the two premium cards held close to their March numbers. The four budget cards slowed as they filled, and all of them slowed further once the Skiff warmed up. The card controller throttles writes and reads together when it gets hot, and a full card spends more time on wear levelling.', + 'Fast travel to the harbor took 6.8 seconds on the worst card, far past the 4.5 second camera move.', + 'Worst sustained read across the budget cards, full and warm: 61 MB/s. Plan Skiff loading and streaming against that number, not 92 MB/s.' + ), + derives_from: ['iss-ft'], + invalidates: ['fnd-sd-speed', 'dec-seamless-ft'], + cites: ['cit-sd-bench'], + created_by: KENJI, + }, + { + at: '2026-04-24T10:00:00Z', + key: 'dec-ft-loading', + type: 'WriteDecision', + title: 'Show a tide-chart loading screen for Skiff fast travel', + body: 'Skiff fast travel shows a loading screen with the tide chart for the destination. The screen stays up until the destination tiles are in, up to 7 seconds on slow cards. It also gives the pipeline cache a chance to warm.', + derives_from: ['iss-ft', 'fnd-sd-speed-2'], + created_by: PRIYA, + }, + { + at: '2026-04-27T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-ft-loading', + }, + { + at: '2026-04-27T09:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-ft', + resolution: 'resolved', + resolvedBy: ['dec-ft-loading'], + }, + { + at: '2026-05-04T13:00:00Z', + key: 'fnd-thermal', + type: 'WriteFinding', + kind: 'measurement', + title: 'Skiff GPU clock drops 8 percent after 20 minutes handheld', + body: 'In a 2 hour handheld session at 30 Hz, the Skiff GPU clock fell 8 percent after 20 minutes and stayed there. Dynamic resolution absorbed it; average internal resolution fell from 662p to 640p. No frame went past 33.3 ms. Docked play never throttled.', + derives_from: ['rsk-thermal'], + created_by: PRIYA, + }, + { + at: '2026-05-06T09:00:00Z', + type: 'SetRiskState', + riskId: 'rsk-thermal', + state: 'accepted', + evidence: ['fnd-thermal'], + }, + // --- Certification --------------------------------------------------------- + { + at: '2026-05-11T10:00:00Z', + key: 'cit-skiff-cert-guide', + type: 'WriteCitation', + title: 'Skiff lot check guidelines v3', + body: 'https://devportal.skiff.example/lotcheck/guidelines-v3', + role: 'context', + created_by: PRIYA, + }, + { + at: '2026-05-11T10:20:00Z', + key: 'con-skiff-write', + type: 'WriteConstraint', + kind: 'hard', + title: 'Skiff storage write limit', + body: 'Skiff lot check allows a game to write at most 4 MB per minute to storage, averaged over 10 minutes. Saves, the pipeline cache, and logs all count.', + cites: ['cit-skiff-cert-guide'], + created_by: PRIYA, + }, + { + at: '2026-05-11T10:40:00Z', + key: 'con-skiff-text', + type: 'WriteConstraint', + kind: 'hard', + title: 'Skiff minimum text height', + body: 'Skiff lot check requires all readable text to be at least 9 px tall at 720p in handheld mode.', + cites: ['cit-skiff-cert-guide'], + created_by: PRIYA, + }, + { + at: '2026-05-18T09:00:00Z', + key: 'blb-cert-report', + type: 'WriteBlob', + kind: 'markdown', + title: 'Skiff pre-certification report, build 5530', + body: certReport, + created_by: DARA, + }, + { + at: '2026-05-18T09:05:00Z', + key: 'cit-cert-report', + type: 'WriteCitation', + title: 'Skiff pre-certification report, build 5530', + body: 'Platform holder pre-check results for build 5530, received 2026-05-15.', + role: 'evidence', + blob: 'blb-cert-report', + created_by: DARA, + }, + { + at: '2026-05-18T09:30:00Z', + key: 'fnd-cert-report', + type: 'WriteFinding', + kind: 'survey', + title: 'Skiff pre-certification found two failures and one advisory', + body: 'The platform holder pre-checked build 5530. Two failures must be fixed before full submission: autosave write volume and HUD text size. One advisory covers docked 30 Hz judder on some TVs. Codes and details are in the attached report.', + cites: ['cit-cert-report'], + created_by: DARA, + }, + { + at: '2026-05-18T10:00:00Z', + key: 'iss-cert-skiff-save', + type: 'WriteIssue', + kind: 'defect', + title: 'Skiff cert: autosave writes 11 MB per minute', + body: 'Autosave rewrites the whole tide state every 30 seconds, about 11 MB a minute on Skiff. Lot check fails it.', + derives_from: ['fnd-cert-report'], + created_by: PRIYA, + }, + { + at: '2026-05-18T10:10:00Z', + key: 'iss-cert-skiff-hud', + type: 'WriteIssue', + kind: 'defect', + title: 'Skiff cert: HUD text below minimum height', + body: 'The stamina and tide labels render 6 px tall on the Skiff screen. Lot check fails it.', + derives_from: ['fnd-cert-report', 'con-skiff-text'], + created_by: PRIYA, + }, + { + at: '2026-05-18T10:20:00Z', + key: 'iss-cert-skiff-flicker', + type: 'WriteIssue', + kind: 'defect', + title: 'Skiff cert: docked 30 Hz judder on some TVs', + body: 'Docked at 30 Hz, a few 50 Hz TVs show judder during camera pans. The fix would need a 25 Hz docked mode.', + derives_from: ['fnd-cert-report'], + created_by: PRIYA, + }, + { + at: '2026-05-20T11:00:00Z', + key: 'iss-cert-meridian-suspend', + type: 'WriteIssue', + kind: 'defect', + title: 'Meridian cert: resume from suspend drops the co-op session', + body: 'Meridian pre-check: after a suspend of 8 hours, resuming the game leaves the player alone in an empty world. The checklist requires a clean return or a clear message.', + cites: ['cit-meridian-trc'], + created_by: SOFIA, + }, + { + at: '2026-05-20T11:20:00Z', + key: 'iss-cert-meridian-cards', + type: 'WriteIssue', + kind: 'defect', + title: 'Meridian cert: activity cards missing for two biomes', + body: 'Meridian shows an activity card for each biome on the console home screen. The glass forest and the drowned quarry have none. The checklist marks this as should-fix, not must-fix.', + cites: ['cit-meridian-trc'], + created_by: DARA, + }, + { + at: '2026-05-22T10:00:00Z', + key: 'dec-delta-save', + type: 'WriteDecision', + title: 'Write delta saves on Skiff', + body: 'Autosave on Skiff writes only the tide cells and inventory slots that changed since the last save, plus a full save every 10 minutes. Expected volume: 2.6 MB a minute, including the pipeline cache.', + derives_from: ['iss-cert-skiff-save', 'con-skiff-write'], + created_by: PRIYA, + }, + { + at: '2026-05-22T10:30:00Z', + key: 'dec-hud-scale', + type: 'WriteDecision', + title: 'Scale the Skiff HUD to 125 percent', + body: 'Scale every HUD element by 125 percent on Skiff handheld. Plain scaling turns the 6 px labels into blurry 7.5 px ones, still under the minimum, so Yusuf Demir redrew the label font at 9 px for Skiff and the panels grow to fit.', + derives_from: ['iss-cert-skiff-hud', 'con-skiff-text'], + created_by: YUSUF, + }, + { + at: '2026-05-25T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-delta-save', + }, + { + at: '2026-05-25T09:05:00Z', + type: 'AcceptDecision', + decisionId: 'dec-hud-scale', + }, + { + at: '2026-05-26T14:00:00Z', + key: 'fnd-suspend', + type: 'WriteFinding', + kind: 'measurement', + title: 'Meridian drops co-op sessions because the relay socket times out', + body: 'Sofia Marchetti traced the suspend defect: the co-op relay closes an idle socket after 30 seconds, and Meridian suspends the network stack with the game. On resume the client still thinks the socket is open and waits forever.', + derives_from: ['iss-cert-meridian-suspend'], + created_by: SOFIA, + }, + { + at: '2026-05-27T10:00:00Z', + key: 'dec-suspend', + type: 'WriteDecision', + title: 'Rejoin the co-op session after Meridian resumes', + body: 'On the Meridian resume event the client drops its socket, reconnects to the relay, and rejoins the session if the host is still there. If not, the player lands in a solo copy of the world with a message.', + derives_from: ['fnd-suspend'], + created_by: SOFIA, + }, + { + at: '2026-05-27T10:30:00Z', + type: 'AcceptDecision', + decisionId: 'dec-suspend', + }, + { + at: '2026-05-28T09:00:00Z', + key: 'fnd-waiver', + type: 'WriteFinding', + kind: 'survey', + title: 'Platform holder waived the docked 30 Hz judder advisory', + body: 'Dara Whitlock asked the Skiff platform holder to waive the docked judder advisory. The waiver came back the same day: it affects TVs that cannot accept 60 Hz input, under 1 percent of the installed base.', + derives_from: ['iss-cert-skiff-flicker'], + created_by: DARA, + }, + { + at: '2026-05-28T09:10:00Z', + type: 'ResolveIssue', + issueId: 'iss-cert-skiff-flicker', + resolution: 'wontfix', + resolvedBy: ['fnd-waiver'], + }, + { + at: '2026-05-29T10:00:00Z', + key: 'dec-cards-patch', + type: 'WriteDecision', + title: 'Ship the missing Meridian activity cards in the day-one patch', + body: 'The two missing activity cards need new art and a localization pass. They go in the day-one patch, not the disc build.', + derives_from: ['iss-cert-meridian-cards'], + created_by: DARA, + }, + { + at: '2026-05-29T10:10:00Z', + type: 'AcceptDecision', + decisionId: 'dec-cards-patch', + }, + { + at: '2026-05-29T10:20:00Z', + type: 'ResolveIssue', + issueId: 'iss-cert-meridian-cards', + resolution: 'deferred', + resolvedBy: ['dec-cards-patch'], + }, + { + at: '2026-05-30T09:00:00Z', + type: 'ResolveIssue', + issueId: 'iss-cert-skiff-save', + resolution: 'resolved', + resolvedBy: ['dec-delta-save'], + }, + { + at: '2026-05-30T09:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-cert-skiff-hud', + resolution: 'resolved', + resolvedBy: ['dec-hud-scale'], + }, + { + at: '2026-05-30T09:10:00Z', + type: 'ResolveIssue', + issueId: 'iss-cert-meridian-suspend', + resolution: 'resolved', + resolvedBy: ['dec-suspend'], + }, + // --- Beta: Skiff becomes a launch platform -------------------------------- + { + at: '2026-06-01T09:00:00Z', + key: 'dec-skiff-launch', + type: 'WriteDecision', + title: 'Make Skiff a launch platform', + body: 'Skiff ships on launch day with PC and Meridian. The harbor fits in 7.7 GB, the pipeline cache works, and both cert failures are fixed. Dara Whitlock confirmed the date with the platform holder at the beta review.', + derives_from: [ + 'con-skiff-mem-8', + 'con-frame-2', + 'fnd-mem-kelp', + 'fnd-cache-warm', + ], + created_by: DARA, + }, + { + at: '2026-06-01T09:30:00Z', + type: 'AcceptDecision', + decisionId: 'dec-skiff-launch', + }, + { + at: '2026-06-03T10:00:00Z', + key: 'rsk-cert-slip', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'high', + title: 'Skiff certification slips past the release candidate', + body: 'Full Skiff lot check takes 10 working days and a failure restarts the clock. If the first full submission fails, Skiff misses the 2026-09-30 release candidate.', + derives_from: ['dec-skiff-launch'], + created_by: DARA, + }, + { + at: '2026-06-08T11:00:00Z', + key: 'fnd-noise-shader', + type: 'WriteFinding', + kind: 'measurement', + title: 'Shader cache hit rate reaches 97 percent', + body: 'Shader cache hit rate is 97 percent across the last 50 builds. Cold compiles fell from 41 minutes to 6.', + created_by: LIAM, + }, + { + at: '2026-06-08T11:30:00Z', + type: 'Retract', + recordId: 'fnd-noise-shader', + reason: + 'Build farm compile cache numbers posted to the wrong Effort. They say nothing about the Skiff on-device pipeline cache.', + }, + { + at: '2026-06-22T15:00:00Z', + key: 'fnd-retro', + type: 'WriteFinding', + kind: 'retrospective', + title: 'Beta retrospective for the Skiff port', + body: p( + 'What went well: the Kelp high-ratio switch took one week end to end and saved 900 MB, just as predicted. The 40 Hz mode cost less than feared because dynamic resolution already existed. The cert pre-check caught both failures early enough to fix them before beta.', + 'What went badly: twice we trusted a test that ran on a better setup than players have. The December pipeline blob test ran on the same firmware the blobs were built for. The March storage test ran on new, empty cards on a cold Skiff. Both looked fine and both were wrong.', + 'We also sized memory against the 9 GB figure for four months after the platform holder had hinted at a bigger system reserve. Priya Natarajan now checks the SDK release notes every Monday.', + 'Cost: the wrong pipeline choice cost 6 weeks of schedule: the beta slipped 6 weeks past its planned date while the team rebuilt pipelines as an on-device cache. Rule from here: run every platform test on retail firmware and on the worst hardware a player can buy.' + ), + derives_from: ['fnd-driver-keyed', 'fnd-sd-speed-2', 'fnd-mem-kelp'], + created_by: PRIYA, + }, + { + at: '2026-07-06T10:00:00Z', + key: 'con-noise-frame', + type: 'WriteConstraint', + kind: 'hard', + title: 'Frame budget', + body: 'Meridian 120 Hz performance mode: 8.3 ms per frame on CPU and GPU.', + created_by: TOMASZ, + }, + { + at: '2026-07-06T15:00:00Z', + type: 'Retract', + recordId: 'con-noise-frame', + reason: + "Copied from the render Effort's Frame budget by mistake. The Meridian 120 Hz mode belongs to render; this Effort's Frame budget covers Skiff and Meridian 60 Hz.", + }, + { + at: '2026-07-10T17:00:00Z', + key: 'cmp-2', + type: 'WriteCompaction', + title: 'Ports status after beta', + body: p( + 'Skiff is a launch platform. Skiff memory budget is 8 GB; the harbor peak is 7.7 GB with Kelp high-ratio textures.', + 'Frame budget: Skiff 30 Hz at 33.3 ms, 40 Hz mode at 25 ms. Dynamic resolution floor on Skiff is 576p. Tern runs at the Performance preset on Skiff.', + 'Pipeline compiles: the on-device pipeline cache replaced prebuilt blobs; second visits hit the cache 99.6 percent of the time. Fast travel on Skiff shows a tide-chart loading screen. World tiles stream in 2 MB reads.', + 'Open risks: tide streaming on slow storage, and Skiff certification slipping past the release candidate.' + ), + derives_from: [ + 'con-skiff-mem-8', + 'con-frame-2', + 'dec-dynres-2', + 'dec-tern-skiff', + 'dec-pso-ondevice', + 'dec-ft-loading', + 'dec-stream-block', + 'rsk-skiff-stream', + 'dec-skiff-launch', + 'rsk-cert-slip', + ], + created_by: PRIYA, + }, + // --- After the summary: storms and the new floor -------------------------- + { + at: '2026-07-20T14:00:00Z', + key: 'fnd-dynres-gpu', + type: 'WriteFinding', + kind: 'measurement', + title: 'The 576p floor misses the 40 Hz budget in tide storms', + body: 'Tomasz Brandt captured the 40 Hz mode during a tide storm on the dunes. At the 576p floor the GPU frame reached 26.9 ms, over the 25 ms budget, for 14 seconds. At 504p it fell to 23.8 ms. Side by side, Tern Performance from 504p looked better than the old 540p image because Tern now reuses saltglass history, and caustic shimmer stayed at 2 of 10 views.', + derives_from: ['dec-dynres-2', 'con-frame-2'], + created_by: TOMASZ, + }, + { + at: '2026-07-22T10:00:00Z', + key: 'dec-dynres-3', + type: 'WriteDecision', + title: 'Lower the Skiff dynamic resolution floor to 504p behind Tern', + body: 'Dynamic resolution on Skiff now ranges from 504p to 720p. The floor relies on Tern at the Performance preset to rebuild a clean 720p image; without Tern, 504p would shimmer worse than 540p did. The 30 Hz mode rarely drops below 600p.', + supersedes: ['dec-dynres-2'], + derives_from: [ + 'iss-dynres-q', + 'fnd-dynres-gpu', + 'con-frame-2', + 'dec-tern-skiff', + ], + created_by: TOMASZ, + }, + { + at: '2026-07-24T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-dynres-3', + }, + { + at: '2026-08-10T15:00:00Z', + key: 'fnd-storm-capture', + type: 'WriteFinding', + kind: 'measurement', + title: 'Tide storms push Skiff 40 Hz frames to 28.4 ms on the CPU', + body: 'Priya Natarajan captured the full storm sequence on a retail-firmware Skiff. Even at the 504p floor, the CPU frame reached 28.4 ms in the 40 Hz mode, over the 25 ms budget. Storm particles and their tide collision cost 6.1 ms of it. The GPU stayed inside budget.', + derives_from: ['dec-dynres-3'], + created_by: PRIYA, + }, + { + at: '2026-08-11T09:00:00Z', + key: 'iss-blk-storm', + type: 'WriteIssue', + kind: 'blocker', + title: 'Skiff cert blocker: 40 Hz mode misses frames in tide storms', + body: 'Lot check requires a selectable mode to hold its advertised rate. The 40 Hz mode drops to about 35 Hz in storms. Full Skiff submission cannot go in until this is fixed or the mode is pulled.', + derives_from: ['fnd-storm-capture'], + created_by: PRIYA, + }, + { + at: '2026-08-13T10:00:00Z', + key: 'dec-storm-cap', + type: 'WriteDecision', + title: 'Cap tide-storm particles at 6,000 on Skiff', + body: 'Cap storm particles at 6,000 on Skiff, down from 14,000, and skip tide collision for particles more than 40 m away. Yusuf Demir estimates a 3.8 ms CPU saving. The storm will look thinner on Skiff.', + derives_from: ['iss-blk-storm', 'con-frame-2'], + created_by: YUSUF, + }, + { + at: '2026-08-13T10:30:00Z', + key: 'dec-storm-30', + type: 'WriteDecision', + title: 'Drop Skiff to 30 Hz while a tide storm is on screen', + body: 'While a storm runs, switch the 40 Hz mode to 30 Hz and switch back when it ends. Lot check may still flag it as not holding the advertised rate; Dara Whitlock has asked the platform holder.', + derives_from: ['iss-blk-storm', 'con-frame-2'], + created_by: PRIYA, + }, + { + at: '2026-09-08T16:00:00Z', + key: 'fnd-storm-cap-test', + type: 'WriteFinding', + kind: 'measurement', + title: 'Prototype storm particle cap saves 3.5 ms on the Skiff CPU', + body: 'Yusuf Demir built the 6,000 particle cap behind a debug flag. On the storm sequence the CPU frame fell from 28.4 ms to 24.9 ms in the 40 Hz mode, 0.1 ms inside budget. Art has not signed off on the thinner storm, and nobody has chosen between the cap and the 30 Hz fallback yet.', + derives_from: ['dec-storm-cap'], + created_by: YUSUF, + }, + ], +}; diff --git a/benchmarks/proof-recall/spec/render/core.mjs b/benchmarks/proof-recall/spec/render/core.mjs new file mode 100644 index 00000000..8b51b9b2 --- /dev/null +++ b/benchmarks/proof-recall/spec/render/core.mjs @@ -0,0 +1,341 @@ +// Frame budgets, memory, gaps, the vertical-slice blocker, and the four +// compactions. The head compaction goes stale after content lock. +import { d, INES, TOMASZ, YUSUF, PRIYA, LIAM, DARA } from './people.mjs'; + +export default [ + { + at: d('2025-09-02 09:00'), + key: 'con-budget-1', + type: 'WriteConstraint', + kind: 'hard', + title: 'Frame budget', + created_by: INES, + body: + 'Lantern must finish a Meridian frame in 16.6 ms, which is 60 Hz. For pre-production the GPU passes may use the whole 16.6 ms; ' + + 'the render thread on the CPU runs in parallel and is budgeted elsewhere. Every pass owner reports against this number in the weekly capture review. ' + + 'Numbers come from the cliffs and dunes benchmarks, never from the menu scene.', + }, + { + at: d('2025-09-02 10:00'), + key: 'con-vram', + type: 'WriteConstraint', + kind: 'hard', + title: 'Render-target memory on Meridian', + created_by: INES, + body: + "Lantern's render targets, transient attachments, shadow pages and GI volumes must fit in 1.8 GB of the 13.5 GB Meridian gives the game. " + + 'Streaming owns the rest. An allocation over 1.8 GB fails the nightly memory check and blocks the build.', + }, + { + at: d('2025-09-03 09:00'), + key: 'con-saltglass-2km', + type: 'WriteConstraint', + kind: 'soft', + title: 'Saltglass must read at 2 km', + created_by: YUSUF, + body: + 'Art direction wants refraction through saltglass dunes, cliffs and ruins to read out to 2 km. Caustics may fade past 800 m, but the glass must still bend what is behind it. ' + + 'This is an art target, not a platform rule. Yusuf Demir will accept a cheaper look past 1.2 km if it keeps the silhouette.', + }, + { + at: d('2025-09-04 09:00'), + key: 'cit-wiki', + type: 'WriteCitation', + role: 'context', + title: 'Lantern overhaul wiki page', + created_by: INES, + body: 'https://wiki.tidewater.example/lantern/overhaul', + }, + { + at: d('2025-09-12 10:00'), + key: 'iss-gap-capture', + type: 'WriteIssue', + kind: 'gap', + title: 'No automated GPU captures on nightly builds', + created_by: INES, + body: + 'Every timing in this Effort so far comes from a capture someone took by hand, on whatever machine was free. ' + + 'Nothing records which build or which hardware produced a number. We need captures taken the same way every night.', + }, + { + at: d('2025-10-06 15:00'), + key: 'dec-nightly-capture', + type: 'WriteDecision', + title: + 'Capture the cliffs and dunes benchmarks on every nightly Meridian build', + created_by: LIAM, + derives_from: ['iss-gap-capture'], + body: + 'The build farm runs the cliffs and dunes benchmarks on a Meridian devkit after each nightly build and stores the GPU capture with the build number and devkit serial. ' + + 'Hand captures stay allowed for exploration, but a number that drives a Decision should come from a nightly capture. ' + + "Liam O'Connell owns the job; the first nightly capture is planned for build r4700.", + }, + { + at: d('2025-10-08 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-nightly-capture', + }, + { + at: d('2025-10-08 10:05'), + type: 'ResolveIssue', + issueId: 'iss-gap-capture', + resolution: 'resolved', + resolvedBy: ['dec-nightly-capture'], + }, + { + at: d('2025-11-25 10:00'), + key: 'iss-rt-reflect', + type: 'WriteIssue', + kind: 'gap', + title: 'No ray-traced reflections on saltglass', + created_by: YUSUF, + body: + 'Saltglass reflects the sky and nearby cliffs with screen-space reflections only. Anything off screen vanishes from the reflection. ' + + 'Yusuf Demir asks whether ray-traced reflections on PC and Meridian are in scope.', + }, + { + at: d('2025-12-01 09:00'), + key: 'iss-slice-budget', + type: 'WriteIssue', + kind: 'blocker', + title: 'Vertical slice runs at 19.4 ms on the dunes flyover', + created_by: INES, + derives_from: ['con-budget-1'], + body: + 'Two weeks before the slice, the dunes flyover runs at 19.4 ms on Meridian, 2.8 ms over the Frame budget. ' + + 'SDF GI with all four clipmap cascades and the saltglass forward pass are the two largest passes. The slice cannot ship at this cost.', + }, + { + at: d('2025-12-03 10:00'), + key: 'dec-slice-cut', + type: 'WriteDecision', + title: 'Drop the far SDF GI cascade for the vertical slice build', + created_by: TOMASZ, + derives_from: ['iss-slice-budget', 'dec-gi-sdf'], + body: + 'For the slice build only, SDF GI traces three clipmap cascades instead of four. The far cascade covers 512 m to 2 km, where the probe-free fallback looks flat but acceptable. ' + + 'Tomasz Brandt measured the flyover at 16.1 ms with the cut. The fourth cascade comes back after the slice.', + }, + { + at: d('2025-12-04 09:00'), + type: 'AcceptDecision', + decisionId: 'dec-slice-cut', + }, + { + at: d('2025-12-12 10:00'), + type: 'ResolveIssue', + issueId: 'iss-slice-budget', + resolution: 'resolved', + resolvedBy: ['dec-slice-cut'], + }, + { + at: d('2025-12-18 10:00'), + key: 'cmp-1', + type: 'WriteCompaction', + title: 'Lantern at the vertical slice', + created_by: INES, + derives_from: [ + 'dec-vb-3', + 'dec-csm', + 'dec-gi-sdf', + 'dec-slice-cut', + 'dec-refr-ss', + 'dec-caustics-photon', + 'dec-tern', + 'dec-filmic', + 'dec-cull-gpu', + 'dec-meshlet-64', + ], + body: + 'The vertical slice shipped on 2025-12-15. The dunes flyover ran at 16.1 ms on Meridian after the far SDF GI cascade was dropped for the slice build, so the 16.6 ms Frame budget held.\n\n' + + 'Opaque geometry renders through a visibility buffer, with foliage and saltglass in a forward pass after the resolve. Sun shadows use four cascaded shadow maps; virtual shadow maps were rejected on a 3.1 ms cost. ' + + 'GI is signed-distance-field GI at 2.2 ms. Saltglass refraction is screen-space, although a Finding has shown it loses off-screen content at grazing angles and a replacement is due in January. ' + + 'Caustics are photon splats. Tern is the only upscaler. Tonemapping uses the stock filmic curve. Culling is GPU-driven with 64-vertex meshlets.', + }, + { + at: d('2025-12-19 10:00'), + key: 'con-budget-2', + type: 'WriteConstraint', + kind: 'hard', + title: 'Frame budget', + created_by: INES, + supersedes: ['con-budget-1'], + body: + 'After the vertical slice the 16.6 ms Meridian frame is split: 15.2 ms for Lantern GPU passes and 1.4 ms held back for system overlays and dynamic-resolution headroom. ' + + 'The slice ran passes to the full 16.6 ms and the system overlay pushed two capture runs over. Pass owners must give back time to fit 15.2 ms.', + }, + { + at: d('2025-12-22 10:00'), + type: 'ResolveIssue', + issueId: 'iss-rt-reflect', + resolution: 'wontfix', + resolvedBy: ['con-budget-2'], + }, + { + at: d('2026-02-10 10:00'), + key: 'iss-gap-skiff-profiles', + type: 'WriteIssue', + kind: 'gap', + title: 'No Skiff GPU timings for Lantern passes', + created_by: TOMASZ, + body: + 'Every Lantern pass has Meridian timings from the nightly capture, but none has Skiff timings. The visibility buffer, Tern and VSM were all chosen without a Skiff number. ' + + 'Tomasz Brandt wants Skiff numbers before alpha.', + }, + { + at: d('2026-02-11 10:00'), + key: 'fnd-skiff-devkit-eta', + type: 'WriteFinding', + kind: 'survey', + title: 'Skiff devkits reach the render team in April', + created_by: DARA, + derives_from: ['iss-gap-skiff-profiles'], + body: + 'Dara Whitlock checked with the platform holder: the render team gets two Skiff devkits in the first week of April 2026. ' + + 'Until then only the ports team has hardware, and it is booked for memory work.', + }, + { + at: d('2026-02-12 10:00'), + type: 'ResolveIssue', + issueId: 'iss-gap-skiff-profiles', + resolution: 'deferred', + resolvedBy: ['fnd-skiff-devkit-eta'], + }, + { + at: d('2026-03-05 10:00'), + key: 'cmp-2', + type: 'WriteCompaction', + title: 'Lantern at alpha', + created_by: INES, + derives_from: [ + 'dec-vb-4', + 'dec-vsm', + 'dec-gi-sdf', + 'fnd-gi-sdf-recapture', + 'dec-refr-hybrid', + 'iss-caustic-flicker', + 'dec-tern', + 'dec-brine-1', + 'dec-presets-3', + 'con-budget-2', + ], + body: + 'Alpha landed on 2026-03-02. The visibility buffer now resolves materials in compute, and foliage is back in the buffer thanks to meshlet alpha masks; saltglass still renders forward.\n\n' + + 'Virtual shadow maps replaced cascaded shadow maps on 2026-02-16 after the 3.1 ms cost Finding turned out to be a capture error. ' + + 'SDF GI remains the accepted GI Decision, but the recapture on a Meridian devkit measured 4.7 ms, not 2.2 ms, and nobody has re-weighed the GI Decision. ' + + 'Refraction is screen-space with a ray-marched fallback. Caustics flicker under Tern; the blocker is open with two proposed fixes. ' + + 'Tonemapping moved to the Brine curve. Tern ships three presets. The Frame budget gives GPU passes 15.2 ms.', + }, + { + at: d('2026-03-20 10:00'), + key: 'con-120-1', + type: 'WriteConstraint', + kind: 'soft', + title: 'Meridian 120 Hz performance mode budget', + created_by: DARA, + body: + 'Marketing asked for a 120 Hz performance mode on Meridian. A 120 Hz frame is 8.3 ms. For now this is a stretch goal: Lantern will try to hit 8.3 ms with a lower internal resolution and cheaper GI, ' + + 'but Dara Whitlock can still cut the mode if it does not fit by beta.', + }, + { + at: d('2026-04-02 10:00'), + key: 'con-budget-3', + type: 'WriteConstraint', + kind: 'hard', + title: 'Frame budget', + created_by: INES, + supersedes: ['con-budget-2'], + body: + 'Meridian quality mode stays at 60 Hz: 16.6 ms per frame, of which Lantern GPU passes get 15.0 ms and 1.6 ms is headroom. The headroom grew by 0.2 ms because the new system overlay costs more than the old one. ' + + 'The 120 Hz performance mode has its own Constraint with an 8.3 ms frame; this record covers quality mode only. Skiff budgets belong to the ports Effort.', + }, + { + at: d('2026-06-02 10:00'), + key: 'con-budget-noise', + type: 'WriteConstraint', + kind: 'hard', + title: 'Frame budget', + created_by: PRIYA, + body: 'Skiff 40 Hz mode: 25 ms per frame for CPU and GPU together. Skiff becomes a launch platform at beta, so Lantern passes on Skiff must fit inside 25 ms.', + }, + { + at: d('2026-06-02 16:00'), + type: 'Retract', + recordId: 'con-budget-noise', + reason: + 'Written to the render Effort by mistake. The Skiff 40 Hz budget belongs to the Frame budget record in the ports Effort.', + }, + { + at: d('2026-06-03 10:00'), + key: 'con-120-2', + type: 'WriteConstraint', + kind: 'hard', + title: 'Meridian 120 Hz performance mode budget', + created_by: DARA, + supersedes: ['con-120-1'], + body: + 'As of beta the 120 Hz performance mode is a launch commitment on Meridian. Each frame gets 8.3 ms: Lantern GPU passes get 7.4 ms and 0.9 ms is headroom. ' + + "The mode may drop GI quality and run Tern's lowest preset, but it must not drop saltglass refraction. GI gets at most 1.0 ms of the 7.4 ms.", + }, + { + at: d('2026-06-04 10:00'), + key: 'cmp-3', + type: 'WriteCompaction', + title: 'Lantern at beta', + created_by: INES, + derives_from: [ + 'dec-vb-5', + 'dec-vsm', + 'dec-tern-reactive', + 'fnd-tern-cost-3', + 'dec-brine-2', + 'iss-caustic-flicker', + 'iss-120-gi', + 'con-budget-3', + 'con-120-2', + 'rsk-vsm-overflow', + ], + body: + 'Beta landed on 2026-06-01 with Skiff as a launch platform. The visibility buffer runs on PC and Meridian; Skiff falls back to forward+ because the April Skiff capture put the buffer at 11.2 ms.\n\n' + + 'Virtual shadow maps are in, and the page-pool overflow Risk is open. Tern gets a saltglass reactive mask, which removes 90 percent of the ghosting, and the Halcyon vendor upscaler was rejected a second time. ' + + 'Tern costs 1.6 ms at 4K output. The Brine curve has a separate HDR shoulder. The 120 Hz performance mode is now a hard launch commitment at 8.3 ms; GI does not fit it yet and that blocker is open. ' + + 'Caustic flicker is still open with two proposed fixes. Quality mode keeps 15.0 ms of GPU time.', + }, + { + at: d('2026-08-26 10:00'), + key: 'cmp-4', + type: 'WriteCompaction', + title: 'Lantern at content lock', + created_by: INES, + derives_from: [ + 'dec-vb-6', + 'dec-vsm', + 'dec-tern', + 'dec-tern-reactive', + 'dec-presets-4b', + 'dec-brine-2', + 'iss-caustic-flicker', + 'iss-hdr-cert', + 'rsk-hdr-cert', + 'con-120-2', + ], + body: + 'Content locked on 2026-08-24. The visibility buffer runs on every platform; Skiff resolves materials at half rate and the Skiff forward+ path is gone.\n\n' + + 'Virtual shadow maps cover sun shadows, but shadow pages still run out at spring low tide. Tern is the only upscaler, with four presets including Ultra Performance for the 120 Hz mode, and a saltglass reactive mask against ghosting. ' + + "The Brine curve's HDR shoulder starts at 1,000 nits. HDR certification failed its first pre-check on paper white; two fixes are proposed, and Priya Natarajan expects the resubmission on 2026-09-12 to pass. " + + 'Caustic flicker under Tern is still an open blocker after seven months, and neither proposed fix has been accepted. The 120 Hz mode holds 8.3 ms per frame.', + }, + { + at: d('2026-09-25 10:00'), + key: 'fnd-rc-capture', + type: 'WriteFinding', + kind: 'measurement', + title: + 'Release-candidate capture: quality mode 14.6 ms, performance mode 7.3 ms', + created_by: TOMASZ, + derives_from: ['con-budget-3', 'con-120-2'], + body: + 'Nightly capture of the release-candidate build on a Meridian devkit, dunes flyover. Quality mode GPU time is 14.6 ms against the 15.0 ms allowance. ' + + 'Performance mode GPU time is 7.3 ms against 7.4 ms, with 0.1 ms to spare. Spring low tide was not part of this run.', + }, +]; diff --git a/benchmarks/proof-recall/spec/render/culling.mjs b/benchmarks/proof-recall/spec/render/culling.mjs new file mode 100644 index 00000000..5930a583 --- /dev/null +++ b/benchmarks/proof-recall/spec/render/culling.mjs @@ -0,0 +1,232 @@ +// GPU-driven culling and meshlets. Cone culling is accepted on a count that +// is later shown wrong, and the Decision is left standing. +import { d, TOMASZ, YUSUF, RHEA } from './people.mjs'; + +export default [ + { + at: d('2025-10-09 10:00'), + key: 'iss-cull-q', + type: 'WriteIssue', + kind: 'question', + title: 'How should Lantern cull geometry?', + created_by: TOMASZ, + body: 'The dunes benchmark submits 38,000 draws when the tide is out. The CPU spends more time deciding what to draw than the GPU spends drawing it. Options: GPU-driven culling, or keep CPU culling and add software occlusion.', + }, + { + at: d('2025-10-13 10:00'), + key: 'fnd-cull-cpu-cost', + type: 'WriteFinding', + kind: 'measurement', + title: 'CPU culling and draw submission cost 3.2 ms on the dunes benchmark', + created_by: TOMASZ, + derives_from: ['iss-cull-q'], + body: 'Frustum culling, LOD selection and draw submission for the dunes benchmark take 3.2 ms of render-thread time on Meridian. A GPU-driven prototype brings submission to 0.6 ms with two-phase occlusion.', + }, + { + at: d('2025-10-15 09:00'), + key: 'con-mesh-skiff', + type: 'WriteConstraint', + kind: 'hard', + title: 'Skiff has no mesh shader support', + created_by: TOMASZ, + body: "Skiff's GPU and driver do not support mesh or amplification shaders, and the platform holder has no plans to add them. Any meshlet path needs a fallback through the classic vertex pipeline on Skiff.", + }, + { + at: d('2025-10-27 10:00'), + key: 'dec-cull-gpu', + type: 'WriteDecision', + title: 'Move to GPU-driven two-phase occlusion culling', + created_by: TOMASZ, + derives_from: ['iss-cull-q', 'fnd-cull-cpu-cost'], + body: "Cull instances on the GPU against last frame's depth pyramid, draw the survivors, rebuild the pyramid, then test the rejected ones again. The CPU only uploads instance data. Submission drops from 3.2 ms to 0.6 ms.", + }, + { + at: d('2025-10-27 11:00'), + key: 'dec-cull-cpu', + type: 'WriteDecision', + title: 'Keep CPU frustum culling with software occlusion', + created_by: RHEA, + derives_from: ['iss-cull-q'], + body: 'Keep culling on the CPU and add a software occlusion rasterizer on two worker threads. Kestrel gameplay already knows which objects exist, so this keeps one source of truth. Rhea Valdés expects 1.4 ms back.', + }, + { + at: d('2025-11-05 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-cull-gpu', + }, + { + at: d('2025-11-05 10:05'), + type: 'ResolveIssue', + issueId: 'iss-cull-q', + resolution: 'resolved', + resolvedBy: ['dec-cull-gpu'], + }, + { + at: d('2025-11-12 11:00'), + key: 'iss-meshlet-q', + type: 'WriteIssue', + kind: 'question', + title: 'What meshlet size should Lantern use?', + created_by: TOMASZ, + body: 'GPU culling works per meshlet as well as per instance. Meshlet size trades culling precision against per-meshlet overhead. Pick one size for all saltglass and terrain meshes.', + }, + { + at: d('2025-11-18 15:00'), + key: 'blb-meshlet-sweep', + type: 'WriteBlob', + kind: 'markdown', + title: 'Meshlet size sweep on the cliffs benchmark', + created_by: TOMASZ, + body: + '| Max vertices | Max triangles | Meshlets (cliffs) | Raster ms | Culled triangles |\n' + + '| --- | --- | --- | --- | --- |\n' + + '| 32 | 60 | 412,000 | 1.42 | 58% |\n' + + '| 64 | 124 | 208,000 | 1.18 | 54% |\n' + + '| 128 | 256 | 104,000 | 1.25 | 47% |\n\n' + + 'Build lantern-2025.11.17-r5260, Meridian devkit, 1440p.', + }, + { + at: d('2025-11-18 15:05'), + key: 'cit-meshlet-sweep', + type: 'WriteCitation', + role: 'evidence', + title: 'Table: meshlet size sweep', + created_by: TOMASZ, + blob: 'blb-meshlet-sweep', + body: 'https://captures.tidewater.example/lantern/r5260/meshlet_sweep', + }, + { + at: d('2025-11-20 10:00'), + key: 'fnd-meshlet-sweep', + type: 'WriteFinding', + kind: 'measurement', + title: 'Meshlet size sweep on the cliffs benchmark', + created_by: TOMASZ, + derives_from: ['iss-meshlet-q'], + cites: ['cit-meshlet-sweep'], + body: 'Tomasz Brandt swept three meshlet sizes on the cliffs benchmark. The middle size rasterizes fastest; the largest culls noticeably fewer triangles. The table is attached.', + }, + { + at: d('2025-11-21 10:00'), + key: 'dec-meshlet-64', + type: 'WriteDecision', + title: 'Use 64-vertex meshlets with up to 124 triangles', + created_by: TOMASZ, + derives_from: ['iss-meshlet-q', 'fnd-meshlet-sweep'], + body: 'Build all saltglass and terrain meshes into meshlets of at most 64 vertices and 124 triangles. Fastest raster in the sweep, and fine enough for per-meshlet culling.', + }, + { + at: d('2025-11-21 11:00'), + key: 'dec-meshlet-128', + type: 'WriteDecision', + title: 'Use 128-vertex meshlets with up to 256 triangles', + created_by: RHEA, + derives_from: ['iss-meshlet-q'], + body: 'Larger meshlets halve the meshlet count and the culling dispatch size, and match what Kestrel tools already export. Rhea Valdés prefers fewer, bigger units.', + }, + { + at: d('2025-11-26 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-meshlet-64', + }, + { + at: d('2025-11-26 10:05'), + type: 'ResolveIssue', + issueId: 'iss-meshlet-q', + resolution: 'resolved', + resolvedBy: ['dec-meshlet-64'], + }, + { + at: d('2025-12-05 10:00'), + key: 'dec-meshlet-skiff', + type: 'WriteDecision', + title: 'Expand meshlets to index buffers in compute on Skiff', + created_by: TOMASZ, + derives_from: ['con-mesh-skiff', 'dec-meshlet-64'], + body: 'On Skiff, a compute pass writes the surviving meshlets into an index buffer each frame, and the classic vertex pipeline draws it with one indirect call. Culling stays per meshlet.', + }, + { + at: d('2025-12-06 10:00'), + key: 'rsk-meshlet-skiff', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'medium', + title: 'Compute meshlet expansion is too slow on Skiff', + created_by: TOMASZ, + derives_from: ['dec-meshlet-skiff'], + body: 'Writing index buffers every frame costs bandwidth Skiff does not have much of. On the cliffs benchmark the expansion could take 1.5 ms or more. No Skiff measurement exists yet.', + }, + { + at: d('2025-12-08 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-meshlet-skiff', + }, + { + at: d('2026-01-28 10:00'), + key: 'fnd-meshlet-cone', + type: 'WriteFinding', + kind: 'measurement', + title: 'Meshlet cone culling rejects 31 percent of triangles', + created_by: TOMASZ, + derives_from: ['dec-meshlet-64'], + body: 'Testing each meshlet against a normal cone before rasterizing rejects 31 percent of triangles on the cliffs benchmark, for 0.1 ms of culling work. Cliff faces turned away from the camera are the bulk of it.', + }, + { + at: d('2026-02-03 10:00'), + key: 'dec-meshlet-cone', + type: 'WriteDecision', + title: 'Enable meshlet cone culling on all platforms', + created_by: TOMASZ, + derives_from: ['fnd-meshlet-cone'], + body: 'Turn on per-meshlet normal-cone culling everywhere, including the Skiff compute expansion. A 31 percent cut in triangles for 0.1 ms is an easy win.', + }, + { + at: d('2026-02-04 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-meshlet-cone', + }, + { + at: d('2026-03-10 10:00'), + key: 'iss-cull-popping', + type: 'WriteIssue', + kind: 'defect', + title: 'Objects pop in for one frame when the tide uncovers them', + created_by: YUSUF, + derives_from: ['dec-cull-gpu'], + body: "When a tide step uncovers rocks and wrecks, they are missing from the previous frame's depth pyramid and from the first culling phase, and appear one frame late. Visible as a flash at the waterline.", + }, + { + at: d('2026-03-25 10:00'), + key: 'dec-cull-tide-hint', + type: 'WriteDecision', + title: + 'Mark tide-exposed instances visible for one frame after a tide step', + created_by: TOMASZ, + derives_from: ['iss-cull-popping'], + body: 'The world streaming system already knows which instances a tide step uncovers. Kenji Arakawa adds a flag for them, and the first culling phase treats flagged instances as visible for one frame.', + }, + { + at: d('2026-03-26 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-cull-tide-hint', + }, + { + at: d('2026-03-30 10:00'), + type: 'ResolveIssue', + issueId: 'iss-cull-popping', + resolution: 'resolved', + resolvedBy: ['dec-cull-tide-hint'], + }, + { + at: d('2026-05-26 10:00'), + key: 'fnd-meshlet-cone-recount', + type: 'WriteFinding', + kind: 'measurement', + title: 'Meshlet cone culling rejects 9 percent of triangles', + created_by: RHEA, + invalidates: ['fnd-meshlet-cone'], + body: + 'Rhea Valdés recounted the cone-culling numbers. The January count included triangles that back-face culling already removed, so they were counted twice. ' + + 'Cone culling on its own rejects 9 percent of triangles on the cliffs benchmark. It still pays for its 0.1 ms on PC and Meridian; on Skiff it is close to break-even.', + }, +]; diff --git a/benchmarks/proof-recall/spec/render/gi.mjs b/benchmarks/proof-recall/spec/render/gi.mjs new file mode 100644 index 00000000..08eec9b4 --- /dev/null +++ b/benchmarks/proof-recall/spec/render/gi.mjs @@ -0,0 +1,277 @@ +// Global illumination: SDF GI accepted on a capture from the wrong platform. +// The capture is invalidated, but the accepted Decision is never re-weighed. +import { d, json, INES, TOMASZ, YUSUF, DARA } from './people.mjs'; + +export default [ + { + at: d('2025-09-15 10:00'), + key: 'iss-gi-q', + type: 'WriteIssue', + kind: 'question', + title: 'How should Lantern do global illumination?', + created_by: INES, + body: + 'Tides move every 40 minutes and the sun crosses the sky in 90, so baked lighting is out. Candidates: a relit probe grid, signed-distance-field GI, or a hybrid of the two. ' + + 'Light must bounce through saltglass and must not leak through thin glass walls.', + }, + { + at: d('2025-10-13 15:00'), + key: 'blb-gi-sdf', + type: 'WriteBlob', + kind: 'json', + title: 'GPU capture: SDF GI on the dunes benchmark', + created_by: TOMASZ, + body: json({ + build: 'lantern-2025.10.10-r4630', + device: 'PC workstation (Meridian clock profile)', + scene: 'dunes_bench_01', + resolution: '2560x1440', + clipmap_cascades: 4, + clipmap_size: '64^3', + passes_ms: { sdf_update: 0.4, trace: 1.3, filter: 0.3, apply: 0.2 }, + total_ms: 2.2, + l2_hit_rate: 0.81, + }), + }, + { + at: d('2025-10-13 15:05'), + key: 'cit-gi-sdf', + type: 'WriteCitation', + role: 'evidence', + title: 'Capture: SDF GI dunes benchmark', + created_by: TOMASZ, + blob: 'blb-gi-sdf', + body: 'https://captures.tidewater.example/lantern/r4630/sdf_gi', + }, + { + at: d('2025-10-15 10:00'), + key: 'fnd-gi-sdf-cost', + type: 'WriteFinding', + kind: 'measurement', + title: 'SDF GI costs 2.2 ms on Meridian', + created_by: TOMASZ, + derives_from: ['iss-gi-q'], + cites: ['cit-gi-sdf'], + body: + 'SDF GI with four clipmap cascades of 64 cubed costs 2.2 ms per frame at 1440p on the dunes benchmark, with tracing the largest part at 1.3 ms. ' + + 'That is affordable inside the Frame budget. The capture is attached.', + }, + { + at: d('2025-10-15 10:05'), + key: 'fnd-gi-sdf-cost-noise', + type: 'WriteFinding', + kind: 'measurement', + title: 'SDF GI costs 2.4 ms on Meridian', + created_by: TOMASZ, + derives_from: ['iss-gi-q'], + body: 'SDF GI costs 2.4 ms per frame at 1440p on the dunes benchmark.', + }, + { + at: d('2025-10-16 10:00'), + type: 'Retract', + recordId: 'fnd-gi-sdf-cost-noise', + reason: + 'Draft written before the capture finished; the 2.4 ms figure included the debug overlay. The 2.2 ms Finding is the one to use.', + }, + { + at: d('2025-10-17 10:00'), + key: 'fnd-gi-probe-leak', + type: 'WriteFinding', + kind: 'measurement', + title: 'Probe grid leaks light through thin saltglass walls', + created_by: YUSUF, + derives_from: ['iss-gi-q'], + body: + 'With 1 m probe spacing, probes behind 20 cm saltglass walls in the ruins see the sunlit side, and the dark side glows. ' + + 'Halving the spacing to 0.5 m cuts the leak by about half and costs eight times the probes.', + }, + { + at: d('2025-10-20 13:00'), + key: 'dec-gi-probe', + type: 'WriteDecision', + title: 'Use a relit probe grid for global illumination', + created_by: YUSUF, + derives_from: ['iss-gi-q'], + body: + 'Place probes on a 1 m grid near the player and 4 m further out, and relight them each frame from the sun and sky. Cheap at about 0.6 ms. ' + + 'Leaks through thin saltglass walls are the known weakness.', + }, + { + at: d('2025-10-20 14:00'), + key: 'dec-gi-sdf', + type: 'WriteDecision', + title: 'Use signed-distance-field GI', + created_by: TOMASZ, + derives_from: ['iss-gi-q', 'fnd-gi-sdf-cost', 'fnd-gi-probe-leak'], + body: + 'Trace short cones against a signed-distance-field clipmap of the scene, four cascades of 64 cubed. Thin saltglass walls block light correctly because the distance field knows they are there. ' + + 'At 2.2 ms on Meridian it fits the Frame budget.', + }, + { + at: d('2025-10-20 15:00'), + key: 'dec-gi-hybrid', + type: 'WriteDecision', + title: 'Use a probe grid for the far field and SDF tracing near the camera', + created_by: INES, + derives_from: ['iss-gi-q'], + body: 'Trace the distance field within 64 m of the camera and fall back to the relit probe grid beyond it. More code than either option alone, but each half does what it is good at.', + }, + { + at: d('2025-10-28 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-gi-sdf', + }, + { + at: d('2025-10-28 10:05'), + type: 'ResolveIssue', + issueId: 'iss-gi-q', + resolution: 'resolved', + resolvedBy: ['dec-gi-sdf'], + }, + { + at: d('2025-11-05 10:00'), + key: 'fnd-gi-frame-share', + type: 'WriteFinding', + kind: 'analysis', + title: 'GI takes 13 percent of the quality-mode frame', + created_by: INES, + derives_from: ['fnd-gi-sdf-cost', 'con-budget-1'], + body: 'At 2.2 ms, SDF GI is 13 percent of the 16.6 ms Meridian frame. Ines Okafor uses this share to plan the other passes: shadows, refraction and Tern together may take 5 ms.', + }, + { + at: d('2025-11-06 10:00'), + key: 'rsk-sdf-memory', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'medium', + title: 'SDF volumes outgrow the render-target memory budget', + created_by: TOMASZ, + derives_from: ['dec-gi-sdf', 'con-vram'], + body: 'Four 64-cubed clipmaps plus the per-mesh distance fields could pass 500 MB once all the ruins are in. That would squeeze shadow pages and the visibility buffer inside 1.8 GB.', + }, + { + at: d('2026-02-02 15:00'), + key: 'blb-gi-recap', + type: 'WriteBlob', + kind: 'json', + title: 'GPU capture: SDF GI on a Meridian devkit, dunes benchmark', + created_by: TOMASZ, + body: json({ + build: 'lantern-2026.02.01-r5840', + device: 'Meridian devkit MRD-0031, retail clocks', + scene: 'dunes_bench_01', + resolution: '2560x1440', + clipmap_cascades: 4, + passes_ms: { sdf_update: 0.6, trace: 3.2, filter: 0.5, apply: 0.4 }, + total_ms: 4.7, + l2_hit_rate: 0.52, + }), + }, + { + at: d('2026-02-02 15:05'), + key: 'cit-gi-recap', + type: 'WriteCitation', + role: 'evidence', + title: 'Capture: SDF GI on a Meridian devkit', + created_by: TOMASZ, + blob: 'blb-gi-recap', + body: 'https://captures.tidewater.example/lantern/r5840/sdf_gi_devkit', + }, + { + at: d('2026-02-05 10:00'), + key: 'fnd-gi-sdf-recapture', + type: 'WriteFinding', + kind: 'measurement', + title: 'SDF GI costs 4.7 ms on Meridian', + created_by: TOMASZ, + invalidates: ['fnd-gi-sdf-cost'], + cites: ['cit-gi-recap'], + body: + 'The October SDF GI number was not a Meridian number. The first nightly devkit capture of the dunes benchmark puts SDF GI at 4.7 ms, more than twice the 2.2 ms the GI Decision was accepted on. ' + + 'Tracing went from 1.3 ms to 3.2 ms; the distance-field update and the filter grew a little too. ' + + 'The October capture predates the nightly capture job and was taken by hand; its attached capture names the machine it ran on.\n\n' + + 'Why the gap is so large: SDF tracing is bound by cache misses. Each cone step reads a different part of the clipmap, so the trace pass lives or dies on the L2 cache. ' + + "The Decision 'Use signed-distance-field GI' still stands on the 2.2 ms figure and nobody has re-weighed it against the probe grid. " + + 'Tomasz Brandt does not propose reversing it yet, because the probe grid still leaks through thin walls.\n\n' + + 'The L2 hit rate in the trace pass fell from 81 percent in the October capture to 52 percent on the devkit.', + }, + { + at: d('2026-03-09 10:00'), + key: 'fnd-sdf-memory', + type: 'WriteFinding', + kind: 'measurement', + title: 'SDF volumes use 410 MB of render-target memory', + created_by: TOMASZ, + derives_from: ['rsk-sdf-memory'], + body: + 'With every ruin in the alpha build loaded, the clipmaps and per-mesh distance fields use 410 MB of the 1.8 GB render-target budget. ' + + 'That fits today, but leaves about 90 MB of slack for new ruins before the 500 MB line the Risk named.', + }, + { + at: d('2026-03-10 10:00'), + type: 'SetRiskState', + riskId: 'rsk-sdf-memory', + state: 'accepted', + evidence: ['fnd-sdf-memory'], + }, + { + at: d('2026-03-24 10:00'), + key: 'iss-120-gi', + type: 'WriteIssue', + kind: 'blocker', + title: 'GI does not fit the 120 Hz performance-mode budget', + created_by: INES, + derives_from: ['con-120-1', 'fnd-gi-sdf-recapture'], + body: + 'At 4.7 ms SDF GI alone takes more than half of an 8.3 ms performance-mode frame. The 120 Hz mode cannot ship with GI as it is. ' + + 'Some cheaper GI path for performance mode is needed.', + }, + { + at: d('2026-03-25 10:00'), + key: 'rsk-120-gi', + type: 'WriteRisk', + likelihood: 'high', + severity: 'high', + title: 'GI cannot fit the 120 Hz performance mode', + created_by: DARA, + derives_from: ['iss-120-gi'], + body: 'If no GI path fits the performance-mode budget, the 120 Hz mode either ships with flat lighting or does not ship. Marketing has already announced it.', + }, + { + at: d('2026-03-26 10:00'), + key: 'dec-gi-120-probe', + type: 'WriteDecision', + title: 'Use the probe grid alone in 120 Hz performance mode', + created_by: YUSUF, + derives_from: ['iss-120-gi', 'fnd-gi-probe-leak'], + body: 'In performance mode only, replace SDF GI with the relit probe grid at 2 m spacing. It costs about 0.6 ms. The leak through thin saltglass walls comes back, and Yusuf Demir would hide the worst ruins with authored blockers.', + }, + { + at: d('2026-04-10 10:00'), + key: 'dec-gi-120-quarter', + type: 'WriteDecision', + title: 'Trace SDF GI at quarter resolution in performance mode', + created_by: TOMASZ, + derives_from: ['iss-120-gi'], + body: 'Keep SDF GI in performance mode but trace at quarter resolution and upsample with a depth-aware filter. Thin walls stay correct. Tomasz Brandt expects about 1.3 ms.', + }, + { + at: d('2026-06-24 10:00'), + key: 'fnd-120-gi-cost', + type: 'WriteFinding', + kind: 'measurement', + title: 'Quarter-resolution SDF GI costs 1.9 ms in performance mode', + created_by: TOMASZ, + derives_from: ['dec-gi-120-quarter', 'con-120-2'], + body: + 'Quarter-resolution tracing measured 1.9 ms on the dunes benchmark in performance mode, not the 1.3 ms hoped for; the upsample filter costs 0.5 ms by itself. ' + + 'Performance mode allows GI at most 1.0 ms. Neither proposal fits as written.', + }, + { + at: d('2026-06-25 10:00'), + type: 'SetRiskState', + riskId: 'rsk-120-gi', + state: 'realized', + evidence: ['fnd-120-gi-cost'], + }, +]; diff --git a/benchmarks/proof-recall/spec/render/hdr.mjs b/benchmarks/proof-recall/spec/render/hdr.mjs new file mode 100644 index 00000000..9c27f4ce --- /dev/null +++ b/benchmarks/proof-recall/spec/render/hdr.mjs @@ -0,0 +1,330 @@ +// Tonemapping from stock filmic to the Brine curve; Meridian HDR certification. +// The Brine curve and the certification Risk both move after the last compaction. +import { d, json, INES, TOMASZ, YUSUF, PRIYA, DARA } from './people.mjs'; + +export default [ + { + at: d('2025-10-07 10:00'), + key: 'iss-tonemap-q', + type: 'WriteIssue', + kind: 'question', + title: 'Which tonemapping curve should Lantern use?', + created_by: YUSUF, + body: + 'Saltglass caustics are the brightest thing on screen, often 30 times brighter than the sand around them. The tonemapping curve decides whether they read as light or as white blobs. ' + + 'Options: a stock filmic curve, or a neutral curve with all the look in grading LUTs.', + }, + { + at: d('2025-10-09 14:00'), + key: 'dec-filmic', + type: 'WriteDecision', + title: 'Use the stock filmic tonemapping curve', + created_by: TOMASZ, + derives_from: ['iss-tonemap-q'], + body: 'Use the stock filmic curve that Kestrel already ships. Artists know it, and it rolls off highlights softly in SDR.', + }, + { + at: d('2025-10-09 15:00'), + key: 'dec-neutral', + type: 'WriteDecision', + title: 'Use a neutral curve and grade everything in LUTs', + created_by: YUSUF, + derives_from: ['iss-tonemap-q'], + body: 'Use a near-linear neutral curve and put all of the look into per-biome grading LUTs. Most control for art, most work for art.', + }, + { + at: d('2025-10-20 16:00'), + type: 'AcceptDecision', + decisionId: 'dec-filmic', + }, + { + at: d('2025-10-20 16:05'), + type: 'ResolveIssue', + issueId: 'iss-tonemap-q', + resolution: 'resolved', + resolvedBy: ['dec-filmic'], + }, + { + at: d('2025-10-22 10:00'), + key: 'con-ui-nits', + type: 'WriteConstraint', + kind: 'soft', + title: 'UI composites at a fixed 203 nits in HDR', + created_by: YUSUF, + body: 'In HDR output the HUD and menus composite at a fixed 203 nits so text looks the same on every display. UI art is authored against that level.', + }, + { + at: d('2025-11-18 10:00'), + key: 'con-hdr-cert', + type: 'WriteConstraint', + kind: 'hard', + title: 'Meridian HDR certification requirements', + created_by: PRIYA, + body: + 'Meridian certification runs an HDR test pass on every submission, and a failure blocks release. Priya Natarajan summarized the parts that touch Lantern. ' + + 'The game must read the display peak luminance from the system calibration and never exceed it, so a curve that assumes a fixed peak fails on dimmer panels. ' + + 'The 10,000-nit test ramp must not clip below the calibrated peak. The game must start in HDR when the system is in HDR, without asking. ' + + 'The user must be able to choose paper white anywhere from 80 to 400 nits, and the game must start from the system paper-white value on first boot.\n\n' + + 'Black level must follow the system setting as well; crushing the bottom 1 percent of the ramp is a failure. ' + + 'The test also checks that SDR and HDR screenshots match in content, so the HDR path cannot hide or add effects.\n\n' + + 'A title may fail the HDR pass at most twice per release candidate; a third failure sends the whole submission back for a full re-review.', + }, + { + at: d('2025-12-08 10:00'), + key: 'dec-hdr-fixed-pw', + type: 'WriteDecision', + title: 'Hard-code HDR paper white at 200 nits on Meridian', + created_by: TOMASZ, + derives_from: ['con-ui-nits'], + body: 'Set paper white to a fixed 200 nits on Meridian, close to the 203-nit UI level, and skip the system setting for now. One less setting to test before the slice.', + }, + { + at: d('2025-12-09 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-hdr-fixed-pw', + }, + { + at: d('2026-01-15 15:00'), + key: 'blb-highlight', + type: 'WriteBlob', + kind: 'json', + title: 'Highlight histogram: caustic pixels under the stock filmic curve', + created_by: YUSUF, + body: json({ + build: 'lantern-2026.01.14-r5650', + scene: 'dunes_noon', + curve: 'kestrel_filmic_v2', + caustic_pixels: 182000, + clipped_caustic_pixels: 69160, + clipped_pct: 38, + white_point_nits_equiv: 11.2, + }), + }, + { + at: d('2026-01-15 15:05'), + key: 'cit-highlight', + type: 'WriteCitation', + role: 'evidence', + title: 'Histogram: caustic highlights under filmic', + created_by: YUSUF, + blob: 'blb-highlight', + body: 'https://captures.tidewater.example/lantern/r5650/filmic_highlights', + }, + { + at: d('2026-01-16 10:00'), + key: 'fnd-filmic-clip', + type: 'WriteFinding', + kind: 'measurement', + title: 'Stock filmic curve clips 38 percent of caustic highlights', + created_by: YUSUF, + invalidates: ['dec-filmic'], + cites: ['cit-highlight'], + body: + 'On the dunes at noon, 38 percent of caustic pixels hit the top of the stock filmic curve and turn flat white. The caustic pattern, which is the whole point of the effect, disappears where it is brightest. ' + + 'The curve was the wrong choice for saltglass from the start; its shoulder was tuned for skies, not for small, very bright sources.', + }, + { + at: d('2026-01-30 10:00'), + key: 'dec-brine-1', + type: 'WriteDecision', + title: 'Use the custom Brine curve for tonemapping', + created_by: YUSUF, + supersedes: ['dec-filmic'], + derives_from: ['fnd-filmic-clip'], + body: + 'Replace the stock filmic curve with the Brine curve: a custom curve with a long, slow shoulder that keeps caustic detail up to 40 times scene mid-grey. ' + + 'Yusuf Demir tuned it on the dunes at noon and at dusk. The SDR and HDR outputs share the curve below the shoulder.', + }, + { + at: d('2026-02-02 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-brine-1', + }, + { + at: d('2026-02-03 10:00'), + key: 'rsk-brine-match', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'low', + title: 'Artists cannot match concept paintings under the Brine curve', + created_by: YUSUF, + derives_from: ['dec-brine-1'], + body: 'The concept paintings were made against the stock filmic look. Under the Brine curve some key shots may never match them.', + }, + { + at: d('2026-03-18 10:00'), + key: 'iss-hdr-banding', + type: 'WriteIssue', + kind: 'defect', + title: 'Banding in the dusk sky with the Brine curve on 10-bit output', + created_by: YUSUF, + derives_from: ['dec-brine-1'], + body: "In HDR on 10-bit output, the dusk sky shows visible bands where the Brine curve's shoulder is steepest. SDR is fine. Dithering hides some of it.", + }, + { + at: d('2026-03-31 10:00'), + key: 'fnd-brine-review', + type: 'WriteFinding', + kind: 'survey', + title: + 'Concept match review: 11 of 14 key shots pass under the Brine curve', + created_by: DARA, + derives_from: ['rsk-brine-match'], + body: + 'The art review compared 14 key shots against the concept paintings. 11 pass. The three that fail are night harbor shots, and art direction chose to repaint the concepts rather than bend the curve. ' + + 'Dara Whitlock accepted the remaining gap.', + }, + { + at: d('2026-04-01 10:00'), + type: 'SetRiskState', + riskId: 'rsk-brine-match', + state: 'accepted', + evidence: ['fnd-brine-review'], + }, + { + at: d('2026-05-06 10:00'), + key: 'dec-brine-2', + type: 'WriteDecision', + title: 'Brine curve with a separate HDR shoulder at 1,000 nits', + created_by: YUSUF, + supersedes: ['dec-brine-1'], + derives_from: ['iss-hdr-banding'], + body: 'Split the Brine curve: SDR keeps the original shoulder, HDR gets its own gentler shoulder starting at 1,000 nits. The gentler slope removes the dusk banding on 10-bit output without dithering.', + }, + { + at: d('2026-05-07 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-brine-2', + }, + { + at: d('2026-05-08 10:00'), + type: 'ResolveIssue', + issueId: 'iss-hdr-banding', + resolution: 'resolved', + resolvedBy: ['dec-brine-2'], + }, + { + at: d('2026-07-14 15:00'), + key: 'blb-hdr-precheck', + type: 'WriteBlob', + kind: 'markdown', + title: 'Meridian HDR certification pre-check report, July', + created_by: PRIYA, + body: + '# HDR pre-check, build lantern-2026.07.13-r7400\n\n' + + '| Test | Name | Result |\n| --- | --- | --- |\n' + + '| HDR-01 | Starts in HDR when system is HDR | PASS |\n' + + '| HDR-03 | Peak luminance follows calibration | PASS |\n' + + '| HDR-05 | Test ramp does not clip below peak | PASS |\n' + + '| HDR-07 | Paper white follows system setting and range | FAIL |\n' + + '| HDR-09 | SDR and HDR content match | PASS |\n\n' + + 'HDR-07 note: paper white stayed at 200 nits for system values of 100 and 350. No in-game control found.', + }, + { + at: d('2026-07-14 15:05'), + key: 'cit-hdr-precheck', + type: 'WriteCitation', + role: 'evidence', + title: 'Report: Meridian HDR pre-check, July', + created_by: PRIYA, + blob: 'blb-hdr-precheck', + body: 'https://cert.tidewater.example/meridian/precheck/r7400', + }, + { + at: d('2026-07-15 10:00'), + key: 'fnd-hdr-precheck', + type: 'WriteFinding', + kind: 'measurement', + title: 'Meridian HDR certification pre-check failed on paper white', + created_by: PRIYA, + invalidates: ['dec-hdr-fixed-pw'], + cites: ['cit-hdr-precheck'], + body: + 'The July pre-check failed one test: paper white ignores the system setting and offers no user range. The hard-coded 200 nits was never allowed by the certification requirements. ' + + 'Every other HDR test passed. The report is attached.', + }, + { + at: d('2026-07-16 10:00'), + key: 'iss-hdr-cert', + type: 'WriteIssue', + kind: 'blocker', + title: 'Meridian HDR certification fails the paper-white test', + created_by: PRIYA, + derives_from: ['fnd-hdr-precheck', 'con-hdr-cert'], + body: 'Release on Meridian is blocked until paper white follows the system and offers the required range. The UI pass assumes a fixed level, so the fix touches UI compositing as well as tonemapping.', + }, + { + at: d('2026-07-17 10:00'), + key: 'rsk-hdr-cert', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'high', + title: 'HDR certification slips the release candidate', + created_by: DARA, + derives_from: ['iss-hdr-cert'], + body: 'Each certification resubmission takes about ten days. If the paper-white fix fails a second time, the Meridian release candidate on 2026-09-30 slips.', + }, + { + at: d('2026-07-20 10:00'), + key: 'dec-hdr-pw-system', + type: 'WriteDecision', + title: + 'Read paper white from the Meridian system setting and scale the UI with it', + created_by: PRIYA, + derives_from: ['iss-hdr-cert'], + body: 'On first boot, read paper white from the Meridian system setting. Composite the UI at that level instead of a fixed 203 nits. Smallest change that passes the system half of the test.', + }, + { + at: d('2026-07-21 10:00'), + key: 'dec-hdr-pw-slider', + type: 'WriteDecision', + title: 'Add an in-game paper-white slider from 80 to 400 nits', + created_by: YUSUF, + derives_from: ['iss-hdr-cert'], + body: 'Add a paper-white slider to the display menu, from 80 to 400 nits, starting at the system value. Covers the range half of the test. UI art needs checking at both ends.', + }, + { + at: d('2026-09-07 10:00'), + key: 'fnd-shoulder-clip', + type: 'WriteFinding', + kind: 'measurement', + title: 'Brine HDR shoulder clips caustics on 800-nit panels', + created_by: PRIYA, + derives_from: ['dec-brine-2', 'con-hdr-cert'], + body: 'On panels calibrated to 800 nits, the HDR shoulder starting at 1,000 nits never begins before the panel peak, so caustics clip hard at 800. The certification lab uses an 800-nit panel for the ramp test.', + }, + { + at: d('2026-09-08 10:00'), + key: 'dec-brine-3', + type: 'WriteDecision', + title: 'Brine curve with an HDR shoulder at 800 nits', + created_by: YUSUF, + supersedes: ['dec-brine-2'], + derives_from: ['fnd-shoulder-clip'], + body: 'Move the Brine HDR shoulder down to start at 800 nits, and scale it to the calibrated peak on brighter panels. Dusk banding stays fixed at the new slope.', + }, + { + at: d('2026-09-09 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-brine-3', + }, + { + at: d('2026-09-14 10:00'), + key: 'fnd-hdr-precheck-2', + type: 'WriteFinding', + kind: 'measurement', + title: 'Meridian HDR certification pre-check failed again on paper white', + created_by: PRIYA, + derives_from: ['iss-hdr-cert'], + body: + 'The second pre-check, on 2026-09-12, failed the paper-white test again. Neither proposed fix was merged in time, so the build still used a fixed paper white. ' + + 'The next submission window opens on 2026-09-24.', + }, + { + at: d('2026-09-15 10:00'), + type: 'SetRiskState', + riskId: 'rsk-hdr-cert', + state: 'realized', + evidence: ['fnd-hdr-precheck-2'], + }, +]; diff --git a/benchmarks/proof-recall/spec/render/index.mjs b/benchmarks/proof-recall/spec/render/index.mjs new file mode 100644 index 00000000..09b43fe4 --- /dev/null +++ b/benchmarks/proof-recall/spec/render/index.mjs @@ -0,0 +1,31 @@ +// The render Effort: Lantern, Kestrel's renderer, across the whole project. +// Each thread lives in its own module; events are merged in time order. +import core from './core.mjs'; +import vb from './vb.mjs'; +import shadows from './shadows.mjs'; +import gi from './gi.mjs'; +import saltglass from './saltglass.mjs'; +import tern from './tern.mjs'; +import hdr from './hdr.mjs'; +import culling from './culling.mjs'; + +const threads = [core, vb, shadows, gi, saltglass, tern, hdr, culling]; +const events = threads + .flatMap((thread, t) => thread.map((event, i) => ({ event, t, i }))) + .sort( + (a, b) => a.event.at.localeCompare(b.event.at) || a.t - b.t || a.i - b.i + ) + .map(({ event }) => event); + +export default { + key: 'render', + effort: { + title: 'Lantern renderer overhaul', + body: + "Lantern is Kestrel's renderer. This Effort covers its overhaul for Saltglass Reach: the move to a visibility buffer, sun and local shadows, global illumination, " + + 'saltglass refraction and caustics, the Tern upscaler, HDR and tonemapping, GPU-driven culling, and the Meridian frame budgets including the 120 Hz performance mode. ' + + 'Ines Okafor leads it.', + created_at: '2025-09-01T09:00:00Z', + }, + events, +}; diff --git a/benchmarks/proof-recall/spec/render/people.mjs b/benchmarks/proof-recall/spec/render/people.mjs new file mode 100644 index 00000000..f0884f72 --- /dev/null +++ b/benchmarks/proof-recall/spec/render/people.mjs @@ -0,0 +1,15 @@ +// Names and a time helper shared by the render thread modules. +export const INES = 'Ines Okafor'; +export const TOMASZ = 'Tomasz Brandt'; +export const YUSUF = 'Yusuf Demir'; +export const RHEA = 'Rhea Valdés'; +export const KENJI = 'Kenji Arakawa'; +export const PRIYA = 'Priya Natarajan'; +export const LIAM = "Liam O'Connell"; +export const DARA = 'Dara Whitlock'; + +/** '2025-09-03 11:00' -> '2025-09-03T11:00:00Z' */ +export const d = (s) => `${s.replace(' ', 'T')}:00Z`; + +/** Pretty JSON for Blob bodies. */ +export const json = (value) => JSON.stringify(value, null, 2); diff --git a/benchmarks/proof-recall/spec/render/saltglass.mjs b/benchmarks/proof-recall/spec/render/saltglass.mjs new file mode 100644 index 00000000..40d2faa3 --- /dev/null +++ b/benchmarks/proof-recall/spec/render/saltglass.mjs @@ -0,0 +1,301 @@ +// Saltglass refraction and caustics: screen-space refraction shown wrong and +// replaced by a hybrid; caustic flicker under Tern stays an open blocker. +import { d, json, INES, TOMASZ, YUSUF, DARA } from './people.mjs'; + +export default [ + { + at: d('2025-09-18 10:00'), + key: 'iss-refr-q', + type: 'WriteIssue', + kind: 'question', + title: 'How should Lantern render saltglass refraction?', + created_by: YUSUF, + body: + 'Saltglass is the signature look of Saltglass Reach. Dunes, cliffs and ruins bend whatever is behind them, out to 2 km. ' + + 'Options: screen-space refraction, ray-marching through the saltglass distance field, or refracting into local cubemaps.', + }, + { + at: d('2025-10-02 10:00'), + key: 'fnd-refr-cost', + type: 'WriteFinding', + kind: 'measurement', + title: 'Refraction cost: screen-space 0.9 ms, ray-marched 3.4 ms', + created_by: TOMASZ, + derives_from: ['iss-refr-q'], + body: + 'On the cliffs benchmark with saltglass covering 40 percent of the screen, screen-space refraction costs 0.9 ms and a 64-step ray march through the distance field costs 3.4 ms. ' + + 'Local cubemaps cost 0.5 ms but show the wrong place behind the glass whenever the camera moves away from the capture point.', + }, + { + at: d('2025-10-03 10:00'), + key: 'dec-refr-ss', + type: 'WriteDecision', + title: 'Use screen-space refraction for saltglass', + created_by: TOMASZ, + derives_from: ['iss-refr-q', 'fnd-refr-cost'], + body: 'Offset the scene-color lookup by the refracted view ray, in screen space. At 0.9 ms it is the cheapest option that shows the right thing behind the glass most of the time.', + }, + { + at: d('2025-10-03 11:00'), + key: 'dec-refr-rm', + type: 'WriteDecision', + title: 'Ray-march refraction through the saltglass distance field', + created_by: YUSUF, + derives_from: ['iss-refr-q'], + body: 'March the refracted ray through the distance field up to 64 steps and shade the hit. Correct even when the refracted point is off screen. Costs 3.4 ms.', + }, + { + at: d('2025-10-03 12:00'), + key: 'dec-refr-cube', + type: 'WriteDecision', + title: 'Refract into local cubemaps', + created_by: INES, + derives_from: ['iss-refr-q'], + body: 'Capture cubemaps every 50 m along the coast and refract into the nearest one. Cheapest at 0.5 ms, but parallax is wrong and tides make the captures stale every 40 minutes.', + }, + { + at: d('2025-10-06 11:00'), + key: 'iss-caustics-q', + type: 'WriteIssue', + kind: 'question', + title: 'How should Lantern draw saltglass caustics?', + created_by: YUSUF, + body: 'Sunlight through saltglass dunes should throw moving caustic patterns on the sand below. Options: project animated caustic textures along the sun, or splat photons traced through the glass.', + }, + { + at: d('2025-10-10 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-refr-ss', + }, + { + at: d('2025-10-10 10:05'), + type: 'ResolveIssue', + issueId: 'iss-refr-q', + resolution: 'resolved', + resolvedBy: ['dec-refr-ss'], + }, + { + at: d('2025-10-14 15:00'), + key: 'fnd-caustic-proto', + type: 'WriteFinding', + kind: 'measurement', + title: 'Photon caustics cost 1.1 ms from a 512 by 512 sun-space map', + created_by: TOMASZ, + derives_from: ['iss-caustics-q'], + body: 'Tracing one photon per texel of a 512 by 512 sun-space map through the saltglass and splatting the hits costs 1.1 ms on Meridian. Projected textures cost 0.2 ms but do not follow the shape of the glass.', + }, + { + at: d('2025-10-15 14:00'), + key: 'dec-caustics-proj', + type: 'WriteDecision', + title: 'Project animated caustic textures along the sun direction', + created_by: YUSUF, + derives_from: ['iss-caustics-q'], + body: 'Project a tiling animated caustic texture along the sun direction under any saltglass. Costs 0.2 ms. Artists control the look directly.', + }, + { + at: d('2025-10-15 15:00'), + key: 'dec-caustics-photon', + type: 'WriteDecision', + title: 'Splat caustic photons from a sun-space map', + created_by: TOMASZ, + derives_from: ['iss-caustics-q', 'fnd-caustic-proto'], + body: 'Trace photons from a 512 by 512 sun-space map through the saltglass, jitter them each frame, and splat the hits into a caustic buffer that lighting reads. The pattern follows the real glass shape. Costs 1.1 ms.', + }, + { + at: d('2025-10-24 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-caustics-photon', + }, + { + at: d('2025-10-24 10:05'), + type: 'ResolveIssue', + issueId: 'iss-caustics-q', + resolution: 'resolved', + resolvedBy: ['dec-caustics-photon'], + }, + { + at: d('2025-11-26 10:00'), + key: 'fnd-refr-halo', + type: 'WriteFinding', + kind: 'measurement', + title: 'Screen-space refraction halos around the player', + created_by: YUSUF, + derives_from: ['dec-refr-ss'], + body: 'When the player stands in front of saltglass, the refraction samples the player instead of what is behind the glass, leaving a bright halo two to six pixels wide around the silhouette. A depth test on the offset sample removes most of it.', + }, + { + at: d('2025-12-04 14:00'), + key: 'fnd-refr-offscreen', + type: 'WriteFinding', + kind: 'measurement', + title: 'Screen-space refraction loses off-screen content at grazing angles', + created_by: YUSUF, + invalidates: ['dec-refr-ss'], + body: + 'Looking along the dunes at grazing angles, 30 to 45 percent of refracted rays leave the screen, and those pixels show smeared edge color. ' + + 'This is the common view in the game, not a corner case. Screen-space refraction cannot be the answer for saltglass on its own; the vertical slice will ship with the artifact.', + }, + { + at: d('2025-12-09 10:00'), + key: 'fnd-caustic-proj-tiling', + type: 'WriteFinding', + kind: 'measurement', + title: 'Projected caustic textures tile visibly past 600 m', + created_by: YUSUF, + invalidates: ['dec-caustics-proj'], + body: + 'Yusuf Demir kept the projected caustic textures alive as a possible Skiff fallback and tested them on the far dunes. Past 600 m the texture repeat is obvious on every dune face. ' + + 'The projected option is wrong for saltglass at any distance the game shows.', + }, + { + at: d('2026-01-08 10:00'), + key: 'dec-refr-hybrid', + type: 'WriteDecision', + title: + 'Screen-space refraction with a ray-marched fallback for off-screen rays', + created_by: TOMASZ, + supersedes: ['dec-refr-ss'], + derives_from: ['fnd-refr-offscreen', 'fnd-refr-cost'], + body: + 'Refraction first tries the screen-space lookup. When the refracted ray leaves the screen, or the depth test from the halo fix rejects the sample, the pixel falls back to a ray march through the saltglass distance field. ' + + 'On the dunes at grazing angles about 40 percent of saltglass pixels take the fallback, and the total refraction cost is 1.8 ms on Meridian, against 0.9 ms for screen-space alone and 3.4 ms for marching everything.\n\n' + + 'The halo fix stays in. Ray-marching every pixel, the option rejected in October, is still too expensive; this Decision uses the march only where screen space has nothing to show. ' + + 'Past 2 km the fallback samples the sky cubemap instead of marching.\n\n' + + 'The fallback march is capped at 32 steps, half of the 64 steps the October cost Finding measured.', + }, + { + at: d('2026-01-09 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-refr-hybrid', + }, + { + at: d('2026-01-22 15:00'), + key: 'blb-caustic-trace', + type: 'WriteBlob', + kind: 'json', + title: 'Luminance trace: caustics under Tern, dunes at noon', + created_by: YUSUF, + body: json({ + build: 'lantern-2026.01.21-r5720', + platform: 'Meridian devkit', + scene: 'dunes_noon', + internal_resolution: '1280x720', + output_resolution: '2560x1440', + frames: 600, + peak_flicker_hz: 4.7, + flicker_band_hz: [3, 6], + max_luma_delta: 0.31, + pixels_over_threshold_pct: 6.2, + }), + }, + { + at: d('2026-01-22 15:05'), + key: 'cit-caustic-trace', + type: 'WriteCitation', + role: 'evidence', + title: 'Trace: caustic luminance under Tern', + created_by: YUSUF, + blob: 'blb-caustic-trace', + body: 'https://captures.tidewater.example/lantern/r5720/caustic_flicker', + }, + { + at: d('2026-01-23 10:00'), + key: 'fnd-caustic-flicker', + type: 'WriteFinding', + kind: 'measurement', + title: 'Caustics flicker at 3 to 6 Hz under Tern', + created_by: YUSUF, + derives_from: ['dec-caustics-photon', 'dec-tern'], + cites: ['cit-caustic-trace'], + body: + 'Photon jitter changes the caustic pattern every frame. At 720p internal resolution Tern cannot tell new caustic detail from noise, clamps it away on some frames and keeps it on others, and the sand under the dunes flickers at 3 to 6 Hz. ' + + 'Full trace attached. At native resolution there is no visible flicker.', + }, + { + at: d('2026-01-26 10:00'), + key: 'iss-caustic-flicker', + type: 'WriteIssue', + kind: 'blocker', + title: 'Caustics flicker under Tern at low internal resolution', + created_by: INES, + derives_from: ['fnd-caustic-flicker'], + body: + 'Flicker in the 3 to 6 Hz band is a photosensitivity problem as well as an ugly one. Release cannot happen with it. ' + + 'Any fix must keep the caustics moving with the tide and must work at the internal resolutions Tern uses on every platform.', + }, + { + at: d('2026-01-26 10:02'), + key: 'iss-caustic-flicker-dup', + type: 'WriteIssue', + kind: 'blocker', + title: 'Caustics flicker under Tern at low internal resolutions', + created_by: INES, + body: 'Caustics flicker under Tern at low internal resolution. Blocker for release.', + }, + { + at: d('2026-01-27 10:00'), + type: 'Retract', + recordId: 'iss-caustic-flicker-dup', + reason: 'Duplicate of the blocker filed two minutes earlier.', + }, + { + at: d('2026-01-27 11:00'), + key: 'rsk-caustic-flicker', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'high', + title: 'Caustic flicker fails photosensitivity review', + created_by: DARA, + derives_from: ['iss-caustic-flicker'], + body: 'Platform photosensitivity review rejects flashing between 3 and 30 Hz over large areas. If the caustic flicker survives to submission, both consoles can fail review.', + }, + { + at: d('2026-02-12 10:00'), + key: 'dec-caustic-clamp', + type: 'WriteDecision', + title: "Exclude caustic luminance from Tern's history clamp", + created_by: TOMASZ, + derives_from: ['iss-caustic-flicker'], + body: 'Write caustic light to a separate buffer that Tern accumulates without neighborhood clamping, then add it back after upscaling. Tern then averages the jitter instead of fighting it.', + }, + { + at: d('2026-03-03 10:00'), + key: 'dec-caustic-seed', + type: 'WriteDecision', + title: 'Lock caustic photon jitter to the tide phase', + created_by: YUSUF, + derives_from: ['iss-caustic-flicker'], + body: 'Seed the photon jitter from the tide phase instead of the frame number, so the pattern changes only as the water moves. Tern then sees a stable pattern between tide steps.', + }, + { + at: d('2026-05-20 10:00'), + key: 'fnd-caustic-seed-test', + type: 'WriteFinding', + kind: 'measurement', + title: + 'Tide-locked jitter halves caustic flicker but stalls caustic motion', + created_by: YUSUF, + derives_from: ['dec-caustic-seed'], + body: + 'Yusuf Demir built the tide-locked seed on the r6600 branch and ran the dunes noon trace again. Peak flicker energy in the 3 to 6 Hz band drops by about half. ' + + 'It does not go away, because Tern still sees sub-pixel photon positions change between tide steps.\n\n' + + 'The bigger problem is motion. Caustics are supposed to crawl with the water, and the tide only moves the pattern when the phase advances. ' + + 'Around slack water the phase barely moves, so the caustics stand still while the water surface keeps rippling. Reviewers in the art meeting called it frozen. ' + + 'Yusuf Demir tried adding a slow drift on top of the tide seed, and the flicker came straight back.\n\n' + + 'Around slack tide the caustic pattern freezes for about 4 minutes of each 40-minute cycle.', + }, + { + at: d('2026-08-12 10:00'), + key: 'fnd-caustic-clamp-test', + type: 'WriteFinding', + kind: 'measurement', + title: + 'Clamp exclusion removes caustic flicker but ghosts caustics for 9 frames', + created_by: TOMASZ, + derives_from: ['dec-caustic-clamp'], + body: + 'With caustic light outside the history clamp, the 3 to 6 Hz flicker is gone in the dunes noon trace. But when a cliff shadow or the player crosses the caustics, the old pattern lingers for 9 frames. ' + + 'Tomasz Brandt thinks a reactive mask could fix it, as it did for refraction; nobody has tried yet.', + }, +]; diff --git a/benchmarks/proof-recall/spec/render/shadows.mjs b/benchmarks/proof-recall/spec/render/shadows.mjs new file mode 100644 index 00000000..d21489cd --- /dev/null +++ b/benchmarks/proof-recall/spec/render/shadows.mjs @@ -0,0 +1,308 @@ +// Sun shadows: CSM accepted on a bad VSM capture, VSM reopened and accepted +// after it supersedes CSM. Ray-traced shadows reopened and left proposed. +// Local lights get their own question with a near-duplicate VSM option. +import { d, json, INES, TOMASZ, YUSUF, DARA } from './people.mjs'; + +export default [ + { + at: d('2025-09-08 10:00'), + key: 'iss-shadow-q', + type: 'WriteIssue', + kind: 'question', + title: 'Which shadow technique should Lantern use for sun shadows?', + created_by: INES, + body: + 'The sun drives most of the light on the coast, and saltglass makes shadow errors easy to see because refraction bends them. ' + + 'Candidates: cascaded shadow maps, virtual shadow maps, or ray-traced sun shadows. Shadows must reach 2 km and fit the Frame budget on Meridian.', + }, + { + at: d('2025-09-25 15:00'), + key: 'blb-vsm-cost', + type: 'WriteBlob', + kind: 'json', + title: 'GPU capture: virtual shadow map prototype, dunes benchmark', + created_by: TOMASZ, + body: json({ + build: 'lantern-2025.09.24-r4561', + platform: 'Meridian devkit', + scene: 'dunes_bench_01', + virtual_resolution: 16384, + page_size: 128, + pool_pages: 4096, + page_pool_clear: 'every_frame', + pages_rendered_per_frame: 3870, + passes_ms: { page_mark: 0.3, page_raster: 2.4, page_sample: 0.4 }, + total_ms: 3.1, + csm_reference_ms: 1.6, + }), + }, + { + at: d('2025-09-25 15:05'), + key: 'cit-vsm-cost', + type: 'WriteCitation', + role: 'evidence', + title: 'Capture: virtual shadow map prototype', + created_by: TOMASZ, + blob: 'blb-vsm-cost', + body: 'https://captures.tidewater.example/lantern/r4561/vsm_proto', + }, + { + at: d('2025-09-29 10:00'), + key: 'fnd-vsm-cost', + type: 'WriteFinding', + kind: 'measurement', + title: 'Virtual shadow maps cost 3.1 ms on Meridian', + created_by: TOMASZ, + derives_from: ['iss-shadow-q'], + cites: ['cit-vsm-cost'], + body: + 'The virtual shadow map prototype, at 16k virtual resolution with 128-texel pages, costs 3.1 ms on the dunes benchmark. Four cascaded shadow maps cost 1.6 ms on the same view. ' + + 'Most of the VSM time is page rasterization. On these numbers VSM is twice the price of CSM.', + }, + { + at: d('2025-09-30 10:00'), + key: 'dec-csm', + type: 'WriteDecision', + title: 'Use cascaded shadow maps with four cascades', + created_by: TOMASZ, + derives_from: ['iss-shadow-q', 'fnd-vsm-cost'], + body: + 'Sun shadows use four cascaded shadow maps out to 2 km, with the last cascade updated every fourth frame. ' + + 'Cost is 1.6 ms on the dunes benchmark against 3.1 ms for virtual shadow maps. The technique is well understood and needs no new page management.', + }, + { + at: d('2025-09-30 11:00'), + key: 'dec-vsm', + type: 'WriteDecision', + title: 'Use virtual shadow maps for the sun', + created_by: INES, + derives_from: ['iss-shadow-q'], + body: + 'Sun shadows use one 16k virtual shadow map split into 128-texel pages, allocated where the camera needs detail and cached between frames. ' + + 'Resolution follows the screen, so there are no cascade boundaries to show through saltglass. Pages for static geometry stay valid until the sun moves far enough or a tide step changes the terrain.\n\n' + + 'Page caching is the whole point: a static scene should redraw only a few hundred pages a frame. The page pool holds 4,096 pages, which is 256 MB inside the render-target memory budget. ' + + 'Moving objects use a small separate page set that is redrawn every frame. Tomasz Brandt will own page management; Ines Okafor owns the sampling side.\n\n' + + 'Beyond 1.2 km, VSM pages are not allocated at all; a distance-field shadow covers 1.2 km to 2 km.', + }, + { + at: d('2025-09-30 12:00'), + key: 'dec-rt-shadows', + type: 'WriteDecision', + title: 'Use ray-traced sun shadows', + created_by: YUSUF, + derives_from: ['iss-shadow-q'], + body: + 'Trace one shadow ray per pixel against the hardware acceleration structure, with denoising. Soft penumbrae through saltglass come for free. ' + + 'Skiff has no ray-tracing hardware, so Skiff would need a second technique anyway.', + }, + { at: d('2025-10-06 10:00'), type: 'AcceptDecision', decisionId: 'dec-csm' }, + { + at: d('2025-10-06 10:05'), + type: 'ResolveIssue', + issueId: 'iss-shadow-q', + resolution: 'resolved', + resolvedBy: ['dec-csm'], + }, + { + at: d('2025-11-03 10:00'), + key: 'iss-csm-seams', + type: 'WriteIssue', + kind: 'defect', + title: 'Cascade seams visible through saltglass at 300 to 800 m', + created_by: YUSUF, + derives_from: ['dec-csm'], + body: + 'Refraction through saltglass bends view rays across cascade boundaries, so a shadow sampled from cascade 2 sits next to one from cascade 3. ' + + 'The seam reads as a hard line in the glass at 300 to 800 m. Blending cascades hides it on sand but not inside the glass.', + }, + { + at: d('2025-11-10 10:00'), + key: 'iss-shadow-local-q', + type: 'WriteIssue', + kind: 'question', + title: 'Which shadow technique should Lantern use for local lights?', + created_by: TOMASZ, + body: 'Lanterns, campfires and glowing ruins cast local shadows. There can be 40 shadowed local lights on screen in the harbor. Pick a technique separate from the sun.', + }, + { + at: d('2025-11-12 10:00'), + key: 'dec-local-atlas', + type: 'WriteDecision', + title: 'Use a cached shadow atlas for local lights', + created_by: TOMASZ, + derives_from: ['iss-shadow-local-q'], + body: 'Local lights render cube or spot shadows into one 8k atlas, cached until something in range moves. The harbor with 40 shadowed lights costs 0.9 ms. Simple and predictable.', + }, + { + at: d('2025-11-12 11:00'), + key: 'dec-local-vsm', + type: 'WriteDecision', + title: 'Use virtual shadow maps for local lights', + created_by: INES, + derives_from: ['iss-shadow-local-q'], + body: 'Give each local light its own virtual shadow map sharing the sun page pool. One system for every light. The harbor would need about 1,500 extra pages.', + }, + { + at: d('2025-11-19 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-local-atlas', + }, + { + at: d('2025-11-19 10:05'), + type: 'ResolveIssue', + issueId: 'iss-shadow-local-q', + resolution: 'resolved', + resolvedBy: ['dec-local-atlas'], + }, + { + at: d('2025-11-22 15:00'), + key: 'blb-vsm-recap', + type: 'WriteBlob', + kind: 'json', + title: + 'GPU capture: virtual shadow maps with page caching, dunes benchmark', + created_by: TOMASZ, + body: json({ + build: 'lantern-2025.11.21-r5310', + platform: 'Meridian devkit', + scene: 'dunes_bench_01', + page_pool_clear: 'on_invalidation', + pages_rendered_per_frame: 212, + passes_ms: { page_mark: 0.3, page_raster: 0.7, page_sample: 0.4 }, + total_ms: 1.4, + csm_reference_ms: 1.6, + }), + }, + { + at: d('2025-11-22 15:05'), + key: 'cit-vsm-recap', + type: 'WriteCitation', + role: 'evidence', + title: 'Capture: virtual shadow maps with page caching', + created_by: TOMASZ, + blob: 'blb-vsm-recap', + body: 'https://captures.tidewater.example/lantern/r5310/vsm_cached', + }, + { + at: d('2025-11-24 10:00'), + key: 'fnd-vsm-recapture', + type: 'WriteFinding', + kind: 'measurement', + title: 'Virtual shadow maps cost 1.4 ms on Meridian with cached pages', + created_by: TOMASZ, + invalidates: ['fnd-vsm-cost'], + cites: ['cit-vsm-recap'], + body: + "The September capture had the prototype's debug flag on, which threw away cached pages and redrew the whole pool each frame. " + + 'With caching as designed, only pages touched by moving objects or by the slow sun drift redraw. Dunes benchmark: 1.4 ms, against 1.6 ms for four cascades.', + }, + { + at: d('2026-01-12 10:00'), + type: 'ReopenDecision', + decisionId: 'dec-vsm', + reason: + 'The cost Finding that sank virtual shadow maps was a capture error; with cached pages VSM costs 1.4 ms, less than four cascades. Cascade seams through saltglass remain unsolved under CSM.', + }, + { + at: d('2026-02-16 10:00'), + type: 'Supersede', + supersederId: 'dec-vsm', + targetId: 'dec-csm', + }, + { at: d('2026-02-17 10:00'), type: 'AcceptDecision', decisionId: 'dec-vsm' }, + { + at: d('2026-02-17 10:05'), + type: 'ResolveIssue', + issueId: 'iss-csm-seams', + resolution: 'resolved', + resolvedBy: ['dec-vsm'], + }, + { + at: d('2026-02-18 10:00'), + key: 'rsk-vsm-overflow', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'high', + title: 'VSM page pool overflows when tides expose the flats', + created_by: TOMASZ, + derives_from: ['dec-vsm'], + body: + 'A falling tide exposes kilometres of wet flats at once, all needing fresh shadow pages. If the requests exceed the 4,096-page pool, shadows drop to low resolution or pop. ' + + 'Nobody has measured a spring tide yet.', + }, + { + at: d('2026-05-12 10:00'), + type: 'ReopenDecision', + decisionId: 'dec-rt-shadows', + reason: + 'Yusuf Demir wants ray-traced sun shadows considered again as a PC ultra option now that PC has GPU time to spare.', + }, + { + at: d('2026-06-12 15:00'), + key: 'blb-vsm-pages', + type: 'WriteBlob', + kind: 'json', + title: 'Page-pool trace: virtual shadow maps across a spring tide', + created_by: TOMASZ, + body: json({ + build: 'lantern-2026.06.11-r7020', + platform: 'Meridian devkit', + scene: 'flats_spring_tide', + pool_pages: 4096, + samples: [ + { tide_phase: 'spring high', pages_requested: 1880 }, + { tide_phase: 'mid ebb', pages_requested: 3410 }, + { tide_phase: 'spring low', pages_requested: 5912 }, + { tide_phase: 'mid flood', pages_requested: 3120 }, + ], + peak_pages_requested: 5912, + frames_over_pool: 1430, + worst_tide_phase: 'spring low, 31 minutes into the 40-minute cycle', + }), + }, + { + at: d('2026-06-12 15:05'), + key: 'cit-vsm-pages', + type: 'WriteCitation', + role: 'evidence', + title: 'Trace: VSM page pool across a spring tide', + created_by: TOMASZ, + blob: 'blb-vsm-pages', + body: 'https://captures.tidewater.example/lantern/r7020/vsm_spring_tide', + }, + { + at: d('2026-06-15 10:00'), + key: 'fnd-vsm-overflow', + type: 'WriteFinding', + kind: 'measurement', + title: 'VSM page pool overflows during spring tides', + created_by: TOMASZ, + derives_from: ['rsk-vsm-overflow'], + cites: ['cit-vsm-pages'], + body: + 'A full spring-tide cycle on the flats asks for far more shadow pages at low water than the pool holds. Shadows on the far flats drop to the fallback resolution and visibly pop as pages come back. ' + + 'The trace is attached. Neap tides stay inside the pool; only the two spring tides of each in-game month overflow.\n\n' + + 'Tomasz Brandt checked three cheaper ideas before writing this up. Dropping the page size to 64 texels makes the overflow worse, because the page table grows. ' + + 'Skipping pages for wet sand that is darker than a threshold saves about 600 pages, not enough. Freezing pages on the far flats for a whole tide step hides the popping but leaves shadows pointing the wrong way at sunset.\n\n' + + 'Raising the pool from 4,096 to 6,144 pages would end the overflow and cost another 128 MB, which the render-target memory budget does not have.', + }, + { + at: d('2026-06-16 10:00'), + type: 'SetRiskState', + riskId: 'rsk-vsm-overflow', + state: 'realized', + evidence: ['fnd-vsm-overflow'], + }, + { + at: d('2026-06-17 10:00'), + key: 'iss-vsm-tide', + type: 'WriteIssue', + kind: 'blocker', + title: 'Shadow pages run out at spring low tide', + created_by: INES, + derives_from: ['fnd-vsm-overflow'], + body: + 'Shadow popping on the flats at spring low tide is a ship blocker for Dara Whitlock: the flats are where the main quest line crosses. ' + + 'No fix is chosen. Options discussed in review: a coarser page level for wet sand, or streaming the flats in later.', + }, +]; diff --git a/benchmarks/proof-recall/spec/render/tern.mjs b/benchmarks/proof-recall/spec/render/tern.mjs new file mode 100644 index 00000000..02a942d2 --- /dev/null +++ b/benchmarks/proof-recall/spec/render/tern.mjs @@ -0,0 +1,326 @@ +// Tern against the Halcyon vendor upscaler; ghosting on saltglass; presets. +// Halcyon is rejected, reopened, and rejected again by an outside Decision. +import { d, json, INES, TOMASZ, YUSUF, PRIYA, DARA } from './people.mjs'; + +export default [ + { + at: d('2025-10-01 11:00'), + key: 'iss-upscaler-q', + type: 'WriteIssue', + kind: 'question', + title: 'Which upscaler should Lantern ship?', + created_by: INES, + body: 'Lantern renders below output resolution on every platform and needs a temporal upscaler. Options: Tern, the studio upscaler inside Lantern; Halcyon, a vendor upscaler with an SDK; or a split between them by platform.', + }, + { + at: d('2025-10-02 09:00'), + key: 'con-one-upscaler', + type: 'WriteConstraint', + kind: 'soft', + title: 'One upscaler path on every platform', + created_by: INES, + body: + 'Lantern should carry one temporal upscaler across PC, Meridian and Skiff. Every reactive mask, motion vector fix and saltglass special case otherwise has to be done twice. ' + + 'Ines Okafor will bend this only for a large quality gain.', + }, + { + at: d('2025-10-16 10:00'), + key: 'fnd-halcyon-eval', + type: 'WriteFinding', + kind: 'survey', + title: 'Halcyon vendor upscaler: quality and platform coverage', + created_by: TOMASZ, + derives_from: ['iss-upscaler-q'], + body: + 'Halcyon gives cleaner disocclusions than Tern on PC and costs 1.2 ms at 4K output on Meridian. The SDK ships for PC and Meridian only; there is no Skiff build and the vendor gives no date for one. ' + + 'The license is per title and needs legal review. Halcyon is a closed binary, so saltglass fixes would mean filing vendor tickets.', + }, + { + at: d('2025-10-16 11:00'), + key: 'fnd-tern-cost-1', + type: 'WriteFinding', + kind: 'measurement', + title: 'Tern cost at 4K output on Meridian', + created_by: TOMASZ, + derives_from: ['iss-upscaler-q'], + body: 'Tern upscaling 1440p to 4K on Meridian costs 1.9 ms on the dunes benchmark, with history reprojection the largest part. That is 0.7 ms more than Halcyon on the same view.', + }, + { + at: d('2025-10-28 13:00'), + key: 'dec-tern', + type: 'WriteDecision', + title: "Ship Tern as Lantern's only upscaler", + created_by: TOMASZ, + derives_from: [ + 'iss-upscaler-q', + 'con-one-upscaler', + 'fnd-tern-cost-1', + 'fnd-halcyon-eval', + ], + body: + 'Tern is the only temporal upscaler Lantern ships, on PC, Meridian and Skiff. Halcyon has no Skiff build, and shipping it on two platforms would break the one-upscaler Constraint. ' + + 'Tern costs 0.7 ms more than Halcyon on Meridian today; Tomasz Brandt expects to recover most of that.\n\n' + + 'Owning the code matters more for saltglass than raw quality. Refraction moves light independently of geometry motion vectors, and the caustics change every frame. ' + + 'Both need upscaler changes the team can make the same week, not vendor tickets. There is no license to negotiate.\n\n' + + 'Other Efforts may pick a Tern preset per platform, but no Effort may add a second upscaler without reopening this Decision. ' + + "Tern's history buffer is stored as 16-bit float per channel, and every preset shares it.", + }, + { + at: d('2025-10-28 14:00'), + key: 'dec-vendor', + type: 'WriteDecision', + title: 'Ship the Halcyon vendor upscaler on PC and Meridian', + created_by: PRIYA, + derives_from: ['iss-upscaler-q', 'fnd-halcyon-eval'], + body: 'Use Halcyon on PC and Meridian, where it is 0.7 ms cheaper than Tern and cleaner on disocclusions. Skiff would need something else. Priya Natarajan thinks platform holders will favor the vendor SDK.', + }, + { + at: d('2025-10-28 15:00'), + key: 'dec-split-upscaler', + type: 'WriteDecision', + title: 'Ship Halcyon on PC and Meridian and Tern on Skiff', + created_by: YUSUF, + derives_from: ['iss-upscaler-q'], + body: 'Use each upscaler where it is strongest: Halcyon on PC and Meridian, Tern on Skiff. Two upscalers to tune for saltglass, but the best image on each platform.', + }, + { + at: d('2025-10-28 16:00'), + key: 'dec-tern-dup', + type: 'WriteDecision', + title: 'Ship Tern as the only upscaler in Lantern', + created_by: TOMASZ, + derives_from: ['iss-upscaler-q'], + body: 'Tern is the only upscaler. Draft.', + }, + { + at: d('2025-11-10 10:00'), + type: 'Retract', + recordId: 'dec-tern-dup', + reason: + 'Draft of the upscaler Decision saved by mistake; the full Decision was written three hours earlier.', + }, + { at: d('2025-11-12 10:00'), type: 'AcceptDecision', decisionId: 'dec-tern' }, + { + at: d('2025-11-12 10:05'), + type: 'ResolveIssue', + issueId: 'iss-upscaler-q', + resolution: 'resolved', + resolvedBy: ['dec-tern'], + }, + { + at: d('2025-12-10 10:00'), + key: 'fnd-tern-cost-2', + type: 'WriteFinding', + kind: 'measurement', + title: 'Tern cost at 4K output on Meridian after FP16 packing', + created_by: TOMASZ, + supersedes: ['fnd-tern-cost-1'], + body: 'Packing the reprojection inputs as FP16 and merging two passes brings Tern at 4K output on Meridian to 1.4 ms on the dunes benchmark, down from 1.9 ms.', + }, + { + at: d('2026-02-20 10:00'), + key: 'iss-presets-q', + type: 'WriteIssue', + kind: 'question', + title: 'Which Tern quality presets should ship?', + created_by: INES, + body: 'Players and the ports team need named Tern presets. How many, and at what render scale? Fewer presets means less tuning of saltglass and caustics per preset.', + }, + { + at: d('2026-02-23 15:00'), + key: 'blb-tern-presets', + type: 'WriteBlob', + kind: 'json', + title: 'Tern preset table: render scale and cost per platform', + created_by: TOMASZ, + body: json({ + build: 'lantern-2026.02.22-r5990', + output: '4K on PC and Meridian, 720p on Skiff', + presets: { + quality: { scale: 0.67, meridian_ms: 1.4, skiff_ms: 3.9 }, + balanced: { scale: 0.58, meridian_ms: 1.3, skiff_ms: 3.0 }, + performance: { scale: 0.5, meridian_ms: 1.2, skiff_ms: 2.1 }, + ultra_performance: { scale: 0.33, meridian_ms: 1.0, skiff_ms: null }, + }, + notes: 'Ultra Performance is untested on Skiff.', + }), + }, + { + at: d('2026-02-23 15:05'), + key: 'cit-tern-presets', + type: 'WriteCitation', + role: 'evidence', + title: 'Tern preset table', + created_by: TOMASZ, + blob: 'blb-tern-presets', + body: 'https://captures.tidewater.example/lantern/r5990/tern_presets', + }, + { + at: d('2026-02-24 10:00'), + key: 'fnd-tern-presets', + type: 'WriteFinding', + kind: 'measurement', + title: 'Tern preset render scales and costs', + created_by: TOMASZ, + derives_from: ['iss-presets-q', 'dec-tern'], + cites: ['cit-tern-presets'], + body: + 'Tomasz Brandt measured four candidate Tern presets on Meridian and Skiff. Cost falls slowly with render scale because reprojection runs at output resolution. ' + + 'Saltglass edges hold up to Performance; below that, refraction detail turns to mush. The table is attached.', + }, + { + at: d('2026-02-25 10:00'), + key: 'dec-presets-3', + type: 'WriteDecision', + title: 'Ship three Tern quality presets', + created_by: INES, + derives_from: ['iss-presets-q', 'fnd-tern-presets'], + body: 'Ship Quality, Balanced and Performance. Three presets keep saltglass tuning manageable, and every one keeps refraction edges readable.', + }, + { + at: d('2026-02-25 11:00'), + key: 'dec-presets-4', + type: 'WriteDecision', + title: 'Ship four Tern quality presets', + created_by: YUSUF, + derives_from: ['iss-presets-q'], + body: 'Ship Quality, Balanced, Performance and an Ultra Performance preset for players on low-end PCs. More choice for players, one more preset to tune.', + }, + { + at: d('2026-03-02 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-presets-3', + }, + { + at: d('2026-03-02 10:05'), + type: 'ResolveIssue', + issueId: 'iss-presets-q', + resolution: 'resolved', + resolvedBy: ['dec-presets-3'], + }, + { + at: d('2026-04-02 10:00'), + key: 'fnd-tern-ghost', + type: 'WriteFinding', + kind: 'measurement', + title: 'Tern ghosts behind moving saltglass', + created_by: YUSUF, + derives_from: ['dec-tern'], + body: + 'When saltglass moves across the background, or the camera orbits a glass cliff, the refracted image carries no motion vectors of its own. ' + + 'Tern reprojects the old refracted image and leaves trails up to 14 frames long. Press previews have already shown it.', + }, + { + at: d('2026-04-03 10:00'), + key: 'rsk-tern-ghost', + type: 'WriteRisk', + likelihood: 'high', + severity: 'medium', + title: 'Tern ghosting on saltglass draws reviewer complaints', + created_by: INES, + derives_from: ['fnd-tern-ghost'], + body: 'Saltglass is in every marketing shot. If reviewers notice trails behind it, the signature feature looks broken.', + }, + { + at: d('2026-04-03 11:00'), + key: 'iss-tern-ghost', + type: 'WriteIssue', + kind: 'defect', + title: 'Tern ghosting on moving saltglass', + created_by: YUSUF, + derives_from: ['fnd-tern-ghost'], + body: 'Trails behind moving saltglass and orbiting cameras, up to 14 frames long. Reproduces on every platform and every preset.', + }, + { + at: d('2026-04-20 10:00'), + type: 'ReopenDecision', + decisionId: 'dec-vendor', + reason: + 'Dara Whitlock asked to weigh Halcyon again after the saltglass ghosting reports, since Halcyon ships its own reactive mask for transparency.', + }, + { + at: d('2026-05-14 10:00'), + key: 'fnd-tern-ghost-fix', + type: 'WriteFinding', + kind: 'measurement', + title: 'A saltglass reactive mask removes 90 percent of Tern ghosting', + created_by: TOMASZ, + derives_from: ['iss-tern-ghost'], + body: 'Saltglass writes a reactive mask that tells Tern to trust the current frame where refraction moves. In the glass-cliff orbit test the trail length drops from 14 frames to one or two, a 90 percent cut in ghosting energy. Cost: 0.2 ms.', + }, + { + at: d('2026-05-18 10:00'), + key: 'dec-tern-reactive', + type: 'WriteDecision', + title: 'Feed a saltglass reactive mask into Tern', + created_by: TOMASZ, + derives_from: ['iss-tern-ghost', 'fnd-tern-ghost-fix'], + body: 'Saltglass writes a reactive mask each frame and Tern trusts the current frame where the mask is set. This fixes the ghosting inside Tern, so there is no case for switching to Halcyon; the reopened Halcyon proposal is rejected again.', + }, + { + at: d('2026-05-20 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-tern-reactive', + rejects: ['dec-vendor'], + }, + { + at: d('2026-05-20 10:05'), + type: 'MitigateRisk', + riskId: 'rsk-tern-ghost', + decisionId: 'dec-tern-reactive', + }, + { + at: d('2026-05-20 10:10'), + type: 'ResolveIssue', + issueId: 'iss-tern-ghost', + resolution: 'resolved', + resolvedBy: ['dec-tern-reactive'], + }, + { + at: d('2026-05-22 10:00'), + key: 'fnd-tern-cost-3', + type: 'WriteFinding', + kind: 'measurement', + title: 'Tern cost at 4K output on Meridian with the reactive mask', + created_by: TOMASZ, + supersedes: ['fnd-tern-cost-2'], + body: 'With the saltglass reactive mask, Tern at 4K output on Meridian costs 1.6 ms on the dunes benchmark, up from 1.4 ms.', + }, + { + at: d('2026-06-08 10:00'), + key: 'fnd-tern-ghost-recheck', + type: 'WriteFinding', + kind: 'measurement', + title: + 'Reactive mask removes 61 percent of saltglass ghosting with a moving camera', + created_by: YUSUF, + derives_from: ['dec-tern-reactive'], + body: + 'The 90 percent figure came from the orbit test with a fixed orbit speed, which the mask was tuned on. On the free-camera dunes route the mask removes 61 percent of ghosting energy, and trails of five or six frames remain behind fast glass. ' + + 'The mask helps but the earlier number overstated it.', + }, + { + at: d('2026-06-09 10:00'), + type: 'Invalidate', + findingId: 'fnd-tern-ghost-recheck', + targetId: 'fnd-tern-ghost-fix', + }, + { + at: d('2026-06-10 10:00'), + key: 'dec-presets-4b', + type: 'WriteDecision', + title: + 'Ship four Tern quality presets, adding Ultra Performance for 120 Hz mode', + created_by: INES, + supersedes: ['dec-presets-3'], + derives_from: ['iss-presets-q', 'con-120-2', 'fnd-tern-presets'], + body: + 'The 120 Hz performance mode on Meridian needs a cheaper preset than Performance, so Tern ships four presets: Quality, Balanced, Performance and Ultra Performance. ' + + 'Ultra Performance is offered only in the 120 Hz mode, not as a general menu option, which keeps saltglass tuning to the one mode that needs it.', + }, + { + at: d('2026-06-11 10:00'), + type: 'AcceptDecision', + decisionId: 'dec-presets-4b', + }, +]; diff --git a/benchmarks/proof-recall/spec/render/vb.mjs b/benchmarks/proof-recall/spec/render/vb.mjs new file mode 100644 index 00000000..42318567 --- /dev/null +++ b/benchmarks/proof-recall/spec/render/vb.mjs @@ -0,0 +1,385 @@ +// Clustered forward+ to a visibility buffer: a six-version Decision chain +// that is refined, partly reversed for Skiff, then restored. +import { d, json, INES, TOMASZ, YUSUF, DARA } from './people.mjs'; + +export default [ + { + at: d('2025-09-03 11:00'), + key: 'iss-vb-q', + type: 'WriteIssue', + kind: 'question', + title: + 'Should Lantern replace clustered forward+ with a visibility buffer?', + created_by: INES, + body: + 'Lantern shades with clustered forward+. Saltglass cliffs are dense meshes with many small triangles, and quad overdraw is high. ' + + 'Options on the table: keep forward+ and tune it, move to a deferred G-buffer, or move to a visibility buffer. Decide before the vertical slice so the material system can follow.', + }, + { + at: d('2025-09-09 14:00'), + key: 'blb-cliffs', + type: 'WriteBlob', + kind: 'json', + title: 'GPU capture: forward+ on the cliffs benchmark, Meridian', + created_by: TOMASZ, + body: json({ + build: 'lantern-2025.09.08-r4411', + platform: 'Meridian devkit', + scene: 'cliffs_bench_02', + resolution: '2560x1440', + passes_ms: { + depth_prepass: 1.1, + light_cull: 0.6, + forward_opaque: 7.9, + saltglass_forward: 2.3, + post: 1.4, + }, + quad_overdraw: 3.4, + triangles_visible: 14200000, + worst_tile_lights: 212, + notes: + 'Overdraw measured with the helper-lane counter; cliff face LOD0 dominates.', + }), + }, + { + at: d('2025-09-09 14:05'), + key: 'cit-cliffs', + type: 'WriteCitation', + role: 'evidence', + title: 'Capture: forward+ cliffs benchmark', + created_by: TOMASZ, + blob: 'blb-cliffs', + body: 'https://captures.tidewater.example/lantern/r4411/cliffs_bench_02', + }, + { + at: d('2025-09-10 10:00'), + key: 'fnd-fplus-overdraw', + type: 'WriteFinding', + kind: 'measurement', + title: 'Forward+ overdraw on saltglass cliffs', + created_by: TOMASZ, + derives_from: ['iss-vb-q'], + cites: ['cit-cliffs'], + body: + 'On the cliffs benchmark, forward+ opaque shading takes 7.9 ms of the 16.6 ms Meridian frame. Quad overdraw averages 3.4x because the cliff meshes are dense with sub-pixel triangles. ' + + 'Light culling itself is cheap at 0.6 ms; the cost is shading quads that never reach the screen. The full capture is attached.', + }, + { + at: d('2025-09-22 15:00'), + key: 'blb-vb-proto', + type: 'WriteBlob', + kind: 'markdown', + title: 'Timing table: visibility buffer prototype against forward+', + created_by: TOMASZ, + body: + '| Pass (cliffs_bench_02, Meridian, 1440p) | Forward+ (ms) | Visibility buffer (ms) |\n' + + '| --- | --- | --- |\n' + + '| Depth prepass | 1.1 | - |\n' + + '| Visibility raster | - | 1.2 |\n' + + '| Material resolve | - | 1.9 |\n' + + '| Opaque shading | 7.9 | 1.5 |\n' + + '| Total opaque | 9.0 | 4.6 |\n\n' + + 'Extra memory for a 64-bit visibility target at 4K: 96 MB. The 32-bit target used here costs 48 MB at 4K.\n' + + 'Build lantern-2025.09.19-r4520, captured by hand on devkit MRD-0031.', + }, + { + at: d('2025-09-22 15:05'), + key: 'cit-vb-proto', + type: 'WriteCitation', + role: 'evidence', + title: 'Timing table: visibility buffer prototype', + created_by: TOMASZ, + blob: 'blb-vb-proto', + body: 'https://captures.tidewater.example/lantern/r4520/vb_proto', + }, + { + at: d('2025-09-24 10:00'), + key: 'fnd-vb-proto', + type: 'WriteFinding', + kind: 'measurement', + title: 'Visibility buffer prototype timings', + created_by: TOMASZ, + derives_from: ['fnd-fplus-overdraw'], + cites: ['cit-vb-proto'], + body: + "The visibility buffer prototype draws the cliffs benchmark opaque work in 4.6 ms against forward+'s 9.0 ms on Meridian. The win comes from shading each pixel once. " + + 'The prototype packs instance and triangle into 32 bits, which may not be enough for the dunes. Pass-by-pass numbers are in the attached table.', + }, + { + at: d('2025-09-26 10:00'), + key: 'dec-vb-1', + type: 'WriteDecision', + title: 'Adopt a visibility buffer for all opaque geometry', + created_by: INES, + derives_from: ['iss-vb-q', 'fnd-vb-proto', 'con-budget-1'], + body: + 'Lantern replaces clustered forward+ with a visibility buffer for all opaque geometry. Rasterize instance and triangle ids, then shade each visible pixel once in a resolve pass. ' + + 'The prototype saves 4.4 ms on the cliffs benchmark, which is the single biggest win available against the Frame budget. Saltglass, being transparent, is not opaque geometry and is out of scope here.', + }, + { + at: d('2025-09-26 10:01'), + key: 'dec-vb-1-dup', + type: 'WriteDecision', + title: 'Adopt a visibility buffer for all opaque geometry', + created_by: INES, + derives_from: ['iss-vb-q'], + body: 'Lantern replaces clustered forward+ with a visibility buffer for all opaque geometry.', + }, + { + at: d('2025-09-26 15:00'), + type: 'Retract', + recordId: 'dec-vb-1-dup', + reason: + 'Duplicate write from a retried session; the Decision written a minute earlier is the real one.', + }, + { + at: d('2025-09-27 10:00'), + key: 'dec-fplus-tune', + type: 'WriteDecision', + title: 'Keep clustered forward+ and tune light culling', + created_by: TOMASZ, + derives_from: ['iss-vb-q', 'fnd-fplus-overdraw'], + body: + 'Keep forward+, add a depth-only prepass for the cliffs and tighten cluster bounds. The material system stays as it is, so the risk is low. ' + + 'Tomasz Brandt estimates 1.5 ms back on the cliffs benchmark, against the 4.4 ms the visibility buffer prototype saves.', + }, + { + at: d('2025-09-27 11:00'), + key: 'dec-deferred', + type: 'WriteDecision', + title: 'Move to a deferred G-buffer', + created_by: YUSUF, + derives_from: ['iss-vb-q'], + body: + 'A classic G-buffer: four render targets at 1440p cost 118 MB and about 2.8 ms of bandwidth on Meridian. Artists and tools already understand it. ' + + 'It does not fix overdraw on dense meshes as well as a visibility buffer, because the G-buffer pass still writes every covered quad.', + }, + { at: d('2025-10-01 10:00'), type: 'AcceptDecision', decisionId: 'dec-vb-1' }, + { + at: d('2025-10-01 10:05'), + type: 'ResolveIssue', + issueId: 'iss-vb-q', + resolution: 'resolved', + resolvedBy: ['dec-vb-1'], + }, + { + at: d('2025-10-14 10:00'), + key: 'fnd-vb-idpack', + type: 'WriteFinding', + kind: 'measurement', + title: '32-bit visibility ids overflow on the dunes benchmark', + created_by: TOMASZ, + derives_from: ['dec-vb-1'], + body: + "The prototype's 32-bit id gives 20 bits to the instance and 12 to the triangle. The dunes benchmark draws 1.6 million instances when the tide is out, past the 1,048,576 limit, and the far flats shade with the wrong materials. " + + 'A 64-bit target fixes it and costs 28 MB more at 1440p.', + }, + { + at: d('2025-10-20 10:00'), + key: 'dec-vb-2', + type: 'WriteDecision', + title: 'Adopt a visibility buffer with 64-bit instance and triangle ids', + created_by: TOMASZ, + supersedes: ['dec-vb-1'], + derives_from: ['fnd-vb-idpack'], + body: + 'Same visibility buffer for all opaque geometry, but the id target is 64-bit: 32 bits of instance and 32 of triangle. ' + + 'The extra 28 MB at 1440p fits inside the render-target memory budget. Material resolve is unchanged.', + }, + { at: d('2025-10-21 10:00'), type: 'AcceptDecision', decisionId: 'dec-vb-2' }, + { + at: d('2025-11-04 10:00'), + key: 'fnd-vb-foliage', + type: 'WriteFinding', + kind: 'measurement', + title: 'Alpha-tested foliage costs 2.1 ms in the visibility buffer', + created_by: YUSUF, + derives_from: ['dec-vb-2'], + body: + 'Dune grass and kelp are alpha-tested. In the visibility buffer the alpha test runs in the raster pass with a texture fetch per pixel, and foliage on the coast benchmark goes from 0.8 ms in forward+ to 2.1 ms. ' + + 'Saltglass cannot live in the buffer at all, because it refracts what is behind it and needs that image first.', + }, + { + at: d('2025-11-14 10:00'), + key: 'dec-vb-3', + type: 'WriteDecision', + title: + 'Visibility buffer for opaque geometry; foliage and saltglass stay forward', + created_by: INES, + supersedes: ['dec-vb-2'], + derives_from: ['fnd-vb-foliage'], + body: + 'A partial step back. Opaque geometry stays in the 64-bit visibility buffer, but alpha-tested foliage and refractive saltglass render in a forward pass after the resolve. ' + + 'That keeps foliage at 0.8 ms and gives saltglass the resolved scene to refract. Ines Okafor accepts carrying two shading paths until foliage has a better answer.', + }, + { at: d('2025-11-15 10:00'), type: 'AcceptDecision', decisionId: 'dec-vb-3' }, + { + at: d('2025-11-20 10:00'), + key: 'rsk-shader-perm', + type: 'WriteRisk', + likelihood: 'high', + severity: 'medium', + title: 'Visibility buffer material resolve multiplies shader permutations', + created_by: TOMASZ, + derives_from: ['dec-vb-3'], + body: + 'Resolving materials per tile class means one shader per material per tile class. With 310 saltglass and terrain materials and 6 tile classes that is 1,860 resolve shaders on top of the forward ones. ' + + 'Compile times and the shader count both grow past what the build farm handles today.', + }, + { + at: d('2025-12-02 10:00'), + key: 'dec-uber-resolve', + type: 'WriteDecision', + title: + 'Resolve materials with one uber shader over bindless material tables', + created_by: TOMASZ, + derives_from: ['dec-vb-3', 'rsk-shader-perm'], + body: + 'Material resolve uses one uber shader per tile class that reads material parameters from bindless material tables, instead of one shader per material. ' + + 'The shader count for resolve drops from 1,860 to 6. Cost on the cliffs benchmark rises 0.2 ms because of branching, which Tomasz Brandt accepts.', + }, + { + at: d('2025-12-04 11:00'), + type: 'AcceptDecision', + decisionId: 'dec-uber-resolve', + }, + { + at: d('2025-12-04 11:05'), + type: 'MitigateRisk', + riskId: 'rsk-shader-perm', + decisionId: 'dec-uber-resolve', + }, + { + at: d('2026-01-16 10:00'), + key: 'fnd-foliage-meshlet', + type: 'WriteFinding', + kind: 'measurement', + title: + 'Meshlet alpha masks bring foliage back into the visibility buffer at 0.7 ms', + created_by: TOMASZ, + derives_from: ['dec-meshlet-64', 'fnd-vb-foliage'], + body: + 'With 64-vertex meshlets each carrying a coarse alpha-coverage mask, the raster pass skips fully transparent meshlets, and the per-pixel alpha test runs on 22 percent of the pixels it ran on before. ' + + 'Coast benchmark foliage costs 0.7 ms in the buffer against 0.8 ms in the forward pass.', + }, + { + at: d('2026-01-20 10:00'), + key: 'dec-vb-4', + type: 'WriteDecision', + title: + 'Visibility buffer with compute material resolve; foliage back in the buffer', + created_by: INES, + supersedes: ['dec-vb-3'], + derives_from: ['fnd-foliage-meshlet', 'dec-uber-resolve'], + body: + 'Foliage moves back into the visibility buffer using meshlet alpha masks, so only saltglass renders forward. Material resolve runs in compute over the bindless material tables. ' + + 'This removes the second shading path for foliage that the previous version carried.', + }, + { at: d('2026-01-21 10:00'), type: 'AcceptDecision', decisionId: 'dec-vb-4' }, + { + at: d('2026-04-07 15:00'), + key: 'blb-skiff-capture', + type: 'WriteBlob', + kind: 'json', + title: 'GPU capture: visibility buffer on Skiff, cliffs benchmark', + created_by: TOMASZ, + body: json({ + build: 'lantern-2026.04.06-r6120', + build_config: 'debug-gpu-validation', + platform: 'Skiff devkit SKF-0007', + scene: 'cliffs_bench_02', + resolution: '1280x720', + passes_ms: { + visibility_raster: 2.6, + material_resolve: 5.0, + saltglass_forward: 2.1, + post: 1.5, + }, + total_vb_ms: 11.2, + forward_plus_reference_ms: 8.9, + notes: 'First capture on the new Skiff devkits.', + }), + }, + { + at: d('2026-04-07 15:05'), + key: 'cit-skiff-capture', + type: 'WriteCitation', + role: 'evidence', + title: 'Capture: visibility buffer on Skiff', + created_by: TOMASZ, + blob: 'blb-skiff-capture', + body: 'https://captures.tidewater.example/lantern/r6120/skiff_cliffs', + }, + { + at: d('2026-04-08 10:00'), + key: 'fnd-skiff-vb-cost', + type: 'WriteFinding', + kind: 'measurement', + title: 'Visibility buffer costs 11.2 ms on Skiff', + created_by: TOMASZ, + derives_from: ['dec-vb-4'], + cites: ['cit-skiff-capture'], + body: + "First Skiff devkit capture of the cliffs benchmark at 720p: the visibility buffer path costs 11.2 ms, against forward+'s 8.9 ms. Material resolve alone is 5.0 ms. " + + "Skiff's memory bandwidth looks like the limit, since every resolve fetch goes through the bindless material tables.", + }, + { + at: d('2026-04-09 10:00'), + key: 'rsk-vb-skiff', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'high', + title: 'Visibility buffer bandwidth is too high for Skiff', + created_by: TOMASZ, + derives_from: ['fnd-skiff-vb-cost'], + body: 'If the visibility buffer stays 2.3 ms slower than forward+ on Skiff, the Skiff port cannot hold its frame rate with saltglass on screen. Skiff becomes a launch platform at beta, so this cannot wait.', + }, + { + at: d('2026-04-15 10:00'), + key: 'dec-vb-5', + type: 'WriteDecision', + title: 'Visibility buffer on PC and Meridian; forward+ fallback on Skiff', + created_by: INES, + supersedes: ['dec-vb-4'], + derives_from: ['fnd-skiff-vb-cost', 'con-mesh-skiff'], + body: + 'PC and Meridian keep the visibility buffer as before. Skiff goes back to clustered forward+ for opaque geometry, because the visibility buffer costs 11.2 ms there against 8.9 ms. ' + + 'This reverses part of the original move and means two opaque paths to maintain until release. Dara Whitlock agreed to the extra maintenance.', + }, + { at: d('2026-04-16 10:00'), type: 'AcceptDecision', decisionId: 'dec-vb-5' }, + { + at: d('2026-04-16 10:05'), + type: 'MitigateRisk', + riskId: 'rsk-vb-skiff', + decisionId: 'dec-vb-5', + }, + { + at: d('2026-06-22 10:00'), + key: 'fnd-skiff-vb-recapture', + type: 'WriteFinding', + kind: 'measurement', + title: 'Visibility buffer costs 7.4 ms on Skiff in a release build', + created_by: TOMASZ, + invalidates: ['fnd-skiff-vb-cost'], + body: + 'The April Skiff capture ran with GPU validation on, which roughly doubles the cost of every bindless fetch. In a release build the cliffs benchmark visibility buffer path costs 7.4 ms against forward+ at 8.1 ms, at 720p. ' + + 'With material resolve at half rate the visibility buffer path is 6.3 ms. The April number should not have driven a Decision.', + }, + { + at: d('2026-07-08 10:00'), + key: 'dec-vb-6', + type: 'WriteDecision', + title: + 'Visibility buffer on all platforms; Skiff resolves materials at half rate', + created_by: INES, + supersedes: ['dec-vb-5'], + derives_from: ['fnd-skiff-vb-recapture'], + body: + 'Skiff returns to the visibility buffer. The release-build capture puts it at 7.4 ms against 8.1 ms for forward+, and at 6.3 ms with material resolve at half rate, so the forward+ fallback is no longer worth keeping.\n\n' + + 'On Skiff, material resolve shades every other pixel in a checkerboard and Tern fills the gaps from history. PC and Meridian resolve at full rate. ' + + 'Saltglass still renders in a forward pass after the resolve on every platform, because refraction needs the resolved scene behind it. ' + + 'The ports team has signed off on the half-rate look on the handheld screen; Yusuf Demir saw no difference on foliage and a slight softening on cliff detail.\n\n' + + 'Keeping two opaque paths cost one engineer-week a month in fixes. The Skiff forward+ path will be deleted from the codebase on 2026-07-24, after one week of nightly captures confirm the half-rate numbers.', + }, + { at: d('2026-07-10 10:00'), type: 'AcceptDecision', decisionId: 'dec-vb-6' }, +]; diff --git a/benchmarks/proof-recall/spec/tools.mjs b/benchmarks/proof-recall/spec/tools.mjs new file mode 100644 index 00000000..ab4e45d6 --- /dev/null +++ b/benchmarks/proof-recall/spec/tools.mjs @@ -0,0 +1,615 @@ +// The build farm's shader compile cache. A small Effort that completes. +// "Shader cache" here always means the farm's compile cache; the Skiff +// on-device pipeline cache belongs to the ports Effort. +const LIAM = "Liam O'Connell"; +const DARA = 'Dara Whitlock'; +const YUSUF = 'Yusuf Demir'; +const TOMASZ = 'Tomasz Brandt'; +const INES = 'Ines Okafor'; +const PRIYA = 'Priya Natarajan'; + +export default { + key: 'tools', + effort: { + title: 'Shader compile cache and build farm', + body: + "Liam O'Connell owns this Effort. It covers the build farm's shader compile cache, the cache key, " + + 'remote execution of shader compiles, and the flaky nightly builds that came with them. ' + + 'In this Effort "shader cache" means the farm-side compile cache that stores compiled Lantern bytecode. ' + + 'It is not the on-device pipeline cache on Skiff, which the ports Effort owns. ' + + 'The Effort ends when every farm build reads from the cache.', + created_at: '2025-09-08T09:00:00Z', + }, + events: [ + { + at: '2025-09-09T10:00:00Z', + key: 'iss-slow', + type: 'WriteIssue', + kind: 'gap', + title: 'Full shader rebuilds take 47 minutes on the build farm', + body: + 'A clean rebuild of every Lantern shader permutation takes 47 minutes on the 12-agent farm. ' + + 'There are about 38,000 permutations today and Ines Okafor expects 50,000 by alpha. ' + + 'Yusuf Demir reports that a one-line change to the saltglass refraction shader blocks art iteration for most of an hour, ' + + 'because the farm recompiles every permutation that includes the shared lighting header.', + created_by: LIAM, + }, + { + at: '2025-09-12T14:00:00Z', + key: 'fnd-baseline', + type: 'WriteFinding', + kind: 'measurement', + title: 'Most shader compile time on the farm repeats identical work', + body: + "Liam O'Connell hashed the compiled output of every permutation over five days of nightly and on-demand builds (61 builds). " + + '61% of permutation compiles produced bytecode identical to the previous build of the same permutation. ' + + 'Another 22% changed only because an unrelated define moved in a shared header. ' + + 'A cache keyed on the right inputs could have skipped roughly 29 of the 47 minutes on an average build.', + created_by: LIAM, + derives_from: ['iss-slow'], + }, + { + at: '2025-09-12T16:00:00Z', + key: 'con-farm', + type: 'WriteConstraint', + kind: 'hard', + title: 'The build farm stays at 12 agents until alpha', + body: + 'Dara Whitlock confirmed there is no hardware budget for more farm agents before alpha on 2026-03-02. ' + + 'Any fix for shader build time has to fit the 12 agents and the 4 TB shared volume we already own.', + created_by: DARA, + }, + { + at: '2025-09-15T09:30:00Z', + key: 'iss-approach', + type: 'WriteIssue', + kind: 'question', + title: 'How should the farm stop recompiling unchanged shaders?', + body: + "The baseline says most of the farm's shader work repeats. We need one approach to stop doing it. " + + 'Options on the table: a shared content-addressed cache, more agents, or per-agent incremental builds.', + created_by: LIAM, + derives_from: ['fnd-baseline', 'con-farm'], + }, + { + at: '2025-09-16T10:00:00Z', + key: 'dec-cache', + type: 'WriteDecision', + title: + 'Build a content-addressed shader compile cache shared by all farm agents', + body: + 'Store each compiled permutation on the shared volume under a hash of its inputs. ' + + 'Any agent that needs a permutation fetches it if the hash exists, and compiles and uploads it if not. ' + + 'This attacks the 61% of repeat work directly and needs no new hardware. ' + + 'The hard part is the key: a key that misses an input ships stale bytecode, and a key that over-includes gets no hits.', + created_by: LIAM, + derives_from: ['iss-approach', 'fnd-baseline'], + }, + { + at: '2025-09-16T10:30:00Z', + key: 'dec-agents', + type: 'WriteDecision', + title: 'Buy eight more build agents for shader compiles', + body: + 'Twenty agents instead of 12 would cut a clean rebuild from 47 minutes to about 29. ' + + 'It is the simplest fix, but it scales cost with permutation count and breaks the 12-agent limit before alpha.', + created_by: DARA, + derives_from: ['iss-approach'], + }, + { + at: '2025-09-16T11:00:00Z', + key: 'dec-incremental', + type: 'WriteDecision', + title: 'Keep a local incremental shader build on each agent', + body: + 'Each agent keeps its own build directory and recompiles only what changed since its last job. ' + + 'Cheap to try, but jobs land on different agents each time, so Tomasz Brandt measured only a 19% local hit rate on a two-day trial.', + created_by: TOMASZ, + derives_from: ['iss-approach'], + }, + { + at: '2025-09-19T15:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-cache', + }, + { + at: '2025-09-19T15:30:00Z', + type: 'ResolveIssue', + issueId: 'iss-approach', + resolution: 'resolved', + resolvedBy: ['dec-cache'], + }, + { + at: '2025-09-22T09:00:00Z', + key: 'iss-key', + type: 'WriteIssue', + kind: 'question', + title: 'What should the shader compile cache key hash?', + body: + 'The cache key decides both correctness and hit rate. ' + + 'Two candidates: hash the shader source text with the compiler version, or use file modification times as a cheap proxy.', + created_by: LIAM, + derives_from: ['dec-cache'], + }, + { + at: '2025-09-22T11:00:00Z', + key: 'dec-key-v1', + type: 'WriteDecision', + title: 'Key the shader cache on raw source text and compiler version', + body: + 'Key = SHA-256 of the shader file text plus the compiler version string. ' + + 'Simple and fast: hashing all 38,000 permutations takes 9 seconds. ' + + "Liam O'Connell flagged a doubt: included headers are not part of the hash yet.", + created_by: LIAM, + derives_from: ['iss-key'], + }, + { + at: '2025-09-22T11:30:00Z', + key: 'dec-key-mtime', + type: 'WriteDecision', + title: 'Key the shader cache on file modification times', + body: + 'Use the newest modification time of the shader and its includes. ' + + 'Nearly free to compute, but Git checkouts reset modification times, so every fresh agent would see a cold cache.', + created_by: TOMASZ, + derives_from: ['iss-key'], + }, + { + at: '2025-09-26T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-key-v1', + }, + { + at: '2025-10-14T08:30:00Z', + key: 'fnd-stale-include', + type: 'WriteFinding', + kind: 'defect', + title: 'Raw-source cache keys served stale shaders after header edits', + body: + 'Three nightly builds between 2025-10-09 and 2025-10-13 shipped refraction shaders compiled against an old lighting header. ' + + 'The raw-source key did not change when only an included header changed, so agents fetched stale bytecode. ' + + "Yusuf Demir caught it when saltglass caustics rendered with last week's falloff curve.", + created_by: YUSUF, + derives_from: ['dec-key-v1'], + }, + { + at: '2025-10-16T10:00:00Z', + key: 'dec-key-v2', + type: 'WriteDecision', + title: + 'Key the shader cache on preprocessed source, defines, compiler version and target', + body: + 'Run the preprocessor first and hash its output, so every included header is part of the key. ' + + 'Add the full define set and the target platform (PC, Meridian or Skiff) to the hash. ' + + 'Preprocessing costs 70 seconds per clean build, which is a fair price for never shipping stale includes again.', + created_by: LIAM, + derives_from: ['iss-key', 'fnd-stale-include'], + supersedes: ['dec-key-v1'], + }, + { + at: '2025-10-16T11:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-key-v2', + }, + { + at: '2025-11-03T13:00:00Z', + key: 'fnd-remote-bench', + type: 'WriteFinding', + kind: 'measurement', + title: 'Remote execution spreads cache misses across all 12 agents', + body: + 'With the cache warm, a typical build still misses about 2,400 permutations. ' + + 'Compiled on the agent that started the job, those misses take 11 minutes. ' + + 'Fanned out to all 12 agents through remote execution, they take 1 minute 50 seconds, plus 25 seconds of scheduling overhead.', + created_by: LIAM, + derives_from: ['dec-cache'], + }, + { + at: '2025-11-04T10:00:00Z', + key: 'dec-remote', + type: 'WriteDecision', + title: + 'Fan shader cache misses out to every farm agent through remote execution', + body: + 'Every shader compile that misses the cache becomes a remote job any idle agent can take. ' + + 'Results upload to the cache, so the next build hits. ' + + 'This keeps us inside the 12-agent limit while making a cold build tolerable.', + created_by: LIAM, + derives_from: ['fnd-remote-bench', 'con-farm'], + }, + { + at: '2025-11-05T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-remote', + }, + { + at: '2025-11-10T10:00:00Z', + key: 'con-repro', + type: 'WriteConstraint', + kind: 'soft', + title: 'A cache hit must give the same bytes as a fresh compile', + body: + 'Ines Okafor will not debug rendering bugs that only appear on cached builds. ' + + 'Bytecode served from the cache must match a fresh compile byte for byte, or the cache is not trusted.', + created_by: INES, + }, + { + at: '2025-11-10T11:00:00Z', + key: 'rsk-poison', + type: 'WriteRisk', + likelihood: 'low', + severity: 'high', + title: 'A bad cache entry could ship broken bytecode to every build', + body: + 'If an agent with a broken compiler install uploads bad output, every later build fetches it. ' + + 'One poisoned entry for the water shader would reach every platform build until someone noticed.', + created_by: LIAM, + derives_from: ['dec-remote', 'con-repro'], + }, + { + at: '2025-11-11T10:00:00Z', + key: 'dec-verify', + type: 'WriteDecision', + title: 'Recompile a 1-in-50 sample of cache hits and compare bytes', + body: + 'Each build recompiles 2% of its cache hits on an idle agent and compares bytes with the cached copy. ' + + 'A mismatch evicts the entry and fails the build loudly. ' + + 'This adds about 40 seconds to a build and should catch a poisoned entry within two or three builds.', + created_by: LIAM, + derives_from: ['rsk-poison', 'con-repro'], + }, + { + at: '2025-11-12T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-verify', + }, + { + at: '2025-11-12T09:05:00Z', + type: 'MitigateRisk', + riskId: 'rsk-poison', + decisionId: 'dec-verify', + }, + { + at: '2025-11-18T14:00:00Z', + key: 'rsk-storage', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'medium', + title: 'Shader cache storage could outgrow the 4 TB farm volume', + body: + 'Every key change, compiler update and define tweak adds new entries; nothing evicts old ones yet. ' + + 'At the current rate the cache grows about 210 GB a month. ' + + "Liam O'Connell is not sure an eviction policy is worth building before release.", + created_by: LIAM, + derives_from: ['dec-cache', 'con-farm'], + }, + { + at: '2025-12-01T09:00:00Z', + key: 'iss-flaky', + type: 'WriteIssue', + kind: 'defect', + title: + 'Nightly builds fail about 1 in 9 runs with shader compile timeouts', + body: + 'Since remote execution went live, 7 of the last 63 nightly builds failed with "shader job timed out". ' + + 'A rerun always passes. The failures cluster after 02:00 UTC, when every platform builds at once.', + created_by: LIAM, + derives_from: ['dec-remote'], + }, + { + at: '2025-12-05T11:00:00Z', + key: 'fnd-flaky-net', + type: 'WriteFinding', + kind: 'diagnosis', + title: 'Flaky nightly builds trace to cache server fetch timeouts', + body: + 'The failed jobs all logged a cache fetch that took longer than the 5-second fetch timeout. ' + + "The cache server's network card peaks at 94% during the 02:00 burst. " + + 'Tomasz Brandt thinks the slow fetches cascade into job timeouts.', + created_by: TOMASZ, + derives_from: ['iss-flaky'], + }, + { + at: '2025-12-08T10:00:00Z', + key: 'dec-timeout', + type: 'WriteDecision', + title: + 'Raise the shader cache fetch timeout from 5 seconds to 30 seconds', + body: + 'A longer fetch timeout should ride out the 02:00 network peak. ' + + 'A fetch that takes 30 seconds is still faster than recompiling most permutations.', + created_by: TOMASZ, + derives_from: ['fnd-flaky-net'], + }, + { + at: '2025-12-08T15:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-timeout', + }, + { + at: '2025-12-10T16:00:00Z', + key: 'fnd-noise', + type: 'WriteFinding', + kind: 'measurement', + title: 'Shader cache warms in 40 seconds on first boot', + body: + 'On a Skiff devkit, the pipeline cache took 40 seconds to warm on first boot of the coast level, ' + + 'with hitches of up to 120 ms while it filled. Second boot showed no hitches.', + created_by: PRIYA, + }, + { + at: '2025-12-11T09:00:00Z', + type: 'Retract', + recordId: 'fnd-noise', + reason: + 'Filed in the wrong Effort. This measures the on-device pipeline cache on Skiff, which the ports Effort owns, not the build farm shader compile cache.', + }, + { + at: '2026-01-12T10:00:00Z', + key: 'cit-dxc', + type: 'WriteCitation', + role: 'context', + title: 'Shader compiler release notes for build 1.8.2407', + body: 'https://github.com/microsoft/DirectXShaderCompiler/releases', + created_by: LIAM, + }, + { + at: '2026-01-12T11:00:00Z', + key: 'fnd-compiler-drift', + type: 'WriteFinding', + kind: 'defect', + title: + 'Two compiler builds with the same version string emit different bytecode', + body: + 'Agents 3 and 8 both report shader compiler version 1.8.2407, but agent 8 runs a hotfix build with a different optimizer. ' + + 'The byte-compare check from the sampling Decision flagged 14 mismatched water shader permutations in one week. ' + + 'Hashing the version string is not enough: the key must hash the compiler binary itself.', + created_by: LIAM, + derives_from: ['dec-verify'], + cites: ['cit-dxc'], + }, + { + at: '2026-01-15T10:00:00Z', + key: 'dec-key-v3', + type: 'WriteDecision', + title: + 'Key the shader cache on preprocessed source, defines, target and compiler binary hash', + body: [ + 'This replaces the version-string key. The key is now the SHA-256 of these inputs, in this order:', + '', + '1. The preprocessed shader source, so every included header counts.', + '2. The sorted define set for the permutation.', + '3. The target platform: PC, Meridian or Skiff.', + '4. The SHA-256 of the shader compiler binary and its optimizer library, not the version string.', + '5. The compile flags after normalization (flag order no longer matters).', + '', + 'Hashing the compiler binary costs nothing per permutation: each agent hashes its install once at startup and caches the result.', + 'Rolling the key forward invalidates the whole cache once, so the first build after the change runs cold, about 14 minutes with remote execution.', + "Liam O'Connell considered keeping the old entries as a fallback and decided against it, since the old key is exactly what let mismatched bytecode through.", + '', + 'One input is left out on purpose: the shader debug name. Lantern embeds debug names in the bytecode only in development builds, ' + + 'and including the name split identical permutations into 3,100 extra entries in a trial. ' + + 'Debug names are stripped before hashing and re-added after a fetch.', + ].join('\n'), + created_by: LIAM, + derives_from: ['iss-key', 'fnd-compiler-drift', 'con-repro'], + supersedes: ['dec-key-v2'], + }, + { + at: '2026-01-15T14:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-key-v3', + }, + { + at: '2026-01-15T14:30:00Z', + type: 'ResolveIssue', + issueId: 'iss-key', + resolution: 'resolved', + resolvedBy: ['dec-key-v3'], + }, + { + at: '2026-01-26T10:00:00Z', + key: 'blb-hitrate', + type: 'WriteBlob', + kind: 'json', + title: + 'Shader cache hit-rate report, four weeks after the binary-hash key', + body: JSON.stringify( + { + report: 'farm shader compile cache, weekly', + key_version: 'binary-hash key', + weeks: [ + { + week: 1, + builds: 118, + hit_rate: 71.0, + median_build_minutes: 12.5, + }, + { week: 2, builds: 124, hit_rate: 84.6, median_build_minutes: 9.1 }, + { week: 3, builds: 131, hit_rate: 89.9, median_build_minutes: 7.8 }, + { week: 4, builds: 127, hit_rate: 92.4, median_build_minutes: 7.2 }, + ], + p95_fetch_ms: 180, + storage_used_tb: 1.4, + }, + null, + 2 + ), + created_by: LIAM, + }, + { + at: '2026-01-26T10:10:00Z', + key: 'cit-hitrate', + type: 'WriteCitation', + role: 'evidence', + title: 'Weekly shader cache hit-rate report', + body: 'Weekly hit rate, build time and storage for the farm shader compile cache. Full series in the attached report.', + blob: 'blb-hitrate', + created_by: LIAM, + }, + { + at: '2026-01-26T11:00:00Z', + key: 'fnd-hitrate', + type: 'WriteFinding', + kind: 'measurement', + title: 'Shader cache hit rate climbs steadily after the key change', + body: + 'The first week on the binary-hash key started cold and hit 71% of permutations. ' + + 'The rate climbed every week after that; the weekly figures are in the attached report. ' + + 'Median build time is now well under the 47 minutes we started from.', + created_by: LIAM, + derives_from: ['dec-key-v3'], + cites: ['cit-hitrate'], + }, + { + at: '2026-02-10T16:00:00Z', + key: 'cmp-feb', + type: 'WriteCompaction', + title: 'Shader compile cache: where things stand in February', + body: + 'The farm shader compile cache is live on nightly builds. Remote execution spreads cache misses across all 12 agents. ' + + 'The current key hashes preprocessed source, defines, target and the compiler binary; hit rate reached the low 90s. ' + + 'Flaky nightly builds are still open. The working diagnosis is cache server fetch timeouts during the 02:00 burst, ' + + 'and the fix in place is the 30-second fetch timeout. Storage growth is an open Risk. ' + + 'Next: turn the cache on for every build, then close the Effort before alpha.', + created_by: LIAM, + derives_from: [ + 'dec-cache', + 'dec-key-v3', + 'dec-remote', + 'dec-timeout', + 'fnd-flaky-net', + 'fnd-hitrate', + 'iss-flaky', + 'iss-slow', + 'rsk-storage', + ], + }, + { + at: '2026-02-24T09:00:00Z', + key: 'fnd-flaky-oom', + type: 'WriteFinding', + kind: 'diagnosis', + title: + 'Flaky nightly builds are compiler processes running out of memory on agents 7 and 11', + body: + 'The 30-second fetch timeout did not help: 4 of the next 31 nightly builds still failed. ' + + 'Every failed job since December ran on agent 7 or agent 11, the two agents with 32 GB of RAM instead of 64 GB. ' + + 'During the 02:00 burst those agents run 16 parallel compiles, the compiler hits the memory limit, and the job hangs until it times out. ' + + 'The slow cache fetches were a symptom of swapping, not the cause.', + created_by: LIAM, + derives_from: ['iss-flaky', 'dec-timeout'], + }, + { + at: '2026-02-24T09:10:00Z', + type: 'Invalidate', + findingId: 'fnd-flaky-oom', + targetId: 'fnd-flaky-net', + }, + { + at: '2026-02-26T10:00:00Z', + key: 'dec-cap-jobs', + type: 'WriteDecision', + title: 'Cap each farm agent at 6 parallel shader compile jobs', + body: + 'The remote execution scheduler now caps every agent at 6 parallel shader compiles, whatever its core count. ' + + 'On agents 7 and 11 this keeps peak compiler memory under 26 GB. ' + + 'Cold builds get about 50 seconds slower; flaky failures should stop.', + created_by: LIAM, + derives_from: ['fnd-flaky-oom'], + }, + { + at: '2026-02-26T11:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-cap-jobs', + }, + { + at: '2026-03-09T09:00:00Z', + key: 'iss-devws', + type: 'WriteIssue', + kind: 'gap', + title: 'Developer workstations cannot read the farm shader cache', + body: + 'Only farm agents can reach the cache volume. A developer workstation still compiles every shader locally, ' + + 'about 22 minutes after a fresh sync. Opening read access needs a VPN change and a cache proxy.', + created_by: YUSUF, + derives_from: ['dec-cache'], + }, + { + at: '2026-03-16T09:00:00Z', + type: 'ResolveIssue', + issueId: 'iss-flaky', + resolution: 'resolved', + resolvedBy: ['dec-cap-jobs'], + }, + { + at: '2026-03-20T10:00:00Z', + key: 'dec-ship', + type: 'WriteDecision', + title: 'Turn the shader compile cache on for every farm build', + body: + 'Nightly, on-demand and release builds all read from and write to the cache from today. ' + + 'Release builds keep the 1-in-50 byte-compare sample. Fresh compiles remain available with a build flag.', + created_by: LIAM, + derives_from: ['dec-cache', 'dec-key-v3', 'dec-cap-jobs'], + }, + { + at: '2026-03-20T11:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-ship', + }, + { + at: '2026-03-20T11:30:00Z', + type: 'ResolveIssue', + issueId: 'iss-slow', + resolution: 'resolved', + resolvedBy: ['dec-ship'], + }, + { + at: '2026-04-28T15:00:00Z', + key: 'fnd-retro', + type: 'WriteFinding', + kind: 'retrospective', + title: 'Retrospective on the shader compile cache', + body: [ + 'The cache has run on every farm build for five weeks. What went well and what did not:', + '', + '- The content-addressed design held up. Two key changes were needed before the cache could be trusted: the first after stale headers, the second after the compiler hotfix build.', + '- Remote execution made cold builds tolerable inside the 12-agent limit.', + '- We lost about three weeks blaming the network for the flaky nightly builds. The real cause was memory on agents 7 and 11.', + '- The byte-compare sample caught real problems twice and never fired falsely.', + '', + 'Numbers at the end of the Effort:', + '', + '- Steady-state hit rate: 94%.', + '- Storage used: 1.9 TB of the 4 TB volume, growing about 210 GB a month, which leaves roughly ten months of headroom.', + '', + "Dara Whitlock and Liam O'Connell agreed not to build cache eviction before release; storage growth is accepted as it stands.", + 'Workstation access to the cache is deferred until after release; it needs a VPN change nobody has time for.', + '', + 'Final clean rebuild time with a warm cache: 6 min 40 s, down from 47 minutes.', + ].join('\n'), + created_by: LIAM, + derives_from: ['dec-ship', 'fnd-hitrate', 'rsk-storage', 'iss-devws'], + }, + { + at: '2026-05-04T10:00:00Z', + type: 'ResolveIssue', + issueId: 'iss-devws', + resolution: 'deferred', + resolvedBy: ['fnd-retro'], + }, + { + at: '2026-05-04T10:05:00Z', + type: 'SetRiskState', + riskId: 'rsk-storage', + state: 'accepted', + evidence: ['fnd-retro'], + }, + { + at: '2026-05-06T09:00:00Z', + type: 'SetEffortStatus', + status: 'completed', + }, + ], +}; diff --git a/benchmarks/proof-recall/spec/world/cells.mjs b/benchmarks/proof-recall/spec/world/cells.mjs new file mode 100644 index 00000000..b14ca4bb --- /dev/null +++ b/benchmarks/proof-recall/spec/world/cells.mjs @@ -0,0 +1,227 @@ +// Thread 3: world partition cell size. 256 m, then 128 m, then 192 m. +const RHEA = 'Rhea Valdés'; +const KENJI = 'Kenji Arakawa'; +const MARTA = 'Marta Lindqvist'; +const DARA = 'Dara Whitlock'; + +export default [ + { + at: '2025-09-18T14:00:00Z', + key: 'iss-cell-size', + type: 'WriteIssue', + kind: 'question', + created_by: KENJI, + title: 'What cell size should the world partition use?', + body: `The world partition splits the coast into square cells that stream in and out around each player. Full-detail content streams within 768 m of a player; beyond that, distant glass is drawn from impostors. Cell size sets how many cells are resident, how much each costs, and how much a tide change forces us to reload.`, + }, + { + at: '2025-09-25T10:00:00Z', + key: 'fnd-cell-sweep', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['iss-cell-size', 'con-pool-1'], + title: 'Cell size sweep for the 768 m streaming radius', + body: `Kenji Arakawa swept three cell sizes over the coast test map. With 512 m cells, 25 cells are resident at about 96 MB each, 2.4 GB in total, which breaks the 2.0 GB streaming pool. With 256 m cells, 49 cells are resident at about 24 MB each, 1.18 GB. With 128 m cells, 169 cells are resident; content per cell is small, but per-cell overhead was not measured yet.`, + }, + { + at: '2025-09-29T10:00:00Z', + key: 'dec-cell-256', + type: 'WriteDecision', + created_by: KENJI, + derives_from: ['iss-cell-size', 'fnd-cell-sweep'], + title: 'Partition the world into 256 m cells', + body: `Use 256 m cells. They fit the streaming pool with room to spare (1.18 GB of 2.0 GB) and keep the file count low. The tide is not yet modelled in streaming; Kenji Arakawa will revisit once tides change terrain in the build.`, + }, + { + at: '2025-09-29T11:00:00Z', + key: 'dec-cell-512', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['iss-cell-size', 'fnd-cell-sweep'], + title: 'Partition the world into 512 m cells', + body: `Use 512 m cells and stream lower mips for the outer ring to fit the pool. Fewer, larger files suit the console storage APIs, which prefer big sequential reads.`, + }, + { + at: '2025-09-30T16:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-cell-256', + }, + { + at: '2025-09-30T16:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-cell-size', + resolution: 'resolved', + resolvedBy: ['dec-cell-256'], + }, + { + at: '2025-11-10T15:00:00Z', + key: 'blob-trace-tide-turn', + type: 'WriteBlob', + kind: 'json', + created_by: KENJI, + title: 'Streaming trace of a falling tide on Skiff, 256 m cells', + body: JSON.stringify( + { + capture: 'stream-trace-1110-skiff', + platform: 'Skiff dev kit', + cell_size_m: 256, + tide_event: 'falling, high to low', + duration_s: 40, + cells_reloaded: 18, + peak_read_mb_s: 410, + mean_read_mb_s: 236, + stall_frames: 37, + worst_cell: 'c(14,-3)', + read_share_by_type: { + textures: 0.61, + geometry: 0.27, + navigation: 0.07, + audio: 0.05, + }, + }, + null, + 2 + ), + }, + { + at: '2025-11-10T15:10:00Z', + key: 'cit-trace-tide-turn', + type: 'WriteCitation', + role: 'evidence', + blob: 'blob-trace-tide-turn', + created_by: KENJI, + title: 'Skiff streaming trace stream-trace-1110', + body: 'https://perf.tidewater.internal/kestrel/stream-traces/stream-trace-1110-skiff.json', + }, + { + at: '2025-11-11T10:00:00Z', + key: 'fnd-tide-burst', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['dec-cell-256'], + cites: ['cit-trace-tide-turn'], + title: 'A falling tide reloads 18 cells at 410 MB/s peak', + body: `When the tide falls, about 30% of a coastal 256 m cell changes: sand paths appear and glass ridges surface. Today the whole cell reloads. In the Skiff trace, one falling tide reloads 18 cells over 40 seconds with a 410 MB/s peak read rate, and the game drops frames while it does. The trace breaks the reads down by asset type.`, + }, + { + at: '2025-11-14T10:00:00Z', + key: 'fnd-cell-128-estimate', + type: 'WriteFinding', + kind: 'estimate', + created_by: KENJI, + derives_from: ['fnd-tide-burst', 'fnd-cell-sweep'], + title: '128 m cells should add only 40 MB of per-cell overhead', + body: `Each cell carries a 0.25 MB header (bounds, index, dependency list). At 169 resident 128 m cells the headers cost about 40 MB, a fair price for reloading only the cells the tide touches. This is an estimate from header sizes alone.`, + }, + { + at: '2025-11-20T10:00:00Z', + key: 'dec-cell-128', + type: 'WriteDecision', + created_by: KENJI, + derives_from: ['fnd-tide-burst', 'fnd-cell-128-estimate'], + supersedes: ['dec-cell-256'], + title: 'Partition the world into 128 m cells', + body: `Halve the cell size to 128 m. A tide change then reloads only the narrow coastal cells it touches, and the replayed Skiff trace peaks at 190 MB/s instead of 410 MB/s. Per-cell overhead is estimated at 40 MB in total.`, + }, + { + at: '2025-11-21T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-cell-128', + }, + { + at: '2025-11-25T10:00:00Z', + key: 'con-cell-deadline', + type: 'WriteConstraint', + kind: 'soft', + created_by: KENJI, + derives_from: ['fnd-tide-burst'], + title: 'Cell load deadline', + body: `A cell that the tide is about to expose must be resident 8 seconds before exposure. The tide forecast is exact, so the deadline is known a full cycle ahead.`, + }, + { + at: '2026-03-20T10:00:00Z', + key: 'fnd-cell-overhead', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['dec-cell-128', 'fnd-cell-128-estimate'], + title: '128 m cells cost 216 MB of per-cell overhead on Skiff', + body: `Kenji Arakawa measured per-cell overhead on the alpha build instead of estimating it from headers. The November estimate counted only the 0.25 MB cell header. Each resident cell also owns a physics broadphase grid of about 0.5 MB and navigation tile metadata of about 0.35 MB, so the real overhead is 1.1 MB per cell. + +The alpha build keeps 196 cells resident on Skiff, because the streaming radius grew to cover tide pools. At 1.1 MB each that is 216 MB of overhead, more than five times the estimate and over a tenth of the streaming pool. + +File handling is the second cost. Small cells mean many small files. Skiff's storage queue holds 32 requests, and a falling tide now issues so many small reads that the queue stays full and the scheduler cannot slip in urgent reads. + +Over one tide turn the 128 m layout performs 4,100 file opens, against 600 for the old 256 m layout.`, + }, + { + at: '2026-03-20T15:00:00Z', + type: 'Invalidate', + findingId: 'fnd-cell-overhead', + targetId: 'fnd-cell-128-estimate', + }, + { + at: '2026-04-02T09:00:00Z', + key: 'dec-cell-192-dup', + type: 'WriteDecision', + created_by: DARA, + derives_from: ['fnd-cell-overhead'], + title: 'Partition the world into 192 meter cells', + body: `From the planning meeting: move to 192 m cells.`, + }, + { + at: '2026-04-02T10:00:00Z', + key: 'dec-cell-192', + type: 'WriteDecision', + created_by: KENJI, + derives_from: ['fnd-cell-overhead', 'fnd-tide-burst'], + supersedes: ['dec-cell-128'], + title: 'Partition the world into 192 m cells', + body: `Move to 192 m cells. About 88 cells are resident on Skiff, so overhead falls to roughly 97 MB, and a falling tide reloads 9 cells with a replayed peak of 240 MB/s. That is above the 128 m peak but well under the 410 MB/s of 256 m cells, and the file count drops by half. 192 m is also three 64 m tiles wide.`, + }, + { + at: '2026-04-02T16:00:00Z', + type: 'Retract', + recordId: 'dec-cell-192-dup', + reason: + "Duplicate of Kenji Arakawa's proposal, written from the planning meeting notes.", + }, + { + at: '2026-04-03T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-cell-192', + }, + { + at: '2026-04-08T10:00:00Z', + key: 'rsk-cell-seams', + type: 'WriteRisk', + likelihood: 'high', + severity: 'medium', + created_by: KENJI, + derives_from: ['dec-cell-192'], + title: '192 m cells split the 128 m navigation tiles', + body: `Navigation tiles are 128 m, sized for the old cells. A 192 m cell edge cuts every second tile in half, so a tile would belong to two cells and reload with either. Path queries across a seam could fail while one half is missing.`, + }, + { + at: '2026-04-16T10:00:00Z', + key: 'dec-nav-64', + type: 'WriteDecision', + created_by: MARTA, + derives_from: ['rsk-cell-seams'], + title: 'Cut navigation tiles to 64 m so three fit along each cell edge', + body: `Rebuild navigation tiles at 64 m. Three tiles fit along each 192 m edge, so every tile belongs to exactly one cell. Nav build time rises by 18%, which Marta Lindqvist accepts.`, + }, + { + at: '2026-04-20T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-nav-64', + }, + { + at: '2026-04-21T09:00:00Z', + type: 'MitigateRisk', + riskId: 'rsk-cell-seams', + decisionId: 'dec-nav-64', + }, +]; diff --git a/benchmarks/proof-recall/spec/world/compactions.mjs b/benchmarks/proof-recall/spec/world/compactions.mjs new file mode 100644 index 00000000..6b4a9b27 --- /dev/null +++ b/benchmarks/proof-recall/spec/world/compactions.mjs @@ -0,0 +1,93 @@ +// Compactions: short accounts of where the world Effort stands, spread over the year. +const RHEA = 'Rhea Valdés'; + +export default [ + { + at: '2025-12-12T16:00:00Z', + key: 'cmp-1', + type: 'WriteCompaction', + created_by: RHEA, + derives_from: [ + 'dec-ecs-hybrid', + 'dec-jobs-3', + 'dec-cell-128', + 'dec-tide-fixed', + 'dec-codec-kelp', + 'dec-gull-tree', + 'con-pool-1', + 'dec-save-delta', + 'dec-pool-lru', + 'dec-io-queue', + ], + title: 'World core state before the vertical slice', + body: `Components live in archetype tables, with volatile tide tags in sparse sets. Engine jobs run on fibers (160 fibers, 64 KB stacks) after two thread-pool versions left workers idle on waits. The world is partitioned into 128 m cells, halved from 256 m because falling tides forced whole-cell reloads. The tide simulation runs in 32.32 fixed point and matches bit for bit across platforms. Streamed assets use Kelp, read through one async request queue per platform, inside a 2.0 GB streaming pool with LRU eviction. Gull stays on its tree-walking interpreter until alpha content lands. Saves store player deltas against the tide-free baseline.`, + }, + { + at: '2026-03-06T16:00:00Z', + key: 'cmp-2', + type: 'WriteCompaction', + created_by: RHEA, + derives_from: [ + 'dec-jobs-4', + 'dec-cell-128', + 'dec-codec-dict', + 'dec-gull-bytecode', + 'dec-gull-reload', + 'dec-save-delta-2', + 'dec-pool-forecast', + 'con-pool-1', + 'dec-tide-fixed', + 'dec-ecs-chunk', + ], + title: 'World core state at alpha', + body: `Engine jobs run on fibers, and Gull scripts are pinned to two dedicated threads after fiber migration broke the VM's thread-local state. Cells stay 128 m. Kelp keeps streaming with a 1 MB dictionary, after a cold-cache rerun showed the 4 MB dictionary losing to Zstandard on Skiff. Gull now compiles to bytecode for a register VM, 4.1x faster than the interpreter, and hot reload swaps bytecode at frame boundaries, which applies 94% of edits. Saves key each delta to the tide phase. The 2.0 GB pool evicts by distance and tide forecast. ECS chunks are grouped by tide band.`, + }, + { + at: '2026-05-18T12:30:00Z', + type: 'Invalidate', + findingId: 'fnd-gull-reload-coro', + targetId: 'cmp-2', + }, + { + at: '2026-06-10T16:00:00Z', + key: 'cmp-3', + type: 'WriteCompaction', + created_by: RHEA, + derives_from: [ + 'dec-jobs-5', + 'dec-cell-192', + 'con-pool-2', + 'dec-codec-dict', + 'dec-save-version', + 'dec-save-delta-2', + 'dec-pool-forecast', + 'dec-gull-bytecode', + 'dec-io-tide-priority', + 'dec-tide-fixed', + ], + title: 'World core state after beta', + body: `Engine jobs are back on a thread pool with continuation waits; fibers are gone, and Gull keeps two dedicated threads. Cells are 192 m, with 64 m navigation tiles. The streaming pool is 1.6 GB, cut from 2.0 GB to fit the Skiff memory budget. Reads for tide-exposed cells take top priority. Saves carry a schema version and upgrade step by step on load; beta saves must load in every later build. Hot reload drops suspended coroutines, so its real success rate is about 71%. The tide stays in 32.32 fixed point.`, + }, + { + at: '2026-08-20T16:00:00Z', + key: 'cmp-4', + type: 'WriteCompaction', + created_by: RHEA, + derives_from: [ + 'dec-jobs-6', + 'dec-cell-192', + 'con-pool-3', + 'dec-tide-fixed', + 'dec-tide-harmonic', + 'dec-save-version', + 'dec-codec-dict', + 'dec-gull-bytecode', + 'iss-blk-save-harmonic', + 'iss-blk-io-starve', + ], + title: 'World core state before content lock', + body: `Engine jobs and Gull scripts share one thread pool with continuation waits; the dedicated Gull threads are gone. The world uses 192 m cells. The streaming pool is 1.6 GB, with 320 MB reserved for tide-band cells during a turn. The tide runs in 32.32 fixed point and now has a second harmonic for spring and neap tides. Kelp with a 1 MB dictionary decodes at 2.2 GB/s cold on Skiff, so decode has headroom. Saves are versioned and upgraded on load. + +Two blockers are open. Beta saves lack the second harmonic's phase, with two proposed fixes. Tide-priority reads starve player-proximity loads, and a deadline scheduler is proposed. Gull hot reload still drops suspended coroutines.`, + }, +]; diff --git a/benchmarks/proof-recall/spec/world/ecs.mjs b/benchmarks/proof-recall/spec/world/ecs.mjs new file mode 100644 index 00000000..1d3b0e04 --- /dev/null +++ b/benchmarks/proof-recall/spec/world/ecs.mjs @@ -0,0 +1,239 @@ +// Thread 1: ECS storage. Archetype tables vs sparse sets vs a hybrid. +const RHEA = 'Rhea Valdés'; +const MARTA = 'Marta Lindqvist'; + +export default [ + { + at: '2025-09-03T09:00:00Z', + key: 'iss-ecs-storage', + type: 'WriteIssue', + kind: 'question', + created_by: RHEA, + title: 'How should Kestrel store entity components?', + body: `Kestrel needs one component storage model before gameplay code piles up on it. The candidates are archetype tables (dense columns per component set), sparse sets (one packed array per component type), or a mix of the two. The hard case is the tide: every tide turn flips state on tens of thousands of shoreline entities at once, and whichever layout we pick has to survive that spike.`, + }, + { + at: '2025-09-09T14:00:00Z', + key: 'blob-ecs-profile', + type: 'WriteBlob', + kind: 'json', + created_by: RHEA, + title: 'ECS storage microbenchmark profile, September 2025', + body: JSON.stringify( + { + capture: 'ecs-bench run-0909', + machine: 'PC dev box, 16 cores, DDR5-5600', + entities: 1000000, + spawn_templates: 1, + archetype_count: 3, + layouts: [ + { + layout: 'archetype_tables', + iterate_transforms_ms: 1.9, + add_remove_component_ns: 380, + memory_mb: 212, + }, + { + layout: 'sparse_sets', + iterate_transforms_ms: 4.6, + add_remove_component_ns: 45, + memory_mb: 340, + }, + { + layout: 'hybrid', + iterate_transforms_ms: 2.1, + add_remove_component_ns: 52, + memory_mb: 236, + }, + ], + }, + null, + 2 + ), + }, + { + at: '2025-09-09T14:10:00Z', + key: 'cit-ecs-profile', + type: 'WriteCitation', + role: 'evidence', + blob: 'blob-ecs-profile', + created_by: RHEA, + title: 'ecs-bench profile run-0909', + body: 'https://perf.tidewater.internal/kestrel/ecs-bench/run-0909.json', + }, + { + at: '2025-09-10T10:00:00Z', + key: 'fnd-ecs-iter-bench', + type: 'WriteFinding', + kind: 'measurement', + created_by: RHEA, + derives_from: ['iss-ecs-storage'], + cites: ['cit-ecs-profile'], + title: 'Archetype tables iterate transforms 2.4x faster than sparse sets', + body: `Rhea Valdés ran ecs-bench with one million entities on the PC dev box. Iterating every transform takes 1.9 ms with archetype tables and 4.6 ms with sparse sets. The cost runs the other way for structural changes: adding or removing one component costs 380 ns with archetype tables, because the row moves to a new table, and 45 ns with sparse sets. The hybrid layout sits close to the best of both. The full profile, including memory per layout, is in the attached capture.`, + }, + { + at: '2025-09-15T11:00:00Z', + key: 'fnd-ecs-churn', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['iss-ecs-storage'], + title: 'Tide turns toggle the Submerged tag on 40,000 entities', + body: `The tide turns every 20 minutes, twice per 40-minute cycle. In the coast test map, 40,000 entities gain or lose the Submerged tag on each turn. With archetype tables every flip moves a row: 40,000 x 380 ns is 15.2 ms on the main thread in one frame. With sparse sets the same flips cost 1.8 ms. Marta Lindqvist expects the count to double once the full coast is populated.`, + }, + { + at: '2025-09-17T09:00:00Z', + key: 'dec-ecs-archetype', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['iss-ecs-storage', 'fnd-ecs-iter-bench'], + title: 'Store all components in archetype tables', + body: `Use archetype tables for every component. Iteration speed matters most for transforms, physics proxies, and render handles, and archetype tables win that by 2.4x. The tide spike would need batching of Submerged flips across several frames.`, + }, + { + at: '2025-09-17T09:30:00Z', + key: 'dec-ecs-sparse', + type: 'WriteDecision', + created_by: MARTA, + derives_from: ['iss-ecs-storage', 'fnd-ecs-churn'], + title: 'Store all components in sparse sets', + body: `Use sparse sets for every component. Structural changes cost 45 ns instead of 380 ns, which makes the tide spike disappear. Iteration is slower, but Marta Lindqvist argues that most gameplay queries touch few entities.`, + }, + { + at: '2025-09-18T10:00:00Z', + key: 'dec-ecs-hybrid', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['iss-ecs-storage', 'fnd-ecs-iter-bench', 'fnd-ecs-churn'], + title: + 'Store components in archetype tables and volatile tags in sparse sets', + body: `Keep hot, stable components (transforms, physics proxies, render handles) in archetype tables. Store volatile tags that flip often, starting with Submerged, Exposed, and Buried, in sparse sets beside the tables. A tide turn then flips sparse entries only, and bulk iteration keeps the archetype speed. Queries that mix the two pay a join.`, + }, + { + at: '2025-09-18T10:20:00Z', + key: 'dec-ecs-hybrid-dup', + type: 'WriteDecision', + created_by: MARTA, + derives_from: ['iss-ecs-storage'], + title: + 'Store components in archetype tables and volatile tags in sparse set', + body: `Hybrid storage: archetype tables for stable components, a sparse set for tide tags.`, + }, + { + at: '2025-09-18T15:00:00Z', + type: 'Retract', + recordId: 'dec-ecs-hybrid-dup', + reason: 'Duplicate submission of the hybrid proposal from the review form.', + }, + { + at: '2025-09-24T16:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-ecs-hybrid', + }, + { + at: '2025-09-24T16:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-ecs-storage', + resolution: 'resolved', + resolvedBy: ['dec-ecs-hybrid'], + }, + { + at: '2025-09-25T10:00:00Z', + key: 'rsk-ecs-join', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'medium', + created_by: RHEA, + derives_from: ['dec-ecs-hybrid'], + title: 'Queries that join tables with sparse tags may lose cache locality', + body: `A query such as "every transform that is Submerged" walks an archetype column and probes a sparse set per row. If the sparse set is large and the archetype count grows, the probe pattern could thrash the cache, especially on Skiff's smaller caches.`, + }, + { + at: '2025-09-26T09:00:00Z', + key: 'con-ecs-structural', + type: 'WriteConstraint', + kind: 'soft', + created_by: RHEA, + derives_from: ['dec-ecs-hybrid'], + title: 'Archetype changes happen only at frame sync points', + body: `Jobs never move entities between archetype tables directly. They record structural changes in command buffers, and the scheduler flushes those buffers at two sync points per frame: after simulation and after streaming. Sparse tag flips are exempt.`, + }, + { + at: '2025-11-03T10:00:00Z', + key: 'iss-ecs-names', + type: 'WriteIssue', + kind: 'gap', + created_by: MARTA, + title: 'Entity debug names are missing in release builds', + body: `Crash reports from release builds show entities as bare numbers. Marta Lindqvist asks whether the Name component can ship in release so the crash reports are readable.`, + }, + { + at: '2025-11-06T11:00:00Z', + key: 'fnd-ecs-names-cost', + type: 'WriteFinding', + kind: 'measurement', + created_by: RHEA, + derives_from: ['iss-ecs-names'], + title: 'Shipping entity names costs 57 MB at full population', + body: `A Name component averages 48 bytes. At the 1.2 million entities of a fully populated coast that is 57 MB, which no console budget can spare. The crash pipeline can map entity numbers back to names from the build's symbol file instead.`, + }, + { + at: '2025-11-06T11:30:00Z', + type: 'ResolveIssue', + issueId: 'iss-ecs-names', + resolution: 'wontfix', + resolvedBy: ['fnd-ecs-names-cost'], + }, + { + at: '2026-01-19T10:00:00Z', + key: 'fnd-ecs-iter-redo', + type: 'WriteFinding', + kind: 'measurement', + created_by: RHEA, + derives_from: ['fnd-ecs-iter-bench'], + title: 'Archetype iteration takes 3.4 ms in the alpha world, not 1.9 ms', + body: `Rhea Valdés repeated the transform iteration test on a capture of the alpha world instead of the synthetic ecs-bench world. The September benchmark spawned every entity from a single template, so nearly all entities shared one table and the iteration was one long linear walk. That is not what a real coast looks like. + +The alpha world has 912 archetypes. Most tables hold fewer than 2,000 rows, so the iterator jumps between tables constantly and the hardware prefetcher never settles. Iterating one million transforms takes 3.4 ms on the PC dev box, not 1.9 ms. Sparse sets on the same capture take 4.9 ms, so archetype tables still win, but by 1.4x and not 2.4x. + +The join between archetype tables and sparse tags is the bigger surprise. On Skiff the join of transforms with the Submerged tag across the crab herd takes 5.1 ms, which is most of a 30 Hz frame's simulation share. The September numbers should not be quoted again.`, + }, + { + at: '2026-01-19T12:00:00Z', + type: 'Invalidate', + findingId: 'fnd-ecs-iter-redo', + targetId: 'fnd-ecs-iter-bench', + }, + { + at: '2026-01-20T09:00:00Z', + type: 'SetRiskState', + riskId: 'rsk-ecs-join', + state: 'realized', + evidence: ['fnd-ecs-iter-redo'], + }, + { + at: '2026-01-27T10:00:00Z', + key: 'dec-ecs-chunk', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['fnd-ecs-iter-redo', 'dec-ecs-hybrid'], + title: 'Group archetype chunks by tide band to cut fragmentation', + body: `Allocate archetype chunks per tide band (dry, intertidal, submerged) so that entities a tide query visits sit in the same chunks. This keeps the hybrid layout and attacks the join cost directly. Expected effect: the Skiff crab join drops below 3.5 ms.`, + }, + { + at: '2026-02-02T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-ecs-chunk', + }, + { + at: '2026-09-16T10:00:00Z', + key: 'fnd-ecs-chunk-gain', + type: 'WriteFinding', + kind: 'measurement', + created_by: RHEA, + derives_from: ['dec-ecs-chunk'], + title: 'Tide-band chunks cut the Skiff crab join to 3.2 ms', + body: `With chunks grouped by tide band, the Skiff join of transforms with the Submerged tag across the crab herd takes 3.2 ms, down from the figure measured on the alpha world. The gain comes from fewer chunk switches: 140 per query instead of 610.`, + }, +]; diff --git a/benchmarks/proof-recall/spec/world/gull.mjs b/benchmarks/proof-recall/spec/world/gull.mjs new file mode 100644 index 00000000..21864d51 --- /dev/null +++ b/benchmarks/proof-recall/spec/world/gull.mjs @@ -0,0 +1,244 @@ +// Thread 7: the Gull scripting VM. Interpreter, then a JIT-free bytecode VM; hot reload. +const RHEA = 'Rhea Valdés'; +const MARTA = 'Marta Lindqvist'; +const PRIYA = 'Priya Natarajan'; +const LIAM = "Liam O'Connell"; +const YUSUF = 'Yusuf Demir'; + +export default [ + { + at: '2025-10-06T10:00:00Z', + key: 'iss-gull-vm', + type: 'WriteIssue', + kind: 'question', + created_by: MARTA, + title: 'Should Gull run on a tree-walking interpreter or a bytecode VM?', + body: `Gull, Kestrel's scripting language, drives creature AI, tide events, and quests. Today it runs on a tree-walking interpreter that came with the language prototype. Designers rely on editing scripts while the game runs.`, + }, + { + at: '2025-10-07T10:00:00Z', + key: 'con-no-jit', + type: 'WriteConstraint', + kind: 'hard', + created_by: PRIYA, + title: 'No runtime code generation on consoles', + body: `Meridian and Skiff never grant game processes writable executable memory. Nothing may generate machine code at run time on consoles: no JIT compilers, no runtime-patched code. PC builds may, but shipping one code path is preferred.`, + }, + { + at: '2025-10-15T10:00:00Z', + key: 'fnd-gull-interp', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['iss-gull-vm'], + title: "Gull's tree-walking interpreter spends 1.8 ms on 300 crabs", + body: `The slice map's 300 crabs run their AI in Gull. The tree-walking interpreter spends 1.8 ms per frame on them on Meridian, about 11 times what the same logic costs in C++. Hot reload is trivial: the interpreter just reparses the edited file.`, + }, + { + at: '2025-10-16T10:00:00Z', + key: 'dec-gull-tree', + type: 'WriteDecision', + created_by: MARTA, + derives_from: ['iss-gull-vm', 'fnd-gull-interp'], + title: 'Keep Gull on the tree-walking interpreter', + body: `Keep the interpreter through pre-production. 1.8 ms fits the slice, and designers keep instant hot reload. Revisit when alpha content lands.`, + }, + { + at: '2025-10-16T11:00:00Z', + key: 'dec-gull-bytecode', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['iss-gull-vm', 'fnd-gull-interp', 'con-no-jit'], + title: 'Compile Gull to bytecode for a register VM', + body: `Compile Gull to compact bytecode and run it on a register-based VM with no JIT, which the consoles forbid. Rhea Valdés expects a 3x to 5x speed-up over the interpreter. Hot reload needs new work: swapping compiled functions safely.`, + }, + { + at: '2025-10-20T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-gull-tree', + }, + { + at: '2025-10-20T10:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-gull-vm', + resolution: 'resolved', + resolvedBy: ['dec-gull-tree'], + }, + { + at: '2025-10-21T10:00:00Z', + key: 'con-gull-tick', + type: 'WriteConstraint', + kind: 'soft', + created_by: MARTA, + title: 'Gull script tick budget', + body: `All Gull scripts together get 2.0 ms per frame on Meridian and 3.0 ms per frame on Skiff. Scripts over budget are time-sliced across frames.`, + }, + { + at: '2026-01-14T10:00:00Z', + key: 'fnd-gull-alpha-tick', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['con-gull-tick', 'dec-gull-tree'], + title: 'Alpha content needs 6.2 ms of Gull time per frame', + body: `Alpha content has 1,200 crabs, tide-pool creatures, and 40 quest scripts. On Meridian the interpreter needs 6.2 ms per frame, three times the 2.0 ms budget. Time-slicing makes crabs visibly stutter.`, + }, + { + at: '2026-01-16T10:00:00Z', + type: 'ReopenDecision', + decisionId: 'dec-gull-bytecode', + reason: + 'Alpha content needs three times the Gull tick budget on the interpreter.', + }, + { + at: '2026-01-19T10:00:00Z', + key: 'dec-gull-transpile', + type: 'WriteDecision', + created_by: LIAM, + derives_from: ['fnd-gull-alpha-tick'], + title: 'Transpile Gull to C++ at build time', + body: `Liam O'Connell proposes translating Gull scripts to C++ during the build. Native speed, and no runtime code generation. The cost: every script edit needs a rebuild, so hot reload is gone, and build times grow by about 6 minutes.`, + }, + { + at: '2026-01-23T10:00:00Z', + key: 'fnd-gull-vm-proto', + type: 'WriteFinding', + kind: 'measurement', + created_by: RHEA, + derives_from: ['dec-gull-bytecode', 'fnd-gull-alpha-tick'], + title: 'Register VM prototype runs the crab herd 4.1x faster', + body: `Rhea Valdés's register VM prototype runs the 1,200-crab herd in 1.5 ms per frame on Meridian, against 6.2 ms on the interpreter: 4.1x faster. Bytecode for all alpha scripts is 2.3 MB.`, + }, + { + at: '2026-01-28T10:00:00Z', + type: 'Supersede', + supersederId: 'dec-gull-bytecode', + targetId: 'dec-gull-tree', + }, + { + at: '2026-01-28T11:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-gull-bytecode', + rejects: ['dec-gull-transpile'], + }, + { + at: '2026-02-16T10:00:00Z', + key: 'iss-gull-reload-structs', + type: 'WriteIssue', + kind: 'gap', + created_by: MARTA, + derives_from: ['dec-gull-bytecode'], + title: 'Gull hot reload rejects struct layout changes', + body: `With bytecode, live objects have a fixed layout. An edit that adds or removes a field in a Gull struct cannot be applied to objects that already exist, so the editor refuses the reload.`, + }, + { + at: '2026-02-20T10:00:00Z', + key: 'fnd-gull-reload-proto', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['iss-gull-reload-structs', 'dec-gull-bytecode'], + title: 'Bytecode swap at frame boundaries reloads 94% of edits', + body: `Marta Lindqvist replayed 500 script edits from the design team's history against a reload prototype that swaps function bytecode between frames. 94% applied cleanly; the rest changed struct layouts.`, + }, + { + at: '2026-02-24T10:00:00Z', + key: 'dec-gull-reload', + type: 'WriteDecision', + created_by: MARTA, + derives_from: ['fnd-gull-reload-proto', 'iss-gull-reload-structs'], + title: 'Hot-reload Gull functions by swapping bytecode at frame boundaries', + body: `Between frames, replace the bytecode of every edited function. Running code picks up the new version on its next call. Struct layout changes still need a restart of the level.`, + }, + { + at: '2026-02-25T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-gull-reload', + }, + { + at: '2026-02-25T09:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-gull-reload-structs', + resolution: 'deferred', + resolvedBy: ['dec-gull-reload'], + }, + { + at: '2026-02-26T10:00:00Z', + key: 'rsk-gull-reload-state', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'medium', + created_by: MARTA, + derives_from: ['dec-gull-reload'], + title: 'Hot reload may corrupt live script state', + body: `A swapped function may read locals or object fields in a different order than the old version wrote them. Designers would see creatures behave strangely after a reload and blame their own edit.`, + }, + { + at: '2026-05-18T10:00:00Z', + key: 'fnd-gull-reload-coro', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['dec-gull-reload', 'fnd-gull-reload-proto'], + title: 'Hot reload drops suspended Gull coroutines', + body: `The 94% figure replayed edits on idle scripts. In real sessions most creature scripts are suspended coroutines waiting on a timer or a tide event. A suspended coroutine holds a return address into the old bytecode; after a swap it resumes into the new bytecode at a wrong offset, so the runtime kills it. Logged over two weeks of design sessions, only 71% of reloads kept every script running.`, + }, + { + at: '2026-05-18T12:00:00Z', + type: 'Invalidate', + findingId: 'fnd-gull-reload-coro', + targetId: 'fnd-gull-reload-proto', + }, + { + at: '2026-05-19T10:00:00Z', + key: 'iss-gull-reload-coro', + type: 'WriteIssue', + kind: 'defect', + created_by: YUSUF, + derives_from: ['fnd-gull-reload-coro'], + title: 'Gull hot reload drops suspended coroutines', + body: `Yusuf Demir loses tide-pool creature behaviour after almost every reload: the creatures freeze until the level restarts.`, + }, + { + at: '2026-05-19T10:10:00Z', + key: 'iss-gull-reload-coro-dup', + type: 'WriteIssue', + kind: 'defect', + created_by: YUSUF, + title: 'Gull hot-reload drops suspended coroutines', + body: `Creatures freeze after reload.`, + }, + { + at: '2026-05-19T14:00:00Z', + type: 'Retract', + recordId: 'iss-gull-reload-coro-dup', + reason: "Filed twice from the editor's bug button.", + }, + { + at: '2026-08-27T10:00:00Z', + key: 'iss-blk-gull-debug', + type: 'WriteIssue', + kind: 'blocker', + created_by: MARTA, + derives_from: ['dec-gull-bytecode'], + title: 'The Gull debugger cannot attach on Skiff dev kits', + body: `Since the late-August dev kit update, the Gull debugger times out when attaching to a Skiff build. Script bugs that reproduce only on Skiff cannot be stepped through, and three such bugs are open for the release candidate.`, + }, + { + at: '2026-09-10T10:00:00Z', + key: 'fnd-gull-debug-cause', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['iss-blk-gull-debug'], + title: 'Skiff dev kit firmware blocks the Gull debugger port', + body: `The new Skiff dev kit firmware closes every inbound port except the platform's own debug service. The Gull debugger listens on its own port, so the attach never connects. Tunnelling through the platform debug service would work, but nobody has built it.`, + }, + { + at: '2026-09-22T10:00:00Z', + type: 'ResolveIssue', + issueId: 'iss-gull-reload-coro', + resolution: 'deferred', + resolvedBy: ['fnd-gull-reload-coro'], + }, +]; diff --git a/benchmarks/proof-recall/spec/world/index.mjs b/benchmarks/proof-recall/spec/world/index.mjs new file mode 100644 index 00000000..259675fe --- /dev/null +++ b/benchmarks/proof-recall/spec/world/index.mjs @@ -0,0 +1,29 @@ +// The `world` Effort: Kestrel world streaming and simulation core. +// Each thread lives in its own module; events merge here in time order. +// The sort is stable, so events that share a time keep their module order. +import compactions from './compactions.mjs'; +import cells from './cells.mjs'; +import ecs from './ecs.mjs'; +import gull from './gull.mjs'; +import io from './io.mjs'; +import jobs from './jobs.mjs'; +import pool from './pool.mjs'; +import save from './save.mjs'; +import tides from './tides.mjs'; + +const threads = [ecs, jobs, cells, tides, io, save, gull, pool, compactions]; +const events = threads + .flat() + .map((event, order) => ({ event, order, time: Date.parse(event.at) })) + .sort((a, b) => a.time - b.time || a.order - b.order) + .map(({ event }) => event); + +export default { + key: 'world', + effort: { + title: 'Kestrel world streaming and simulation core', + body: `Kestrel's engine core for Saltglass Reach: entity storage, the job system, world partition and streaming, the tide simulation, asset compression, save games, the Gull scripting VM, and memory budgets. Rhea Valdés leads; Kenji Arakawa owns streaming and Marta Lindqvist owns gameplay systems.`, + created_at: '2025-09-01T09:00:00Z', + }, + events, +}; diff --git a/benchmarks/proof-recall/spec/world/io.mjs b/benchmarks/proof-recall/spec/world/io.mjs new file mode 100644 index 00000000..39eafcc8 --- /dev/null +++ b/benchmarks/proof-recall/spec/world/io.mjs @@ -0,0 +1,490 @@ +// Thread 5: asset streaming I/O and the Kelp codec against off-the-shelf codecs. +const RHEA = 'Rhea Valdés'; +const KENJI = 'Kenji Arakawa'; +const PRIYA = 'Priya Natarajan'; +const DARA = 'Dara Whitlock'; + +const table = (rows) => rows.map((row) => `| ${row.join(' | ')} |`).join('\n'); + +export default [ + { + at: '2025-09-22T10:00:00Z', + key: 'iss-io-api', + type: 'WriteIssue', + kind: 'question', + created_by: KENJI, + title: 'Which read path should streaming use on each platform?', + body: `Streaming needs one read path that works on PC, Meridian, and Skiff. The choice is between an explicit async request queue and memory-mapping the packed cell archives and letting page faults pull data in.`, + }, + { + at: '2025-09-26T10:00:00Z', + key: 'fnd-io-mmap-skiff', + type: 'WriteFinding', + kind: 'survey', + created_by: PRIYA, + derives_from: ['iss-io-api'], + title: "Skiff's file system cannot memory-map packed archives", + body: `Priya Natarajan checked the platform SDKs. PC and Meridian can memory-map files. Skiff's file system maps only loose files under 64 MB, and the packed cell archives are several gigabytes. A mapped design would need a second read path for Skiff anyway.`, + }, + { + at: '2025-09-29T14:00:00Z', + key: 'dec-io-queue', + type: 'WriteDecision', + created_by: KENJI, + derives_from: ['iss-io-api', 'fnd-io-mmap-skiff'], + title: 'Read streamed assets through one async request queue per platform', + body: `Every streamed read goes through an async request queue with a priority and a completion callback. Each platform backs the queue with its native async API. One code path, explicit priorities, and no page-fault stalls on the main thread.`, + }, + { + at: '2025-09-29T14:30:00Z', + key: 'dec-io-mmap', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['iss-io-api'], + title: 'Memory-map packed cell archives and fault data in', + body: `Map the packed archives and let the OS page data in on first touch. Least code, and the OS cache does the work.`, + }, + { + at: '2025-10-02T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-io-queue', + }, + { + at: '2025-10-02T10:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-io-api', + resolution: 'resolved', + resolvedBy: ['dec-io-queue'], + }, + { + at: '2025-10-01T09:00:00Z', + key: 'iss-codec', + type: 'WriteIssue', + kind: 'question', + created_by: KENJI, + title: 'Which codec should compress streamed assets?', + body: `Streamed cells are compressed on disk and decoded on job workers. We can use Kelp, the studio's own codec, or an off-the-shelf codec. Decode speed per core matters more than ratio, because decode competes with simulation for workers during a tide turn.`, + }, + { + at: '2025-10-13T15:00:00Z', + key: 'blob-codec-1', + type: 'WriteBlob', + kind: 'markdown', + created_by: KENJI, + title: 'Codec benchmark, warm cache, October 2025', + body: `# Codec benchmark, warm cache (PC dev box, one core) + +Decode rate in GB/s of output; ratio is uncompressed over compressed. + +${table([ + [ + 'Asset class', + 'Kelp ratio', + 'Kelp GB/s', + 'Zstandard ratio', + 'Zstandard GB/s', + 'LZ4 ratio', + 'LZ4 GB/s', + ], + ['---', '---', '---', '---', '---', '---', '---'], + ['Textures', '3.4', '3.1', '3.0', '1.5', '2.2', '3.9'], + ['Geometry', '2.9', '2.8', '2.7', '1.3', '2.0', '3.8'], + ['Audio banks', '1.6', '2.4', '1.7', '1.2', '1.4', '3.6'], + ['Navigation', '4.1', '3.0', '3.8', '1.6', '2.6', '4.0'], + ['All assets (weighted)', '3.1', '2.9', '2.8', '1.4', '2.1', '3.8'], +])} + +Zstandard at level 9; LZ4 in high-compression mode. Kelp dictionary: 4 MB, loaded once before the run.`, + }, + { + at: '2025-10-13T15:10:00Z', + key: 'cit-codec-1', + type: 'WriteCitation', + role: 'evidence', + blob: 'blob-codec-1', + created_by: KENJI, + title: 'Codec benchmark table, October 2025', + body: 'https://perf.tidewater.internal/kestrel/codec/bench-1013.md', + }, + { + at: '2025-10-14T10:00:00Z', + key: 'fnd-codec-1-typo', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['iss-codec'], + title: 'Kelp decodes streamed assets at 29 GB/s per core', + body: `Kelp decodes streamed assets at 29 GB/s per core on the PC dev box.`, + }, + { + at: '2025-10-14T11:00:00Z', + key: 'fnd-codec-1', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['iss-codec'], + cites: ['cit-codec-1'], + title: 'Kelp decodes streamed assets at 2.9 GB/s per core', + body: `On the PC dev box, Kelp decodes streamed assets at 2.9 GB/s per core with a 3.1:1 ratio. Zstandard at level 9 decodes at 1.4 GB/s with 2.8:1. LZ4 decodes fastest, 3.8 GB/s, but its 2.1:1 ratio would grow the install by a third. The per-class table is attached.`, + }, + { + at: '2025-10-14T11:05:00Z', + type: 'Retract', + recordId: 'fnd-codec-1-typo', + reason: + 'Unit typo: 29 GB/s should read 2.9 GB/s; the corrected finding replaces it.', + }, + { + at: '2025-10-16T10:00:00Z', + key: 'dec-codec-kelp', + type: 'WriteDecision', + created_by: KENJI, + derives_from: ['iss-codec', 'fnd-codec-1'], + title: 'Compress streamed assets with Kelp', + body: `Use Kelp for every streamed asset class. It decodes twice as fast as Zstandard with a better ratio, and the studio owns the code, so console-specific tuning is in our hands.`, + }, + { + at: '2025-10-16T10:30:00Z', + key: 'dec-codec-zstd', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['iss-codec', 'fnd-codec-1'], + title: 'Compress streamed assets with Zstandard', + body: `Use Zstandard, an off-the-shelf codec with years of fuzzing and platform ports behind it. Rhea Valdés would rather not own a codec, even at half the decode speed.`, + }, + { + at: '2025-10-16T11:00:00Z', + key: 'dec-codec-lz4', + type: 'WriteDecision', + created_by: KENJI, + derives_from: ['iss-codec', 'fnd-codec-1'], + title: 'Compress streamed assets with LZ4', + body: `Use LZ4 for the fastest decode and accept the larger install.`, + }, + { + at: '2025-10-20T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-codec-kelp', + }, + { + at: '2025-10-20T10:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-codec', + resolution: 'resolved', + resolvedBy: ['dec-codec-kelp'], + }, + { + at: '2025-10-22T10:00:00Z', + key: 'rsk-kelp-cache', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'high', + created_by: RHEA, + derives_from: ['dec-codec-kelp'], + title: "Kelp's 4 MB dictionary may thrash the Skiff cache", + body: `Kelp's speed comes from a 4 MB shared dictionary. The October run used a PC with a large cache. Skiff's last-level cache is much smaller, and a dictionary that does not fit could make every decode a cache miss.`, + }, + { + at: '2025-12-08T10:00:00Z', + key: 'fnd-io-trace-1', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['dec-io-queue'], + title: 'Skiff streaming reads sustain 260 MB/s', + body: `On a Skiff dev kit, the async queue sustains 260 MB/s of streaming reads over a 10-minute run along the coast.`, + }, + { + at: '2025-12-09T10:00:00Z', + key: 'con-io-budget', + type: 'WriteConstraint', + kind: 'soft', + created_by: KENJI, + derives_from: ['fnd-io-trace-1'], + title: 'Streaming I/O budget', + body: `Sustained streaming reads stay under 220 MB/s on Skiff, leaving headroom below the measured 260 MB/s for saves and audio.`, + }, + { + at: '2026-01-09T15:00:00Z', + key: 'blob-codec-2', + type: 'WriteBlob', + kind: 'markdown', + created_by: KENJI, + title: 'Codec benchmark, cold cache on Skiff, January 2026', + body: `# Codec benchmark, cold cache (Skiff retail unit, one core) + +Caches flushed before each asset. Decode rate in GB/s of output. + +${table([ + ['Asset class', 'Kelp 4 MB dict GB/s', 'Zstandard GB/s'], + ['---', '---', '---'], + ['Textures', '1.2', '1.4'], + ['Geometry', '0.8', '1.2'], + ['Audio banks', '1.0', '1.1'], + ['Navigation', '1.3', '1.5'], + ['All assets (weighted)', '1.1', '1.3'], +])} + +LZ4 was not rerun. Spread across three retail units was under 4%.`, + }, + { + at: '2026-01-09T15:10:00Z', + key: 'cit-codec-2', + type: 'WriteCitation', + role: 'evidence', + blob: 'blob-codec-2', + created_by: KENJI, + title: 'Codec benchmark table, January 2026, Skiff cold cache', + body: 'https://perf.tidewater.internal/kestrel/codec/bench-0109-skiff.md', + }, + { + at: '2026-01-12T10:00:00Z', + key: 'fnd-codec-2', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['fnd-codec-1', 'rsk-kelp-cache'], + cites: ['cit-codec-2'], + title: 'Kelp decodes at 1.1 GB/s on Skiff with a cold cache', + body: `The October benchmark that put Kelp at 2.9 GB/s was wrong for our use. It ran on the PC dev box, it loaded Kelp's 4 MB dictionary once before the run, and it decoded every asset class back to back. The dictionary stayed hot in the PC's cache for the whole run. + +Streaming never looks like that. Cells arrive in bursts between simulation jobs, and by the time a decode job runs, simulation has evicted the dictionary. Kenji Arakawa reran the benchmark on Skiff retail units with caches flushed before each asset. + +Cold, Kelp decodes at 1.1 GB/s and Zstandard at 1.3 GB/s. Zstandard's working set is small enough that a cold start costs it little. Kelp loses on every asset class. The full table is attached. + +Kenji Arakawa repeated the cold run on three retail Skiff units, and the spread between units was under 4 percent.`, + }, + { + at: '2026-01-12T12:00:00Z', + type: 'Invalidate', + findingId: 'fnd-codec-2', + targetId: 'fnd-codec-1', + }, + { + at: '2026-01-13T09:00:00Z', + type: 'SetRiskState', + riskId: 'rsk-kelp-cache', + state: 'realized', + evidence: ['fnd-codec-2'], + }, + { + at: '2026-01-15T10:00:00Z', + type: 'ReopenDecision', + decisionId: 'dec-codec-zstd', + reason: + 'The Kelp benchmark that beat Zstandard ran with a warm cache; cold on Skiff, Zstandard is faster.', + }, + { + at: '2026-02-03T10:00:00Z', + key: 'fnd-codec-3', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['fnd-codec-2'], + title: 'Kelp with a 1 MB dictionary decodes at 2.2 GB/s cold on Skiff', + body: `Kenji Arakawa retrained Kelp's dictionary at 1 MB, which fits Skiff's cache next to the decode job. Cold on Skiff, Kelp now decodes at 2.2 GB/s, against 1.3 GB/s for Zstandard. The ratio drops from 3.1:1 to 2.9:1, which grows the install by about 7%.`, + }, + { + at: '2026-02-06T10:00:00Z', + key: 'dec-codec-dict', + type: 'WriteDecision', + created_by: KENJI, + derives_from: ['fnd-codec-3', 'dec-codec-kelp'], + title: "Shrink Kelp's dictionary to 1 MB for streamed assets", + body: `Keep Kelp and ship the 1 MB dictionary on every platform. Cold on Skiff it beats Zstandard by 1.7x. The reopened Zstandard option is closed again by this decision.`, + }, + { + at: '2026-02-09T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-codec-dict', + rejects: ['dec-codec-zstd'], + }, + { + at: '2026-02-17T15:00:00Z', + key: 'blob-trace-retail', + type: 'WriteBlob', + kind: 'json', + created_by: PRIYA, + title: 'Streaming read trace, retail Skiff against dev kit', + body: JSON.stringify( + { + capture: 'stream-trace-0217', + route: 'coast loop, 10 minutes', + units: [ + { + unit: 'Skiff dev kit', + storage: 'dev kit SSD', + sustained_mb_s: 262, + p99_latency_ms: 9, + }, + { + unit: 'Skiff retail A', + storage: 'retail flash', + sustained_mb_s: 191, + p99_latency_ms: 24, + }, + { + unit: 'Skiff retail B', + storage: 'retail flash', + sustained_mb_s: 188, + p99_latency_ms: 27, + }, + ], + note: 'Dev kits ship a faster SSD than retail units.', + }, + null, + 2 + ), + }, + { + at: '2026-02-17T15:10:00Z', + key: 'cit-trace-retail', + type: 'WriteCitation', + role: 'evidence', + blob: 'blob-trace-retail', + created_by: PRIYA, + title: 'Retail Skiff streaming trace stream-trace-0217', + body: 'https://perf.tidewater.internal/kestrel/stream-traces/stream-trace-0217.json', + }, + { + at: '2026-02-20T10:00:00Z', + key: 'fnd-io-trace-2', + type: 'WriteFinding', + kind: 'measurement', + created_by: PRIYA, + derives_from: ['fnd-io-trace-1'], + cites: ['cit-trace-retail'], + title: 'Retail Skiff units sustain only 190 MB/s of streaming reads', + body: `The December figure came from a dev kit, which has faster storage than retail units. On two retail Skiff units the same coast loop sustains about 190 MB/s, and tail latency is nearly three times worse. The trace lists each unit.`, + }, + { + at: '2026-02-20T12:00:00Z', + type: 'Invalidate', + findingId: 'fnd-io-trace-2', + targetId: 'fnd-io-trace-1', + }, + { + at: '2026-02-24T10:00:00Z', + key: 'con-io-budget-2', + type: 'WriteConstraint', + kind: 'soft', + created_by: KENJI, + derives_from: ['fnd-io-trace-2'], + supersedes: ['con-io-budget'], + title: 'Streaming I/O budget', + body: `Sustained streaming reads stay under 160 MB/s on Skiff, measured on retail units, not dev kits. The rest of the 190 MB/s is reserved for saves, audio, and the tide-turn burst.`, + }, + { + at: '2026-05-11T10:00:00Z', + key: 'dec-io-tide-priority', + type: 'WriteDecision', + created_by: KENJI, + derives_from: ['con-cell-deadline', 'dec-cell-192'], + title: 'Give reads for tide-exposed cells top priority', + body: `Reads for cells the tide is about to expose jump to the head of the request queue, ahead of all other streaming reads. This is the simplest way to meet the 8-second cell load deadline.`, + }, + { + at: '2026-05-12T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-io-tide-priority', + }, + { + at: '2026-08-07T15:00:00Z', + key: 'blob-trace-starve', + type: 'WriteBlob', + kind: 'json', + created_by: KENJI, + title: 'Streaming trace: inland sprint during a falling tide on Skiff', + body: JSON.stringify( + { + capture: 'stream-trace-0807-skiff', + cell_size_m: 192, + player_speed_m_s: 7.5, + tide_event: 'falling, spring tide', + tide_cells_queued: 11, + proximity_reads_delayed: 46, + max_untextured_s: 6.8, + worst_location: 'Glassreef inlet', + queue_depth_max: 32, + }, + null, + 2 + ), + }, + { + at: '2026-08-07T15:10:00Z', + key: 'cit-trace-starve', + type: 'WriteCitation', + role: 'evidence', + blob: 'blob-trace-starve', + created_by: KENJI, + title: 'Skiff streaming trace stream-trace-0807', + body: 'https://perf.tidewater.internal/kestrel/stream-traces/stream-trace-0807-skiff.json', + }, + { + at: '2026-08-10T10:00:00Z', + key: 'fnd-io-starve', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['dec-io-tide-priority'], + cites: ['cit-trace-starve'], + title: 'Tide-priority reads starve player-proximity loads', + body: `Giving tide-exposed cells absolute priority was a mistake. On a falling spring tide, the second harmonic exposes far more coast than a normal tide, and the queue fills with tide-cell reads for minutes at a time. + +A player who sprints inland during that window outruns streaming. Proximity reads for the cells ahead of the player wait behind every queued tide read, because nothing outranks the tide lane. The ground arrives as untextured glass and fills in seconds later. + +The tide deadline itself is met with time to spare: tide cells finish 20 seconds before exposure on average, against an 8-second deadline. The priority rule protects a deadline that had slack while it starves the reads that had none. + +In the worst capture, at the Glassreef inlet, inland terrain stayed untextured for 6.8 seconds.`, + }, + { + at: '2026-08-10T12:00:00Z', + type: 'Invalidate', + findingId: 'fnd-io-starve', + targetId: 'dec-io-tide-priority', + }, + { + at: '2026-08-11T10:00:00Z', + key: 'iss-blk-io-starve', + type: 'WriteIssue', + kind: 'blocker', + created_by: KENJI, + derives_from: ['fnd-io-starve'], + title: 'Tide turns leave inland terrain untextured for seconds', + body: `Untextured terrain during spring tides blocks content lock sign-off for the coast region. Streaming needs a read scheduler that serves both the tide deadline and the player.`, + }, + { + at: '2026-08-14T10:00:00Z', + key: 'dec-io-deadline', + type: 'WriteDecision', + created_by: KENJI, + derives_from: ['iss-blk-io-starve', 'fnd-io-starve', 'con-cell-deadline'], + title: 'Schedule streaming reads by deadline instead of fixed priority', + body: `Give every read a deadline: tide cells get exposure time minus 8 seconds, proximity cells get the time the player will reach them at current speed. The queue serves the earliest deadline first. Tide reads with slack then yield to the player.`, + }, + { + at: '2026-08-28T10:00:00Z', + key: 'rsk-io-rework', + type: 'WriteRisk', + likelihood: 'high', + severity: 'medium', + created_by: DARA, + derives_from: ['iss-blk-io-starve', 'dec-io-deadline'], + title: + 'Reworking the read scheduler may slip the coast sign-off past the release candidate', + body: `Content lock has passed and the deadline scheduler is still a proposal. Dara Whitlock estimates three weeks to build and soak it, which lands within days of the release candidate on 2026-09-30.`, + }, + { + at: '2026-09-02T10:00:00Z', + key: 'fnd-codec-4', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['dec-codec-dict'], + supersedes: ['fnd-codec-3'], + title: + 'Kelp with a 1 MB dictionary decodes at 1.5 GB/s cold on Skiff after firmware 3.2', + body: `Skiff firmware 3.2 shrank the cache share given to game cores. Cold on Skiff, Kelp with the 1 MB dictionary now decodes at 1.5 GB/s, down from 2.2 GB/s. Zstandard dropped from 1.3 to 1.2 GB/s. Kelp still wins, by 1.25x instead of 1.7x.`, + }, +]; diff --git a/benchmarks/proof-recall/spec/world/jobs.mjs b/benchmarks/proof-recall/spec/world/jobs.mjs new file mode 100644 index 00000000..d6455c29 --- /dev/null +++ b/benchmarks/proof-recall/spec/world/jobs.mjs @@ -0,0 +1,284 @@ +// Thread 2: the job system. Thread pool, then fibers, then back to a pool. +const RHEA = 'Rhea Valdés'; +const KENJI = 'Kenji Arakawa'; +const MARTA = 'Marta Lindqvist'; +const LIAM = "Liam O'Connell"; +const DARA = 'Dara Whitlock'; + +export default [ + { + at: '2025-09-05T10:00:00Z', + key: 'iss-jobs-model', + type: 'WriteIssue', + kind: 'question', + created_by: RHEA, + title: 'Which job model should the Kestrel scheduler use?', + body: `Every Kestrel system will run as jobs: simulation, streaming, decompression, Gull scripts, and render setup. We need to pick the execution model now, because changing it later touches every system that waits on another.`, + }, + { + at: '2025-09-08T15:00:00Z', + key: 'fnd-jobs-survey', + type: 'WriteFinding', + kind: 'survey', + created_by: RHEA, + derives_from: ['iss-jobs-model'], + title: 'Fibers hide waits but need custom stacks and debugger support', + body: `Rhea Valdés surveyed two models. A work-stealing thread pool is simple and every debugger understands it, but a job that waits blocks its worker. Fibers let a job yield on a wait and resume later on any worker, but they need custom stack allocation, and the Meridian and Skiff debuggers show fiber stacks only through a vendor plug-in that is still in beta.`, + }, + { + at: '2025-09-10T10:00:00Z', + key: 'dec-jobs-1', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['iss-jobs-model', 'fnd-jobs-survey'], + title: 'Run engine jobs on a work-stealing thread pool', + body: `Run one worker per hardware thread, minus one for the main thread. Jobs must not block: a job that needs data schedules a follow-up job instead of waiting. This keeps the scheduler small and debuggable for pre-production.`, + }, + { + at: '2025-09-10T10:30:00Z', + key: 'dec-jobs-fibers-early', + type: 'WriteDecision', + created_by: KENJI, + derives_from: ['iss-jobs-model', 'fnd-jobs-survey'], + title: 'Run engine jobs on fibers from the start', + body: `Kenji Arakawa proposes fibers from day one. Streaming code is full of waits on I/O and decompression, and rewriting those as follow-up jobs is error-prone. Fibers make a wait a yield.`, + }, + { + at: '2025-09-12T17:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-jobs-1', + }, + { + at: '2025-09-12T17:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-jobs-model', + resolution: 'resolved', + resolvedBy: ['dec-jobs-1'], + }, + { + at: '2025-10-14T10:00:00Z', + key: 'fnd-jobs-stalls', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['dec-jobs-1'], + title: 'Streaming jobs block workers while waiting on reads', + body: `The no-blocking rule is not holding. Decompression jobs wait for their reads instead of chaining, because the read API has no completion callback yet. On Meridian, workers sit idle for 3.1 ms per frame, and frame-critical jobs queue behind blocked streaming jobs.`, + }, + { + at: '2025-10-21T10:00:00Z', + key: 'dec-jobs-2', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['fnd-jobs-stalls'], + supersedes: ['dec-jobs-1'], + title: 'Run engine jobs on a work-stealing thread pool with priority lanes', + body: `Keep the thread pool but split it into three lanes: frame-critical, streaming, and background. Waits are allowed only in the streaming lane, so a blocked read never delays a frame-critical job. Two workers serve the streaming lane on every platform.`, + }, + { + at: '2025-10-22T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-jobs-2', + }, + { + at: '2025-11-18T10:00:00Z', + key: 'fnd-jobs-idle', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['fnd-jobs-stalls', 'dec-jobs-2'], + title: 'Priority lanes still leave workers 28% idle during tide turns', + body: `During a tide turn the streaming lane gets 18 cell reloads at once. Both streaming workers block on reads, the lane backs up, and across the pool workers are idle 28% of the time while work waits. Adding streaming workers only moves the problem, because each new worker also blocks.`, + }, + { + at: '2025-11-26T10:00:00Z', + key: 'dec-jobs-3', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['fnd-jobs-idle', 'fnd-jobs-survey'], + supersedes: ['dec-jobs-2'], + title: 'Move engine jobs to fibers', + body: `Replace the thread pool with a fiber scheduler: 160 fibers with 64 KB stacks, run by one worker thread per hardware thread. A wait yields the fiber and the worker picks up other work. This is the model Kenji Arakawa proposed in September; the lane split showed that blocking waits cannot be scheduled away.`, + }, + { + at: '2025-11-27T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-jobs-3', + }, + { + at: '2025-11-28T10:00:00Z', + key: 'rsk-fiber-debug', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'high', + created_by: RHEA, + derives_from: ['dec-jobs-3'], + title: 'Fiber stacks may make crash dumps unreadable', + body: `Crash dumps capture thread stacks. A crash inside a fiber shows the worker's scheduler frames, not the job's frames, unless the dump tool walks fiber stacks too. The console vendor plug-in for that is still in beta.`, + }, + { + at: '2026-01-30T10:00:00Z', + key: 'iss-jobs-gull-crash', + type: 'WriteIssue', + kind: 'defect', + created_by: MARTA, + title: 'Gull scripts crash after a fiber resumes on another worker', + body: `Gull scripts that wait (for an animation, a timer, or a tide event) crash at random after resuming. The crash is always inside the Gull VM's register access.`, + }, + { + at: '2026-02-04T10:00:00Z', + key: 'fnd-gull-fiber-tls', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['iss-jobs-gull-crash', 'dec-jobs-3'], + title: 'The Gull VM reads thread-local registers after fiber migration', + body: `Marta Lindqvist traced the Gull crashes to thread-local storage. The Gull VM keeps its register file and its current-script pointer in thread-local variables, which was safe on a thread pool because a job never changed threads mid-run. + +Under fibers, a Gull script that waits yields its fiber. When the fiber resumes, the scheduler may run it on a different worker thread. The VM then reads the new thread's register file, which belongs to some other script, and either corrupts that script or dereferences a stale pointer. + +Moving the VM state out of thread-local storage means touching every native binding, about 1,400 functions. The debugger has the same problem in reverse: it shows the worker's stack, so a script breakpoint lands in scheduler code. + +Measured on the alpha build, the failure rate is one crash per 900 script waits, which works out to a crash every four minutes in a four-player session.`, + }, + { + at: '2026-02-04T15:00:00Z', + type: 'Invalidate', + findingId: 'fnd-gull-fiber-tls', + targetId: 'dec-jobs-3', + }, + { + at: '2026-02-10T10:00:00Z', + key: 'dec-jobs-4', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['fnd-gull-fiber-tls', 'iss-jobs-gull-crash'], + supersedes: ['dec-jobs-3'], + title: + 'Run engine jobs on fibers and pin Gull scripts to two dedicated threads', + body: `Keep fibers for engine jobs, but take Gull out of the fiber pool. Gull scripts run on two dedicated threads that never migrate, so the VM's thread-local state stays valid. Engine code that calls into Gull posts a request to those threads.`, + }, + { + at: '2026-02-11T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-jobs-4', + }, + { + at: '2026-02-12T09:00:00Z', + type: 'ResolveIssue', + issueId: 'iss-jobs-gull-crash', + resolution: 'resolved', + resolvedBy: ['dec-jobs-4'], + }, + { + at: '2026-03-16T10:00:00Z', + key: 'fnd-fiber-crash-stacks', + type: 'WriteFinding', + kind: 'measurement', + created_by: LIAM, + derives_from: ['rsk-fiber-debug'], + title: '41% of alpha crash reports have no usable stack', + body: `Liam O'Connell sampled 600 crash reports from the alpha build. In 246 of them (41%) the crashing thread was a fiber worker and the dump shows only scheduler frames. The vendor fiber plug-in recovers stacks on Meridian but still crashes the dump tool on Skiff.`, + }, + { + at: '2026-03-17T09:00:00Z', + type: 'SetRiskState', + riskId: 'rsk-fiber-debug', + state: 'realized', + evidence: ['fnd-fiber-crash-stacks'], + }, + { + at: '2026-03-25T10:00:00Z', + key: 'iss-blk-crash-triage', + type: 'WriteIssue', + kind: 'blocker', + created_by: DARA, + derives_from: ['fnd-fiber-crash-stacks'], + title: 'Crash triage stalls because fiber stacks are unreadable', + body: `QA cannot route 41% of crashes to an owner. Dara Whitlock marks this as a blocker for the beta certification pass, which needs a crash rate per system.`, + }, + { + at: '2026-04-02T10:00:00Z', + key: 'fnd-jobs-continuations', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['fnd-jobs-idle', 'iss-blk-crash-triage'], + title: 'A thread pool with continuation waits keeps workers 93% busy', + body: `Kenji Arakawa prototyped a thread pool where a wait registers a continuation job instead of blocking. The read API now has completion callbacks, which it lacked in October. During a tide turn, workers are idle 7% of the time, against 28% for the lane pool and 5% for fibers. Every stack in a crash dump is a normal thread stack.`, + }, + { + at: '2026-04-13T16:00:00Z', + key: 'dec-jobs-5-dup', + type: 'WriteDecision', + created_by: KENJI, + derives_from: ['fnd-jobs-continuations'], + title: 'Return engine jobs to the thread pool with continuation waits', + body: `Draft: go back to a thread pool, waits become continuations.`, + }, + { + at: '2026-04-14T09:00:00Z', + type: 'Retract', + recordId: 'dec-jobs-5-dup', + reason: + "Kenji Arakawa's draft; Rhea Valdés wrote the version under review.", + }, + { + at: '2026-04-14T10:00:00Z', + key: 'dec-jobs-5', + type: 'WriteDecision', + created_by: RHEA, + derives_from: [ + 'fnd-fiber-crash-stacks', + 'fnd-jobs-continuations', + 'iss-blk-crash-triage', + ], + supersedes: ['dec-jobs-4'], + title: 'Return engine jobs to a thread pool with continuation waits', + body: `Retire the fiber scheduler. Engine jobs run on a work-stealing thread pool again, one worker per hardware thread minus one. A job that must wait registers a continuation, and the scheduler runs the continuation when the read, decompression, or job it waits on completes. + +Why now: 41% of alpha crash reports had no usable stack, crash triage is blocked for beta, and the continuation prototype keeps workers 93% busy during tide turns, close to the 95% fibers gave. Fibers bought two points of utilisation at the price of unreadable crashes and the Gull thread-local bug. + +Migration: Kenji Arakawa converts the streaming and decompression waits first, then simulation. Each system keeps a wait wrapper during the move so both models can run in one build. + +Gull keeps its two dedicated threads for now. Marta Lindqvist will measure whether Gull can rejoin the pool once no job ever changes threads mid-run.`, + }, + { + at: '2026-04-15T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-jobs-5', + }, + { + at: '2026-04-15T09:30:00Z', + type: 'ResolveIssue', + issueId: 'iss-blk-crash-triage', + resolution: 'resolved', + resolvedBy: ['dec-jobs-5'], + }, + { + at: '2026-06-18T10:00:00Z', + key: 'fnd-gull-threads-idle', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['dec-jobs-5'], + title: "Gull's two dedicated threads sit idle 70% of each frame", + body: `On the beta build the two Gull threads are busy only 30% of the frame on Meridian and 34% on Skiff, while the job pool is saturated during tide turns. With fibers gone, a Gull job never resumes on another thread, so the thread-local problem no longer applies.`, + }, + { + at: '2026-06-24T10:00:00Z', + key: 'dec-jobs-6', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['fnd-gull-threads-idle'], + supersedes: ['dec-jobs-5'], + title: + 'Run engine jobs and Gull scripts on one thread pool with continuation waits', + body: `Fold Gull back into the job thread pool. Gull scripts become ordinary jobs; a script wait registers a continuation like any other job. The two dedicated Gull threads are removed. A Gull job is never moved between threads mid-run, which keeps the VM's thread-local state valid.`, + }, + { + at: '2026-06-25T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-jobs-6', + }, +]; diff --git a/benchmarks/proof-recall/spec/world/pool.mjs b/benchmarks/proof-recall/spec/world/pool.mjs new file mode 100644 index 00000000..35e33dd4 --- /dev/null +++ b/benchmarks/proof-recall/spec/world/pool.mjs @@ -0,0 +1,236 @@ +// Thread 8: memory. The streaming pool Constraint (WORLD.md fact 2) and eviction. +const KENJI = 'Kenji Arakawa'; +const MARTA = 'Marta Lindqvist'; +const PRIYA = 'Priya Natarajan'; +const DARA = 'Dara Whitlock'; + +export default [ + { + at: '2025-09-12T10:00:00Z', + key: 'con-pool-1', + type: 'WriteConstraint', + kind: 'hard', + created_by: KENJI, + title: 'Streaming pool budget', + body: `The streaming pool, which holds every resident cell's textures, geometry, navigation, and audio, may use at most 2.0 GB on every platform. Streaming must evict before it allocates past that line.`, + }, + { + at: '2025-10-24T10:00:00Z', + key: 'iss-pool-evict', + type: 'WriteIssue', + kind: 'question', + created_by: KENJI, + derives_from: ['con-pool-1'], + title: 'How should the streaming pool choose cells to evict?', + body: `When the pool is full and a new cell must load, streaming evicts resident cells. The policy decides how often we reload a cell we just threw away.`, + }, + { + at: '2025-10-27T10:00:00Z', + key: 'dec-pool-lru', + type: 'WriteDecision', + created_by: KENJI, + derives_from: ['iss-pool-evict'], + title: 'Evict the least recently used cells first', + body: `Evict the cell that was touched longest ago. Cheap to track and well understood.`, + }, + { + at: '2025-10-27T11:00:00Z', + key: 'dec-pool-fifo', + type: 'WriteDecision', + created_by: MARTA, + derives_from: ['iss-pool-evict'], + title: 'Evict cells in the order they were loaded', + body: `Evict the oldest-loaded cell first. Simpler than LRU and needs no per-frame bookkeeping.`, + }, + { + at: '2025-10-30T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-pool-lru', + }, + { + at: '2025-10-30T10:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-pool-evict', + resolution: 'resolved', + resolvedBy: ['dec-pool-lru'], + }, + { + at: '2026-01-05T10:00:00Z', + key: 'fnd-pool-thrash', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['dec-pool-lru'], + title: 'LRU eviction thrashes during tide turns', + body: `Cells the tide is about to expose have not been touched for a whole cycle, so LRU evicts them first, just before they are needed. In a slice playtest, 38% of tide-turn reloads were cells evicted in the previous 60 seconds.`, + }, + { + at: '2026-01-05T12:00:00Z', + type: 'Invalidate', + findingId: 'fnd-pool-thrash', + targetId: 'dec-pool-lru', + }, + { + at: '2026-01-08T10:00:00Z', + key: 'fnd-pool-sim', + type: 'WriteFinding', + kind: 'simulation', + created_by: KENJI, + derives_from: ['fnd-pool-thrash'], + title: 'Simulated forecast eviction cuts reloads by 63%', + body: `Kenji Arakawa simulated an eviction policy that scores cells by distance from the player and by the tide forecast. Over 50 simulated tide cycles, it cuts reloads by 63% against LRU.`, + }, + { + at: '2026-01-12T10:00:00Z', + key: 'dec-pool-forecast', + type: 'WriteDecision', + created_by: KENJI, + derives_from: ['fnd-pool-thrash', 'fnd-pool-sim'], + supersedes: ['dec-pool-lru'], + title: 'Evict cells by distance and tide forecast', + body: `Score each resident cell by distance from the nearest player and by how soon the tide forecast needs it. Evict the lowest score first. Cells the tide will expose within one turn are never evicted.`, + }, + { + at: '2026-01-14T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-pool-forecast', + }, + { + at: '2026-02-02T10:00:00Z', + key: 'rsk-pool-cut', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'high', + created_by: DARA, + derives_from: ['con-pool-1'], + title: 'Ports may need to shrink the streaming pool for Skiff', + body: `Skiff has the smallest memory of the three platforms, and every system's budget is still provisional. If the Skiff total shrinks, the 2.0 GB streaming pool is the largest single budget and the likeliest to be cut.`, + }, + { + at: '2026-03-03T15:00:00Z', + key: 'blob-pool-occupancy', + type: 'WriteBlob', + kind: 'json', + created_by: KENJI, + title: 'Streaming pool occupancy, alpha playtest', + body: JSON.stringify( + { + capture: 'pool-occupancy-0303', + sessions: 12, + hours: 19.5, + pool_gb: 2.0, + mean_occupancy_gb: 1.71, + peak_occupancy_gb: 1.98, + reloads: { lru_replay: 4120, forecast: 3214, reduction: 0.22 }, + player_reversals_per_min: 3.4, + evicted_then_reloaded_within_60s: 0.19, + }, + null, + 2 + ), + }, + { + at: '2026-03-03T15:10:00Z', + key: 'cit-pool-occupancy', + type: 'WriteCitation', + role: 'evidence', + blob: 'blob-pool-occupancy', + created_by: KENJI, + title: 'Pool occupancy capture pool-occupancy-0303', + body: 'https://perf.tidewater.internal/kestrel/pool/pool-occupancy-0303.json', + }, + { + at: '2026-03-04T10:00:00Z', + key: 'fnd-pool-field', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['fnd-pool-sim', 'dec-pool-forecast'], + cites: ['cit-pool-occupancy'], + title: 'Field captures show forecast eviction cuts reloads by 22%, not 63%', + body: `Kenji Arakawa captured pool behaviour across twelve alpha playtest sessions and replayed the same sessions under LRU for comparison. Forecast eviction is better, but nowhere near the simulation's figure: it cuts reloads by 22%, not 63%. + +The tide half of the score works as designed. No cell the tide exposed had to reload during a turn. The distance half is the problem. Each resident cell is scored by straight-line distance from the nearest player, and players do not move like that. + +The simulation assumed players walk in straight lines toward a goal. Real players double back to pick up salvage, look at caustics, or wait for a friend, so a cell evicted for being behind the player is often needed again a minute later. In the field captures, players reversed direction 3.4 times per minute on average. + +The decision stands, because 22% is still a gain and the tide protection matters most. The 63% figure should not be quoted.`, + }, + { + at: '2026-03-04T12:00:00Z', + type: 'Invalidate', + findingId: 'fnd-pool-field', + targetId: 'fnd-pool-sim', + }, + { + at: '2026-06-02T10:00:00Z', + key: 'fnd-pool-cut-notice', + type: 'WriteFinding', + kind: 'survey', + created_by: PRIYA, + derives_from: ['rsk-pool-cut'], + title: + 'Ports cut the Skiff memory total, and streaming must give back 400 MB', + body: `Priya Natarajan reports that Skiff is now a launch platform, so the world must fit the ports Constraint "Skiff memory budget", which fell from 9 GB to 8 GB in February. The ports team split the 1 GB cut across systems, and streaming's share is 400 MB.`, + }, + { + at: '2026-06-03T09:00:00Z', + type: 'SetRiskState', + riskId: 'rsk-pool-cut', + state: 'realized', + evidence: ['fnd-pool-cut-notice'], + }, + { + at: '2026-06-04T09:00:00Z', + key: 'con-pool-draft', + type: 'WriteConstraint', + kind: 'hard', + created_by: KENJI, + title: 'Streaming pool budget (draft)', + body: `Draft: streaming pool at most 1.8 GB on every platform.`, + }, + { + at: '2026-06-04T10:00:00Z', + type: 'Retract', + recordId: 'con-pool-draft', + reason: 'Draft figure written before the ports team set the final cut.', + }, + { + at: '2026-06-04T11:00:00Z', + key: 'con-pool-2', + type: 'WriteConstraint', + kind: 'hard', + created_by: KENJI, + derives_from: ['fnd-pool-cut-notice'], + supersedes: ['con-pool-1'], + title: 'Streaming pool budget', + body: `The streaming pool may use at most 1.6 GB on every platform, down from 2.0 GB. The reason is the ports Constraint "Skiff memory budget", which fell from 9 GB to 8 GB in February and now binds the world because Skiff became a launch platform; streaming's share of that cut is 400 MB. One budget for all platforms keeps content tuning in one place, so PC and Meridian take the same 1.6 GB. + +How the 400 MB comes back: Kenji Arakawa lowers texture mip residency in the outer ring, compacts audio banks per cell, and drops navigation detail for cells the player cannot reach until the tide falls. + +The forecast eviction policy keeps tide-exposed cells resident, so the cut falls on cells behind the player. Expect more reloads when players double back. + +Of the 400 MB, texture mips give back 260 MB, audio banks 90 MB, and navigation 50 MB.`, + }, + { + at: '2026-07-10T10:00:00Z', + key: 'fnd-pool-tideband', + type: 'WriteFinding', + kind: 'measurement', + created_by: KENJI, + derives_from: ['con-pool-2', 'dec-tide-harmonic'], + title: 'Tide-band cells need 320 MB resident during a spring tide turn', + body: `With the second harmonic, a spring tide exposes up to 11 coastal cells at once. Keeping them resident through the turn needs 320 MB of the pool. Without a reservation, forecast eviction pushes out cells near the player to make room.`, + }, + { + at: '2026-07-15T10:00:00Z', + key: 'con-pool-3', + type: 'WriteConstraint', + kind: 'hard', + created_by: KENJI, + derives_from: ['fnd-pool-tideband', 'con-pool-2'], + supersedes: ['con-pool-2'], + title: 'Streaming pool budget', + body: `The streaming pool may use at most 1.6 GB on every platform. Of that, 320 MB is reserved for tide-band cells during a tide turn; outside a turn the reservation is free for any cell. The total is unchanged from the June cut.`, + }, +]; diff --git a/benchmarks/proof-recall/spec/world/save.mjs b/benchmarks/proof-recall/spec/world/save.mjs new file mode 100644 index 00000000..d7726e1c --- /dev/null +++ b/benchmarks/proof-recall/spec/world/save.mjs @@ -0,0 +1,320 @@ +// Thread 6: save system format and versioning across tide states. +const RHEA = 'Rhea Valdés'; +const MARTA = 'Marta Lindqvist'; +const DARA = 'Dara Whitlock'; + +export default [ + { + at: '2025-12-01T10:00:00Z', + key: 'iss-save-format', + type: 'WriteIssue', + kind: 'question', + created_by: MARTA, + title: 'How should save games store the changing world?', + body: `A save must restore everything players changed: dug sand, moved salvage, opened ruins, and the tide itself. The world is large and the tide reshapes it, so the save format decides both save size and what a reload looks like.`, + }, + { + at: '2025-12-04T10:00:00Z', + key: 'fnd-save-snapshot-size', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['iss-save-format'], + title: 'A full world snapshot save is 310 MB', + body: `Serializing every entity and the terrain height field of the slice map produces a 310 MB save that takes 4.2 s to write on Skiff. Players changed less than 1% of that data.`, + }, + { + at: '2025-12-05T10:00:00Z', + key: 'dec-save-snapshot', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['iss-save-format', 'fnd-save-snapshot-size'], + title: 'Save full world snapshots', + body: `Write the whole world state into each save. Simple, and a load needs no baseline data. Size can be cut later with compression.`, + }, + { + at: '2025-12-05T11:00:00Z', + key: 'dec-save-delta', + type: 'WriteDecision', + created_by: MARTA, + derives_from: ['iss-save-format', 'fnd-save-snapshot-size'], + title: 'Save player changes as deltas against the tide-free baseline', + body: `Save only what players changed, as deltas against the shipped world with the tide removed. Loading applies the deltas to the baseline, then runs the tide forward to the saved time. Saves shrink to a few hundred kilobytes.`, + }, + { + at: '2025-12-10T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-save-delta', + }, + { + at: '2025-12-10T10:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-save-format', + resolution: 'resolved', + resolvedBy: ['dec-save-delta'], + }, + { + at: '2026-02-18T10:00:00Z', + key: 'fnd-save-tide-mismatch', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['dec-save-delta'], + title: 'Deltas saved at low tide replay wrongly at high tide', + body: `The delta format assumes that a player change means the same thing at any tide. It does not. A player who digs out a salvage chest at low tide changes sand that only exists at low tide. The delta stores the dig against the tide-free baseline, where that sand has a different height. + +On load, the game applies the delta to the baseline and then runs the tide forward to the saved time. The tide rebuilds the sand on top of the dig, and the chest is buried again or pushed sideways by the terrain solver. + +QA reproduced this in 31 of 50 saves taken at low tide and 4 of 50 taken at high tide. Saves taken mid-turn were not tested. + +In the worst case the terrain solver pushed a salvage chest 11 m inland, onto a ridge the player could not reach.`, + }, + { + at: '2026-02-18T12:00:00Z', + type: 'Invalidate', + findingId: 'fnd-save-tide-mismatch', + targetId: 'dec-save-delta', + }, + { + at: '2026-02-19T10:00:00Z', + key: 'iss-save-tide', + type: 'WriteIssue', + kind: 'defect', + created_by: MARTA, + derives_from: ['fnd-save-tide-mismatch'], + title: 'Loaded saves misplace objects the tide moved', + body: `Objects players moved in tide-dependent terrain reappear buried or shifted after a reload. Repro rate is 62% for saves taken at low tide.`, + }, + { + at: '2026-02-24T10:00:00Z', + key: 'dec-save-delta-2', + type: 'WriteDecision', + created_by: MARTA, + derives_from: ['fnd-save-tide-mismatch', 'dec-tide-fixed'], + supersedes: ['dec-save-delta'], + title: 'Save player changes as deltas keyed to the tide phase', + body: `Store each delta together with the 32.32 tide phase at which it was made. On load, the tide runs to each delta's phase before that delta applies, so a dig made at low tide lands in low-tide sand. Because the tide is deterministic, replaying to a phase gives the same terrain every time.`, + }, + { + at: '2026-02-26T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-save-delta-2', + }, + { + at: '2026-02-26T09:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-save-tide', + resolution: 'resolved', + resolvedBy: ['dec-save-delta-2'], + }, + { + at: '2026-03-10T10:00:00Z', + key: 'con-save-compat', + type: 'WriteConstraint', + kind: 'hard', + created_by: DARA, + title: 'Saves from beta onward must load in every later build', + body: `Beta players keep their progress into launch. Any save written by the beta build (2026-06-01) or later must load in every later build, including the release candidate and patches.`, + }, + { + at: '2026-03-11T10:00:00Z', + key: 'fnd-save-upgrade-cost', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['dec-save-delta-2'], + title: 'Each save upgrade step costs under 5 ms', + body: `A prototype upgrade step that renames one delta field runs in 3 ms on a 2-hour test save. Marta Lindqvist expects every step to cost under 5 ms, so a chain of upgrades is free at load time.`, + }, + { + at: '2026-03-12T10:00:00Z', + key: 'dec-save-version', + type: 'WriteDecision', + created_by: MARTA, + derives_from: [ + 'con-save-compat', + 'dec-save-delta-2', + 'fnd-save-upgrade-cost', + ], + title: + 'Stamp each save with a schema version and upgrade it step by step on load', + body: `Every save header carries a schema version number. Each format change adds one upgrade step that converts version N to N+1. On load, the game runs every step from the save's version to the current one, in order, before applying deltas. + +Rules for steps: a step is a pure function of the old save; it never reads the current world data; and a step is never edited or deleted once a build that writes its input version has shipped to players. + +Tide state is part of the versioned format. A change to the tide simulation's state, such as a new phase value, needs its own upgrade step that fills the new value for old saves. + +The version counter starts at 1 with this decision. Each upgrade step must be covered by a golden save from the build that wrote its input version, kept in the save test corpus.`, + }, + { + at: '2026-03-13T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-save-version', + }, + { + at: '2026-03-14T10:00:00Z', + key: 'rsk-save-size', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'low', + created_by: MARTA, + derives_from: ['dec-save-delta-2'], + title: 'Delta saves may outgrow console save slots', + body: `Tide-keyed deltas never merge, because two changes at different tide phases cannot collapse into one. A long game could accumulate tens of thousands of deltas.`, + }, + { + at: '2026-04-28T10:00:00Z', + key: 'rsk-save-midturn', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'high', + created_by: MARTA, + derives_from: ['dec-save-delta-2'], + title: 'Saving during a tide turn may record a half-applied tide', + body: `The tide applies terrain changes over several frames during a turn. An autosave in that window could record deltas against terrain that is half old and half new.`, + }, + { + at: '2026-05-05T10:00:00Z', + key: 'fnd-save-midturn', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['rsk-save-midturn'], + title: '3 of 200 saves taken mid-turn fail to load', + body: `QA forced 200 autosaves during tide turns. Three fail to load: the terrain solver rejects a delta whose height lies between the old and new tide surfaces.`, + }, + { + at: '2026-05-05T12:00:00Z', + type: 'SetRiskState', + riskId: 'rsk-save-midturn', + state: 'realized', + evidence: ['fnd-save-midturn'], + }, + { + at: '2026-05-08T10:00:00Z', + key: 'dec-save-defer-turn', + type: 'WriteDecision', + created_by: MARTA, + derives_from: ['fnd-save-midturn'], + title: 'Delay autosaves until the tide turn finishes', + body: `An autosave requested during a tide turn waits until the turn's terrain changes finish, at most 40 seconds. Manual saves show a short "the tide is turning" notice and wait the same way.`, + }, + { + at: '2026-05-08T14:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-save-defer-turn', + }, + { + at: '2026-05-18T15:00:00Z', + key: 'blob-save-sizes', + type: 'WriteBlob', + kind: 'csv', + created_by: MARTA, + title: 'Delta save sizes by hours played', + body: `hours_played,delta_count,save_mb,load_s_skiff +2,1840,0.4,0.6 +10,9120,1.6,1.1 +20,17900,3.1,1.7 +40,35400,6.2,2.9 +80,69800,12.3,5.4 +`, + }, + { + at: '2026-05-18T15:10:00Z', + key: 'cit-save-sizes', + type: 'WriteCitation', + role: 'evidence', + blob: 'blob-save-sizes', + created_by: MARTA, + title: 'Save size sweep from the playtest save corpus', + body: 'https://perf.tidewater.internal/kestrel/saves/size-sweep-0518.csv', + }, + { + at: '2026-05-20T10:00:00Z', + key: 'fnd-save-size', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['rsk-save-size'], + cites: ['cit-save-sizes'], + title: 'Delta saves reach 6.2 MB after 40 hours', + body: `Across the playtest save corpus, delta saves grow linearly, about 0.15 MB per hour. A 40-hour save is 6.2 MB. Every platform's save slot allows far more than that, so size is not a problem for any realistic playthrough. The sweep also lists load times on Skiff.`, + }, + { + at: '2026-05-20T12:00:00Z', + type: 'SetRiskState', + riskId: 'rsk-save-size', + state: 'accepted', + evidence: ['fnd-save-size'], + }, + { + at: '2026-05-25T10:00:00Z', + key: 'iss-save-cloud', + type: 'WriteIssue', + kind: 'gap', + created_by: DARA, + title: 'Cross-platform cloud saves are unplanned', + body: `Players will ask to continue a PC save on Skiff. Nothing in the save design covers cloud sync or conflict handling between platforms.`, + }, + { + at: '2026-06-02T10:00:00Z', + key: 'fnd-save-cloud-scope', + type: 'WriteFinding', + kind: 'survey', + created_by: DARA, + derives_from: ['iss-save-cloud'], + title: 'Cross-platform cloud saves need platform agreements we do not have', + body: `Each platform holder must approve cross-platform save transfer, and none of the three agreements is in place. Dara Whitlock moves cloud saves to a post-launch patch.`, + }, + { + at: '2026-06-02T11:00:00Z', + type: 'ResolveIssue', + issueId: 'iss-save-cloud', + resolution: 'deferred', + resolvedBy: ['fnd-save-cloud-scope'], + }, + { + at: '2026-07-14T10:00:00Z', + key: 'iss-blk-save-harmonic', + type: 'WriteIssue', + kind: 'blocker', + created_by: MARTA, + derives_from: ['dec-tide-harmonic', 'con-save-compat'], + title: "Beta saves lack the second tide harmonic's phase", + body: `The second tide harmonic adds a phase value to the tide state. Beta saves do not have it, and every tide-keyed delta in them was made against a one-harmonic tide. Loading a beta save in the current build replays the deltas against different terrain. Beta saves must load, so this blocks the release candidate.`, + }, + { + at: '2026-07-17T10:00:00Z', + key: 'dec-save-harmonic-clock', + type: 'WriteDecision', + created_by: MARTA, + derives_from: ['iss-blk-save-harmonic', 'dec-save-version'], + title: "Derive the missing harmonic phase from each save's world clock", + body: `Add an upgrade step that computes the second harmonic's phase from the save's world clock, as if the harmonic had always existed, and replays each delta against the two-harmonic tide. Deltas made on a sand bar that the new tide never exposes are dropped and listed in the save log.`, + }, + { + at: '2026-07-17T11:00:00Z', + key: 'dec-save-harmonic-zero', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['iss-blk-save-harmonic'], + title: 'Start the second harmonic at zero phase for beta saves', + body: `Set the second harmonic's phase to zero for beta saves, so the harmonic adds nothing at load and grows in over the next cycle. Deltas replay against the tide they were made on. The tide in an upgraded save then differs from a fresh game's tide for up to seven cycles.`, + }, + { + at: '2026-07-20T10:00:00Z', + key: 'fnd-save-upgrade-real', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['fnd-save-upgrade-cost', 'dec-save-version'], + title: 'A 40-hour save takes 1.9 s to upgrade through six steps', + body: `The 5 ms estimate came from a 2-hour save with a field rename. Real steps rewrite every delta, and a 40-hour save holds 35,400 of them. Upgrading such a save through the six steps written so far takes 1.9 s on Skiff, on top of the 2.9 s load.`, + }, + { + at: '2026-07-20T12:00:00Z', + type: 'Invalidate', + findingId: 'fnd-save-upgrade-real', + targetId: 'fnd-save-upgrade-cost', + }, +]; diff --git a/benchmarks/proof-recall/spec/world/tides.mjs b/benchmarks/proof-recall/spec/world/tides.mjs new file mode 100644 index 00000000..d8f85355 --- /dev/null +++ b/benchmarks/proof-recall/spec/world/tides.mjs @@ -0,0 +1,323 @@ +// Thread 4: tide simulation determinism (WORLD.md fact 1). +const RHEA = 'Rhea Valdés'; +const MARTA = 'Marta Lindqvist'; +const SOFIA = 'Sofia Marchetti'; +const DARA = 'Dara Whitlock'; + +export default [ + { + at: '2025-10-08T10:00:00Z', + key: 'iss-tide-desync', + type: 'WriteIssue', + kind: 'defect', + created_by: SOFIA, + title: 'Tide heights differ between co-op peers', + body: `In a two-player session, one player walked across a sand path that the other player saw under water. Sofia Marchetti logged both machines' tide heights: they agree at session start and differ later. Co-op cannot ship if peers disagree about which ground is walkable.`, + }, + { + at: '2025-10-10T10:00:00Z', + key: 'fnd-tide-drift-1', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['iss-tide-desync'], + title: 'Float tide heights drift apart between PCs after 18 minutes', + body: `Marta Lindqvist ran the same tide simulation on two PCs with different CPUs and the same binary. Heights match to the bit for the first minutes, then drift: the difference passes 1 cm, enough to flip a walkable tile, after 18 minutes. The likely cause is differing vector code paths in the math library.`, + }, + { + at: '2025-10-20T10:00:00Z', + key: 'fnd-tide-drift-2', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['iss-tide-desync'], + supersedes: ['fnd-tide-drift-1'], + title: + 'Float tide heights drift apart between PC and Meridian within 9 minutes', + body: `Across platforms the drift comes sooner. PC against Meridian passes 1 cm within 9 minutes. The Meridian compiler contracts multiply-adds into fused instructions, which round differently from the PC build.`, + }, + { + at: '2025-10-28T15:00:00Z', + key: 'blob-tide-drift', + type: 'WriteBlob', + kind: 'json', + created_by: MARTA, + title: 'Tide drift log: PC, Meridian, and Skiff over 6 minutes', + body: JSON.stringify( + { + capture: 'tide-drift-1028', + threshold_cm: 1.0, + pairs: [ + { + pair: 'PC vs Meridian', + first_over_threshold_min: 8.7, + max_delta_cm_at_6_min: 0.4, + }, + { + pair: 'PC vs Skiff', + first_over_threshold_min: 5.6, + max_delta_cm_at_6_min: 3.8, + }, + { + pair: 'Meridian vs Skiff', + first_over_threshold_min: 5.9, + max_delta_cm_at_6_min: 2.9, + }, + ], + first_walkable_flip: { + pair: 'PC vs Skiff', + tile: [212, 87], + minute: 5.8, + }, + suspected_causes: [ + 'fused multiply-add contraction', + 'sin() differs by 1 ulp on Skiff', + ], + }, + null, + 2 + ), + }, + { + at: '2025-10-28T15:10:00Z', + key: 'cit-tide-drift', + type: 'WriteCitation', + role: 'evidence', + blob: 'blob-tide-drift', + created_by: MARTA, + title: 'Tide drift log tide-drift-1028', + body: 'https://perf.tidewater.internal/kestrel/tide/tide-drift-1028.json', + }, + { + at: '2025-10-29T10:00:00Z', + key: 'fnd-tide-drift-3', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['iss-tide-desync'], + supersedes: ['fnd-tide-drift-2'], + cites: ['cit-tide-drift'], + title: 'Float tides drift apart between machines within 6 minutes', + body: `With Skiff in the mix, float tides drift apart between machines within 6 minutes. The worst pair is PC against Skiff, which passes the 1 cm threshold first. Two causes stack: fused multiply-add contraction, and a Skiff sin() that differs by one ulp. Any co-op session longer than 6 minutes will disagree about walkable ground. The per-pair numbers and the first tile to flip are in the drift log.`, + }, + { + at: '2025-10-29T14:00:00Z', + key: 'fnd-tide-drift-dup', + type: 'WriteFinding', + kind: 'measurement', + created_by: SOFIA, + derives_from: ['iss-tide-desync'], + title: 'Float tides drift apart between machines within six minutes', + body: `Copied from the netcode channel: tides drift within six minutes across machines.`, + }, + { + at: '2025-10-30T09:00:00Z', + type: 'Retract', + recordId: 'fnd-tide-drift-dup', + reason: + "Duplicate of Marta Lindqvist's measurement, copied from the netcode channel.", + }, + { + at: '2025-10-30T10:00:00Z', + key: 'iss-tide-math', + type: 'WriteIssue', + kind: 'question', + created_by: RHEA, + derives_from: ['fnd-tide-drift-3'], + title: 'How do we make the tide simulation deterministic across machines?', + body: `Peers must agree on every tide height for the whole 90-minute day. Pick the approach before co-op work builds on the tide state.`, + }, + { + at: '2025-10-31T10:00:00Z', + key: 'con-tide-bitexact', + type: 'WriteConstraint', + kind: 'hard', + created_by: RHEA, + derives_from: ['fnd-tide-drift-3'], + title: 'Tide state must be bit-identical on every peer', + body: `Given the same inputs, every machine must produce the same tide state bit for bit, on PC, Meridian, and Skiff, for an entire session. Close enough is not enough: a 1 cm difference flips walkable ground.`, + }, + { + at: '2025-11-02T10:00:00Z', + key: 'dec-tide-fixed', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['iss-tide-math', 'fnd-tide-drift-3', 'con-tide-bitexact'], + title: 'Run the tide simulation in 32.32 fixed point', + body: `Run the whole tide simulation in 32.32 fixed-point arithmetic: 32 integer bits and 32 fraction bits in a signed 64-bit value. Integer adds and multiplies give the same bits on every CPU and compiler, so the drift that float tides show within 6 minutes cannot happen. + +Scope: tide phase, wave height field, and the walkability mask derived from it. Rendering reads the result and converts to float, so Lantern is unaffected. Physics reads the walkability mask only. + +Trigonometry uses a 4,096-entry sine table in fixed point with linear interpolation, generated at build time and checked into the repository, so no platform math library is involved. + +The tide simulation steps at 10 Hz and the renderer interpolates between steps. Co-op peers exchange only inputs; they never send tide heights.`, + }, + { + at: '2025-11-02T11:00:00Z', + key: 'dec-tide-strict', + type: 'WriteDecision', + created_by: MARTA, + derives_from: ['iss-tide-math'], + title: 'Force strict IEEE float mode for the tide simulation', + body: `Compile the tide simulation with strict floating point: no fused multiply-add contraction and no reassociation. This keeps the float code and needs only compiler flags.`, + }, + { + at: '2025-11-02T12:00:00Z', + key: 'dec-tide-host', + type: 'WriteDecision', + created_by: SOFIA, + derives_from: ['iss-tide-math'], + title: 'Have the host stream tide heights to every peer', + body: `Only the host simulates tides; peers receive the height field over the network. Determinism stops mattering because there is one source of truth.`, + }, + { + at: '2025-11-04T10:00:00Z', + key: 'fnd-tide-strict-test', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['dec-tide-strict'], + title: + "Strict float mode still diverges because Skiff's sin() differs by one ulp", + body: `With strict flags on every platform, PC against Meridian now matches for 2 hours. PC against Skiff still drifts past 1 cm at minute 11, because Skiff's math library returns a sin() that differs by one ulp for some inputs. Strict mode fixes the compiler, not the library.`, + }, + { + at: '2025-11-04T14:00:00Z', + key: 'fnd-tide-host-bw', + type: 'WriteFinding', + kind: 'measurement', + created_by: SOFIA, + derives_from: ['dec-tide-host'], + title: 'Streaming tide heights costs 46 KB/s per peer', + body: `A compressed tide height field for the area around each player costs 46 KB/s per peer at 10 updates a second. The co-op bandwidth target is 16 KB/s per peer for everything, so host streaming is out by a factor of three before any gameplay traffic.`, + }, + { + at: '2025-11-07T10:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-tide-fixed', + }, + { + at: '2025-11-07T10:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-tide-math', + resolution: 'resolved', + resolvedBy: ['dec-tide-fixed'], + }, + { + at: '2025-11-10T10:00:00Z', + key: 'rsk-tide-overflow', + type: 'WriteRisk', + likelihood: 'low', + severity: 'high', + created_by: RHEA, + derives_from: ['dec-tide-fixed'], + title: 'The fixed-point tide phase may overflow in long sessions', + body: `The tide phase accumulates every step. With 32 integer bits, a phase counted in milliseconds overflows after about 24 days of play, and a phase counted in microseconds after 36 minutes. A bad unit choice anywhere in the accumulation would wrap mid-session.`, + }, + { + at: '2025-11-12T10:00:00Z', + key: 'dec-tide-wrap', + type: 'WriteDecision', + created_by: RHEA, + derives_from: ['rsk-tide-overflow', 'dec-tide-fixed'], + title: 'Wrap the tide phase accumulator at each 40-minute cycle', + body: `Store the tide phase as a fraction of the 40-minute cycle and wrap it to zero at each cycle boundary. The accumulator then never holds more than one cycle and cannot overflow.`, + }, + { + at: '2025-11-13T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-tide-wrap', + }, + { + at: '2025-11-13T09:05:00Z', + type: 'MitigateRisk', + riskId: 'rsk-tide-overflow', + decisionId: 'dec-tide-wrap', + }, + { + at: '2025-12-02T10:00:00Z', + key: 'fnd-tide-fixed-skiff', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['dec-tide-fixed'], + title: 'Fixed-point tide step costs 0.9 ms on Skiff', + body: `One fixed-point tide step costs 0.9 ms on Skiff, against 0.4 ms for the old float step. Most of the extra time is 64-bit multiplies in the wave height field.`, + }, + { + at: '2025-12-02T11:00:00Z', + key: 'fnd-tide-fixed-meridian', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['dec-tide-fixed'], + title: 'Fixed-point tide step costs 0.3 ms on Meridian', + body: `One fixed-point tide step costs 0.3 ms on Meridian, against 0.2 ms for the float step. Meridian's wider multiplier hides most of the cost.`, + }, + { + at: '2025-12-03T10:00:00Z', + key: 'fnd-tide-fixed-verify', + type: 'WriteFinding', + kind: 'measurement', + created_by: MARTA, + derives_from: ['dec-tide-fixed', 'iss-tide-desync'], + title: + 'Fixed-point tides match bit for bit across all platforms for 4 hours', + body: `A soak test ran the fixed-point tide simulation on PC, Meridian, and Skiff side by side for 4 hours, almost three full days of game time. Every tide state hash matched on every step.`, + }, + { + at: '2025-12-03T11:00:00Z', + type: 'ResolveIssue', + issueId: 'iss-tide-desync', + resolution: 'resolved', + resolvedBy: ['fnd-tide-fixed-verify', 'dec-tide-fixed'], + }, + { + at: '2025-12-05T10:00:00Z', + key: 'rsk-tide-skiff-cost', + type: 'WriteRisk', + likelihood: 'medium', + severity: 'medium', + created_by: MARTA, + derives_from: ['fnd-tide-fixed-skiff'], + title: 'Fixed-point tides may crowd the Skiff simulation budget', + body: `At 0.9 ms per step, the tide costs more than twice its float price on Skiff. If other simulation work grows, the tide step could push frames over budget.`, + }, + { + at: '2025-12-09T10:00:00Z', + type: 'SetRiskState', + riskId: 'rsk-tide-skiff-cost', + state: 'accepted', + evidence: ['fnd-tide-fixed-skiff'], + }, + { + at: '2026-06-29T10:00:00Z', + key: 'iss-tide-flat', + type: 'WriteIssue', + kind: 'gap', + created_by: DARA, + title: 'Tides feel identical every cycle', + body: `Beta playtesters report that every tide looks the same. Design wants spring and neap tides: some cycles reach higher and lower than others, so some paths open only on rare low tides.`, + }, + { + at: '2026-07-06T10:00:00Z', + key: 'dec-tide-harmonic', + type: 'WriteDecision', + created_by: MARTA, + derives_from: ['iss-tide-flat', 'dec-tide-fixed'], + title: 'Add a second tide harmonic for spring and neap tides', + body: `Add a second harmonic with a period of seven 40-minute cycles to the fixed-point tide simulation. The tide state gains one more 32.32 phase value. The sine table is reused, so determinism holds.`, + }, + { + at: '2026-07-08T09:00:00Z', + type: 'AcceptDecision', + decisionId: 'dec-tide-harmonic', + }, + { + at: '2026-07-08T09:05:00Z', + type: 'ResolveIssue', + issueId: 'iss-tide-flat', + resolution: 'resolved', + resolvedBy: ['dec-tide-harmonic'], + }, +]; diff --git a/docs/positioning.md b/docs/positioning.md index 4b04ae42..27a1102b 100644 --- a/docs/positioning.md +++ b/docs/positioning.md @@ -23,8 +23,8 @@ Citations, and Blobs against it. Each record is a markdown file under `.flatbread-proof/`, so it is committed, diffed, reviewed, and reverted like source. Writes go through `flatbread proof write`; reads come back as bounded digests from `flatbread proof list`, `flatbread proof records`, -`flatbread proof relations`, `flatbread proof blocking-decisions`, and -`flatbread proof get`. +`flatbread proof relations`, `flatbread proof blocking-decisions`, +`flatbread proof brief`, and `flatbread proof get`. That solves a plain problem: an agent that closes its session forgets why it chose what it chose. Putting the reasoning in the repository keeps it next to diff --git a/packages/flatbread/bin/flatbread.js b/packages/flatbread/bin/flatbread.js index f15cbe41..6bdd1889 100755 --- a/packages/flatbread/bin/flatbread.js +++ b/packages/flatbread/bin/flatbread.js @@ -1,6 +1,7 @@ #!/usr/bin/env node import { dirname, resolve } from 'path'; import { existsSync } from 'fs'; +import { request } from 'http'; import { fileURLToPath } from 'url'; const cliPath = resolve( @@ -8,16 +9,73 @@ const cliPath = resolve( '../dist/cli/index.js' ); -// In CI, skip the import when dist is not built yet so the process -// does not throw before `pnpm build`. Check the file next to this -// bin, not `cwd/node_modules/flatbread`, because spawned tests and -// user projects run with a different working directory. -if (process.env.FLATBREAD_CI) { - if (existsSync(cliPath)) { - import('../dist/cli/index.js'); +function loadCli() { + // In CI, skip the import when dist is not built yet so the process + // does not throw before `pnpm build`. Check the file next to this + // bin, not `cwd/node_modules/flatbread`, because spawned tests and + // user projects run with a different working directory. + if (process.env.FLATBREAD_CI) { + if (existsSync(cliPath)) { + import('../dist/cli/index.js'); + } else { + console.log("Flatbread's CLI is not available"); + } } else { - console.log("Flatbread's CLI is not available"); + import('../dist/cli/index.js'); } -} else { - import('../dist/cli/index.js'); } + +// Reads `flatbread proof serve` answers. Keep in step with SERVED_READS in +// src/cli/serve.ts; anything else, writes included, runs locally. +const SERVED_READS = new Set([ + 'list', + 'records', + 'get', + 'relations', + 'blocking-decisions', + 'brief', +]); + +/** + * With FLATBREAD_PROOF_SERVER set to a `proof serve` socket, forward a read + * there before loading the CLI bundle, so the graph is not rebuilt per call. + * If the server cannot be reached, run the read locally instead. + */ +function forwardRead(socketPath, argv) { + const body = JSON.stringify({ argv, cwd: process.cwd() }); + const req = request( + { + socketPath, + path: '/read', + method: 'POST', + headers: { + 'content-type': 'application/json', + 'content-length': Buffer.byteLength(body), + }, + }, + (res) => { + let text = ''; + res.setEncoding('utf8'); + res.on('data', (chunk) => (text += chunk)); + res.on('end', () => { + let reply; + try { + reply = JSON.parse(text); + } catch { + return loadCli(); + } + process.stdout.write(reply.stdout ?? ''); + process.stderr.write(reply.stderr ?? ''); + process.exitCode = reply.code ?? 1; + }); + } + ); + req.on('error', () => loadCli()); + req.end(body); +} + +const [, , group, command] = process.argv; +const server = process.env.FLATBREAD_PROOF_SERVER; +if (server && group === 'proof' && SERVED_READS.has(command)) + forwardRead(server, process.argv.slice(3)); +else loadCli(); diff --git a/packages/flatbread/src/cli/index.ts b/packages/flatbread/src/cli/index.ts index 49d5f7f0..b5dbce75 100644 --- a/packages/flatbread/src/cli/index.ts +++ b/packages/flatbread/src/cli/index.ts @@ -8,6 +8,7 @@ import orchestrateProcesses from './runner'; import initConfig from './initConfig'; import { createCodegenCommand } from '@flatbread/codegen'; import { registerProofCommands } from './proof'; +import { registerProofServe } from './serve'; import { EXPLORER_ENDPOINT, GRAPHQL_ENDPOINT, @@ -138,6 +139,7 @@ prog }); registerProofCommands(prog); +registerProofServe(prog); prog.parse(process.argv, { unknown: (arg) => `Unknown option: ${arg}` }); diff --git a/packages/flatbread/src/cli/proof.test.ts b/packages/flatbread/src/cli/proof.test.ts index 7a0dbb27..6c817dcb 100644 --- a/packages/flatbread/src/cli/proof.test.ts +++ b/packages/flatbread/src/cli/proof.test.ts @@ -27,6 +27,7 @@ import { handleEffortGet, handleEffortList, handleEffortRecords, + handleEffortBrief, handleEffortRelations, handleEffortWrite, inspectEffortBootstrap, @@ -1367,7 +1368,7 @@ export default { source: source(), transformer: transformer(), content: proofCon ); test.serial( - 'Retract drops a record from browse reads and keeps get', + 'Retract hides a record from default browse reads, keeps get, and lists it, marked, on request', async (t) => { const cwd = await createTempProject('flatbread-effort-retract-', t); for (const directory of [ @@ -1446,6 +1447,41 @@ export default { const gotDigest = await readFile(got.artifact_path, 'utf8'); t.true(gotDigest.includes('retracted: true')); t.true(gotDigest.includes('temporary review note')); + t.true(gotDigest.includes('> **RETRACTED** on ')); + t.true(gotDigest.includes(': session noise; not a turning point.')); + // Retracted records can be listed on request, always marked as such. + const only = await handleEffortRecords(effortId, { + cwd, + kinds: ['finding', 'decision'], + retracted: 'only', + strictMinGeneration: retracted.generation, + }); + const onlyDigest = await readFile(only.artifact_path, 'utf8'); + t.is(only.page.returned, 1); + t.regex(only.summary, /retracted 1/); + t.true( + onlyDigest.includes(`- [\`${findingId}\`](#${findingId}) (retracted)`) + ); + t.true(onlyDigest.includes('This record is not live.')); + t.false(onlyDigest.includes(decisionId)); + const both = await handleEffortRecords(effortId, { + cwd, + kinds: ['finding', 'decision'], + retracted: 'include', + strictMinGeneration: retracted.generation, + }); + const bothDigest = await readFile(both.artifact_path, 'utf8'); + t.is(both.page.returned, 2); + t.true(bothDigest.includes(`- [\`${decisionId}\`](#${decisionId})\n`)); + t.is(bothDigest.split('> **RETRACTED**').length - 1, 1); + t.not(both.artifact_path, listed.artifact_path); + await t.throwsAsync( + handleEffortRecords(effortId, { + cwd, + retracted: 'hidden' as never, + }), + { message: /Invalid retracted mode: hidden/ } + ); const neighbors = await handleEffortRelations(effortId, decisionId, { cwd, relations: ['derives_from'], @@ -1532,3 +1568,149 @@ export default { source: source(), transformer: transformer(), content: proofCon t.true(reopenedText.includes(id)); } ); + +test.serial( + 'brief reports the head compaction, its changes, and staleness', + async (t) => { + const cwd = await createTempProject('flatbread-effort-brief-', t); + await writeFile( + join(cwd, 'flatbread.config.js'), + `import { source } from '@flatbread/source-filesystem'; +import { transformer } from '@flatbread/transformer-markdown'; +import { proofContent } from '@flatbread/proof'; +export default { + source: source(), + transformer: transformer(), + content: proofContent('.flatbread-proof'), +};` + ); + const write = async (payload: Record<string, unknown>) => + handleEffortWrite(JSON.stringify(payload), { cwd }); + const effortId = ( + await write({ type: 'CreateEffort', title: 'Brief', body: '' }) + ).artifacts[0].id; + const decisionId = ( + await write({ + type: 'WriteDecision', + effort: effortId, + title: 'Pick the index', + body: 'Use the sorted index.', + }) + ).artifacts[0].id; + + const empty = await handleEffortBrief(effortId, { cwd }); + t.deepEqual(empty.compaction, { + head_id: null, + heads: 0, + stale: false, + changes: 1, + recompact: true, + }); + + const citationId = ( + await write({ + type: 'WriteCitation', + effort: effortId, + title: 'Index benchmark', + body: 'https://example.com/benchmark', + }) + ).artifacts[0].id; + const first = await write({ + type: 'WriteCompaction', + effort: effortId, + title: 'Index choice pending', + body: 'One proposed Decision: the sorted index.', + // A Citation is never live, so it must not read as a moved target. + derives_from: [decisionId, citationId], + }); + const firstId = first.artifacts[0].id; + const fresh = await handleEffortBrief(effortId, { + cwd, + strictMinGeneration: first.generation, + }); + t.deepEqual(fresh.compaction, { + head_id: firstId, + heads: 1, + stale: false, + changes: 0, + recompact: false, + }); + const freshDigest = await readFile(fresh.artifact_path, 'utf8'); + t.true(freshDigest.includes('One proposed Decision: the sorted index.')); + t.false(freshDigest.includes('covers')); + + const accepted = await write({ + type: 'AcceptDecision', + decisionId, + }); + const stale = await handleEffortBrief(effortId, { + cwd, + strictMinGeneration: accepted.generation, + }); + t.like(stale.compaction, { head_id: firstId, stale: true, changes: 1 }); + t.true(stale.compaction?.recompact); + const staleDigest = await readFile(stale.artifact_path, 'utf8'); + t.true( + staleDigest.includes( + `- changed | ${decisionId} | decision | proposed -> accepted | Pick the index` + ) + ); + t.true(staleDigest.includes('## Stale derivations')); + + const second = await write({ + type: 'WriteCompaction', + effort: effortId, + title: 'Index chosen', + body: 'Accepted: the sorted index.', + derives_from: [decisionId], + }); + const secondId = second.artifacts[0].id; + t.deepEqual( + second.touched.map((touched) => touched.id).sort(), + [firstId, secondId].sort() + ); + const result = await runCli( + cwd, + 'proof', + 'brief', + effortId, + '--strict-min-generation', + second.generation + ); + t.is(result.code, 0, result.stderr); + const renewed = JSON.parse(result.stdout); + t.like(renewed.compaction, { + head_id: secondId, + heads: 1, + stale: false, + changes: 0, + recompact: false, + }); + const renewedDigest = await readFile(renewed.artifact_path, 'utf8'); + t.true(renewedDigest.includes('## Lineage checkpoints')); + t.true(renewedDigest.includes(`${firstId} | Index choice pending`)); + t.false(renewedDigest.includes('One proposed Decision')); + + const head = await handleEffortGet(firstId, { + cwd, + resolve: 'head', + strictMinGeneration: second.generation, + }); + t.true( + (await readFile(head.artifact_path, 'utf8')).includes( + 'Accepted: the sorted index.' + ) + ); + + await t.throwsAsync( + write({ + type: 'WriteFinding', + effort: effortId, + title: 'Hand-made', + body: '', + kind: 'compaction', + }), + { message: /WriteCompaction/ } + ); + } +); diff --git a/packages/flatbread/src/cli/proof.ts b/packages/flatbread/src/cli/proof.ts index 0a36f595..0e51cfd5 100644 --- a/packages/flatbread/src/cli/proof.ts +++ b/packages/flatbread/src/cli/proof.ts @@ -14,10 +14,12 @@ import { } from '@flatbread/proof'; import { blockingDecisions, + effortBrief, effortRecords, relations, getRecord, listEfforts, + type RetractedMode, } from '../proof/read.js'; import type { PrimitiveKind, ReadRelation } from '@flatbread/proof'; import { handleEffortInstallSkill } from './installSkill.js'; @@ -36,6 +38,7 @@ export interface EffortCliOptions { limit?: number; cursor?: string; relations?: string[]; + retracted?: RetractedMode; verify?: boolean; dryRun?: boolean; } @@ -67,6 +70,10 @@ export function mapEffortCliOptions( limit: numberOption(options.limit), cursor: typeof options.cursor === 'string' ? options.cursor : undefined, relations: split(options.relations), + retracted: + typeof options.retracted === 'string' + ? (options.retracted as RetractedMode) + : undefined, verify: options.verify === true ? true : undefined, dryRun: options['dry-run'] === true || options.dryRun === true @@ -199,6 +206,7 @@ export async function handleEffortRecords( ? { created_at: { gte: options.since, lte: options.until } } : {}), }, + retracted: options.retracted, page: { limit: options.limit, cursor: options.cursor }, }); } @@ -237,6 +245,19 @@ export async function handleEffortBlockingDecisions( }); } +export async function handleEffortBrief( + effortId: string, + options: EffortCliOptions = {} +): Promise<ReadEnvelope> { + const cwd = options.cwd ?? process.cwd(); + return effortBrief(effortId, { + cwd, + rootDir: await rootFor(cwd), + cacheRoot: resolve(cwd, '.flatbread/proof'), + consistency: consistency(options), + }); +} + export interface EffortBootstrapReport { readonly status: 'ready' | 'action_required'; readonly config_path: string | null; @@ -412,35 +433,32 @@ function validateLimit(limit: number | undefined): void { ); } +/** The JSON a failed Proof command prints on stderr. */ +export function errorPayload(error: unknown): unknown { + if ( + error !== null && + typeof error === 'object' && + 'shape' in error && + typeof (error as { shape: unknown }).shape === 'object' && + (error as { shape: unknown }).shape !== null + ) + return (error as { shape: unknown }).shape; + if (error instanceof Error) { + try { + return JSON.parse(error.message); + } catch { + return { error: { code: 'PROOF_CLI_ERROR', message: error.message } }; + } + } + return { error: { code: 'PROOF_CLI_ERROR', message: String(error) } }; +} + export function registerProofCommands(prog: any): void { - const hasShape = ( - value: unknown - ): value is { shape: Record<string, unknown> } => { - if (value === null || typeof value !== 'object' || !('shape' in value)) - return false; - const candidate = value as { shape: unknown }; - return typeof candidate.shape === 'object' && candidate.shape !== null; - }; const printResult = async (result: Promise<unknown>): Promise<void> => { try { console.log(JSON.stringify(await result)); } catch (error) { - let payload: unknown; - if (hasShape(error)) payload = error.shape; - else if (error instanceof Error) { - try { - payload = JSON.parse(error.message); - } catch { - payload = { - error: { code: 'PROOF_CLI_ERROR', message: error.message }, - }; - } - } else { - payload = { - error: { code: 'PROOF_CLI_ERROR', message: String(error) }, - }; - } - console.error(JSON.stringify(payload)); + console.error(JSON.stringify(errorPayload(error))); process.exitCode = 1; } }; @@ -477,6 +495,19 @@ export function registerProofCommands(prog: any): void { handleEffortBlockingDecisions(effortId, mapEffortCliOptions(options)) ) ); + prog + .command( + 'proof brief <effortId>', + 'Read where an Effort stands: its head compaction and what changed since' + ) + .option( + '--strict-min-generation <token>', + 'Require a durable journal generation' + ) + .option('--timeout-ms <ms>', 'Strict-read wait timeout') + .action(async (effortId: string, options: Record<string, unknown>) => + printResult(handleEffortBrief(effortId, mapEffortCliOptions(options))) + ); const consistencyOptions = (command: any) => command .option( @@ -497,6 +528,10 @@ export function registerProofCommands(prog: any): void { .option('--kind <values>', 'Comma-separated record kinds') .option('--since <iso>', 'Created-at lower bound') .option('--until <iso>', 'Created-at upper bound') + .option( + '--retracted <mode>', + 'exclude (default), include, or only retracted records' + ) ); recordsOptions( prog.command('proof records <effortId>', 'Read records in an Effort') diff --git a/packages/flatbread/src/cli/serve.test.ts b/packages/flatbread/src/cli/serve.test.ts new file mode 100644 index 00000000..ff7c7812 --- /dev/null +++ b/packages/flatbread/src/cli/serve.test.ts @@ -0,0 +1,182 @@ +import test from 'ava'; +import { spawn } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; +import { + lstat, + mkdtemp, + readdir, + readFile, + rm, + symlink, + unlink, + writeFile, +} from 'node:fs/promises'; +import { join } from 'node:path'; +import { tmpdir } from 'node:os'; +import { handleEffortWrite } from './proof.js'; +import { runRead, serveProofReads } from './serve.js'; + +const repositoryNodeModules = fileURLToPath( + new URL('../../../../node_modules/', import.meta.url) +); + +async function createProject(t: { + teardown(callback: () => void | Promise<void>): void; +}): Promise<string> { + const cwd = await mkdtemp(join(tmpdir(), 'flatbread-serve-')); + const nodeModules = join(cwd, 'node_modules'); + await symlink(repositoryNodeModules, nodeModules, 'junction'); + t.teardown(async () => { + if ((await lstat(nodeModules).catch(() => null))?.isSymbolicLink()) + await unlink(nodeModules); + await rm(cwd, { recursive: true, force: true }); + }); + await writeFile( + join(cwd, 'flatbread.config.js'), + `import { source } from '@flatbread/source-filesystem'; +import { transformer } from '@flatbread/transformer-markdown'; +import { proofContent } from '@flatbread/proof'; +export default { + source: source(), + transformer: transformer(), + content: proofContent('.flatbread-proof'), +};` + ); + return cwd; +} + +function runCli( + cwd: string, + env: Record<string, string>, + ...args: string[] +): Promise<{ code: number | null; stdout: string; stderr: string }> { + return new Promise((resolve, reject) => { + const child = spawn( + process.execPath, + [ + '--no-deprecation', + fileURLToPath(new URL('../../bin/flatbread.js', import.meta.url)), + ...args, + ], + { cwd, env: { ...process.env, ...env } } + ); + let stdout = ''; + let stderr = ''; + child.stdout.on('data', (chunk) => (stdout += chunk)); + child.stderr.on('data', (chunk) => (stderr += chunk)); + child.on('error', reject); + child.on('close', (code) => resolve({ code, stdout, stderr })); + }); +} + +test.serial( + 'proof serve answers reads like the CLI, keeps writes local, and sees new writes', + async (t) => { + const cwd = await createProject(t); + const effort = await handleEffortWrite( + JSON.stringify({ type: 'CreateEffort', title: 'E', body: '' }), + { cwd } + ); + const effortId = effort.artifacts[0].id; + await handleEffortWrite( + JSON.stringify({ + type: 'WriteFinding', + effort: effortId, + title: 'First', + body: 'one', + kind: 'measurement', + }), + { cwd } + ); + const socket = join(cwd, '.flatbread/proof/serve.sock'); + const server = await serveProofReads(socket); + t.teardown(() => new Promise((done) => server.close(() => done()))); + const served = { FLATBREAD_PROOF_SERVER: socket }; + + // A served read prints what a local read prints. + const local = await runCli(cwd, {}, 'proof', 'records', effortId); + const remote = await runCli(cwd, served, 'proof', 'records', effortId); + t.is(remote.code, 0); + t.deepEqual(JSON.parse(remote.stdout), JSON.parse(local.stdout)); + t.regex(JSON.parse(remote.stdout).summary, /^1 record/); + + // Writes never go to the server, and the next served read sees them. + const write = await runCli( + cwd, + served, + 'proof', + 'write', + JSON.stringify({ + type: 'WriteFinding', + effort: effortId, + title: 'Second', + body: 'two', + kind: 'measurement', + }) + ); + t.is(write.code, 0, write.stderr); + const after = await runCli(cwd, served, 'proof', 'records', effortId); + t.regex(JSON.parse(after.stdout).summary, /^2 records/); + + // A record changed outside the writer, as a pull or checkout does, also + // reaches the next served read, though the journal generation stays put. + const copied = join(cwd, '.flatbread-proof', 'findings', 'pulled.md'); + const [firstFinding] = ( + await readdir(join(cwd, '.flatbread-proof', 'findings')) + ).sort(); + const text = await readFile( + join(cwd, '.flatbread-proof', 'findings', firstFinding), + 'utf8' + ); + const pulledId = 'fnd-pulled-from-a-teammate--0123456789abcdef'; + await writeFile( + copied, + text + .replace(/^id: .*$/m, `id: ${pulledId}`) + .replace(/^title: .*$/m, 'title: Pulled') + ); + const pulled = await runCli(cwd, served, 'proof', 'records', effortId); + t.regex(JSON.parse(pulled.stdout).summary, /^3 records/); + + // Errors keep the CLI's JSON shape and exit code. + const bad = await runCli(cwd, served, 'proof', 'records'); + t.is(bad.code, 1); + t.is(JSON.parse(bad.stderr).error.code, 'PROOF_INVALID_ARGUMENT'); + const badLimit = await runCli(cwd, served, 'proof', 'list', '--limit', '0'); + t.is(badLimit.code, 1); + t.is(JSON.parse(badLimit.stderr).error.code, 'PROOF_INVALID_ARGUMENT'); + + // A second server cannot take the socket from a live one. + await t.throwsAsync(serveProofReads(socket), { + message: /already answers on/, + }); + + // The server itself refuses anything but a read. + const refused = await runRead(['write', '{}'], cwd); + t.is(refused.code, 1); + t.is( + JSON.parse(refused.stderr).error.message, + 'The read server does not serve "proof write"' + ); + } +); + +test.serial( + 'reads fall back to the local CLI when the server is unreachable', + async (t) => { + const cwd = await createProject(t); + const effort = await handleEffortWrite( + JSON.stringify({ type: 'CreateEffort', title: 'E', body: '' }), + { cwd } + ); + const result = await runCli( + cwd, + { FLATBREAD_PROOF_SERVER: join(cwd, 'missing.sock') }, + 'proof', + 'records', + effort.artifacts[0].id + ); + t.is(result.code, 0, result.stderr); + t.regex(JSON.parse(result.stdout).summary, /^0 records/); + } +); diff --git a/packages/flatbread/src/cli/serve.ts b/packages/flatbread/src/cli/serve.ts new file mode 100644 index 00000000..7783f811 --- /dev/null +++ b/packages/flatbread/src/cli/serve.ts @@ -0,0 +1,195 @@ +import { createServer, request, type Server } from 'node:http'; +import { existsSync } from 'node:fs'; +import { mkdir, rm } from 'node:fs/promises'; +import { dirname, resolve } from 'node:path'; +import { ProofReadValidationError } from '@flatbread/proof'; +import { enableProjectionCache } from '../proof/read.js'; +import { + errorPayload, + handleEffortBlockingDecisions, + handleEffortBrief, + handleEffortGet, + handleEffortList, + handleEffortRecords, + handleEffortRelations, + mapEffortCliOptions, +} from './proof.js'; + +/** + * The commands a read server answers, with how many positional arguments + * each takes. Nothing that writes is here: the server is read-only by + * construction. `bin/flatbread.js` keeps its own copy of these names, so it + * can forward a read without loading this bundle. + */ +export const SERVED_READS: Readonly<Record<string, number>> = { + list: 0, + records: 1, + get: 1, + relations: 2, + 'blocking-decisions': 1, + brief: 1, +}; + +/** What the server sends back: what the CLI would print, and its exit code. */ +export interface ServedRead { + readonly stdout: string; + readonly stderr: string; + readonly code: number; +} + +/** True when something answers HTTP on `socketPath`. */ +function answers(socketPath: string): Promise<boolean> { + return new Promise((resolveAnswer) => { + const probe = request( + { socketPath, path: '/', method: 'GET' }, + (response) => { + response.resume(); + resolveAnswer(true); + } + ); + probe.on('error', () => resolveAnswer(false)); + probe.setTimeout(2000, () => { + probe.destroy(); + resolveAnswer(false); + }); + probe.end(); + }); +} + +function invalid(message: string): never { + throw new ProofReadValidationError('PROOF_INVALID_ARGUMENT', message); +} + +/** Splits `proof <command> …` arguments into positionals and `--name value` options. */ +export function parseReadArgs(argv: readonly string[]): { + command: string; + positional: string[]; + options: Record<string, string>; +} { + const [command, ...rest] = argv; + if (!command || !(command in SERVED_READS)) + invalid(`The read server does not serve "proof ${command ?? ''}"`); + const positional: string[] = []; + const options: Record<string, string> = {}; + for (let i = 0; i < rest.length; i++) { + const arg = rest[i]; + if (!arg.startsWith('--')) { + positional.push(arg); + continue; + } + const eq = arg.indexOf('='); + if (eq > 0) options[arg.slice(2, eq)] = arg.slice(eq + 1); + else if (i + 1 < rest.length) options[arg.slice(2)] = rest[++i]; + else invalid(`Option ${arg} needs a value`); + } + if (positional.length !== SERVED_READS[command]) + invalid( + `proof ${command} takes ${SERVED_READS[command]} argument(s), got ${positional.length}` + ); + return { command, positional, options }; +} + +/** Runs one read as the CLI would in `cwd`. */ +export async function runRead( + argv: readonly string[], + cwd: string +): Promise<ServedRead> { + try { + const { command, positional, options } = parseReadArgs(argv); + const mapped = { ...mapEffortCliOptions(options), cwd }; + const [first, second] = positional; + const result = + command === 'list' + ? await handleEffortList(mapped) + : command === 'records' + ? await handleEffortRecords(first, mapped) + : command === 'get' + ? await handleEffortGet(first, mapped) + : command === 'relations' + ? await handleEffortRelations(first, second, mapped) + : command === 'blocking-decisions' + ? await handleEffortBlockingDecisions(first, mapped) + : await handleEffortBrief(first, mapped); + return { stdout: `${JSON.stringify(result)}\n`, stderr: '', code: 0 }; + } catch (error) { + return { + stdout: '', + stderr: `${JSON.stringify(errorPayload(error))}\n`, + code: 1, + }; + } +} + +/** + * Serves Proof reads over HTTP on a Unix socket, keeping each graph built in + * memory between requests. A request is `POST /read` with + * `{"argv": ["records", "<effortId>", "--kinds", "decision"], "cwd": "…"}`; + * digests are written under that `cwd`, as a local read would write them. + */ +export async function serveProofReads(socketPath: string): Promise<Server> { + enableProjectionCache(); + await mkdir(dirname(socketPath), { recursive: true }); + if (existsSync(socketPath)) { + // Replacing the socket file would strand a live server, still running + // but unreachable. Only a socket nothing answers on is taken over. + if (await answers(socketPath)) + throw new Error(`A proof serve already answers on ${socketPath}`); + await rm(socketPath); + } + const server = createServer((request, response) => { + const reply = (status: number, body: ServedRead) => { + response.writeHead(status, { 'content-type': 'application/json' }); + response.end(JSON.stringify(body)); + }; + if (request.method !== 'POST' || request.url !== '/read') + return reply(404, { + stdout: '', + stderr: + '{"error":{"code":"PROOF_CLI_ERROR","message":"Only POST /read is served"}}\n', + code: 1, + }); + let body = ''; + request.setEncoding('utf8'); + request.on('data', (chunk) => (body += chunk)); + request.on('end', async () => { + let input: { argv?: unknown; cwd?: unknown }; + try { + input = JSON.parse(body); + } catch { + input = {}; + } + if ( + !Array.isArray(input.argv) || + !input.argv.every((arg) => typeof arg === 'string') || + typeof input.cwd !== 'string' + ) + return reply(400, { + stdout: '', + stderr: + '{"error":{"code":"PROOF_CLI_ERROR","message":"Expected {argv: string[], cwd: string}"}}\n', + code: 1, + }); + reply(200, await runRead(input.argv as string[], input.cwd)); + }); + }); + await new Promise<void>((resolveListen, rejectListen) => { + server.once('error', rejectListen); + server.listen(socketPath, () => resolveListen()); + }); + return server; +} + +/** Registers `flatbread proof serve`. */ +export function registerProofServe(prog: any): void { + prog + .command( + 'proof serve', + 'Serve Proof reads from memory on a Unix socket; read-only' + ) + .option('--socket <path>', 'Socket path', '.flatbread/proof/serve.sock') + .action(async (options: Record<string, unknown>) => { + const socket = resolve(String(options.socket)); + await serveProofReads(socket); + console.log(JSON.stringify({ serving: socket, reads: 'read-only' })); + }); +} diff --git a/packages/flatbread/src/proof/read.ts b/packages/flatbread/src/proof/read.ts index b5331f3a..5eba5d10 100644 --- a/packages/flatbread/src/proof/read.ts +++ b/packages/flatbread/src/proof/read.ts @@ -1,6 +1,14 @@ import { FlatbreadProvider, type LoadedFlatbreadConfig } from '@flatbread/core'; import { canonicalizeReadQuery, + compactionChanges, + compactionHeads, + parseCovers, + RECOMPACT_CHANGE_THRESHOLD, + staleDerivations, + type CompactionChange, + type CompactionStatus, + type DigestSection, ProofConsistencyError, ProofCrossEffortRelationError, ProofDanglingRelationError, @@ -17,7 +25,9 @@ import { type PrimitiveKind, } from '@flatbread/proof'; import { loadConfig } from '@flatbread/config'; -import { relative, resolve } from 'node:path'; +import { createHash } from 'node:crypto'; +import { readdir, realpath, stat } from 'node:fs/promises'; +import { join, relative, resolve } from 'node:path'; export interface EffortProjectionOptions { readonly cwd: string; @@ -85,6 +95,8 @@ const FRONTMATTER_FIELDS = [ 'mitigated_by', 'evidence', 'cites', + // Read by `brief`; digests never print it. + 'covers', ] as const; const RELATION_FIELDS = new Set([ 'derives_from', @@ -384,6 +396,7 @@ class EngineProjection { 'resolved_by', 'evidence', 'role', + 'covers', ...((available.has('_content') ? ['_content { raw }'] : []) as string[]), ].filter((field) => available.has(field.split(' ', 1)[0])); for (const relation of [ @@ -423,7 +436,7 @@ class EngineProjection { } } -async function makeProjection( +async function loadProjection( options: EffortProjectionOptions ): Promise<EngineProjection> { const loaded = await loadConfig({ cwd: options.cwd }); @@ -431,6 +444,65 @@ async function makeProjection( return new EngineProjection(configForCwd(loaded.config, options.cwd)); } +// Off by default: each CLI call builds the graph once and exits. A +// long-lived read server turns it on, so later reads skip the build. +let projectionCache: Map<string, Promise<EngineProjection>> | undefined; + +/** + * Keeps built graphs in memory for the life of the process. Entries are keyed + * by the graph root's real path and a fingerprint of its record files, so + * callers in different folders that link to one graph share it, and any + * change to a record file makes the next read build it again. The journal + * generation alone is not enough: it lives in a gitignored folder, and a + * pull, merge, or checkout changes records without bumping it. + */ +export function enableProjectionCache(): void { + projectionCache ??= new Map(); +} + +/** + * A hash of every record file's path, size, and modification time under + * `root`. Statting a few thousand files takes milliseconds, far less than + * rebuilding the graph. + */ +async function recordFingerprint(root: string): Promise<string> { + const hash = createHash('sha256'); + const walk = async (dir: string): Promise<void> => { + const entries = await readdir(dir, { withFileTypes: true }).catch(() => []); + entries.sort((a, b) => a.name.localeCompare(b.name)); + for (const entry of entries) { + if (entry.name === '.journal') continue; + const path = join(dir, entry.name); + if (entry.isDirectory()) await walk(path); + else if (entry.name.endsWith('.md')) { + const info = await stat(path).catch(() => null); + if (info) hash.update(`${path}\0${info.size}\0${info.mtimeMs}\n`); + } + } + }; + await walk(root); + return hash.digest('hex'); +} + +async function makeProjection( + options: EffortProjectionOptions +): Promise<EngineProjection> { + if (!projectionCache) return loadProjection(options); + const root = await realpath(options.rootDir).catch(() => options.rootDir); + const key = `${root}\0${await generation(root)}\0${await recordFingerprint( + root + )}`; + let projection = projectionCache.get(key); + if (!projection) { + for (const stale of [...projectionCache.keys()]) + if (stale.startsWith(`${root}\0`)) projectionCache.delete(stale); + projection = loadProjection(options); + projection.catch(() => projectionCache?.delete(key)); + projectionCache.set(key, projection); + } + return projection; +} + async function render( options: EffortProjectionOptions, query: Record<string, unknown>, @@ -442,6 +514,8 @@ async function render( anomaly?: string; relatedRecords?: ReadRecord[]; fullBody?: boolean; + sections?: DigestSection[]; + compaction?: CompactionStatus; } = {} ): Promise<ReadEnvelope> { const served = await servedGeneration(options.rootDir, options.consistency); @@ -587,6 +661,18 @@ export async function getRecord( ); } +/** + * Which records a browse read returns by retraction: live ones only (the + * default), live and retracted together, or retracted ones only. Digests mark + * every retracted record, so it cannot pass for a live one. + */ +export type RetractedMode = 'exclude' | 'include' | 'only'; +const RETRACTED_MODES: readonly RetractedMode[] = [ + 'exclude', + 'include', + 'only', +]; + export async function effortRecords( effortId: string, options: EffortProjectionOptions & { @@ -597,9 +683,18 @@ export async function effortRecords( kind?: string[]; created_at?: { gte?: string; lte?: string }; }; + retracted?: RetractedMode; page?: { cursor?: string; limit?: number }; } ): Promise<ReadEnvelope> { + const retracted = options.retracted ?? 'exclude'; + if (!RETRACTED_MODES.includes(retracted)) + throw new ProofReadValidationError( + 'PROOF_INVALID_ARGUMENT', + `Invalid retracted mode: ${String( + retracted + )}. Expected exclude, include, or only.` + ); const projection = await makeProjection(options); const kinds = options.kinds?.length ? [...new Set(options.kinds)].sort() @@ -635,7 +730,9 @@ export async function effortRecords( .flat() .filter( (record) => - record.frontmatter.effort === effortId && !isRetracted(record) + record.frontmatter.effort === effortId && + (retracted === 'include' || + (retracted === 'only') === isRetracted(record)) ) ); return render( @@ -645,6 +742,8 @@ export async function effortRecords( effort_id: effortId, kinds, ...(Object.keys(where).length ? { where } : {}), + // Left out by default, so existing queries keep their hashes. + ...(retracted === 'exclude' ? {} : { retracted }), page: options.page, }, records, @@ -836,3 +935,181 @@ export async function blockingDecisions( { relatedRecords: issues } ); } + +// Citations and Blobs are never live records, but `derives_from` may name +// them, so `brief` loads them to check whether those targets moved. +const BRIEF_COLLECTIONS: readonly Collection[] = [ + 'Issue', + 'Finding', + 'Decision', + 'Constraint', + 'Risk', + 'Citation', + 'Blob', +]; +const BRIEF_LINE_LIMIT = 50; +const BRIEF_CHECKPOINT_LIMIT = 5; + +/** Relation fields join the frontmatter so standing reads one flat map. */ +function standingRecord(record: ReadRecord) { + return { + id: record.id, + kind: record.kind, + frontmatter: { ...record.frontmatter, ...record.relations }, + }; +} + +function changeLines(changes: readonly CompactionChange[]): string[] { + const lines = changes + .slice(0, BRIEF_LINE_LIMIT) + .map( + (change) => + `- ${change.change} | ${change.id} | ${change.kind ?? 'unknown'} | ${ + change.from ?? 'none' + } -> ${change.to ?? 'missing'} | ${change.title}` + ); + if (changes.length > BRIEF_LINE_LIMIT) + lines.push( + `- … ${changes.length - BRIEF_LINE_LIMIT} more; write a new compaction` + ); + return lines; +} + +/** + * Where an Effort stands, in one bounded read: the head compaction in full, + * older compactions as one-line checkpoints, and each record whose standing + * moved since the head's `covers` snapshot. Nothing here is generated; every + * line comes from stored records, so the digest is deterministic. + */ +export async function effortBrief( + effortId: string, + options: EffortProjectionOptions +): Promise<ReadEnvelope> { + const projection = await makeProjection(options); + if (!(await projection.one('Effort', effortId))) + throw new ProofReadValidationError( + 'PROOF_INVALID_ARGUMENT', + `Effort ${effortId} does not exist` + ); + const records = ( + await Promise.all( + BRIEF_COLLECTIONS.map((collection) => projection.query(collection)) + ) + ) + .flat() + .filter((record) => record.frontmatter.effort === effortId); + const byId = new Map(records.map((record) => [record.id, record])); + const standing = records.map(standingRecord); + const heads = sortRecords( + compactionHeads(standing).map((head) => byId.get(head.id) as ReadRecord) + ); + const head = heads.at(-1); + const sections: DigestSection[] = []; + const checkpoints: string[] = []; + const anomalies: string[] = []; + let changes: CompactionChange[]; + let stale: CompactionChange[] = []; + let invalidated = false; + if (!head) { + changes = compactionChanges(new Map(), standing); + sections.push({ + heading: 'Live records (no compaction yet)', + lines: changeLines(changes), + }); + } else { + const covers = parseCovers(head.frontmatter.covers); + changes = compactionChanges(covers, standing); + stale = staleDerivations( + covers, + head.relations.derives_from ?? [], + standing + ); + invalidated = (head.relations.invalidated_by ?? []).length > 0; + if (heads.length > 1) + anomalies.push( + `compaction fork: ${heads.length} head compactions; the next WriteCompaction supersedes all of them` + ); + if (invalidated) anomalies.push('head compaction was invalidated'); + // Walk `supersedes` back from the head. Bodies stay out: one line each. + const ancestors = new Map<string, ReadRecord>(); + const queue = [...(head.relations.supersedes ?? [])]; + while (queue.length) { + const id = queue.shift() as string; + const ancestor = byId.get(id); + if (!ancestor || ancestors.has(id)) continue; + ancestors.set(id, ancestor); + queue.push(...(ancestor.relations.supersedes ?? [])); + } + const lineage = sortRecords([...ancestors.values()]).reverse(); + checkpoints.push( + ...lineage + .slice(0, BRIEF_CHECKPOINT_LIMIT) + .map( + (record) => + `${record.id} | ${String( + record.frontmatter.title ?? '' + )} | ${String( + record.frontmatter.created_at ?? '' + )} | superseded_by ${(record.relations.superseded_by ?? []).join( + ', ' + )}` + ) + ); + if (lineage.length > BRIEF_CHECKPOINT_LIMIT) + checkpoints.push( + `… ${lineage.length - BRIEF_CHECKPOINT_LIMIT} older compactions` + ); + sections.push({ + heading: 'Changes since compaction', + lines: changes.length ? changeLines(changes) : ['- none'], + }); + if (stale.length) + sections.push({ + heading: 'Stale derivations', + lines: changeLines(stale), + }); + } + const compaction: CompactionStatus = { + head_id: head?.id ?? null, + heads: heads.length, + stale: stale.length > 0 || invalidated, + changes: changes.length, + recompact: + !head || + heads.length > 1 || + stale.length > 0 || + invalidated || + changes.length >= RECOMPACT_CHANGE_THRESHOLD, + }; + const edges: ReadEdge[] = head + ? (['derives_from', 'supersedes', 'cites'] as const).flatMap((relation) => + (head.relations[relation] ?? []).map((to_id) => ({ + from_id: head.id, + relation, + to_id, + })) + ) + : []; + const changedIds = [...stale, ...changes] + .filter((change) => change.to !== null) + .map((change) => `getRecord("${change.id}")`); + return render( + options, + { type: 'effortBrief', effort_id: effortId }, + head ? [head] : [], + edges, + [ + ...(head + ? [`relations("${effortId}", "${head.id}", ["derives_from"])`] + : [`effortRecords("${effortId}")`]), + ...new Set(changedIds), + ], + { + checkpointLines: checkpoints, + anomaly: anomalies.length ? anomalies.join('; ') : undefined, + fullBody: true, + sections, + compaction, + } + ); +} diff --git a/packages/proof/README.md b/packages/proof/README.md index 6ee56861..99166a5e 100644 --- a/packages/proof/README.md +++ b/packages/proof/README.md @@ -146,14 +146,16 @@ An agent resuming work follows the same bounded loop each time. `flatbread proof records <effortId> --kinds issue,decision --limit 10` summarizes its state, and `flatbread proof blocking-decisions <effortId>` narrows to proposed - Decisions that derive from open blocker Issues. + Decisions that derive from open blocker Issues. When an Effort has a + compaction, `flatbread proof brief <effortId>` gives its current account + and every record that changed since, in one digest. 2. **Zoom in only when needed.** Browse digests excerpt record bodies. Read one full body with `flatbread proof get <id>`, or follow a superseded record to its current head with `flatbread proof get <id> --resolve head`. Reads cap at 25 primary records, one relation hop, 50 displayed edges, and a 64 KiB digest; check `complete`, `page.has_more`, and `cap_reasons` in the envelope before treating a digest as the whole story. -3. **Write only durable knowledge.** All 17 typed mutations go through one +3. **Write only durable knowledge.** All 18 typed mutations go through one command: `flatbread proof write '<json>'`. Before a create or a body edit adds a claim, the packaged skill applies a four-part gate — future need, durable effect, causal value, and unique signal — and writes only when @@ -164,7 +166,11 @@ An agent resuming work follows the same bounded loop each time. `--strict-min-generation <generation>` to get data at or after that generation; Proof waits up to 3000 ms by default, then fails with `PROOF_GENERATION_WAIT_TIMEOUT`. Do not build a polling loop. -5. **Close the loop.** Use lifecycle mutations when the team commits to a +5. **Compact when `brief` asks.** When `brief` reports + `compaction.recompact: true`, write a fresh account of the Effort with + `WriteCompaction`. The writer records which records were live and + supersedes the previous compaction, so older accounts stay one read away. +6. **Close the loop.** Use lifecycle mutations when the team commits to a choice or resolves an Issue. `AcceptDecision` rejects only proposed Decisions tied to the same `question` Issue, even after it closes. Pass `rejects` to name other alternatives and `dryRun: true` to preview the changes. Its result @@ -229,12 +235,13 @@ service; your normal Git workflow decides when records are shared. | Read one full record | `flatbread proof get <id>` | | Follow selected links | `flatbread proof relations <effortId> <fromId> --relations <names>` | | Find choices tied to blockers | `flatbread proof blocking-decisions <effortId>` | +| See where an Effort stands | `flatbread proof brief <effortId>` | | Apply a typed mutation | `flatbread proof write '<json>'` | | Prune old derived digests | `flatbread proof cache prune` | Every command prints one JSON object to standard output; errors print JSON to standard error and exit with status 1. The -[full API reference](./skills/proof/reference.md) lists all 17 mutations, +[full API reference](./skills/proof/reference.md) lists all 18 mutations, read flags, lifecycle states, relation names, paging rules, and error codes. ## Optional explorer diff --git a/packages/proof/skills/proof/SKILL.md b/packages/proof/skills/proof/SKILL.md index cfe62e0f..f4d75e3c 100644 --- a/packages/proof/skills/proof/SKILL.md +++ b/packages/proof/skills/proof/SKILL.md @@ -10,8 +10,8 @@ repository. It has eight record types: **Effort**, **Issue**, **Finding**, **Decision**, **Constraint**, and **Risk** capture the work and reasoning; **Citation** stores a source or reference; and **Blob** stores attached content such as a document, JSON, or image. Every record belongs to one -Effort. Create and update records through 17 typed mutations, and read them -through 5 bounded queries. Do not hand-edit record frontmatter, although you +Effort. Create and update records through 18 typed mutations, and read them +through 6 bounded queries. Do not hand-edit record frontmatter, although you may edit record bodies freely. Read [glossary.md](./glossary.md) for the primitive and edge semantics before @@ -78,13 +78,16 @@ reasoning: 4. **Unique signal:** Does it add a reason or link that code, docs, Git, the PR or tracker issue, and retained records do not already make clear? +`WriteCompaction` restates claims that live records already hold, so it +skips the unique-signal test. The other three tests still apply to its body. + Do not create a record or add body claims unless the information scores **4/4**. An existing or open record does not bypass this gate; appending low-value text still consumes bounded reads. Keep failed candidates in the PR, tracker issue, commit, or run artifact. Citations and Blobs persist only when they support a 4/4 record. -One command for all 17 mutations — pass the payload as a single JSON argument: +One command for all 18 mutations — pass the payload as a single JSON argument: ```bash flatbread proof write '{"type":"WriteDecision","effort":"<eff-id>","title":"...","body":"...","derives_from":["<id>"]}' @@ -94,7 +97,7 @@ flatbread proof write '{"type":"WriteDecision","effort":"<eff-id>","title":"..." For creates, **capture `artifacts[0].id`** to wire later edges. Keep the returned `generation` for strict read-your-writes. -Full payload shapes for all 17 mutations: read [reference.md](./reference.md). +Full payload shapes for all 18 mutations: read [reference.md](./reference.md). Critical semantics: - Creates always start in the initial lifecycle state: `WriteDecision` → @@ -107,8 +110,9 @@ Critical semantics: including foreign `derives_from` links, so reads do not fail closed. Use it for session noise that should never have been journaled. Do not `git rm` records or hand-edit frontmatter. `proof get` still returns a retracted - record. Efforts cannot - be retracted; abandon them instead. + record, and `proof records <effortId> --retracted only` lists an Effort's + retracted records, each marked **RETRACTED** with its date and reason. + Efforts cannot be retracted; abandon them instead. - `AcceptDecision` defaults `rejectSiblings: true`, which rejects only proposed Decisions derived from the same `question` Issue, even if the Issue is closed. Use @@ -139,6 +143,25 @@ Critical semantics: [effort-modeling](../effort-modeling/SKILL.md) when the decision is still being grilled. +### Compactions + +A compaction is a Finding that gives one short, current account of an Effort +and names the records behind it. Write one with `WriteCompaction` when +`proof brief <effortId>` reports `compaction.recompact: true`. Do not write +one after every mutation; between compactions, `brief` lists what changed. + +1. Read the live records, not the previous compaction, and write a body that + stands on its own: what is accepted, what is still open or proposed, and + which constraints and risks bind the work. +2. Put in `derives_from` only the records its sentences rest on, at most 10. + Never name another compaction there. +3. Let the writer do the rest. It records which records were live (`covers`) + and supersedes the previous compaction, so the history stays one + `--resolve head` or `brief` away. + +To correct a compaction, write a new one. Edit its body by hand only to fix +wording, or while the branch is unmerged. + ## Reading (recall) Every read returns a bounded envelope, not records: a ≤160-token `summary`, @@ -170,6 +193,9 @@ flatbread proof relations <effortId> <fromId> --relations derives_from,supersede # Single record with full body; --resolve head follows supersession to the tip flatbread proof get <id> [--resolve head] + +# Where an Effort stands: head compaction in full, then what changed since +flatbread proof brief <effortId> ``` Flags shared by reads: `--strict-min-generation <token>` (with optional @@ -195,7 +221,10 @@ server-side. `proof records <effortId> --kinds issue,decision` and read each record's status/state from that one digest. Run `proof blocking-decisions <effortId>` only for an Effort whose digest shows an open `blocker` Issue — skip it - otherwise. Do not open raw `.flatbread-proof/**/*.md` for briefing; + otherwise. When `proof brief <effortId>` returns a head compaction that is + not stale (`compaction.head_id` set, `compaction.stale` false), its digest + can stand in for the `records` read: it holds the current account and + every change since. Do not open raw `.flatbread-proof/**/*.md` for briefing; browse digests are authoritative for status/state. Budget ≈ (1 + number of active Efforts) digest reads. A 12-run experiment across three model families showed this roughly halves recall tool calls with no loss of diff --git a/packages/proof/skills/proof/glossary.md b/packages/proof/skills/proof/glossary.md index 6d805676..4ddbc0ee 100644 --- a/packages/proof/skills/proof/glossary.md +++ b/packages/proof/skills/proof/glossary.md @@ -30,6 +30,13 @@ Findings cite evidence, resolve Issues, inform Decisions, surface Risks, and may invalidate past Findings or Decisions. A retrospective Finding is evidence gathered after a decision shipped. +A **compaction** is a Finding with `kind: compaction`, written only through +`WriteCompaction`. It gives one short, current account of an Effort and links +to the records behind it through `derives_from`. Its `covers` field, set by +the writer, records which records were live and where each stood, so a later +read can list exactly what changed. Each compaction supersedes the one before +it. + ### Decision A commitment among alternatives. A proposed Decision is an active alternative; @@ -87,8 +94,9 @@ express. on disk with `retracted: true` so ids remain resolvable and `PROOF_DANGLING_RELATION` does not fire. The writer strips inbound relation ids across every Effort in one transaction, including foreign `derives_from` -references. Browse reads omit retracted records. `proof get` still returns -the body and the reason. This is not +references. Browse reads omit retracted records unless asked: +`proof records --retracted only` lists them, each marked as retracted. +`proof get` still returns the body and the reason. This is not supersession (a better same-kind claim) and not invalidation (a Finding that the target was wrong). Git is the undo path for Retract; `ReopenDecision` only returns a rejected Decision to proposed. There is no generic Restore mutation. diff --git a/packages/proof/skills/proof/reference.md b/packages/proof/skills/proof/reference.md index fdeeb436..6adf5d9d 100644 --- a/packages/proof/skills/proof/reference.md +++ b/packages/proof/skills/proof/reference.md @@ -11,7 +11,7 @@ Generated as `<prefix>-<slug>--<16-char-crockford>` with prefixes `eff`, identity. Let the writer generate ids; capture them from mutation results (`artifacts[0].id` for creates). -## The 17 mutations (`flatbread proof write '<json>'`) +## The 18 mutations (`flatbread proof write '<json>'`) Common optional fields on all creates: `id`, `created_at` (ISO with offset), `produced_in`, `created_by` (opaque provenance strings). Forward edge fields @@ -53,6 +53,48 @@ A Citation body alone is valid (commonly a URL). `blob` is optional; use it only when you need to attach stored content such as a document or JSON. When provided, `blob` must be the id of a Blob in the same Effort as the Citation. +### Compaction + +```json +{ + "type": "WriteCompaction", + "effort": "<eff-id>", + "title": "...", + "body": "...", + "derives_from": ["<id>"], + "cites": ["<cit-id>"] +} +``` + +A compaction is a Finding with `kind: compaction`: one short, current account +of where an Effort stands. Only `WriteCompaction` creates one; `WriteFinding` +rejects `kind: compaction`. The writer does two things the payload cannot: + +- It stores `covers`, a sorted list of `<id>@<standing>` entries for every + live Issue, Finding, Decision, Constraint, and Risk in the Effort, plus each + `derives_from` target. A standing is a Decision's or Risk's `state`, an + Issue's `status`, or `live` for a Finding or Constraint. `retracted`, + `superseded`, and `invalidated` take precedence over all of these. Live means + an open Issue, a proposed or accepted Decision, an open or realized Risk, + or a Finding or Constraint that nothing has superseded or invalidated. + Compactions are never live records. +- It sets `supersedes` to every head compaction (a live compaction that + nothing supersedes) and adds the new id to each head's `superseded_by`. A + Git merge can bring in two heads, one from each branch; the next + `WriteCompaction` supersedes both. + +The payload rejects `supersedes`, `invalidates`, `covers`, and `kind`. +`derives_from` holds at most 10 ids from the same Effort: the records the +body's sentences rest on. None may be another compaction; compactions link to +earlier compactions only through `supersedes`. `Supersede` can neither start +from nor target a compaction, and a compaction cannot `Invalidate` anything. +A Finding may `Invalidate` a compaction that was wrong. + +Write the body from the live records, never from the previous compaction, and +make it complete on its own. To correct a compaction, write a new one. Edit +its body by hand only to fix wording, or while the branch is unmerged: a hand +edit cannot update `covers` and does not advance `generation`. + ### Add links between existing records ```json @@ -109,7 +151,10 @@ written. It is not a hard delete and not a fold into a survivor: and strips its id from every other record across all Efforts in the same journal transaction. - Browse reads (`list`, `records`, `blocking-decisions`) omit retracted - records. `proof get` still returns them. `relations` follows stored edges + records. `proof get` still returns them, and `records --retracted include|only` lists them on request. Every digest marks a retracted + record: its index line ends in `(retracted)`, a **RETRACTED** banner with + the date and reason sits under its heading, and the envelope summary + counts `retracted N`. `relations` follows stored edges that remain; after a successful Retract, survivors should have none. - Efforts cannot be retracted. Set status to `abandoned` instead. - Later creates, `Supersede`, `Invalidate`, and lifecycle mutations reject @@ -137,7 +182,7 @@ survivor (score 4/4 if it adds claims) plus `Retract` on the rest. `generation` is a durable, monotonic journal token — the input to strict reads. -## The 5 read queries +## The 6 read queries All reads execute through Flatbread's query engine (in-process GraphQL over the generated schema) and return a `ReadEnvelope`: @@ -162,6 +207,8 @@ lists), one-hop related records, and an edge table. Body policy: - **`proof get`:** full record body (the normal zoom-in path), including Blob payloads and Citation bodies (URLs / short notes). +- **`proof brief`:** full body of the head compaction only. Every other + record appears as one line. - **`list` / `records` / `relations` / `blocking-decisions`:** body excerpt capped at 600 chars / 12 lines (`[…truncated]`). **Blob bodies are omitted** from these digests — use `proof get` for the payload. Citation bodies @@ -196,12 +243,23 @@ digest or `summary` as a data feed. ```bash flatbread proof get <id> [--resolve exact|head] [consistency flags] flatbread proof list [--status active,paused,...] [--limit n] [--cursor c] [consistency flags] -flatbread proof records <effortId> [--kinds k1,k2] [--state s1,s2] [--status s1,s2] [--kind k1,k2] [--since iso] [--until iso] [--limit n] [--cursor c] [consistency flags] +flatbread proof records <effortId> [--kinds k1,k2] [--state s1,s2] [--status s1,s2] [--kind k1,k2] [--since iso] [--until iso] [--retracted exclude|include|only] [--limit n] [--cursor c] [consistency flags] flatbread proof relations <effortId> <fromId> --relations r1,r2 [--limit n] [--cursor c] [consistency flags] flatbread proof blocking-decisions <effortId> [consistency flags] +flatbread proof brief <effortId> [consistency flags] flatbread proof cache prune +flatbread proof serve [--socket .flatbread/proof/serve.sock] ``` +- `proof serve` keeps the graph loaded in one process and answers the six + reads above (`list`, `records`, `get`, `relations`, `blocking-decisions`, + `brief`); it serves nothing that writes. Set `FLATBREAD_PROOF_SERVER` to its + socket and those read commands go to it, in any folder whose graph root + resolves to the same files. Each later read then takes a fraction of a + second instead of rebuilding the graph. A write bumps the journal + generation, and the next served read rebuilds from disk. If the socket is + unreachable, reads run locally as before. + - `--kinds`: `effort|issue|finding|decision|constraint|risk|citation|blob`. `records` includes every non-Effort kind except Blob by default. Add `--kinds blob` when you need Blob records. @@ -232,6 +290,20 @@ flatbread proof cache prune same effort with `kind: blocker` and `status: open`. For "what blockers are open at all", use `records <effortId> --kinds issue --kind blocker --status open`. +- `brief`: where an Effort stands. The digest holds the head compaction with + its full body, then up to 5 older compactions as one-line + `## Lineage checkpoints`, then `## Changes since compaction`: one line per + record that was `added` to the live set, `changed` standing, or `left` it + since `covers` was taken, written as + `- <change> | <id> | <kind> | <before> -> <now> | <title>`. + `## Stale derivations` lists `derives_from` targets whose standing moved. + With no compaction yet, `## Live records (no compaction yet)` lists every + live record instead. Digests never print `covers`. The envelope adds + `compaction`: `{"head_id","heads","stale","changes","recompact"}`. + `stale` is true when a `derives_from` target moved or a Finding invalidated + the head. `recompact` is true when there is no head, more than one head, a + stale head, or at least 5 changes. Programs read these fields, not the + digest. ### Consistency flags diff --git a/packages/proof/src/__tests__/compaction.test.ts b/packages/proof/src/__tests__/compaction.test.ts new file mode 100644 index 00000000..6172643c --- /dev/null +++ b/packages/proof/src/__tests__/compaction.test.ts @@ -0,0 +1,131 @@ +import test from 'ava'; +import { + compactionChanges, + compactionCovers, + compactionHeads, + parseCovers, + recordStanding, + staleDerivations, + type CompactionRecord, +} from '../compaction.js'; + +const suffix = '0123456789abcdef'; +const dec = `dec-choice--${suffix}`; +const dec2 = `dec-other--${suffix}`; +const iss = `iss-question--${suffix}`; +const fnd = `fnd-observation--${suffix}`; +const rsk = `rsk-hazard--${suffix}`; + +function rec( + id: string, + kind: CompactionRecord['kind'], + frontmatter: Record<string, unknown> = {} +): CompactionRecord { + return { id, kind, frontmatter: { title: id, ...frontmatter } }; +} + +test('standing puts retraction, supersession, and invalidation first', (t) => { + t.is(recordStanding(rec(dec, 'decision', { state: 'accepted' })), 'accepted'); + t.is(recordStanding(rec(iss, 'issue', { status: 'resolved' })), 'resolved'); + t.is(recordStanding(rec(fnd, 'finding')), 'live'); + t.is( + recordStanding( + rec(dec, 'decision', { state: 'accepted', invalidated_by: [fnd] }) + ), + 'invalidated' + ); + t.is( + recordStanding( + rec(fnd, 'finding', { superseded_by: [`fnd-x--${suffix}`] }) + ), + 'superseded' + ); + t.is( + recordStanding( + rec(dec, 'decision', { state: 'accepted', retracted: true }) + ), + 'retracted' + ); +}); + +test('covers holds live records only, plus derives_from targets', (t) => { + const records = [ + rec(dec, 'decision', { state: 'accepted' }), + rec(dec2, 'decision', { state: 'rejected' }), + rec(iss, 'issue', { status: 'resolved' }), + // An accepted Risk is closed even though Decisions use the same word. + rec(rsk, 'risk', { state: 'accepted' }), + rec(fnd, 'finding', { kind: 'compaction' }), + ]; + t.deepEqual(compactionCovers(records), [`${dec}@accepted`]); + t.deepEqual(compactionCovers(records, [dec2]), [ + `${dec}@accepted`, + `${dec2}@rejected`, + ]); +}); + +test('changes name added, changed, and departed records', (t) => { + const covers = parseCovers([ + `${dec}@proposed`, + `${iss}@open`, + `${dec2}@rejected`, + ]); + const now = [ + rec(dec, 'decision', { state: 'accepted' }), + rec(iss, 'issue', { status: 'resolved' }), + rec(dec2, 'decision', { state: 'rejected' }), + rec(fnd, 'finding'), + ]; + t.deepEqual( + compactionChanges(covers, now).map(({ change, id, from, to }) => ({ + change, + id, + from, + to, + })), + [ + { change: 'changed', id: dec, from: 'proposed', to: 'accepted' }, + { change: 'added', id: fnd, from: null, to: 'live' }, + { change: 'left', id: iss, from: 'open', to: 'resolved' }, + ] + ); + t.deepEqual(compactionChanges(parseCovers([`${dec}@accepted`]), []), [ + { + change: 'left', + id: dec, + kind: 'decision', + title: '', + from: 'accepted', + to: null, + }, + ]); +}); + +test('a derives_from target that moved makes the compaction stale', (t) => { + const covers = parseCovers([`${dec}@accepted`, `${dec2}@rejected`]); + const now = [ + rec(dec, 'decision', { state: 'superseded', superseded_by: [dec2] }), + rec(dec2, 'decision', { state: 'rejected' }), + ]; + t.deepEqual( + staleDerivations(covers, [dec, dec2], now).map((change) => change.id), + [dec] + ); + t.deepEqual(staleDerivations(covers, [dec2], now), []); +}); + +test('heads are live compactions nothing supersedes', (t) => { + const a = rec(`fnd-a--${suffix}`, 'finding', { kind: 'compaction' }); + const b = rec(`fnd-b--${suffix}`, 'finding', { + kind: 'compaction', + superseded_by: [a.id], + }); + const c = rec(`fnd-c--${suffix}`, 'finding', { + kind: 'compaction', + retracted: true, + }); + t.deepEqual( + compactionHeads([a, b, c, rec(fnd, 'finding')]).map((r) => r.id), + [a.id] + ); +}); diff --git a/packages/proof/src/__tests__/planner.test.ts b/packages/proof/src/__tests__/planner.test.ts index f124460b..734f9a30 100644 --- a/packages/proof/src/__tests__/planner.test.ts +++ b/packages/proof/src/__tests__/planner.test.ts @@ -1539,3 +1539,134 @@ test('Retract refuses the last live Finding when remaining Finding evidence is r { message: new RegExp(`sole closer for ${ids.risk}`) } ); }); + +function compaction( + id: string, + fm: Record<string, unknown> = {} +): ReturnType<typeof record> { + return record(id, 'finding', { + id, + effort: E, + title: 'Where it stands', + kind: 'compaction', + created_at: '2025-01-01T00:00:00.000Z', + covers: [], + ...fm, + }); +} + +test('WriteCompaction records covers and supersedes every head', (t) => { + const openIssue = record(ids.issue, 'issue', { + id: ids.issue, + effort: E, + title: 'Q', + kind: 'question', + status: 'open', + created_at: '2025-01-01T00:00:00.000Z', + }); + const accepted = record(ids.decision, 'decision', { + id: ids.decision, + effort: E, + title: 'D', + state: 'accepted', + created_at: '2025-01-01T00:00:00.000Z', + }); + const rejected = record(ids.decision2, 'decision', { + id: ids.decision2, + effort: E, + title: 'D2', + state: 'rejected', + created_at: '2025-01-01T00:00:00.000Z', + }); + const headA = compaction('fnd-head-a--0123456789abcdef'); + const headB = compaction('fnd-head-b--0123456789abcdef'); + const older = compaction('fnd-older--0123456789abcdef', { + superseded_by: [headA.id], + }); + const id = 'fnd-new-head--0000000000000000'; + const writes = planMutation( + { + type: 'WriteCompaction', + id, + effort: E, + title: 'Now', + body: 'Current account.', + derives_from: [ids.decision, ids.decision2], + }, + snap([openIssue, accepted, rejected, headA, headB, older]), + '/root', + now + ); + const created = writes.find((w) => w.id === id)!; + t.is(created.operation, 'create'); + const fm = parseDocument(created.afterBytes, 'finding').frontmatter; + t.is(fm.kind, 'compaction'); + t.deepEqual(fm.supersedes, [headA.id, headB.id]); + // Live records plus the rejected derives_from target; compactions excluded. + t.deepEqual(fm.covers, [ + `${ids.decision}@accepted`, + `${ids.decision2}@rejected`, + `${ids.issue}@open`, + ]); + for (const head of [headA, headB]) { + const update = writes.find((w) => w.id === head.id)!; + t.deepEqual( + parseDocument(update.afterBytes, 'finding').frontmatter.superseded_by, + [id] + ); + } + t.is(writes.length, 3); +}); + +test('compactions cannot be created, chained, or superseded another way', (t) => { + const head = compaction('fnd-head-a--0123456789abcdef'); + const finding = record(ids.finding, 'finding', { + id: ids.finding, + effort: E, + title: 'F', + kind: 'measurement', + created_at: '2025-01-01T00:00:00.000Z', + }); + const s = snap([head, finding]); + const attempts: ProofMutation[] = [ + { + type: 'WriteFinding', + effort: E, + title: 'X', + body: '', + kind: 'compaction', + }, + { + type: 'WriteCompaction', + effort: E, + title: 'X', + body: '', + derives_from: [head.id], + }, + { + type: 'WriteFinding', + effort: E, + title: 'X', + body: '', + kind: 'measurement', + supersedes: [head.id], + }, + { type: 'Supersede', supersederId: finding.id, targetId: head.id }, + { type: 'Supersede', supersederId: head.id, targetId: finding.id }, + { type: 'Invalidate', findingId: head.id, targetId: finding.id }, + ]; + for (const input of attempts) + t.throws( + () => planMutation(input, s, '/root', now, random), + undefined, + input.type + ); + t.notThrows(() => + planMutation( + { type: 'Invalidate', findingId: finding.id, targetId: head.id }, + s, + '/root', + now + ) + ); +}); diff --git a/packages/proof/src/__tests__/schemas.test.ts b/packages/proof/src/__tests__/schemas.test.ts index 51b21d9c..53c7cf6a 100644 --- a/packages/proof/src/__tests__/schemas.test.ts +++ b/packages/proof/src/__tests__/schemas.test.ts @@ -34,6 +34,13 @@ const validMutations: Record<string, Record<string, unknown>> = { kind: 'measurement', supersedes: [fnd], }, + WriteCompaction: { + type: 'WriteCompaction', + effort: eff, + title: 'Where the work stands', + body: 'b', + derives_from: [dec], + }, WriteDecision: { type: 'WriteDecision', effort: eff, @@ -98,9 +105,9 @@ const validMutations: Record<string, Record<string, unknown>> = { }, }; -test('each of the 17 mutation schemas accepts a valid input', (t) => { +test('each of the 18 mutation schemas accepts a valid input', (t) => { const types = Object.keys(validMutations); - t.is(types.length, 17); + t.is(types.length, 18); for (const type of types) { t.notThrows(() => ProofMutationSchema.parse(validMutations[type]), type); } @@ -280,3 +287,31 @@ test('serialized documents round-trip through @flatbread/transformer-markdown pa t.is(node.hand_authored, 'still here'); t.is((node._content as { raw: string }).raw.trim(), body.trim()); }); + +test('WriteCompaction rejects writer-owned fields and long derives_from', (t) => { + for (const extra of [ + { supersedes: [fnd] }, + { invalidates: [fnd] }, + { covers: [`${dec}@accepted`] }, + { kind: 'compaction' }, + ]) + t.throws(() => + ProofMutationSchema.parse({ ...validMutations.WriteCompaction, ...extra }) + ); + const derives_from = Array.from( + { length: 11 }, + (_, index) => `dec-choice-${index}--${suffix}` + ); + t.throws(() => + ProofMutationSchema.parse({ + ...validMutations.WriteCompaction, + derives_from, + }) + ); + t.notThrows(() => + ProofMutationSchema.parse({ + ...validMutations.WriteCompaction, + derives_from: derives_from.slice(0, 10), + }) + ); +}); diff --git a/packages/proof/src/compaction.ts b/packages/proof/src/compaction.ts new file mode 100644 index 00000000..5e16ea6b --- /dev/null +++ b/packages/proof/src/compaction.ts @@ -0,0 +1,205 @@ +import { PREFIX_KIND } from './ids.js'; +import type { PrimitiveKind } from './types.js'; + +/** + * A compaction is a Finding with `kind: compaction`: one short, current + * account of an Effort. Only `WriteCompaction` creates one, so the writer + * always computes its `covers` snapshot and supersedes the previous head. + */ +export const COMPACTION_KIND = 'compaction'; +/** `derives_from` names the records the body rests on, not the whole Effort. */ +export const COMPACTION_DERIVES_FROM_LIMIT = 10; +/** `brief` asks for a new compaction once this many records changed. */ +export const RECOMPACT_CHANGE_THRESHOLD = 5; + +/** + * Relation fields may live in `frontmatter` (writer snapshots) or be merged in + * from a read projection; callers pass one flat field map either way. + */ +export interface CompactionRecord { + readonly id: string; + readonly kind: PrimitiveKind; + readonly frontmatter: Readonly<Record<string, unknown>>; +} + +export type CompactionChangeType = 'added' | 'changed' | 'left'; + +export interface CompactionChange { + readonly change: CompactionChangeType; + readonly id: string; + readonly kind: PrimitiveKind | undefined; + readonly title: string; + /** Standing when the compaction was written; null when not covered. */ + readonly from: string | null; + /** Standing now; null when no record answers to the id. */ + readonly to: string | null; +} + +const COVERED_KINDS = new Set<PrimitiveKind>([ + 'issue', + 'finding', + 'decision', + 'constraint', + 'risk', +]); + +const LIVE_STANDINGS: Partial<Record<PrimitiveKind, ReadonlySet<string>>> = { + issue: new Set(['open']), + decision: new Set(['proposed', 'accepted']), + risk: new Set(['open', 'realized']), + finding: new Set(['live']), + constraint: new Set(['live']), +}; + +function ids(value: unknown): string[] { + return Array.isArray(value) + ? value.filter((item): item is string => typeof item === 'string') + : typeof value === 'string' + ? [value] + : []; +} + +export function isCompaction(record: CompactionRecord): boolean { + return ( + record.kind === 'finding' && record.frontmatter.kind === COMPACTION_KIND + ); +} + +/** + * One word for where a record stands now. Retraction, supersession, and + * invalidation outrank the stored state, because each takes the record off + * the live graph whatever its state field still says. + */ +export function recordStanding(record: CompactionRecord): string { + const fm = record.frontmatter; + if (fm.retracted === true) return 'retracted'; + if (ids(fm.superseded_by).length) return 'superseded'; + if (ids(fm.invalidated_by).length) return 'invalidated'; + if (record.kind === 'issue') return String(fm.status ?? 'open'); + if (record.kind === 'decision' || record.kind === 'risk') + return String(fm.state ?? 'proposed'); + return 'live'; +} + +export function isLiveStanding( + kind: PrimitiveKind | undefined, + standing: string | null +): boolean { + return ( + kind !== undefined && + standing !== null && + (LIVE_STANDINGS[kind]?.has(standing) ?? false) + ); +} + +function kindForId(id: string): PrimitiveKind | undefined { + return PREFIX_KIND[id.split('-', 1)[0]]; +} + +/** Records a compaction covers: everything live in the Effort but itself. */ +function isCoverable(record: CompactionRecord): boolean { + return ( + COVERED_KINDS.has(record.kind) && + !isCompaction(record) && + isLiveStanding(record.kind, recordStanding(record)) + ); +} + +/** + * The `covers` snapshot: `<id>@<standing>` for each live record in the Effort + * and for each `derives_from` target, so a later read can say exactly what + * moved. Ids never contain `@`. + */ +export function compactionCovers( + effortRecords: readonly CompactionRecord[], + derivesFrom: readonly string[] = [] +): string[] { + const cited = new Set(derivesFrom); + return effortRecords + .filter((record) => isCoverable(record) || cited.has(record.id)) + .map((record) => `${record.id}@${recordStanding(record)}`) + .sort(); +} + +export function parseCovers(value: unknown): Map<string, string> { + const covers = new Map<string, string>(); + for (const entry of ids(value)) { + const at = entry.lastIndexOf('@'); + if (at > 0) covers.set(entry.slice(0, at), entry.slice(at + 1)); + } + return covers; +} + +/** Live compactions nothing has superseded yet; more than one is a fork. */ +export function compactionHeads<T extends CompactionRecord>( + effortRecords: readonly T[] +): T[] { + return effortRecords.filter( + (record) => + isCompaction(record) && + record.frontmatter.retracted !== true && + ids(record.frontmatter.superseded_by).length === 0 + ); +} + +function change( + type: CompactionChangeType, + id: string, + record: CompactionRecord | undefined, + from: string | null +): CompactionChange { + return { + change: type, + id, + kind: record?.kind ?? kindForId(id), + title: String(record?.frontmatter.title ?? ''), + from, + to: record ? recordStanding(record) : null, + }; +} + +/** + * Records whose standing moved since `covers` was taken: new live records, + * live records whose state changed, and covered live records that left the + * live graph. Sorted by id so the digest is deterministic. + */ +export function compactionChanges( + covers: ReadonlyMap<string, string>, + effortRecords: readonly CompactionRecord[] +): CompactionChange[] { + const byId = new Map(effortRecords.map((record) => [record.id, record])); + const changes: CompactionChange[] = []; + for (const record of effortRecords) { + if (!isCoverable(record)) continue; + const before = covers.get(record.id); + if (before === undefined) + changes.push(change('added', record.id, record, null)); + else if (before !== recordStanding(record)) + changes.push(change('changed', record.id, record, before)); + } + for (const [id, before] of covers) { + if (!isLiveStanding(kindForId(id), before)) continue; + const record = byId.get(id); + if (record && isCoverable(record)) continue; + changes.push(change('left', id, record, before)); + } + return changes.sort((a, b) => a.id.localeCompare(b.id)); +} + +/** + * `derives_from` targets whose standing moved. Any one of them makes the + * compaction stale: the body leans on a claim that no longer holds as written. + */ +export function staleDerivations( + covers: ReadonlyMap<string, string>, + derivesFrom: readonly string[], + effortRecords: readonly CompactionRecord[] +): CompactionChange[] { + const byId = new Map(effortRecords.map((record) => [record.id, record])); + return [...new Set(derivesFrom)].sort().flatMap((id) => { + const record = byId.get(id); + const before = covers.get(id) ?? null; + const now = record ? recordStanding(record) : null; + return before === now ? [] : [change('changed', id, record, before)]; + }); +} diff --git a/packages/proof/src/digest.ts b/packages/proof/src/digest.ts index 7553134b..abffd4af 100644 --- a/packages/proof/src/digest.ts +++ b/packages/proof/src/digest.ts @@ -33,6 +33,24 @@ export interface ReadEdge { export type ReadCapReason = 'primary_records' | 'displayed_edges' | 'bytes'; +/** Machine-readable state of an Effort's head compaction (`brief` only). */ +export interface CompactionStatus { + head_id: string | null; + /** Head compactions nothing supersedes; above 1 means a merge forked them. */ + heads: number; + /** A `derives_from` target changed standing, or the head was invalidated. */ + stale: boolean; + /** Records whose standing changed since the head's `covers` snapshot. */ + changes: number; + /** True when no head exists, it forked, it is stale, or changes hit the threshold. */ + recompact: boolean; +} + +export interface DigestSection { + heading: string; + lines: string[]; +} + export interface ReadEnvelope { summary: string; artifact_path: string; @@ -43,6 +61,7 @@ export interface ReadEnvelope { cap_reasons: ReadCapReason[]; page: { returned: number; has_more: boolean; next_cursor: string | null }; hints: string[]; + compaction?: CompactionStatus; } export interface DigestInput { @@ -63,6 +82,9 @@ export interface DigestInput { relatedRecords?: readonly ReadRecord[]; /** When true, primary record bodies are rendered in full (getRecord path). */ fullBody?: boolean; + /** Extra line-per-record sections, rendered after checkpoints. */ + sections?: readonly DigestSection[]; + compaction?: CompactionStatus; } const CAP_RECORDS = 25; @@ -190,6 +212,33 @@ function renderRecordBody( return excerpt(record.body_excerpt); } +function isRetracted(record: ReadRecord): boolean { + return record.frontmatter.retracted === true; +} + +/** + * Printed under a retracted record's heading in every digest, so a reader + * who skips the YAML still cannot take it for a live record. + */ +function retractedBanner(record: ReadRecord): string { + const at = record.frontmatter.retracted_at; + const reason = record.frontmatter.retracted_reason; + return [ + `> **RETRACTED**${typeof at === 'string' ? ` on ${at}` : ''}${ + typeof reason === 'string' && reason.trim() + ? `: ${reason.trim().replace(/\s+/g, ' ')}` + : '' + }.`, + 'This record is not live. Proof keeps it for audit only; do not treat its claims as current.', + ].join(' '); +} + +function indexLine(record: ReadRecord): string { + return `- [\`${record.id}\`](#${record.id})${ + isRetracted(record) ? ' (retracted)' : '' + }`; +} + function renderRecord( record: ReadRecord, options: { bodyMode?: RecordBodyMode } = {} @@ -219,6 +268,7 @@ function renderRecord( .join('\n'); return [ `### ${record.id}`, + ...(isRetracted(record) ? [retractedBanner(record), ''] : []), '```yaml', ...Object.keys(frontmatter) .sort() @@ -239,6 +289,8 @@ function summary( ): string { const states = new Map<string, number>(); const statuses = new Map<string, number>(); + const retracted = records.filter(isRetracted).length; + if (retracted) states.set('retracted', retracted); for (const record of records) { for (const [map, key] of [ [states, 'state'], @@ -301,6 +353,11 @@ export async function renderDigest(input: DigestInput): Promise<ReadEnvelope> { const checkpoints = input.checkpointLines?.length ? ['## Lineage checkpoints', ...input.checkpointLines, ''] : []; + const extraSections = (input.sections ?? []).flatMap((section) => [ + `## ${section.heading}`, + ...section.lines, + '', + ]); const renderPrimary = ( record: ReadRecord, bodyMode: RecordBodyMode = primaryBodyMode @@ -313,15 +370,14 @@ export async function renderDigest(input: DigestInput): Promise<ReadEnvelope> { ...(input.anomaly ? [`> anomaly: ${input.anomaly}`, ''] : []), '# Proof read', '## Index', - ...visible - .filter((record) => !record.foreign_reference) - .map((record) => `- [\`${record.id}\`](#${record.id})`), + ...visible.filter((record) => !record.foreign_reference).map(indexLine), '## Records', ...visible.map((record) => renderPrimary(record)), ...(input.relatedRecords?.length ? ['## Related records', ...input.relatedRecords.map(renderRelated)] : []), ...checkpoints, + ...extraSections, '## Displayed edges', '| From | Relation | To |', '| --- | --- | --- |', @@ -349,9 +405,7 @@ export async function renderDigest(input: DigestInput): Promise<ReadEnvelope> { ...(anomaly ? [`> anomaly: ${anomaly}`, ''] : []), '# Proof read', '## Index', - ...visible - .filter((record) => !record.foreign_reference) - .map((record) => `- [\`${record.id}\`](#${record.id})`), + ...visible.filter((record) => !record.foreign_reference).map(indexLine), ...checkpoints, '## Records', ]; @@ -369,6 +423,7 @@ export async function renderDigest(input: DigestInput): Promise<ReadEnvelope> { const edgeHeader = [ ...header, ...sections, + ...extraSections, '## Displayed edges', '| From | Relation | To |', '| --- | --- | --- |', @@ -426,6 +481,7 @@ export async function renderDigest(input: DigestInput): Promise<ReadEnvelope> { hints: ( input.hints ?? ids.slice(0, 10).map((id) => `getRecord("${id}")`) ).slice(0, 10), + ...(input.compaction ? { compaction: input.compaction } : {}), }; return envelope; } diff --git a/packages/proof/src/index.ts b/packages/proof/src/index.ts index f62b4220..586950ab 100644 --- a/packages/proof/src/index.ts +++ b/packages/proof/src/index.ts @@ -13,6 +13,7 @@ export { recoverJournal } from './journal.js'; export * from './live.js'; export * from './journalBarrier.js'; export * from './digest.js'; +export * from './compaction.js'; export { READ_RELATIONS, ProofConsistencyError, diff --git a/packages/proof/src/planner.ts b/packages/proof/src/planner.ts index 163caf1b..6cbadc5f 100644 --- a/packages/proof/src/planner.ts +++ b/packages/proof/src/planner.ts @@ -11,6 +11,12 @@ import { reopenDecisionLifecycle, supersedeDecisionLifecycle, } from './decision-lifecycle.js'; +import { + COMPACTION_KIND, + compactionCovers, + compactionHeads, + isCompaction, +} from './compaction.js'; import type { ProofSnapshot } from './snapshot.js'; import type { PlannedWrite, PrimitiveKind } from './types.js'; import type { ProofMutation } from './schemas.js'; @@ -196,6 +202,13 @@ function assertDerivesFrom( } } +function assertNotCompaction(record: SnapshotRecord, rule: string): void { + if (isCompaction(record)) + throw new ProofValidationError( + `${record.id} is a compaction; ${rule}. Write a new compaction with WriteCompaction instead.` + ); +} + export function planMutation( input: ProofMutation, snapshot: ProofSnapshot, @@ -277,6 +290,68 @@ export function planMutation( add(r.id, r.kind, { ...r.frontmatter, status: input.status }, r.body); return [...writes.values()]; } + if (input.type === 'WriteCompaction') { + const id = + input.id ?? generateArtifactId('finding', input.title, randomBytes); + if (!validateArtifactId(id, 'finding') || snapshot.hasId(id)) + throw new ProofValidationError('Invalid or duplicate id'); + const effort = get(input.effort); + if (effort.kind !== 'effort') + throw new ProofValidationError('Invalid effort'); + assertCites(get, input.effort, input.cites); + assertDerivesFrom(get, input.derives_from); + for (const targetId of input.derives_from ?? []) + assertNotCompaction( + get(targetId), + 'compactions link to earlier compactions through supersedes, never derives_from' + ); + const effortRecords = snapshot.recordsByEffort(input.effort); + // Superseding every head keeps one chain, and heals a fork left by a merge. + const heads = compactionHeads(effortRecords) + .map((head) => head.id) + .sort(); + add( + id, + 'finding', + { + id, + effort: input.effort, + title: input.title, + kind: COMPACTION_KIND, + created_at: input.created_at ?? now.toISOString(), + ...(input.produced_in !== undefined + ? { produced_in: input.produced_in } + : {}), + ...(input.created_by !== undefined + ? { created_by: input.created_by } + : {}), + ...(input.derives_from?.length + ? { derives_from: input.derives_from } + : {}), + ...(input.cites?.length ? { cites: input.cites } : {}), + ...(heads.length ? { supersedes: heads } : {}), + covers: compactionCovers(effortRecords, input.derives_from), + }, + input.body, + 'create' + ); + for (const headId of heads) { + const head = get(headId); + add( + head.id, + head.kind, + { + ...head.frontmatter, + superseded_by: [ + ...((head.frontmatter.superseded_by as string[] | undefined) ?? []), + id, + ], + }, + head.body + ); + } + return [...writes.values()]; + } if (input.type in kinds) { const kind = kinds[input.type]; const raw = input as Record<string, unknown> & { @@ -291,6 +366,10 @@ export function planMutation( }; if (kind === 'blob' || kind === 'citation') assertNoCitationBlobEdges(input.type, raw); + if (kind === 'finding' && raw.kind === COMPACTION_KIND) + throw new ProofValidationError( + 'WriteFinding cannot create a compaction; use WriteCompaction so the writer records what it covers.' + ); const id = raw.id ?? generateArtifactId(kind, raw.title, randomBytes); if (!validateArtifactId(id, kind) || snapshot.hasId(id)) throw new ProofValidationError('Invalid or duplicate id'); @@ -338,6 +417,8 @@ export function planMutation( for (const targetId of (fm[edge] as string[] | undefined) ?? []) { const target = get(targetId); assertLive(target); + if (edge === 'supersedes') + assertNotCompaction(target, 'only another compaction supersedes it'); if (edge === 'supersedes' && target.kind !== kind) throw new ProofValidationError( 'Supersedes must target the same kind' @@ -384,6 +465,14 @@ export function planMutation( const b = get(input.targetId); assertLive(a); assertLive(b); + if (input.type === 'Supersede') { + assertNotCompaction(a, 'it supersedes only through WriteCompaction'); + assertNotCompaction(b, 'only another compaction supersedes it'); + } else + assertNotCompaction( + a, + 'a compaction summarizes evidence and cannot invalidate it' + ); const edge = input.type === 'Supersede' ? 'supersedes' : 'invalidates'; const back = input.type === 'Supersede' ? 'superseded_by' : 'invalidated_by'; diff --git a/packages/proof/src/read.ts b/packages/proof/src/read.ts index 286e8863..89ae1a09 100644 --- a/packages/proof/src/read.ts +++ b/packages/proof/src/read.ts @@ -44,6 +44,7 @@ export type ReadQuery = effort_id: string; page?: { cursor?: string; limit?: number }; } + | { type: 'effortBrief'; effort_id: string } | { type: 'listEfforts'; status: EffortStatus[]; diff --git a/packages/proof/src/schemas.ts b/packages/proof/src/schemas.ts index f4e57d20..1aa8e6b9 100644 --- a/packages/proof/src/schemas.ts +++ b/packages/proof/src/schemas.ts @@ -1,4 +1,5 @@ import { z } from 'zod'; +import { COMPACTION_DERIVES_FROM_LIMIT } from './compaction.js'; const id = z .string() .regex(/^[a-z]{3}-[a-z0-9-]+--[0123456789abcdefghjkmnpqrstvwxyz]{16}$/); @@ -43,6 +44,16 @@ export const WriteFindingSchema = z.object({ ...createBase, kind: z.string().min(1), }); +// The writer owns `covers` and `supersedes`, so the payload cannot set them. +export const WriteCompactionSchema = z + .object({ + type: z.literal('WriteCompaction'), + ...common, + ...cites, + effort: id, + derives_from: id.array().max(COMPACTION_DERIVES_FROM_LIMIT).optional(), + }) + .strict(); export const WriteDecisionSchema = z.object({ type: z.literal('WriteDecision'), ...createBase, @@ -125,6 +136,7 @@ export const ProofMutationSchema = z.discriminatedUnion('type', [ SetEffortStatusSchema, WriteIssueSchema, WriteFindingSchema, + WriteCompactionSchema, WriteDecisionSchema, WriteConstraintSchema, WriteRiskSchema, diff --git a/skills-lock.json b/skills-lock.json index 59f1d369..f85c3b60 100644 --- a/skills-lock.json +++ b/skills-lock.json @@ -7,6 +7,12 @@ "skillPath": "skills/agent-browser/SKILL.md", "computedHash": "c19a532a3777698b80b35270939a1dc559da451381971b3e1e78174d1ab54863" }, + "gh-stack": { + "source": "github/gh-stack", + "sourceType": "github", + "skillPath": "skills/gh-stack/SKILL.md", + "computedHash": "6a5289601eedbeedc2d79c2d8627277afb9b9a3fbd78b4da3399a46dd788ae0a" + }, "mergify-ci": { "source": "Mergifyio/mergify-cli", "sourceType": "github", @@ -30,12 +36,6 @@ "sourceType": "github", "skillPath": "skills/mergify-merge-queue/SKILL.md", "computedHash": "d9d872f9c44842f890d03579e80d3dab99ce312467a6e988a5d2488cf407f344" - }, - "mergify-stack": { - "source": "Mergifyio/mergify-cli", - "sourceType": "github", - "skillPath": "skills/mergify-stack/SKILL.md", - "computedHash": "425f34041a676c1559f0da81f0953aa1c6b7446349a0a89d821db58d2bba6928" } } }