Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3356694
docs(prd-750): plan the kit authoring loop, one KPI dashboard (PRD-75…
jonit-dev Oct 27, 2026
c2ab8c5
PRD-751 Phase 1: pnpm dashboard is the one KPI hub with CI speed and …
jonit-dev Oct 27, 2026
8b8083e
PRD-735 AC-0: references come from ThreeNativeHQ/threenative-reverse-…
jonit-dev Oct 27, 2026
f799f51
PRD-750 Phase 1 + PRD-751 Phase 2: pnpm kit:loop record and the Kit l…
jonit-dev Oct 27, 2026
0df36c7
Merge remote-tracking branch 'origin/pr563-followup' into prd-750-kit…
jonit-dev Oct 27, 2026
e0b8e18
PRD-735: tick AC-1 (Tier 2 import, 3287 rows) and AC-3 (OoT 17 review…
jonit-dev Oct 27, 2026
b6451c1
PRD-750 iteration 1: baseline ledger row 1 (collectathon, SM64 cold b…
jonit-dev Oct 27, 2026
a4d5345
fix(playtest): a cost bound failed beside other GPU processes names t…
jonit-dev Oct 27, 2026
42cbf97
fix(create-threenative): the scaffold's last line says to start the a…
jonit-dev Oct 27, 2026
c5bc052
feat(engine-mcp): one tool call from the command line for a session t…
jonit-dev Oct 27, 2026
4eae555
docs(prd-750): AC-5 notes: row 1's two retro fixes landed, row 2 pending
jonit-dev Oct 27, 2026
26f51dc
fix(engine-mcp): type runCli's io sink as void so the spec typechecks…
jonit-dev Oct 27, 2026
bac933c
fix(playtest): --scenario takes a shell brace list (playtests/{a,b}.p…
jonit-dev Oct 27, 2026
59d7419
fix(create-threenative): the scaffold's last line says CLAUDE.md copi…
jonit-dev Oct 27, 2026
8b557c4
PRD-750 iteration 2: ledger row 2 (K1 44,483 tokens -55%, K2 22/22 + …
jonit-dev Oct 27, 2026
33aece8
PRD-750: ledger row 3 (K1 47,107, K2 22/22 + CLOSE, K3 0, K4 4); tick…
jonit-dev Oct 27, 2026
620e619
fix: review findings on the PRD-750 retro fixes
jonit-dev Oct 27, 2026
55572d6
test: authoring-layer regression guards from the PRD-750 kit loop
jonit-dev Oct 27, 2026
442f48d
fix(kit-loop): K2 reads met only with all scenarios green, the frame …
jonit-dev Oct 27, 2026
511decf
PRD-750: K2 frame budget is the performance gate's cost p95 (owner de…
jonit-dev Oct 27, 2026
ffbd082
ci(prd-750): record the PRD-735 reference-tool descriptions and allow…
jonit-dev Oct 27, 2026
6f70766
Hook reference search to the new data repository and its release shap…
jonit-dev Oct 27, 2026
985750a
fix(playtest): the HUD audit compares nodeType to 3, not the browser-…
jonit-dev Oct 27, 2026
3bab4fa
Merge remote-tracking branch 'origin/develop' into prd-750-kit-author…
jonit-dev Oct 27, 2026
03754b3
fix(create-threenative): a game named with --genre opens its next ste…
jonit-dev Oct 27, 2026
a50cb8a
fix(create-threenative): --genre runs the reference search and prints…
jonit-dev Oct 27, 2026
c75303c
docs(prd-750): record the reference-trigger probes (sandboxes 4-6)
jonit-dev Oct 27, 2026
8a1ff54
style(create-threenative): sort the scaffold spec imports
jonit-dev Oct 27, 2026
163d335
Merge remote-tracking branch 'origin/pr563-followup' into prd-750-kit…
jonit-dev Oct 27, 2026
f71d036
Merge remote-tracking branch 'origin/pr563-followup' into prd-750-kit…
jonit-dev Oct 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .agents/skills/native-performance-loop/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: native-performance-loop
description: Run an autonomous ThreeNative native-performance optimization loop using existing harnesses, quick synthetic load tests, and representative real games. Profile bottlenecks, make focused changes, accept or reject measured experiments, and maintain an HTML benchmark dashboard. Use for sustained native runtime optimization, frame pacing, startup, memory, or thermal efficiency campaigns, including the Tempest (rain) campaign where the web Wasm engine must beat stock three.js with the same image.
description: Run an autonomous ThreeNative native-performance optimization loop using existing harnesses, quick synthetic load tests, and representative real games. Profile bottlenecks, make focused changes, accept or reject measured experiments, and keep a campaign tab in the one `pnpm dashboard` hub. Use for sustained native runtime optimization, frame pacing, startup, memory, or thermal efficiency campaigns, including the Tempest (rain) campaign where the web Wasm engine must beat stock three.js with the same image.
---

# Native performance loop
Expand Down Expand Up @@ -28,8 +28,8 @@ the developer to supervise each iteration. Creating or editing this skill does n
Browser results are comparison or diagnosis, never substitute native evidence. Read the local
`measure-steady-state-fps` and `probe-android-startup-and-heat` skills when their lanes apply.
4. Create or resume `<primary>/artifacts/native-performance-loop/<campaign-id>/`. Record the
contract and results described in [dashboard.md](references/dashboard.md), and create
`index.html` immediately, including an honest empty state. Choose workloads and targets
contract and results described in [dashboard.md](references/dashboard.md), and show them in a
`pnpm dashboard` tab immediately, including an honest empty state. Choose workloads and targets
autonomously and state them. Default to a two-hour invocation budget, including setup and
verification, unless the user supplied another duration or experiment limit. Reserve the last
20 minutes for confirmation, restoration, and delivery; do not launch work that cannot finish
Expand Down Expand Up @@ -139,7 +139,7 @@ hypothesis; reaching a target does not establish a hardware limit. Do not instal
scheduler or claim work continues after the agent stops.

Before delivery, reproduce the best accepted build, rerun affected repository checks and native
scenarios, refresh `index.html`, and record unrun platforms honestly. Preserve the dashboard and
scenarios, update the campaign record, and record unrun platforms honestly. Preserve the record and
raw artifacts outside a disposable task checkout. Follow the repository's PR and worktree cleanup
rules within the session's existing authorization; no implicit push, merge or publication. Report
any retained worktree's exact path, size and cleanup blocker. Finish with the dashboard link,
Expand Down
36 changes: 18 additions & 18 deletions .agents/skills/native-performance-loop/references/dashboard.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
# Campaign state and HTML dashboard
# Campaign state and the dashboard tab

Generate this on invocation, not when installing the skill. The HTML is the developer's view of
one machine-readable campaign record, not a second manually maintained evidence report.
Create this on invocation, not when installing the skill. The developer's view is one tab of the
single KPI hub, `pnpm dashboard` (`scripts/perf-live.ts`, PRD-751), reading one machine-readable
campaign record. Do not generate a per-campaign HTML page or a second evidence report.

## Files and updates

Use `<primary>/artifacts/native-performance-loop/<campaign-id>/` with:

- `results.json`: versioned contract, environment identities, workloads, baselines, incumbent,
experiment history, status, heartbeat, limits and next hypothesis.
- `index.html`: an offline, self-contained dashboard generated from `results.json`.
- `raw/<experiment-id>/`: existing harness output, exit codes, sample data, profiles, screenshots,
candidate patch/commit reference, build identities and exact reproduction commands.

Reuse a suitable existing report renderer if present. Otherwise generate a small HTML file with
inline CSS, embedded data and minimal browser JavaScript; save the small renderer alongside the
campaign only if needed to regenerate it reliably. No web framework, backend, CDN or new dependency.
It must open with `file://` without fetching JSON. Write JSON and HTML via temporary siblings and
atomic replacement, preserving the last readable snapshot if generation fails.
Reuse an existing hub tab when its reader fits the record (the Shadows vs Unreal tab reads a
campaign `results.json`). Otherwise add one: a small reader beside `scripts/shadow-perf/dashboard.ts`
that reads `results.json`, writes nothing and fails closed (missing = `pending`, malformed =
`invalid`), plus one `TABS` row and one route in `scripts/perf-live.ts`, with a test in
`scripts/__tests__/perf-live.spec.ts`. No web framework, CDN or new dependency. Write
`results.json` via a temporary sibling and atomic replacement, preserving the last readable record.

Create the dashboard before the first benchmark, showing “baseline pending,” never sample wins.
Refresh after each state transition and decision. During long commands, publish a timestamp and
heartbeat at least every 60 seconds using the existing gate status where available. The HTML must
show its snapshot time; when an old snapshot is open, say “reload for current progress” instead of
pretending it is live. If serving locally is already supported, optional refresh must preserve
filters. A stale heartbeat is “stale / check process,” never proof the worker is still active.
Add the tab before the first benchmark, showing “baseline pending,” never sample wins. Update the
record after each state transition and decision. During long commands, publish a timestamp and
heartbeat at least every 60 seconds using the existing gate status where available. The tab shows
the record's update time. A stale heartbeat is “stale / check process,” never proof the worker is
still active.

Escape benchmark names, descriptions, commands and log content as text. If embedding JSON in an
HTML script element, escape `<` as `\u003c` so data cannot terminate the script. Use textContent for
Expand Down Expand Up @@ -73,14 +73,14 @@ FPS derived from percentiles or average several games into an unqualified perfor

## Verify and resume

Before handing off an HTML snapshot, open it in a browser when a browser tool is available. Check
that it opens offline, shows actual recorded values, distinguishes missing/provisional data, and
Before handing off, open the tab in `pnpm dashboard` in a browser when a browser tool is available.
Check that it shows actual recorded values, distinguishes missing/provisional data, and
that filters, keyboard controls and evidence links work. A renderer with non-trivial logic needs
one small runnable check covering metric direction, missing values and unsafe text. If no browser
is available, check generated structure and links and mark visual inspection unverified.

On resume, load the contract and history, verify ownership and process state, and reconcile the
worktree with the recorded incumbent before editing. Check executable/workload/environment hashes;
if any comparison dimension changed, create a new series and baseline instead of connecting its
points to the old curve. Preserve all previous decisions. Link to this dashboard in the PRD/PR and
points to the old curve. Preserve all previous decisions. Link to this tab in the PRD/PR and
final response rather than copying its experiment log into another report.
8 changes: 4 additions & 4 deletions .claude/skills/ci-speed-loop/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: ci-speed-loop
description: Run ThreeNative's CI speed loop — measure how long a change takes to merge, name the biggest cost from the first failing jobs and queue wait, change one thing, re-measure the same window, record the iteration and refresh the HTML dashboard. Use when asked to speed up CI or the merge queue, work PRD-550, check progress toward the 30-minute merge goal, or refresh docs/ci-speed/index.html. Not for runtime FPS (perf-loop).
description: Run ThreeNative's CI speed loop — measure how long a change takes to merge, name the biggest cost from the first failing jobs and queue wait, change one thing, re-measure the same window, record the iteration. Use when asked to speed up CI or the merge queue, work PRD-550, check progress toward the 30-minute merge goal, or read the CI speed tab of `pnpm dashboard`. Not for runtime FPS (perf-loop).
---

# CI speed loop
Expand All @@ -20,11 +20,11 @@ node scripts/ci-merge-latency.mjs --since 2026-10-09 # measure only, pr
node scripts/ci-speed-loop.mjs record --since 2026-10-09 --label "gating board" --notes "..." [--decision keep]
node scripts/ci-speed-loop.mjs show # the ledger
node scripts/ci-speed-loop.mjs discard --iteration 3 --reason "queue outage, 2 PRs only"
node scripts/ci-speed-loop.mjs report # regenerate the HTML only
pnpm dashboard # the CI speed tab renders the ledger
```

`docs/ci-speed/ledger.json` is the record. `docs/ci-speed/index.html` is generated from it and opens with
`file://`. Never edit either by hand. Commit both with the change they measure.
`docs/ci-speed/ledger.json` is the record; the CI speed tab of `pnpm dashboard` renders it on each load
(PRD-751). Do not edit it by hand. Commit it with the change it measures.

## The turn

Expand Down
5 changes: 5 additions & 0 deletions .gitleaksignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,8 @@ e2e871f1feac6fa0f7dc4d372f30d3cb586a8f72:packages/core/__tests__/warmup-default.

# Verified 2026-10-11: PRD-595's slash-separated CellPrewarm counter names are prose, not a credential.
0c2f9e4b57382d980ef98424f6ac03b86e1d785b:docs/PRDs/strata-terrain-hardening/PRD-595-world-cells-splits-by-seam-and-survives-a-race-fuzz.md:generic-api-key:63

# Verified 2026-10-27: PRD-750 scripts/kit-loop.mjs line 45 is a KPI field identifier (k2ScenarioPct), not a credential.
f799f51aba375ce12df5eb43db2a7c69b65d96ae:scripts/kit-loop.mjs:generic-api-key:45
# Verified 2026-10-27: line 31 of this file in commit 0fd2f4d57 quotes that same identifier in a comment; the full-history scan reads every fetched ref.
0fd2f4d574d82305373434bc8cf1c00600b3a36e:.gitleaksignore:generic-api-key:31
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pnpm native:build # opt-in; downloads deps, compiles th
pnpm native:verify:desktop # 300 native frames + a non-blank screenshot
```

**CI.** The pre-push hook runs `pnpm ci:fast` drift checks only; it proves no runtime behaviour. `pnpm ci:local --full` runs the full board; `pnpm ci:local --affected --base origin/develop --target develop` runs what CI would select (dirty or unknown inputs fall back to full). A change touching only Markdown that no fixture consumes (not `AGENTS.md`/`CLAUDE.md`), or only the generated speed-loop record (`docs/ci-speed/ledger.json`, `docs/ci-speed/index.html`, `docs/ci-speed/runs/<run>.jobs.json`), runs no product CI job. Ordinary PRs into develop use the complete candidate diff: CI-only changes run CI contracts, exact template changes run scaffolder contracts and affected templates, and shared executable inputs earn the thin review lane (PRD-731): scope, typecheck, lint, budgets, secrets scan, the unit tests that import a changed file, `test` and `build-artifacts` for a package change, and one template smoke, about 10 minutes; draft PRs run nothing. Template instruction and Markdown changes retain their contract lanes without adding runtime kits. Merge groups run the full selected board once, name the first red job in a PR comment and cancel the rest of the run, so a change pays for one board (PRD-550, PRD-731); `ci-required` rejects a review plan anywhere but a PR into develop, and `pnpm ci:local --affected` runs the queue's board. Develop pushes, explicit full runs, unknown inputs, main qualification and scheduled audits use fresh exhaustive qualification: all shipped templates, both golden journeys and the full supported native matrix. `ci-required` independently rejects a review plan for these events; Integration is a required reusable join on the same candidate, with each selected canonical job proven by a receipt from its latest attempt in the current run and an independently checked completed-success API job; missing, skipped, cancelled, stale or unmapped receipts fail closed. So a red job on an unchanged head needs only `gh run rerun <id> --failed`, not a full run; a fix still needs a push. Native per-leg authoritative completion and cold-path queue feasibility remain follow-ups before deferring any Android PR coverage. Template scenarios run once per selected kit; develop changes run one representative golden journey and full qualification retains both starter and platformer journeys. `ci-required` rejects missing or failed selected checks; retained contexts include `supply-chain`, `template-nonvisual`, `golden-path`, and native `desktop-parity` when applicable. Native host/platform tests run for native or shared runtime consumers, main qualification and unresolved scopes. Unsafe matrix/reusable verdict reuse stays disabled until authoritative complete coverage and per-leg routing exist. One exception (PRD-730): a merge group whose tree equals the tree of its pull request's head, which has a green full `ci.yml` run an author dispatched (a review-lane PR run never counts), reuses that run; `ci-required` re-decides it and writes a receipt, and any doubt runs the board. A new candidate runs fresh tests; only exact-run immutable build artifacts are shared. Details: `docs/PRDs/done/PRD-483-impact-driven-ci-without-repeated-template-setup.md` and `docs/PRDs/done/PRD-373-selective-ci-and-develop-promotion.md`.
**CI.** The pre-push hook runs `pnpm ci:fast` drift checks only; it proves no runtime behaviour. `pnpm ci:local --full` runs the full board; `pnpm ci:local --affected --base origin/develop --target develop` runs what CI would select (dirty or unknown inputs fall back to full). A change touching only Markdown that no fixture consumes (not `AGENTS.md`/`CLAUDE.md`), or only the generated speed-loop record (`docs/ci-speed/ledger.json`, `docs/ci-speed/runs/<run>.jobs.json`), runs no product CI job. Ordinary PRs into develop use the complete candidate diff: CI-only changes run CI contracts, exact template changes run scaffolder contracts and affected templates, and shared executable inputs earn the thin review lane (PRD-731): scope, typecheck, lint, budgets, secrets scan, the unit tests that import a changed file, `test` and `build-artifacts` for a package change, and one template smoke, about 10 minutes; draft PRs run nothing. Template instruction and Markdown changes retain their contract lanes without adding runtime kits. Merge groups run the full selected board once, name the first red job in a PR comment and cancel the rest of the run, so a change pays for one board (PRD-550, PRD-731); `ci-required` rejects a review plan anywhere but a PR into develop, and `pnpm ci:local --affected` runs the queue's board. Develop pushes, explicit full runs, unknown inputs, main qualification and scheduled audits use fresh exhaustive qualification: all shipped templates, both golden journeys and the full supported native matrix. `ci-required` independently rejects a review plan for these events; Integration is a required reusable join on the same candidate, with each selected canonical job proven by a receipt from its latest attempt in the current run and an independently checked completed-success API job; missing, skipped, cancelled, stale or unmapped receipts fail closed. So a red job on an unchanged head needs only `gh run rerun <id> --failed`, not a full run; a fix still needs a push. Native per-leg authoritative completion and cold-path queue feasibility remain follow-ups before deferring any Android PR coverage. Template scenarios run once per selected kit; develop changes run one representative golden journey and full qualification retains both starter and platformer journeys. `ci-required` rejects missing or failed selected checks; retained contexts include `supply-chain`, `template-nonvisual`, `golden-path`, and native `desktop-parity` when applicable. Native host/platform tests run for native or shared runtime consumers, main qualification and unresolved scopes. Unsafe matrix/reusable verdict reuse stays disabled until authoritative complete coverage and per-leg routing exist. One exception (PRD-730): a merge group whose tree equals the tree of its pull request's head, which has a green full `ci.yml` run an author dispatched (a review-lane PR run never counts), reuses that run; `ci-required` re-decides it and writes a receipt, and any doubt runs the board. A new candidate runs fresh tests; only exact-run immutable build artifacts are shared. Details: `docs/PRDs/done/PRD-483-impact-driven-ci-without-repeated-template-setup.md` and `docs/PRDs/done/PRD-373-selective-ci-and-develop-promotion.md`.
Registry commands read auth from `~/.npmrc`; pass a checkout-local untracked `.npmrc` with `npm --userconfig .npmrc <command>`. Never print either file.

TypeScript 7 `strict` (the native `tsc`); `typescript` imports use the official TypeScript 6 compatibility API for AST scripts and tsup declarations, **ESM only**; relative imports end in `.js`. Versions come from the `catalog:` in `pnpm-workspace.yaml`, templates excepted. Biome formats — never hand-format. Interfaces are `I`-prefixed; classes and type aliases are not. Unit tests: `<package>/__tests__/*.spec.ts`, vitest, node environment, DOM and GPU stubbed.
Expand Down
Loading
Loading