pipelines/5090_SETUP_RUNBOOK.md
This document was rebuilt against a fresh-context adversarial critique
(5090_runbook_critique.md, verdict FIXES REQUIRED: 10 blocking · 12 moderate · 8 completeness).
All 10 blocking defects are corrected in place; the moderate and completeness findings are applied
except where noted below. The critique's §7 "VERIFIED CORRECT" list is preserved unchanged — those
facts survived re-derivation and were not re-touched.
Claims WITHDRAWN in this revision (stated honestly rather than quietly deleted):
missing psutil produces a soak report "with no memory-growth data and no error" and that
"neither failure announces itself." That is factually wrong: Tools/run_soak.py:181 writes
- psutil memory sampling: ON | OFF (psutil not installed -- memory n/a) into the body of every
report. The degradation is announced. What *does* stand is that the exit code is unaffected
(a psutil-less soak still exits 0), so the install step at 7.1 is kept — on the honest reason.
TESSERACT_DIR remains a genuine silent-degradation risk (hard-coded path,
harness/rag/ocr_backends.py:48, no existence check) and stays in that class alone.
~8s for ~7k chunks" .rag rebuild figure is withdrawn — it was copied from a staledocstring, not measured. Live numbers are used throughout (B2).
splits code license from weights license and marks MIT-vs-Apache unresolved (B8).
ExecutionTimeLimit backwards (B1).
Also fixed, structurally: the BIOS visit is now ordered before re-cabling and consolidated into
one trip; the pull-the-plug test is split into a safe two-part sequence; four unachievable
drive-table rows now name a mechanism; the decision register is complete; and a single
JOSH AT THE KEYBOARD block gathers every credential-bearing step.
---
Status: DRAFT authored 2026-07-27, revised 2026-07-27 (rev 2) ahead of hardware arrival. Lands in
the canon repo at docs/5090_SETUP_RUNBOOK.md once the parallel editing wave clears — **and is not
"done" until it carries a docs/DOC_MAP.md row** (the anti-orphan rule). Authority for every tool
choice below is the ruled stack: docs/pipeline_review/RESEARCHED_STACK.md,
docs/pipeline_review/HARDWARE_DECISION.md, **the five tech_research/ briefs this runbook draws
on** (UE_BUILD_AUTOMATION, LOCAL_3D_ASSET_GEN, NEOSTACK_AI, AUDIO_STACK,
Q3_2026_MODELS_REFRESH — note the folder holds ten briefs, and RESEARCHED_STACK's own "five
briefs consolidated" is a *different*, earlier five; no claim is made about coverage of the rest),
plus docs/pipeline_review/ALTERNATIVES_MATRIX.md,
docs/pipeline_review/ADVERSARIAL_ADJUDICATION.md,
docs/pipeline_review/REALM_ANALYSIS_ART_PIPELINE_2026-07-27.md, and
docs/PRE_5090_BUILD_PLAN.md's capacity note (2026-07-27p). Where a brief leaves a choice genuinely
open, it is marked [DECISION AT SETUP] rather than guessed.
Source-tier discipline (M8). LOCAL_3D_ASSET_GEN.md opens with *"read the tag before trusting a
number,"* and several figures below are INFERRED at source rather than VERIFIED. Where a number
carries a source tier it is stated inline as [VERIFIED] or [INFERRED]. An INFERRED number is a
planning estimate, not a spec — it never justifies a purchase or a "this must fit" claim on its own.
Repo-lane map (M11). Two trees, one writer each — the hard rule from both CLAUDE.md files:
| Path prefix in this runbook | Repo | Lane |
|---|---|---|
harness/, docs/, registries/, _source/ | C:\dev\humanity-forgotten (canon) | canon lane |
Tools/, Source/, Plugins/, Content/, Config/, Saved/ | C:\dev\Humanity\Humanity (game) | build lane |
Any step below that writes a Tools/* file (e.g. the 0.5 UPS command-file hook) is a game-repo
write and must be routed through the build lane, not authored from the canon session.
The machine (Puget Systems, thermally validated for sustained heavy-AI load — HARDWARE_DECISION
"RECOMMENDATION (applied)"): RTX 5090 32GB · Ryzen 9 9950X3D · 128GB (2×64) DDR5 · 4TB Gen5 NVMe
(slot 1) + 4TB Gen4 NVMe (slot 3) + 8TB SATA (slot 4) · 1700W PSU · Windows. Slot 2 stays free by
ruling (a second card is a drop-in only if a named upgrade trigger fires).
The UPS: CyberPower PR1500RTXL2UC, 1500VA/1500W pure sine, arriving with the machine. The build
draws ~933.5W estimated → ~62% load. At 62% load a 1500VA unit gives minutes, not an hour — its
job is a *graceful shutdown*, never riding out an outage. That is why Stage 0 gates every unattended
run.
The binding licensing rule (JOSH-RULED 2026-07-15, RESEARCHED_STACK residual set): the pipeline
defaults to unrestricted (MIT-class) components so no tool's terms touch the game anywhere;
territory-restricted or revenue-capped tools are never load-bearing in the shipped-asset path —
they may be installed and used freely as previz/internal tools, but nothing they produce enters a
shipped asset.
Register discipline: report each stage at its honest tier. "Installed" ≠ "verified". A stage is
not landed until its VERIFY check returns the stated observable.
Abort / rollback rule (C7): a red VERIFY stops the stage and reports — it never gets waved
through to the next stage. The three tiers: (a) retryable (a download failed, a service was not
up) → re-run once, then report; (b) decision-blocked (a [DECISION AT SETUP] is unanswered) →
park the stage, continue with stages that do not depend on it, list the parked item in the landing
note; (c) hardware-suspect (a burn-in fault, an ECC/thermal anomaly, a drive missing) → **stop
the whole day-one run** and raise it with Puget while the RMA window is young. Nothing unattended
starts on a machine with an open tier-(c) item.
---
The rule, stated once so no stage has to re-derive it: agents never type credentials, never
create accounts, never complete sign-ins, never enter payment details, and never handle a recovery
key. Every step in this block is Josh's action at the keyboard. The director's role is to
sequence them, tell Josh when each is needed, and verify *afterward* by an observable that contains
no secret (a push succeeds, a model pulls, an editor signs in).
They are listed together so Josh can batch them rather than being interrupted eight times across a
long day. Items marked BLOCKS gate a stage that cannot proceed without them.
| # | Step | Stage | Why it is Josh's |
|---|---|---|---|
| J1 | Windows OOBE — local account vs Microsoft account (a Microsoft-account sign-in is what can auto-enable device encryption, see J3) | 1.0 | account creation + sign-in · BLOCKS everything |
| J2 | BIOS / supervisor password, if one is set during the single BIOS visit | 2.2 | credential |
| J3 | BitLocker / device-encryption decision + recovery-key capture and escrow (C2) | 1.9 | a recovery key is a credential; it must be captured somewhere Josh controls, never pasted into a session · BLOCKS unattended reboots |
| J4 | Auto-logon credential, if the C3 decision goes that way | 1.10 | a stored password |
| J5 | GitHub auth for both repos (GCM browser flow or gh auth login) | 3.1 | sign-in · BLOCKS Stage 4 |
| J6 | Epic Games Launcher sign-in | 3.5 | sign-in · BLOCKS the UE install |
| J7 | Claude Code sign-in (and confirming the three Max x20 subscriptions chain) | 4.3 | sign-in · BLOCKS the window |
| J8 | HuggingFace token, if any Stage-5.3 weights repo turns out to be gated | 5.3 | token |
| J9 | UPS cloud-monitoring enrollment, if wanted (and see 0.5 — it may need hardware that was not ordered) | 0.5 | account creation · optional |
| J10 | Remote-access enrollment (Tailscale / RDP account side), if C4 lands on a remote path | 1.11 | sign-in · optional but see C4 |
| J11 | NeoStack account, only if the plugin's licensed features require a sign-in beyond the local bridge (6a.3 says the bridge sign-in is *unnecessary*) | 6a.3 | sign-in · expected to be a no-op |
---
| # | Stage | Attended time | Unattended tail |
|---|---|---|---|
| 0 | Unbox · UPS · transfer proof · auto-graceful-shutdown (gates everything unattended) | 75-120 min | — |
| 1 | Windows prep · burn-in · encryption · logon · remote reach · the three-drive layout | 90-140 min | — |
| 2 | The single BIOS visit (iGPU + AC-power-restore) · NVIDIA driver · CUDA (the Blackwell pins) | 60-80 min | — |
| 3 | Dev toolchain: git · Python · VS · UE 5.8 | 60-90 min | 2-4 h engine download |
| 4 | Repo clones · hooks · Claude Code | 45-75 min | LFS pull |
| 5 | Local inference stack — installs only (14B · 7B/3B · embeddings · OCR models) | 90-150 min | model downloads |
| 5S | The two code seams (LocalScorer, the VLM OCR backend) — canon-repo code, not an install | 3-6 h, own task | — |
| 6 | NeoStack verify + the concept-art image substrate (install + one generation) | 60-120 min | — |
| 6F | Firewall pre-authorization for every listener, before anything unattended | 20-30 min | — |
| 7 | Nightly-soak migration + first full soak | 45 min | 3-6 h soak |
| 8 | First-day validation pass (every lane proven live) | 90 min | — |
Realistic shape of the day: Stages 0-4 land before the models finish downloading; Stage 7's soak runs
overnight; Stage 8 closes the next morning against the soak report.
Two re-budget notes against rev 1 (M6). Stage 5 was budgeted at 90-150 min while containing two
NotImplementedError seams — LocalScorer (5.5) and the VLM OCR backend (5.6). Writing code into
the canon repo is not an install and does not fit inside a setup stage; both are now **Stage 5S, a
separate task with its own critic gate and its own commit**, and Stage 8's checks 8.9 and 8.10 are
explicitly conditioned on 5S, not on day one. Stage 0 and 1 grew because the safe two-part
pull-the-plug sequence, the burn-in, and the encryption/logon/remote decisions are real work.
---
Why this is Stage 0 and not an afterthought. The whole point of the machine is the WINDOW
DIRECTIVE — 7-8 days × 24 hours of continuous autonomous runtime (PRE_5090_BUILD_PLAN 2026-07-27p).
An unattended overnight run on unprotected power is a run that can lose a multi-hour asset-gen job,
a half-written index, or a mid-write registry to a brownout. **No unattended run starts before 0.7
verifies.**
SOURCE WARNING FOR THIS ENTIRE STAGE (M3). The repo's ruled basis for the UPS is **one place
only**: docs/PRE_5090_BUILD_PLAN.md:127-128 — the model (CyberPower PR1500RTXL2UC), 1500W pure
sine, ~62% load at 933.5W estimated, and *"auto-shutdown via PowerPanel/cloud monitoring is the
required config for unattended overnight runs."* That is all that is ruled. Everything else
below — outlet-group behavior, PowerPanel edition capabilities, the pre-shutdown command-file
hook, runtime-vs-percentage trigger semantics, cloud enrollment — is **unsourced operator
reasoning and must be verified against the unit's own manual and against the PowerPanel
edition actually installed** before it is trusted. The stage's own 0.3 instruction ("read the
unit's rear label rather than trusting any doc, this one included") governs the whole stage,
not just the outlet table. Two specific cautions carried from the critique: **PowerPanel Personal
and PowerPanel Business are different products** with different feature sets (a script /
command-file hook before shutdown is a Business-class capability, and the PR rack/tower line
is the Business-paired line — so install the Business agent unless the manual says otherwise);
and **remote/cloud monitoring on this class of unit generally depends on the optional
expansion-slot management card**, not a software checkbox — so J9 may require hardware that was
not ordered. Confirm before promising Josh outage visibility from the Ally X.
0.1 Unbox and inspect. Photograph the Puget packing slip and the as-built spec sheet before
anything else; it is the reference for every "which slot is which drive" question later. Reseat
nothing that Puget shipped seated — the build is validated as delivered. **DOA / damage check
(C7):** before powering anything, look for shipping damage, a shifted GPU or cooler, loose screws
rattling in the case, and bent connector pins. Anything found here is an RMA conversation while the
window is young, not a mid-week discovery. The real burn-in lands at 1.0 — this is the visual pass.
0.2 Plant the UPS first, machine second. Rack/tower unit; give it front-and-rear clearance. Let
it charge while you do the physical build-out — a UPS out of the box is not at full charge and an
early self-test on a partial charge reads pessimistic.
0.3 Outlet layout — the rule, not a memorized outlet map. The PR1500RTXL2UC splits its rear
outlets into battery+surge and surge-only groups; **read the unit's own rear label rather than
trusting any doc, this one included.** Assign by that label:
| Load | Group | Reason |
|---|---|---|
| The workstation (single PSU cable) | Battery + surge | the whole point |
| Primary monitor (one only) | Battery + surge | you must be able to *see* a shutdown in progress |
| Router / modem / switch | Battery + surge | a headless box that survives the outage but loses the network can't be reached, and can't reach Claude |
| Second/third monitors | Surge-only | pure runtime drain, zero value during a 4-minute window |
| Printer, speakers, chargers, anything with a motor or heater | Surge-only, or a different circuit entirely | a laser printer's warm-up spike alone can trip the unit |
0.4 Wall circuit check. The workstation alone can pull ~950W under a sustained asset-gen +
render load. Confirm the wall outlet is not sharing a 15A branch with a space heater / microwave /
window AC. [DECISION AT SETUP] whether a dedicated circuit is warranted — a genuine electrical
question no repo doc rules on; if the breaker trips once under load, the answer is yes.
0.5 Install PowerPanel and configure auto-shutdown. Install CyberPower's PowerPanel agent —
verify which edition the PR1500RTXL2UC line pairs with (Business is expected; see the source
warning above) because the command-file hook below is edition-dependent. Configure, in this order:
this works. Verify the agent sees the unit by model name, not just "a UPS". **Note the coupling
this creates:** the data cable is exactly what makes Windows able to present the UPS as a system
battery, which is what collides with the soak task's battery flags at 7.2. That collision is
resolved there, deliberately — do not skip it.
charge reads pessimistic and this figure becomes a recorded baseline).
percentage is a poor proxy at high load. *(Trigger semantics are an unsourced assumption; confirm
the agent exposes a runtime-based trigger at all before relying on it.)* Trigger with enough
margin that Windows completes a full shutdown (UE editor teardown, a mid-flight Python process,
NTFS flush) with room to spare. Given the measured runtime from calibration, reserve **at least 2×
the observed clean-shutdown duration** and floor it at 2 minutes.
pre-shutdown script (a Business-class capability), point it at a small
Tools/on_ups_power_event.cmd that (a) timestamps a line into a power-event log and (b) signals
any running soak/QA pass to terminate so the qa_pass.lock releases cleanly. **This file lives in
the GAME repo (C:\dev\Humanity\Humanity\Tools\) and is therefore a build-lane write**, not a
canon-session write (see the repo-lane map). Recommendation: defer to the first week — it is a
nice-to-have, not a gate, and it costs a cross-lane commit on the busiest day.
management card (check first). Enrolling a cloud account is Josh's action, never the
director's.
0.6 THE PULL-THE-PLUG TEST, PART (a) — transfer and outlet proof, with the PC NOT as the load.
0.3 deliberately leaves outlet-group assignment to a label read, which means that until this test
passes it is unproven that the workstation sits on a battery group. Running a full outage test
with a brand-new machine as the load — possibly mid-Windows-Update — risks exactly the hard drop
this stage exists to prevent. So prove the wiring at zero risk first:
1. Precondition: the UPS is at 100% charge and calibration (0.5) has completed.
2. Power the workstation off. Leave the monitor and the router on the battery group, and leave
the USB data cable connected to a *powered-off* PC only if the agent can still log — otherwise
run this part with the PC on but idle at the desktop with nothing installing.
3. Physically pull the UPS's wall plug (never a software-simulated outage — it does not exercise
the transfer-to-battery path).
4. Confirm: the battery-group outlets stay live (the monitor does not blink off), the unit alarms,
and PowerPanel logs an on-battery event with a runtime estimate.
5. Restore wall power within seconds. This part is a wiring proof, not an endurance test.
If any battery-group load drops here, the outlet assignment is wrong — fix it and re-run (a) before
going anywhere near (b).
0.7 THE PULL-THE-PLUG TEST, PART (b) — the full run-to-trigger. Only after (a) passes, and only
with these preconditions:
flight** (1.1 runs updates to quiescence; do not overlap them).
system is not idle" — that is both ineffective (Task Manager is not a load) and wrong for this
test. The runtime number worth recording is a real working-load figure, and there is no real
load on an empty machine. Split the two measurements: correctness now, the load-runtime number
at Stage 8 once the inference and asset lanes exist to load the machine with.
what verifies it (see below).
Then: pull the wall plug, let it run down to the trigger — do not restore power early — and
watch the trigger fire, Windows begin an orderly shutdown, and the machine power off cleanly, with
the monitor still lit (0.3) so it can be observed.
The auto-restart chain — configured, not assumed (B6.3 + C3). Rev 1 verified "if you configured
it, the machine restarts automatically" while no step configured it. For a 7-8 day × 24 h window
this is not optional: a *graceful* 3 AM shutdown that never comes back ends the window as surely as
a crash. Three links, all configured before 0.7 runs:
1. BIOS: Restore on AC Power Loss = Power On — set during the single BIOS visit at 2.2
(which therefore happens before this test; sequence Stage 2's BIOS step ahead of 0.7 if the day
runs strictly in order, or accept that 0.7 is the one Stage-0 step that waits for it).
2. Auto-logon — the ruled Interactive soak task (7.2) needs a logged-in session, so a
power-on that lands at a locked login screen yields no soak, no window, and no remote reach.
Configured at 1.10, with its own decision and its own Josh-owned credential (J4).
3. The soak task's battery flags — reconciled at 7.2, or the first thing that happens after
the machine comes back on battery-capable power is a refused or killed soak.
Restore wall power at the end and confirm the UPS recharges, the machine powers on by itself, and it
reaches a logged-in desktop unattended.
VERIFY (Stage 0): part (a) shows every battery-group load riding through a physical pull with a
PowerPanel on-battery event logged; part (b)'s PowerPanel event log contains a full
outage→on-battery→shutdown-command sequence with wall-clock timestamps; the machine powered off
cleanly with no dirty-shutdown entry in the Windows System event log (Kernel-Power 41 absent);
the machine powered back on by itself and reached a logged-in desktop with no keystroke; and the
measured idle on-battery runtime is recorded in the landing note (the *loaded* runtime figure is
captured at Stage 8, not here). Until this reads green, every run is attended.
---
1.0 Windows OOBE and the early burn-in (C7 · J1). Josh completes first-boot setup, including the
local-account vs Microsoft-account choice — this one matters beyond preference, because a
Microsoft-account sign-in is what can silently auto-enable device encryption (1.9). Then, *before*
any install decision is sunk, run a short burn-in: a memory pass (Windows Memory Diagnostic or
MemTest86 for one full pass over 128GB — budget hours, run it during a download window), a CPU
stress pass, and a GPU pass (nvidia-smi -q for ECC/thermal anomalies after a sustained load).
Rev 1 offered the Stage-7.5 soak as the thermal check, but that is the last stage — a hardware
fault found there costs the entire day. A tier-(c) red here stops the run.
1.1 Windows first-boot, updates, and the reboot loop. Run Windows Update to quiescence
(repeatedly — it will find more after each reboot). Do this before drivers so an update doesn't
clobber a hand-picked driver later. Do not overlap this with the Stage-0.7 outage test.
1.2 Power plan. Set the plan so the machine never sleeps and never hibernates, and the
display sleep is short. A 24-hour autonomous window is defeated by a sleep timer. Disable USB
selective suspend (it can drop the UPS's data link mid-run). Disable fast startup (it makes
"clean shutdown" a lie).
1.3 Confirm the three drives and their slots against the Puget spec sheet from 0.1. Note which
one Windows landed on — the assumption below is that Windows is on the Gen5 slot-1 drive, the only
one in the list that reads as a boot device. [DECISION AT SETUP] D-16: if Puget shipped a
different boot arrangement or pre-partitioned differently, do not re-image to match this doc —
re-map the roles below onto what shipped, and record the actual mapping in the landing note.
(Positive control: no repo doc describes the as-shipped partitioning, so this is genuinely open.)
1.4 Assign drive roles. HARDWARE_DECISION's workload analysis is what grounds this: it names the
UE bottlenecks at our scale ("69 World-Partition regions, cooks, lighting builds") as **CPU cores +
RAM + NVMe**, and separately notes book processing and reconstruction as trivially light. So the
fastest device goes to the engine's latency-bound working set, not to the model zoo.
The mechanism column is not decoration (B3). Rev 1 assigned four repo-relative paths to
non-repo drives, which is unachievable as written and produces a step that looks done and is a
no-op. harness/rag/config.json sets "store_dir": ".rag" and `"db_path":
".rag/humanity_rag.sqlite" — both repo-relative, so .rag and .rag/book_src (index.py:195`)
resolve inside C:\dev\humanity-forgotten\, i.e. slot 1. Same for Saved/Terrain (inside the
game repo) and the _ready_for_processing intake
(_source/02_Tier_2_Region_Pages/_ready_for_processing, the index.py --process-folder default).
An env var cannot move any of them. Every row below therefore names how it gets where it goes:
| Drive | Role | What lands there | Mechanism |
|---|---|---|---|
Slot 1 · 4TB Gen5 (C:) | Work tree — the engine's hot path | Windows · UE 5.8 engine install · C:\dev\Humanity\Humanity (Source, Content, Intermediate, DerivedDataCache, Saved) · C:\dev\humanity-forgotten (canon repo, small) · Visual Studio · Python | native — install location |
Slot 3 · 4TB Gen4 (D:) | Models + caches | HuggingFace cache (HF_HOME, HUGGINGFACE_HUB_CACHE) · Ollama blobs (OLLAMA_MODELS) · TORCH_HOME · FASTEMBED_CACHE_PATH · pip cache (PIP_CACHE_DIR) | env var (1.5) — clean |
ComfyUI models/ · llama.cpp GGUFs · WSL2 vhdx if D-1 lands that way | install path / app config — chosen at install, no env var needed | ||
the .rag/ vector store (repo-relative — cannot be env-var'd) | directory junction: mklink /J C:\dev\humanity-forgotten\.rag D:\rag_store — created before the first index.py run, or [DECISION] leave on C: (see below) | ||
Slot 4 · 8TB SATA (E:) | Bulk / cold data | book scan intake staging · concept-art Lane-R reference corpus (the owned National Geographic run) · soak/QA capture archives · local backups · audio libraries (Sonniss/BOOM, see 6c) | native — these are new directories with no repo-relative constraint |
.rag/book_src (repo-relative, under .rag) | inherited from the .rag junction above — it does *not* get its own separate row, and it lands wherever .rag points. If .rag stays on C: and book_src must be elsewhere, that needs a second, nested junction on book_src specifically | ||
Saved/Terrain GeoTIFFs (inside the game repo — slot 1) | junction mklink /J ...\Saved\Terrain E:\terrain, and it is a build-lane action; or leave on C: | ||
_ready_for_processing intake (inside the canon repo — slot 1) | stays on C: — it is a transient staging folder inside a git tree; stage bulk scans on E: and copy a batch in. Do not junction a tracked-tree subpath |
Recommendation on the .rag junction, stated so it can be argued with: the Gen5-endurance
argument is real (the store is rewritten on every full re-index), but a junction under a git tree is
a footgun class of its own — git status, git clean, and gate scripts all walk it. .rag is
gitignored, which makes it the *safest* candidate for a junction, and the alternative (editing the
git-tracked config.json) is a canon-repo edit that is gate-relevant and collides with the parallel
wave. **Recommendation: create the junction, before the first index run, and record it in the
landing note** so the next reader is not confused by a .rag that reports the wrong drive's free
space. If that feels too clever on day one, leaving .rag on C: costs nothing measurable at 10k
chunks — it is ~a few hundred MB, not a terabyte.
Rationale for the overall split, stated so it can be argued with: DDC and shader compilation are the
single most NVMe-latency-sensitive thing UE does at our region count, and they live beside the work
tree, so keeping both on Gen5 avoids a cross-device hop on every cook. Model weights are big
*sequential* reads at load time — Gen4 costs a second or two of load, never a throughput ceiling.
Bulk scans and capture archives are archival and belong on the cheapest capacity.
[DECISION AT SETUP] D-8: whether to split the DDC off the Gen5 onto the Gen4 to protect Gen5
endurance/free space. Recommendation: do not split on day one — measure DDC growth over the first
week's cooks first; splitting is a one-line [InstalledDerivedDataBackendGraph] change any time.
1.5 Redirect the caches by environment variable, before installing anything that populates them.
This is the step that is annoying to undo later. Set as user env vars:
HF_HOME, HUGGINGFACE_HUB_CACHE, TORCH_HOME, OLLAMA_MODELS, PIP_CACHE_DIR,
FASTEMBED_CACHE_PATH → onto the slot-3 drive.
Two vars in this set are read by the scheduled soak task, so they must be set at **user or
system scope where the task will see them** — a var exported only inside an interactive shell will
not reach a scheduled task (7.3 gets this right for the first and rev 1 omitted the second):
UE_EDITOR_CMD — set only if the engine ends up somewhere other than C:\Program Files\Epic Games\UE_5.8\... (the QA tooling probes that path by default —
Tools/run_qa_pass.py EDITOR_CANDIDATES: UE_EDITOR_CMD → UE_5.8 → UE_5.7).
HUMANITY_QA_TIMEOUT (C8) — read by both Tools/run_soak.py (as the --timeout default, 900s) and Tools/run_qa_pass.py. Same visibility trap, same fix. If the new machine's cold-start
editor launch is slower than 900s during the first cook, the soak will time out and report a false
red; set it explicitly rather than discovering the default at 4 AM.
VERIFY both from a task-scoped context, not just a fresh shell — the check is at 7.6.
1.6 Long paths. Enable Win32 long-path support (LongPathsEnabled) plus `git config --system
core.longpaths true` when git lands in Stage 3. UE + this project's deeply-nested Content paths hit
260 chars routinely.
1.7 Defender exclusions. Add real-time-scan exclusions for C:\dev, the UE engine directory,
the model cache root, and the DDC. Shader compilation and DataTable imports generate tens of
thousands of small files; on-access scanning is a measurable throughput tax on exactly the workload
the machine was bought for.
1.8 Machine name + a stable user profile path. The QA lock lives at
%LOCALAPPDATA%\HumanityQA\qa_pass.lock (a deliberate choice — run_qa_pass.py documents *not*
using the temp dir so the machine-wide rendezvous holds across worktrees and sessions). Nothing to
configure; just don't relocate LOCALAPPDATA.
1.9 BitLocker / device encryption — decide it, do not inherit it (C2 · J3). Windows 11 can
auto-enable device encryption on a Microsoft-account sign-in (1.0). Three consequences, all
load-bearing for this machine specifically:
the director's**, and it is never pasted into a session. If encryption is on, capture the key
before anything else depends on the machine booting unattended.
chain (0.7) assumes the machine comes back to a usable desktop; an encryption prompt at boot
breaks it as surely as no power-on setting at all.
workload the machine was bought for — thousands of small shader files and multi-GB weight loads.
[DECISION AT SETUP] D-17. Recommendation: leave C: as Windows configures it (accept
encryption if it is on, and escrow the key — the boot volume holds the repos and the security case
is real), and leave the slot-3 model drive and slot-4 bulk drive UNencrypted — they hold public
model weights, book scans, and rebuildable caches, and the throughput tax buys nothing. Verify the
actual state with Get-BitLockerVolume rather than assuming; Windows may have decided already.
1.10 Auto-logon — the third link in the auto-restart chain (C3 · J4). The soak task is ruled
LogonType: Interactive (7.2), which means it only runs while a user is logged in. Combined
with the 0.7 power-on setting, a UPS-triggered shutdown followed by an automatic power-on lands the
machine at a locked login screen: no soak, no window, no remote reach.
[DECISION AT SETUP] D-18. Two honest options:
netplwiz / the DefaultUserName+DefaultPassword registry pair).It stores a password on the machine — a real security tradeoff, mitigated somewhat by 1.9's
encryption on C: and by this being a single-user workstation on a home network. **The credential
step is Josh's (J4).**
morning, and the runbook states plainly that an unattended power event costs the remainder of that
night.
Recommendation: (a), because the WINDOW DIRECTIVE is 7-8 days × 24 h and option (b) converts
every brownout into a lost night. Whichever is chosen, record it — 0.7's verify tests this exact
chain, so an unrecorded choice becomes a mystery failure.
1.11 Remote reach — configure it or say plainly that there is none (C4). Stage 0.3 puts the
router on battery power with the justification that *"a headless box that survives the outage but
loses the network can't be reached, and can't reach Claude"* — but rev 1 then configured no remote
path at all, and the ROG Ally X appeared only as a UPS-notification target.
[DECISION AT SETUP] D-19. Options: (a) Tailscale (simplest for a home network behind NAT,
no port-forwarding, works from the Ally X and phone; an account sign-in — J10); **(b) Windows
RDP (built in, needs a VPN or port-forward to be safe from outside the LAN); (c) none — state
it plainly**: the window is attended-at-the-desk, and 0.3's router-on-battery justification narrows
to *outbound* reachability (the machine keeps talking to Claude through an outage), which is still a
valid reason to keep the router powered.
Recommendation: (a) Tailscale, because it makes "check on the window from the couch" a real
capability at near-zero configuration cost, and because a machine that can be reached is a machine
whose 4 AM stall can be cleared without walking to it. If Josh prefers no remote surface, take (c)
and delete the reachability half of 0.3's justification so the doc stops implying a capability
it does not have.
**D-19 RULED BY THE TRAVEL CONSTRAINT (Josh, 2026-07-28): option (a) Tailscale, promoted to a
PRE-DEPARTURE GATE. Josh leaves the country Friday 2026-08-07** and runs the whole trip
remote: Humanity on the 5090 via remote access; Continuo remote on the ROG Ally X. So the
setup week compresses: arrival 08-03/04 → setup day 1 (stages 0-4 + J1-J11 incl. J10 Tailscale
+ firewall pre-auth + Stage W watchers + the UPS pull-the-plug test, soak overnight) → Stage 8
close on day 2, then Continuo's up-front box window launches immediately (gold bar day-run
→ re-init overnight → corpus repair + the Sprout LoRA/art batch; projections ~2-4 box-days,
unmeasured) → the handover checkpoint lands 08-07 BEFORE departure: Continuo back to the
Ally X, Humanity holds the 5090, and the full remote path is TESTED from Josh's own
phone/laptop while he is still home (a Tailscale fault must never be discovered from abroad).
Slack rule: a Continuo run that overruns finishes unattended in the trip's first day — the
OPUS_BOX_QUEUE worklist's pass criteria make completion remotely checkable; Humanity's first
box work (kill tests, benchmark day) is remote-drivable. If Puget ships late, the unmovable
pre-Friday item is setup + verified remote access; Continuo's window shifts into the trip's
first days unattended.
**SCHEDULE REVISION (Josh, 2026-07-28 evening) — ARRIVAL PULLS FORWARD; DEPARTURE PINNED
PRECISELY; THE REMOTE STACK WIDENS; BOOKS NEVER GATE THE SLICE.**
- Arrival: possibly THURSDAY 2026-07-30. The integrator finished the build 07-28 and ships
UPS Next Day 07-29 — four-plus days ahead of the 08-03/04 estimate above. Every stage pulls
forward with it; the setup window widens to a full week, and benchmark day (U-40/U-42/U-44)
can run while Josh is still home. If UPS slips, nothing below changes — the unmovable
pre-departure item remains setup + verified remote access.
- Departure — PLAN WORST-CASE-FIRST (the Thursday-evening-only window). Josh's 07-28
evening messages pin: off work Thursday afternoon, "get things going before I leave to the
airport," 5 AM flight with the ~2 AM airport departure the same night. Read together with
the possible Thursday arrival, the operative plan assumes the ENTIRE hands-on window is
Thursday evening 07-30 — checklist done, remote path verified from the phone off-LAN,
before the 2 AM departure. If the flight is in fact the previously-recorded Friday 08-07
(the ruled block above), everything after Thursday evening is slack, benchmark day runs
attended, and nothing in this plan changes — worst-case-first loses nothing either way.
Whichever date holds: there is NO usable time on the flight morning; the handover
checkpoint and the off-LAN remote test complete the evening BEFORE.
- D-19 ADDENDUM — the remote stack is Tailscale + RustDesk (Josh, 2026-07-28 evening):
Tailscale stays the network layer (J10); RustDesk joins as the remote-DESKTOP layer for
phone-first operation — installed with unattended access + a permanent password, and
verified from the phone off-LAN (cellular, not house Wi-Fi) before departure. A remote
fault must never be discovered from abroad.
- Trip topology (refined): Humanity runs FULLY on the 5090; Continuo runs on the ROG
Ally X and touches the 5090 only for what requires it.
- BOOKS NEVER GATE THE SLICE (ruled): book processing runs ~2 more weeks beyond arrival;
its outputs land as ENRICHMENT passes only. Slice completion and AAAAA polish never wait on
the library — composing with the standing incremental book-pipeline doctrine (the pipeline
has visible done-homes and no full-library gate).
- **THE HANDS-ON CHECKLIST (the only things that require a body at the box — do these the
evening it arrives; everything else is remote-drivable):** (1) BIOS: restore-power-on-AC
after outage (+ scheduled power-on if the board supports it); (2) Windows auto-login +
never-sleep/never-hibernate (powercfg), lid/power-button do nothing; (3) Tailscale
enrolled (J10); (4) RustDesk installed, unattended access + permanent password set;
(5) BOTH verified from the phone on cellular; (6) UPS USB seated + agent installed;
(7) repo clones + the big model/asset pulls STARTED on local bandwidth; (8) a cold-reboot
test proving the machine comes back reachable with no keyboard, monitor, or login touch.
- THE WALK-THROUGH MODE (Josh, 2026-07-28 evening): setup day runs as a GUIDED sequence —
Josh's hands, the Humanity lane narrating step-by-step from the ROG Ally X: unbox → UPS
(battery-side outlets for the box + router, USB signal cable) → monitors/peripherals →
first boot → Windows first-run → the hands-on checklist above → **install Claude Code
desktop on the new PC and sign in**. FROM THAT POINT THE ON-BOX SESSION OWNS THE REST
(stages 0-8, J-items, drivers/CUDA/toolchains, cache env vars, watchers, burn-in) — Josh's
remaining role is physical-only asks (cable reseats, BIOS keys) and the off-LAN phone
verification. The Ally X walk-through script is DELIVERED: docs/5090_WALKTHROUGH_SCRIPT.md (fresh-context critic GO_WITH_FIXES, all fixes applied; Puget as-built folds included).
- THE CONTINUO BOX WINDOW — RULED TARGET: ONE DAY (Josh, 2026-07-28 evening). The
Continuo lane's claim of "full Friday–Sunday" is NOT accepted as stated; Josh directs the
window compress to ~ONE full box-day (Friday) by using the tech stack + open-source
efficiencies properly (local-model bulk, deterministic scripts, tiered fan-outs, overnight
unattended runs). A review brief goes to the Continuo lane (via Josh) asking it to (a) name
anything OUR setup must pre-install for its needs while hands are on the box, and (b)
return a compressed one-day worklist with remotely-checkable pass criteria — anything that
genuinely cannot fit runs UNATTENDED afterward without extending box occupancy (the
existing Slack rule generalized: overrun ≠ occupancy). Humanity takes the box after.
- **CONTINUO'S REPLY ACCEPTED (2026-07-28, via Josh) — four Thursday additions (~20 min +
overnight downloads), folded into the hands-on/on-box sequence:** (1) D:\continuo\ — repo
clone + its own Python 3.12 venv, pip install -r requirements.txt started Thursday night;
Continuo touches nothing outside this tree and its models do NOT go in HF_HOME. (2) Model
staging: LAN-copy Qwen2.5-14B-Instruct-Q4_K_M.gguf (~9GB) FROM THE ALLY (never re-download
— ledger rows pin sha256 e47ad95d…c008, VERIFY after copy) + one HF pull of the Q5_K_M
(~10.3GB). (3) Defender/App-Control allow onD:\continuo\. (4)config.local.yamlwith
n_gpu_layers: -1— box-only, never committed. Continuo ships itswindow_runner
(one-command, WINDOW_STATUS.json heartbeat, self-stopping, survives-Josh-unreachable)
before arrival; full detail on Continuo's board (CF-2).
- HUMANITY'S FOUR CONFIRMATIONS BACK (grounded in this runbook, not memory):
(1) MSVC: YES — Stage 3.4 installs Visual Studio (Epic's UE 5.8 pin) with the Desktop
development with C++ workload, a hard Stage-3 item for the C++ game repo regardless of
Continuo; local llama-cpp-python builds will have MSVC. RIDER: any local build goes against
CUDA 12.8, never 13.1 (Stage 2's Blackwell pin — 13.1 segfaults the sm_120 MMQ kernel).
(2) Comfy by Friday ~09:00: YES-CONDITIONAL — ComfyUI is the ruled day-one host install; the
on-box session prioritizes it Thursday night, conditional only on UPS-arrival Thursday and
no hardware-suspect stop (a burn-in fault halts everything by design). (3) The Puget spec
sheet + burn-in outputs PERSIST on disk as W0's thermals baseline (Stage 0.1 photographs +
the 1.0 burn-in logs; the on-box session records the exact path in the setup log).
(4) Watchers are CPU-only — boot-triggered git/task/service checks + a log write (Stage W);
zero GPU cycles during Continuo's Friday.
- **PUGET AS-BUILT + QC EVIDENCE (Josh posted the build checklist + spec sheet, 2026-07-28
evening; the build completed same day):** CONFIRMED against the plan — Windows 11 Pro
preinstalled with OOBE verified as the ship state (J1's assumption exact; the box will NOT
boot to a desktop), Secure Boot ENABLED by Puget QC, restore media created (D-16 fallback),
the three drives match Stage 1's layout letter-for-letter (Kingston Fury Renegade 4TB Gen5
primary · Samsung 990 Pro 4TB Gen4 projects/cache/scratch · Samsung 870 QVO 8TB SATA
long-term), 2×64GB DDR5-5600, ASUS RTX 5090 TUF OC 32GB, Super Flower LEADEX Titanium
1700W, Asetek 240mm AIO + PWM fan kit, plus an LG internal Blu-ray ReWriter (unplanned —
a free media-ingest lane). Courtesy-installed: Parsec (a preinstalled low-latency
remote-desktop FALLBACK — Tailscale + RustDesk stay the ruled stack; Parsec sign-in is
optional and not a Thursday item), NVIDIA App, Chrome.
- STAGE 1.0 BURN-IN RE-SCOPED (director ruling on Josh's report): Puget's Phase 1 memory
testing + Phase 2 stress test (Prime95 + aggressive CUDA load, thermal-camera + wattage
monitored at idle and under load) stand as the burn-in evidence of record, and Puget POSTS
the benchmark results + temperature logs at ship — that posted baseline IS W0's thermals
baseline (the "burn-in sheet" Continuo asked for). Stage 1.0 compresses to a light on-box
confirmation (brief load + nvidia-smi -q thermal/ECC read against Puget's posted numbers);
the on-box session downloads/captures the posted results into the setup artifacts at setup.
Hours of Thursday-night burn-in are RECLAIMED. The hardware-suspect stop rule is unchanged:
a delta from Puget's own baseline is still a stop-and-RMA-query signal.
VERIFY (Stage 1): Get-PhysicalDisk / Get-Volume shows three drives at the expected capacities
with the assigned letters; powercfg /a and the active plan confirm no sleep/hibernate; the cache env
vars resolve (echo $env:HF_HOME etc. in a fresh shell); a Get-MpPreference read shows the
exclusion paths present; Get-BitLockerVolume reports the intended per-volume state and (if
encryption is on) the recovery key is escrowed somewhere Josh controls; the burn-in passes with no
memory errors and no nvidia-smi -q ECC/thermal anomaly; and — if D-18 chose (a) — a **cold reboot
reaches the desktop with no keystroke** (this is the same observable 0.7 depends on; proving it here
means 0.7 tests the power path rather than debugging logon).
---
The Blackwell-specific facts that bind here (M7a — attributed per section, and per source tier):
1. llama.cpp must be built/run against CUDA 12.8, NOT CUDA 13.1 — Q3_2026_MODELS_REFRESH.md
§3.4. 13.1 is documented to segfault llama.cpp's Blackwell (sm_120) MMQ kernel and silently
fall back to slower cuBLAS. Silent degradation is the worst failure mode: it looks like it works.
§3.4's own conclusion is a ruling, not a candidate: *"no change to the existing llama.cpp +
GGUF Q4_K_M reference-runtime pick — pin CUDA 12.8."*
2. NVFP4 / MXFP4 is Blackwell-exclusive — the ~25%-off-Q4_K_M memory figure is §3.3, not
§3.4, and the accuracy claim at source is *within ~1% of FP8 accuracy* — not "~1%
accuracy cost relative to Q4_K_M," which is what rev 1 wrote. [INFERRED] at source. §3.4
separately notes kernel support was "actively merging" at research time. A dev-machine
optimization only; the shipped min-spec quant stays portable GGUF Q4_K_M.
And the third, from LOCAL_3D_ASSET_GEN.md §1.1 [VERIFIED]: **TRELLIS.2 officially pins CUDA 12.4
/ PyTorch 2.6.0 and is Linux-only.** Those pins cannot all be one global toolkit.
2.1 THE SINGLE BIOS VISIT — do this FIRST, before touching a display cable (B5). Rev 1 said
"re-cable the monitors, enable the iGPU in BIOS if it is not already" — **that order can leave the
machine headless.** If the iGPU is disabled, or the initial-display-output is set to PCIe (a common
default when a discrete card is installed), re-cabling first yields no signal on either port and
no way back into BIOS without re-cabling again. The dependency runs the other way.
There should be exactly one BIOS trip on day one, and it does both jobs:
1. With the monitors still on the 5090, enter BIOS.
2. Enable the integrated GPU and set initial display output = iGPU (or Auto).
3. Set "Restore on AC Power Loss" (a.k.a. AC Back / After Power Failure) = Power On. This is
link 1 of the auto-restart chain that Stage 0.7 verifies (B6.3) — a graceful 3 AM shutdown that
never comes back ends the 7-8 day window as surely as a crash.
4. While here: confirm the memory is running at its rated EXPO/XMP profile as Puget configured it
(do not change it — the build is validated as delivered), and note the BIOS version.
5. [J2] If a BIOS/supervisor password is set, that is Josh's keystroke.
6. Save, exit, boot, and confirm the motherboard video port is live before going further.
7. Only now move the monitors to the motherboard outputs.
2.2 THE iGPU RULE — why step 2.1 exists. HARDWARE_DECISION's accelerator addendum rules it
explicitly: *"monitors plug into the motherboard (the 9950X3D's integrated GPU carries Windows/DWM/
browser VRAM), leaving the 5090 headless with ~its full 32GB."* This is what makes the tight
29-of-32GB Hunyuan3D-2.1 combined-mode fit deliverable. Puget will very likely have shipped the
monitors wired to the 5090's display outputs, because that is the normal build — so **expect the
rule to arrive violated** and treat 2.1 as a certainty, not a contingency. After the move, confirm
Windows composites on the iGPU (the Stage-2 VERIFY's near-zero-idle-VRAM check is the proof).
2.3 Driver. Install the current NVIDIA Studio or Game Ready driver for the 5090. Prefer Studio
for a workstation doing sustained compute + DCC work; it is the slower-moving, stability-tuned branch.
Do a clean install (the installer's own "perform a clean installation" checkbox) so nothing from
Puget's factory image lingers. Driver after BIOS, so the iGPU is present when the display stack is
built.
2.4 CUDA toolkits — per-lane, not global. [DECISION AT SETUP] D-2 (narrowed — see M2). Rev 1
framed this as a wide-open decision, which invites re-litigating a pin that is already ruled. **What
is NOT open:** 12.8 for llama.cpp is a ruling (Q3 §3.4, quoted above), and 12.4 for TRELLIS.2 is the
tool's own published requirement — neither is a choice. **What IS open is only the isolation
mechanism**: per-lane venv/conda vs WSL2 vs a ComfyUI-portable bundle (and that overlaps D-1).
Recommendation:
forward-compatible; the *toolkits* live per-environment.
binaries, this is satisfied by the shipped runtime and no toolkit install is needed at all.
(conda/venv, or the WSL2 distro if D-1 lands that way).
resolved upstream.
2.5 Re-check the NVFP4 status. Before locking the inference lane in Stage 5, check whether
llama.cpp's NVFP4/MXFP4 Blackwell kernels have fully landed since the 2026-07-15 research date. If
yes, it is a memory win on the dev box (~25% off Q4_K_M per Q3 §3.3 [INFERRED]). **[DECISION AT
SETUP] D-9** — a cheap re-check, not a research question.
VERIFY (Stage 2): nvidia-smi reports the RTX 5090 with 32GB (32,768 MiB class) and a driver
version, and shows near-zero VRAM in use with the desktop up (that near-zero figure is the proof
the iGPU rule landed — if Windows/DWM is holding 1-2GB on the 5090, the monitors are still on the
wrong port). nvidia-smi -q shows no ECC/thermal anomalies. The BIOS "Restore on AC Power Loss"
setting reads Power On (re-enter BIOS to read it back, or verify behaviorally at 0.7). Record the
idle VRAM figure — it is the baseline every later "did this OOM?" question is measured against.
---
3.1 Git + Git LFS + credentials. Install Git for Windows (which brings the Bash tool's POSIX
shell) and Git LFS — the game repo's .gitattributes routes *.uasset, *.umap, and every
image/audio/media extension through LFS, so a clone without LFS gets pointer files and a project that
will not open. Run git lfs install once per user.
Auth for both GitHub repos — https://github.com/milkman3790/HumanityForgotten.git (canon) and
https://github.com/milkman3790/Humanity.git (game). Authenticate via the Git Credential Manager
browser flow or gh auth login. This is J5 in the JOSH AT THE KEYBOARD block — the standing
rules prohibit an agent entering credentials or completing an account sign-in. The director verifies
afterward by pushing a trivial commit, never by handling the secret.
Set once: git config --global core.longpaths true, git config --global user.name /
user.email to match the existing commit history (milkman3790 / jmilks3790@gmail.com), and
core.autocrlf to match whatever the existing repos use so the first clone doesn't produce a
whole-tree line-ending diff.
3.2 Python. The current machine runs Python 3.14.4 and the harness runs clean on it. Install
the same 3.x line to avoid a version-shift debugging tax on day one, add it to PATH, and confirm
python --version from a fresh shell.
**MEASURED FLOOR: the canon harness requires Python 3.13 or newer — this is a hard floor, not a
preference (recorded 2026-08-02).** Running harness/run_gates.py under the Continuo venv's
Python 3.12.10 (C:\dev\continuo\Continuo\.venv\Scripts\python.exe) turns three gates red:
stress,fidelityandsfx_coverage, the last with
TypeError: Path.read_text() got an unexpected keyword argument 'newline'— thenewline
parameter was added to Path.read_text in 3.13. Under Python 3.14.4 the same tree is 36/36
green, exit 0. The failure is loud rather than silent (run_gates.py exits 1 correctly), but the
findings look like canon damage, so name the cause here: a wrong-interpreter run reads as a
broken repo. Any brief, agent prompt or script that hands out an interpreter path for this
harness must hand out a 3.13+ one; the Continuo venv is that project's interpreter and is not
interchangeable with this one.
3.3 Harness dependencies. The harness's 29 gates are near-stdlib by design, with a small real
dependency set. Read off actual imports rather than a requirements file (the canon repo has none at
top level — only harness/rag/requirements.txt):
harness/rag/requirements.txt (M7c — rev 1 listed pypdf as if it sat outside this file; it is line 4 of it): sqlite-vec (the decided single-file vector store), fastembed
(real local multilingual ONNX embeddings, daemon-free — the primary backend per
harness/rag/config.json), numpy, and pypdf (native-text PDF extraction).
openpyxl (the registry converter / fidelity gate reads the frozen _source/00 xlsx baseline) and fitz / PyMuPDF (the book
skeleton pass and OCR backends).
psutil here rather than at 7.1 if convenient — see 7.1 for the honest reason.Install with python -m pip install -r harness/rag/requirements.txt plus openpyxl and pymupdf
after the repo lands in Stage 4. Note the design property that makes this safe: **every rag dep is
optional at import** — the pipeline degrades to a pure-Python cosine store and a deterministic hash
embedder and stamps embedding_is_real=false in the manifest, so a missing dep never fakes a real
index. Do not accept that fallback on the new machine — Stage 5 verifies embedding_is_real=true.
3.4 Visual Studio + the UE build prerequisites. The game repo is a C++ project (`Source/
Humanity + Source/HumanityEditor, .Target.cs files, native USTRUCT` row types — 36 of them
already generated) and it compiles the NeoStackAI plugin from source. So a full C++ toolchain is
mandatory, not optional:
Game development with C++ (brings the UE installer integration), the Windows 10/11 SDK, and
.NET desktop development (UnrealBuildTool / AutomationTool are .NET).
own "Setting Up Visual Studio" page for 5.8 at setup rather than assuming the version the old
machine had. (Positive control: UE_BUILD_AUTOMATION.md contains no "Visual Studio" / "MSVC" /
"Windows SDK" / ".NET" version string anywhere, so no repo doc rules this — it is genuinely open,
and it was missing from rev 1's register.)
3.5 UE 5.8 install — and the BuildId verify rev 1 never did (M12). Install the **Epic Games
Launcher, sign in (J6 — Josh's action), and install Unreal Engine 5.8.0**.
Install from the Epic Launcher, not a source build. A source build produces a **different
BuildId**, which silently re-breaks the NeoStackAI plugin — the exact failure the never-drop-in-a-
prebuilt rule exists to prevent, arriving from the other direction. The game repo pins **UE 5.8.0,
BuildId 55116800**, and its CLAUDE.md states plainly: *do not upgrade the engine version without the
director lane.*
Rev 1 made "match the BuildId" a hard rule and then never read it. Add the read: after install,
open Engine/Build/Build.version in the engine directory and confirm the BuildId is 55116800
before running the Stage-3.5/4 Build.bat compile. If it does not match, stop — compiling
against a mismatched engine is how the plugin breaks in a way that takes a day to diagnose.
Include the debug symbols if disk allows — the soak greps editor logs for Fatal / Assertion /
LowLevelFatal markers and symbolized crashes are worth the space.
3.6 The engine-association gotcha (found while writing this runbook). Humanity.uproject carries
"EngineAssociation": "{540D9A2B-4BA8-67DE-F699-F685F2EB38D9}" — a GUID, which resolves through
HKCU\Software\Epic Games\Unreal Engine\Builds. On the current machine that key exists but is
empty, so the association is already effectively stale; everything works because every automation
path invokes explicit absolute paths (UnrealEditor-Cmd.exe, Build.bat). On the new machine, either
(a) add the GUID→engine-path value to that Builds key, or (b) leave it and rely on absolute paths —
but know that "Generate Visual Studio project files" and double-click-to-open will prompt for an
engine until it is registered. Do not commit a change to EngineAssociation without the director
lane; it is a tracked file in a one-writer repo.
VERIFY (Stage 3): git lfs version returns; python --version matches the pinned line;
nvcc --version (if a toolkit was installed) reports the intended CUDA; **Engine/Build/Build.version
reads BuildId 55116800**; and — the real check —
Engine\Build\BatchFiles\Build.bat HumanityEditor Win64 Development -project=C:\dev\Humanity\Humanity\Humanity.uproject
compiles to success, foreground, exit code read. That single command proves VS, the SDK, .NET,
UnrealBuildTool, the engine install, and the NeoStackAI-from-source rule all at once. (It runs after
Stage 4's clone; sequence it there and treat Stage 3's verify as provisional until then.)
---
4.1 Clone both repos to the same absolute paths as the old machine. This is not cosmetic — paths
are hard-coded in live tooling: Tools/nightly_soak.cmd does cd /d C:\dev\Humanity\Humanity;
harness/rag/config.json names an absolute out-of-repo memory glob
(C:/Users/joshu/.claude/projects/C--dev-humanity-forgotten/memory/*.md); the game repo's CLAUDE.md
names both trees by absolute path as the one-writer-per-repo boundary.
git clone https://github.com/milkman3790/HumanityForgotten.git C:\dev\humanity-forgotten git clone https://github.com/milkman3790/Humanity.git C:\dev\Humanity\Humanity
Let the game clone pull LFS fully (git lfs pull if the clone used GIT_LFS_SKIP_SMUDGE). Confirm a
.uasset is real content, not a 130-byte pointer file.
4.2 Restore the out-of-repo pieces git does not carry. These are the silent-breakage class —
measure and copy them deliberately:
C:\Users\joshu\.claude\projects\C--dev-humanity-forgotten\memory\ — theMEMORY.md index plus its ~50 topic files. It is indexed by the RAG canon scope and is load-bearing
for orientation. Copy it.
~/.claude/ global config: CLAUDE.md (the global working agreements — model tiering, the director pattern), settings.json (the SessionStart/compact hook that runs
hooks/compaction-recovery.py), the hooks/ directory itself, and keybindings.json if present.
.claude/settings.local.json and .claude/skills/ in the canon repo are git-tracked or local-only depending on the file — verify .claude/settings.local.json came across
(it is typically gitignored) and that .claude/hooks/cascade-continue.py and
compaction-recovery.py are present.
CLAUDE_CODE_EXECUTABLE → the installed claude.exe path. The game repo's CLAUDE.mdrecords this as a *user* env var that NeoStack's ACP bridge depends on to reuse the authenticated
CLI (C:\Users\joshu\.local\bin\claude.exe on the old machine — re-point it to wherever the new
install lands).
.rag/ store: it is a rebuildable build artifact (gitignored) whose git-tracked declaration is harness/rag/index_manifest.json. Recommendation: rebuild it rather than copy it
— rebuilding on the new machine's *real* fastembed backend is strictly better than importing a
store that may have been built on the hash fallback.
Budget it honestly (B2): the live harness/rag/index_manifest.json reads
chunk_count: 10084, elapsed_sec: 309.0 — 10,084 chunks in ~5 minutes, not the "~8s for ~7k
chunks" rev 1 claimed. That figure was copied verbatim from a stale docstring at
harness/check_index_freshness.py:13 (# ~8s, updates the manifest hash) and is wrong by ~38×.
The rebuild-over-copy recommendation still stands on the *real-backend* argument; only the
arithmetic behind it changed. Budget five minutes plus the fastembed model download, and note that
it will grow with the corpus. [DECISION AT SETUP] D-12: .rag/book_src (the processed book
corpus) is a different matter — it is large and expensive to regenerate. Measure it, then copy it to
the slot-4 bulk drive over the network or by external disk. Measure before you plan the copy; a
du -sh on the old machine ran past two minutes while this runbook was being written, which is
itself the datapoint: budget real time for this transfer.
4.3 Claude Code install + auth. Install Claude Code; Josh signs in (J7).
Confirm the three Max x20 subscriptions chain as expected for the factory (the capacity note's own
framing). Verify the project loads its CLAUDE.md stack: the global ~/.claude/CLAUDE.md, the canon
repo's CLAUDE.md, and the game repo's CLAUDE.md are three separate instruction layers and all
three matter.
4.4 Verify the hook environment fires. The SessionStart/compact hook is what re-orients a
session after compaction — a 7-8-day autonomous window will compact many times, so a silently-broken
hook is a real risk. Force or await one compaction and confirm the recovery text appears.
VERIFY (Stage 4): from the canon repo, python harness/run_gates.py (unpiped — the standing
gate-verification gotcha; piping has masked exit codes before) returns exit 0 with all 29 gates
PASS/SKIPPED and no FAIL, and harness/gates_scorecard.md is freshly written. From the game repo, the
Stage-3.5 Build.bat command compiles clean. Both repos show a clean git status and can git push
a trivial no-op branch (proving auth) — then delete the branch.
---
What this lane is for, per HARDWARE_DECISION's workload analysis: local models do **bulk
mechanical work — triage, embeddings, OCR assist, and the 14B-class runtime REFERENCE**. Reasoning
and judgment stay on the Claude Max subscriptions by design. Do not install a local 70B; that
capability is deliberately assigned elsewhere.
| Lane | Model class | VRAM | Source |
|---|---|---|---|
| Runtime reference/ship tier | 14B @ Q4_K_M | ~8-9GB | Q3 §3.3 [INFERRED] |
| Prestige PC tier | 7-8B @ Q4_K_M | ~5GB | UNSOURCED ESTIMATE — see note |
| Min-spec tier | 3-4B | ~2.5GB | UNSOURCED ESTIMATE — see note |
| Draft/ambient tier | 0.6-1.7B | ~1GB | UNSOURCED ESTIMATE — see note |
| Embeddings | fastembed paraphrase-multilingual-MiniLM-L12-v2, 384-dim ONNX | CPU — no VRAM | harness/rag/config.json [VERIFIED] |
| VLM-OCR | PaddleOCR-VL / DeepSeek-OCR class | few GB | ocr_backends.py — a *class*, not a pick |
| 3D-gen (Stage 6 adjacent) | Hunyuan3D-2.1 combined | 29GB — the ceiling case | LOCAL_3D_ASSET_GEN §1.2 [VERIFIED] |
| 3D-gen geometry | TRELLIS.2 | 24GB floor | LOCAL_3D_ASSET_GEN §1.1 [VERIFIED] |
Citation correction (M7b). Rev 1 cited the 7-8B / 3-4B / 0.6-1.7B VRAM figures to "Q3 §3.6."
§3.6 is a candidate-name table with no VRAM figures at all. §3.3 supplies only the 14B (8-9GB)
and 32B (18-20GB) numbers. Those three rows are **plausible operator estimates presented as
citations** in rev 1 — they are relabeled here rather than deleted, because they are still useful
planning figures. Measure them on day one (Stage 5's VERIFY records peak VRAM) and replace the
estimates with observations in the landing note.
The binding arithmetic: 29GB of 32GB is the tight fit the whole hardware decision turns on. That
is why the iGPU rule exists and why heavy lanes run sequentially, not concurrently — a resident
14B (9GB) plus a Hunyuan combined run (29GB) does not fit and never will. An OOM on a real run is
HARDWARE_DECISION's literal upgrade trigger #1, so an OOM caused by our own co-residency sloppiness
would be a *false* trigger. Keep them serialized.
5.1 Day-to-day runtime: Ollama. Q3 §3.4 names it the natural day-to-day dev-tooling choice
(wraps llama.cpp, confirmed working well on the 5090). Install it, point OLLAMA_MODELS at the
slot-3 drive (done in 1.5).
5.2 Reference runtime: llama.cpp, CUDA 12.8. The ruled reference runtime is unchanged —
llama.cpp + GGUF Q4_K_M. If building from source, build against 12.8; if using prebuilt
binaries, verify the build's CUDA version and that it is *not* 13.1.
5.3 Pull the tier ladder. All picks below are Apache-2.0 or MIT — **zero licensing exposure at
ship**, satisfying the unrestricted-by-default rule (Q3 §3.2). Note the two live traps that section
names: Llama 4 / Llama-based DeepSeek distills carry the 700M-MAU clause + attribution +
policy-propagation overhead and there is no longer any reason to reach for them; and **Gemma
4 (2026-03-31) flipped to Apache 2.0**, so the historical Gemma license problem is gone for 4+ only —
Gemma 3/3n still carry the old custom terms.
| Tier | Pull | Note |
|---|---|---|
| 14B reference | [DECISION AT SETUP] D-4 — Qwen3-14B · Phi-4 (14B) · Ministral-3-14B · Gemma-4 12B-class | Q3 §3.6 lists these as co-equal candidates; no single pick is ruled. Recommendation: pull Qwen3-14B and Phi-4 both, A/B on the triage-floor task, keep the winner. |
| 7-8B | Qwen3-8B or Ministral-3-8B | |
| 3-4B | Qwen3-4B · Gemma-4 E4B · Phi-4-mini | |
| 0.6-1.7B | Qwen3-0.6B / 1.7B | the draft/ambient lane |
The 28-32B prestige tier is dev-side/offline only — Q3 §3.3 is concrete that a 32B at ~18-20GB
cannot reliably co-reside with a real UE renderer wanting 12-20GB on one 32GB card. Pull it only if
an offline evaluation actually needs it.
5.4 Embeddings — get embedding_is_real=true, and COMMIT THE MANIFEST (B10).
pip install fastembed sqlite-vec numpy, then rebuild: python harness/rag/index.py --scope canon
(~5 min / ~10k chunks — see the corrected budget at 4.2). Watch for the trap recorded in memory: the
canon rebuild once wiped the shared substrate vector table because index_manifest.json is
shared — rebuild canon scope on a machine where the book substrate has not yet been indexed, i.e.
now, before any book-scope indexing, and re-check the manifest after each scope.
Then commit the manifest — this is a verify-chain break rev 1 shipped.
harness/rag/index_manifest.json is git-tracked (it is the declaration for the gitignored
.rag/ build artifact) and is rewritten by every --scope canon run;
harness/check_index_freshness.py says so in its own guidance: *"rebuild: python
harness/rag/index.py --scope canon (then commit harness/rag/index_manifest.json)."* Rev 1 never
said to commit it, so Stage 8.14's "both repos clean" failed by construction — or, worse, an
operator would "clean" it with a checkout and re-red the index_freshness gate on the next run.
git add harness/rag/index_manifest.json git commit -m "5090 setup: refresh canon index manifest (real fastembed backend)"
Explicit path only — the standing never-git add -A rule (it has swept another lane's work into
a commit before). This is a canon-repo commit and must be **sequenced against the parallel
editing wave**: if the wave is mid-flight, hold the commit and coordinate rather than racing it.
A stale-doc note worth carrying: harness/rag/README.md still calls Ollama+nomic-embed-text
the "primary (recommended)" backend while harness/rag/config.json ranks fastembed first (real,
multilingual, daemon-free). The config is the operative artifact and fastembed is the correct pick.
Flag the README for a one-line correction in the canon lane — a stale doc re-teaches the wrong
default to the next reader. And its neighbor: harness/check_index_freshness.py:13's "~8s"
docstring is stale by ~38× against the live manifest (B2) — correct both in the same pass.
5.5 The triage floor — prove the seam here, WRITE it in 5S. This is the single highest-leverage
thing the machine unlocks — docs/ROADMAP_TO_5090.md Track 4 built the entire pipeline against a
deterministic stub precisely so arrival day is "wire the model and go." harness/rag/triage_floor.py
documents the seam: three backends (stub / local / opus) behind
scorer.score(skeleton, canon_pack), with LocalScorer a NotImplemented loader whose docstring
is the return contract. "Wire the model and go" is still code — it lands in Stage 5S, not in
a setup stage (M6).
Day-one steps (installs and proofs only): (a) python harness/rag/triage_floor.py selftest —
proves the stub path still round-trips on the new machine; (b) build-canon-pack; (c) pull the
candidate model. Implementing LocalScorer is CODE, and it moves to Stage 5S — see below.
[DECISION AT SETUP] D-5: which tier reads the books — 7B (cheap, 1,873 books fast) vs 14B
(better ranking, slower). The floor is a *ranking* problem, not an authoring one; recommendation is
to start at 7-8B, measure, and escalate only if the ranking is visibly noisy. (triage_floor.py:513
says only *"wire the local 7B/14B here"* — no doc picks between them.)
5.6 The OCR / VLM lane — install the models here, wire the seam in 5S.
harness/rag/ocr_backends.py is the pluggable seam: tesseract is the working default (via
ocrmypdf, with split_spreads.py pre-splitting two-page spreads), and get_backend("vlm") is the
NotImplemented seam the 5090 fills. The named target class is PaddleOCR-VL / DeepSeek-OCR
for the hard remainder — the ~3 Oxford Ancient Egypt volumes and non-Latin/degraded scripts sitting
in _needs_ocr/.
[DECISION AT SETUP] D-6: the briefs name a *class*, not a pick (RESEARCHED_STACK: *"a VLM-OCR
(PaddleOCR-VL/DeepSeek-OCR class)"*; ocr_backends.py:237 likewise). Install both candidates on
day one, then decide on measured output quality over the worst three scans — after 5S makes the
backend callable.
Two operational facts rev 1 omitted (M6):
_needs_ocr/_vlm_only/ and are *"never globbed by the current tesseract drain"* — pointing the VLM at _needs_ocr/ alone will miss the actual queue.
<scan>.vlm sidecar override (VLM_MARKER_SUFFIX) — that is theoperator's real selection mechanism for routing one book to the VLM backend.
Confirm TESSERACT_DIR (C:\Program Files\Tesseract-OCR, hard-coded at ocr_backends.py:48
with no existence check) exists on the new machine, or the default backend breaks silently.
This is the genuine silent-degradation risk on this machine — see the withdrawn psutil claim in the
REVISION block for its former, wrongly-accused companion.
5.7 D-7 — ACE: NOT an open fork. A settled recommendation awaiting Josh's ruling (B7).
Rev 1 routed this to "a Josh sitting with a full alternatives brief." That brief already exists
and re-opening it is the worst failure class for a Josh-facing document — it makes him re-adjudicate
analysis he already has.
docs/pipeline_review/ALTERNATIVES_MATRIX.md slot 5 runs the standing decision protocol on
exactly this fork — options A (bespoke) / B (adopt ACE) / C (hybrid) — and lands:
RECOMMENDATION — C, the HYBRID. Adopt ACE as the runtime SUBSTRATE… (line 198)architecture)
RESEARCHED_STACK.md carries it forward as matrix output: *"runtime = HYBRID (ACE substrate + our
strategy-token/canon-graph guardrails) pending the weights spike."*
So the standing posture is HYBRID (option C), and the day-one item reduces to the **two named
pre-condition reads** — nothing more:
1. The bundled-weights license read (see the license correction below).
2. A direct read of whether ACE's Agent tier can be constrained to read-only token emission —
the architectural compatibility question the strongest objection turns on.
Both are desk reads, not engineering. Josh's ruling is still owed, but on a recommendation with a
brief behind it, not on a blank fork. Day-one action stays: install and smoke-test only (a
separate download from the core GitHub repo — developer.nvidia.com/ace-for-games carries the UE5
plugin layer).
The license claim, corrected (B8). Rev 1 stated flatly: *"the ACE Game Agent SDK (v0.5.0,
2026-06-15, Apache 2.0…)."* ADVERSARIAL_ADJUDICATION.md overrules the unqualified form:
unsettled) — the weights-license read is a pre-adoption spike"* (via RESEARCHED_STACK v2
§ADJUDICATED)
code-license from weights-license in Q3 §3.5"*
So the accurate statement is: **the CODE license is Apache-2.0-or-MIT — itself unresolved — and it
does NOT cover the bundled model weights, whose license is an unread pre-adoption spike.** Given
this runbook opens by calling the licensing rule *binding*, restating a contested license as settled
was the highest-stakes citation error in rev 1. The other verified ACE facts stand: v0.5.0,
2026-06-15, on-device, UE5 Blueprint/C++ plugins, ~8GB VRAM budget, shipped in PUBG / Total War:
PHARAOH / Mecha BREAK.
---
Rev 1 budgeted Stage 5 at 90-150 minutes while it contained two NotImplementedError seams.
Writing code into the canon repo is not an install; it needs a design pass, a fresh-context critic
gate, and its own commit. Both move here (M6):
| Seam | File | What must be written | Gates |
|---|---|---|---|
LocalScorer | harness/rag/triage_floor.py | the loader + score(skeleton, canon_pack) against the D-5 model; the existing docstring is the return contract | selftest still green · a --backend local run diffed against the stub's ranking on the same books |
| VLM OCR backend | harness/rag/ocr_backends.py | VLMBackend._load_model() and ocr_pdf() — both currently raise NotImplementedError | one _needs_ocr/_vlm_only/ scan that tesseract failed comes back readable |
Both are canon-repo code changes → full run_gates.py suite unpiped + a fresh-context critic,
per the standing rule that registry/canon edits are never "trivial mechanical." **Stage 8 checks 8.9
and 8.10 are conditioned on 5S**, not on day one — a red there on setup day is expected, not a
defect. Budget 3-6 hours as its own task, scheduled after the machine is proven.
---
VERIFY (Stage 5): an inference smoke test — load the 14B, run a fixed prompt, and record
tokens/sec plus peak VRAM from nvidia-smi during the run; the number goes in the landing note as
the machine's baseline (and it is what replaces the unsourced VRAM estimates above).
harness/rag/index_manifest.json shows embedding_is_real=true and a non-zero chunk count, **and
the refreshed manifest is committed** (5.4). python harness/rag/query.py "<a canon question>"
returns cited hits with [SRC: ...] paths. triage_floor.py selftest passes on the stub path
(the --backend local record is a 5S deliverable, not a Stage-5 one). The index_freshness gate
passes in the full suite.
---
Josh owns NeoStack lifetime (RESEARCHED_STACK: "NeoStack — OWNED (Josh, lifetime)"). The core
plugin is a one-time purchase (~$110), bring-your-own AI subscription, no credits burned by NeoStack
itself; the $20/mo Cloud tier is optional and this project already has its own git+harness CI
equivalent, so it stays skippable.
A contradiction the research briefs and the build lane disagree on — and the build lane wins.
RESEARCHED_STACK.md and NEOSTACK_AI.md §0.3 both carry "NeoStack-on-5.8 UNVERIFIED" as a standing
ENGINEERING-SPIKE, and Q3_2026_MODELS_REFRESH.md §2.5 sharpens it (Josh's Discord quote names
SIK/EIK, not AIK = NeoStack). But the game repo's own CLAUDE.md records the spike as
already closed by hands-on evidence: Plugins/NeoStackAI is **installed as source and compiled
against UE 5.8.0 BuildId 55116800, with the MCP channel verified live 2026-07-19** at
http://127.0.0.1:9315/mcp and smoke-tested end to end (actor spawn + viewport screenshot). Trust
content over labels: the spike is closed; the research briefs are simply older than the evidence.
Carry a correction back to the briefs in the canon lane.
One clause of precision on that correction: what is closed is **source-compiled-on-5.8 + the MCP
channel + Agent Chat. The marketplace/Fab 5.8 tag** remains unconfirmed at source (Q3 §2.5's own
point). Write the correction that way, or the brief-fix overshoots the evidence.
Steps:
6a.1 VERIFY the plugin source is present — do NOT install, download, or overwrite it (B4).
Rev 1 said *"install the NeoStackAI plugin as source into Plugins/NeoStackAI"* — a **no-op at
best, and destructive at worst. git ls-files Plugins/ in the game repo returns 604 tracked
files, including 552 C++ source files under Plugins/NeoStackAI/Source/** (ACPClient.cpp,
ACPAgentManager.cpp, NeoStackAI.Build.cs, …). **The plugin source is already in the repo and the
Stage-4.1 clone delivers it.** There is nothing to install.
Worse, "install … into Plugins/NeoStackAI" reads as fetch-and-drop, which is precisely the
prebuilt/zip overwrite the game repo's CLAUDE.md bans: *"a prebuilt binary drop-in will re-break with
a BuildId mismatch. Never replace it with a prebuilt zip; on plugin or engine updates, rebuild
from source."* A day-one operator following rev 1's line literally could overwrite 552 tracked
source files.
The correct step: confirm Plugins/NeoStackAI/Source/ came across in the clone (`git ls-files
Plugins/ | Measure-Object -Line → 604) and let the Stage-3.5 Build.bat` invocation compile it.
That compile is the only "install" this plugin ever gets. Never download it. Never overwrite it.
6a.2 Confirm the two editor-automation channels the build lane depends on:
http://127.0.0.1:9315/mcp, streamable HTTP, server name unreal-editor, ONE tool by design (execute_script, a Lua meta-tool over 80+ bindings). **Every request after
initialize must echo the MCP-Session-Id response header** — session-less probes 400 and report
"0 tools", which is the classic false-negative here. Re-register it in Claude Code user scope as
unreal-editor.
http://127.0.0.1:8000/mcp, SSE data: lines (parse them, not raw JSON), auto-started by the repo-tracked Config/DefaultEditorPerProjectUserSettings.ini seed
(bAutoStartServer=True). This is a different product from NeoStack (NEOSTACK_AI.md §8) —
narrow Scene/Actor/Material/Object toolsets plus PCG. It carries the PCG seam per the three-seam
routing rule.
6a.3 The known NeoStack sign-in stall. The game repo documents it as a NeoStack bug (their
auth-method parser never populates the terminal-auth command, then spawns the bridge in JSON-RPC
server mode waiting on stdin forever). The sign-in is unnecessary — the bridge's authenticate()
is a no-op and it reuses the valid ~/.claude OAuth. Working practice: close the sign-in terminal and
just send a chat message. This depends on CLAUDE_CODE_EXECUTABLE being set (Stage 4.2).
6a.4 Also confirm at first use (still genuinely open in the briefs): whether NeoStack's own version
line has moved past the changelog's v1.0.50 (Q3 §2.4 records a real unresolved conflict between the
changelog and one aggregator's "v2.0.45" claim — presented, not resolved).
REALM_ANALYSIS_ART_PIPELINE_2026-07-27.md §2 rules the lane structure — and it is the newest and
most specific authority on this slot, which the older stack docs do not cover at all (§2.1 states
plainly that concept art is a new translation-layer slot, not an appendix to TD_ASSETGEN):
| Lane | What | Gating |
|---|---|---|
| R — REFERENCE | rights-cleared real imagery → plate sheets. No model runs. | ungated, runs today |
| P — PAINTOVER | generated imagery composed over a Lane-R underlay, inheriting the reference's structure | **GATED-5090 *for volume*** (M10 — rev 1 dropped "for volume"; §2.2's actual wording permits pre-arrival work at non-volume scale) |
| G — GENERATED | raw local text-to-image | GATED-5090 |
Lane P is the ruled default for Panel B, not Lane G — because a paintover inherits the reference's
proportions, making "the enhanced option is a superset of the accurate one" a *property of the
process* rather than a reviewer's judgement. And the hard rule: **Panel A is Lane R for every realm
whose source tradition is living**; Lane G reaches Panel A only for wholly-invented realms (Atlantis,
the fairy realm). Real cultural forms are never raw-generated, and §2.3 extends that from architecture
to realm iconography of living traditions.
D-3 — the image model: genuinely unnamed, but ALREADY SCHEDULED to benchmark day (B9).
The factual half of rev 1's finding is sound: a grep across the tech_research corpus finds
text-to-image mentioned only incidentally (an "SDXL/Flux" aside in LOCAL_3D_ASSET_GEN.md §4 about
ComfyUI chaining; NVIDIA SANA inside a worldgen blueprint description). **No brief rules an image-gen
model roster.**
But rev 1 then silently moved the pick to setup day, and the doc it itself introduces as *"the
newest and most specific authority on this slot"* already rules the scheduling.
REALM_ANALYSIS_ART_PIPELINE_2026-07-27.md §8 item 5:
THE CONCEPT-ART MODEL ROSTER. A license read is owed before any Lane G or Lane P generation,
identical in kind to TD_ASSETGEN §5's pre-flight. **RECOMMENDATION: fold it into the existing 5090
benchmark-day pre-flight rather than scheduling a separate exercise**, since that pre-flight is
already specified as a cheap GPU-free license re-check.
Rev 1 was also inconsistent with its own scope note two paragraphs later ("the benchmark is NOT
day one … Stage 6's job is to install the lane and prove one asset generates — nothing more"). The
same logic that defers the 3D roster defers the image roster.
Corrected scheduling:
LOCAL_3D_ASSET_GEN.md §4, and it lets image-gen → 3D-gen → texture-bake run as one graph) and
prove one generation runs — any weights, tagged previz, output not entering any asset path.
license pre-flight alongside the 3D roster.
The inherited constraints still govern the eventual pick, and §2.3 states them as binding on this
lane verbatim: unrestricted-by-default in the shipped path; anything MAU-capped, territory-excluded,
revenue-ceilinged, or non-commercial is previz-only, never load-bearing — and §2.3 argues concept
art is arguably *more* license-entangled than a mesh, not less, "because style transfer leaves
fingerprints."
[DECISION AT SETUP] D-1 — the host-OS question for the whole generation stack. This is the
sharpest contradiction the stack docs carry into a Windows machine: LOCAL_3D_ASSET_GEN.md §1.1
states TRELLIS.2 is "OS: Linux-only officially (CUDA 12.4, PyTorch 2.6.0)" with *"Windows access
via community ComfyUI wrappers only,"* and Hunyuan3D-2.1's tooling is Linux-oriented too — yet the
ruled default geometry backend is TRELLIS.2 and the machine is Windows. Three options: **(a) WSL2 +
CUDA passthrough** (closest to the official Linux path, costs a vhdx on the slot-3 drive and a layer
of I/O indirection), (b) ComfyUI-on-Windows via the community wrappers (ComfyUI-3D-Pack,
ComfyUI-Trellis2, ComfyUI-Hi3DGen — the path the briefs implicitly assume, but community-
maintained), (c) dual-boot (rejected — it would take the machine out of the 24-hour autonomous
window every time). Recommendation: **(a) WSL2 for the official-path models, (b) ComfyUI-Windows for
the image lane and rapid iteration** — but this is a real fork with real time cost and it should be
decided deliberately at setup, not discovered mid-benchmark.
D-1 EVIDENCE RIDER (2026-07-28 — Josh photo-grounded + web-verified; strengthens option (a)).
The machine is a Puget Systems build, and Puget publishes free MIT-licensed **Docker App
Packs** (Puget-Systems/puget-docker-app-packs on GitHub; announcement + HOW-TO on
pugetsystems.com): a setup.sh wizard that installs Docker + the NVIDIA Container Toolkit on
Ubuntu 24.04 and builds pre-validated flavors — comfy_ui (ComfyUI + Manager, model select at
install: FLUX.2 Klein 4B / LTX-Video / SDXL, host-mapped model/output volumes), personal_llm
(Ollama + Open WebUI),team_llm(vLLM),docker-base. Verified in the repo: thecomfy_ui
image is nvidia/cuda:12.8.0-runtime-ubuntu24.04 + torch from the cu128 index — the exact
known-good sm_120 stack this runbook budgeted half a day to hand-build, pre-assembled and
5090-validated by the vendor. Caveats verified: install.sh hard-fails on non-Ubuntu (a WSL2
Ubuntu-24.04 distro passes ID=ubuntu but the driver step needs hand-finishing — WSL2 uses
host-driver passthrough); the pack's torch is UNPINNED (pin torch==2.9.0+cu128 in our fork);
the LLM flavors route Blackwell to cu130-NIGHTLY images (preferpersonal_llm, skipteam_llm
on one card). Setup-week action: run the pack INSIDE the WSL2 distro as option (a)'s
environment; ComfyUI-Windows remains the (b) lane. QC-phase action for Josh NOW: **ask the
Puget rep for the burn-in/benchmark sheet** — burn-in runs hours of memory/CPU/GPU/thermal/
power verification + benchmarks but the report is not auto-delivered, and it is the only
pre-arrival thermal/power baseline for this exact machine (feeds Stage 0.5's UPS load math and
benchmark-day comparisons).
Scope note — the benchmark is NOT day one. LOCAL_3D_ASSET_GEN.md §5.2 specifies a full
benchmark-gate protocol (re-check licenses first, a fixed 2-per-class test set, TRELLIS.2 /
Hunyuan3D-2.1 / Hi3DGen / TripoSG / SF3D-SPAR3D, plus Pixal3D and Direct3D-S2 added by Q3 §1.4, scored
on wall-clock, peak VRAM, topology, UV, PBR accuracy, and whether the license actually clears).
That is benchmark day, a scheduled event of its own — and per §8.5 it now also carries the
concept-art image roster (D-3, above). Stage 6's job is to install the lane and prove one asset
generates — nothing more.
THE TEXTURED-PBR LICENSE TRAP — restate it in the stage that says "generate one asset" (M9).
LOCAL_3D_ASSET_GEN.md §1.1 [VERIFIED] (license text quoted directly from nvdiffrast's own
LICENSE) and RESEARCHED_STACK.md (*"the automated textured-PBR leg is an EMPTY SET today"*)
establish that TRELLIS.2's textured path runs through NVIDIA non-commercial
nvdiffrast/nvdiffrec. So:
A textured TRELLIS.2 output is PREVIZ-ONLY and must never enter a shipped-asset path. The
geometry leg is the usable part; the texture leg is not, today. Tag every day-one 3D output
previz at the moment it is written, not later.
This is the one place the runbook's own opening "binding licensing rule" has to be restated inline,
because "one asset generates and opens in a viewer" is exactly the step where an operator would
otherwise produce a textured mesh and file it as a result.
VERIFY (Stage 6): the UE editor opens the project and Plugins/NeoStackAI loads with no BuildId
warning; an MCP round-trip through the NeoStack channel spawns an actor and returns a **viewport
screenshot** (the standing directive: game-side work is verified by *looking*); Epic's MCP
list_toolsets returns the PCG/DataTable/Asset toolsets. For the image lane: one text-to-image
generation completes and the PNG is written and looked at, with peak VRAM recorded and the output
tagged previz. For 3D: one asset generates through the chosen host path (D-1), opens in a viewer,
and is tagged previz (textured outputs especially — see the trap above).
AUDIO_STACK.md sits in this runbook's authority block, and rev 1 then never used it — no install,
no Stage-8 row, no deferral. That reads as coverage that is not there. Stated plainly instead:
The audio lane does not install on day one. It rides the audio lane as its own scheduled task.
What it will carry when it does:
ElevenLabs hero behind a clone gate"*). Small, CPU-or-modest-GPU, no VRAM contention with the heavy
lanes — it is a genuinely easy install whenever the lane opens.
same benchmark-day protocol as the 3D and image rosters, not setup.
the other cold data (a drive-table row, already added at 1.4).
Stage 8 carries a row for this (8.16) so the deferral is visible in the validation table rather
than being an absence. Its green condition on day one is *"deferred, and recorded as deferred"* —
the honest tier.
---
Do this before anything unattended runs — it is a soak-stall class, not a nicety.
First UE editor launch, the two MCP listeners, Ollama, ComfyUI, and the fastembed/HF downloader will
each raise a Windows Defender Firewall prompt. **An unacknowledged firewall dialog at 04:00 under a
non-elevated Interactive scheduled task is a textbook silent soak stall** — and it presents as a
*hung editor*, not as an error, which is the worst possible signature for an overnight run. Nothing
in the soak's teeth or exit codes catches it.
6F.1 Set the network profile to Private (a Public profile is far more restrictive and prompts
more).
6F.2 Pre-authorize the binaries rather than waiting for prompts — add explicit inbound rules (or
run each one once, attended, and accept its prompt) for:
| Listener | Port | Raised by |
|---|---|---|
UnrealEditor.exe / UnrealEditor-Cmd.exe | — | first editor launch (and every soak launch) |
| NeoStack MCP | 127.0.0.1:9315 | the plugin's bridge |
| Epic native Unreal MCP | 127.0.0.1:8000 | auto-started via Config/DefaultEditorPerProjectUserSettings.ini |
| Ollama | 11434 | Stage 5.1 |
| ComfyUI — WSL2 Puget primary | 8188 | Stage 6b · C-1 · NOT PRESENT ON THIS BOX (see below) |
| ComfyUI — Windows-native ART second instance | 127.0.0.1:8189 | C-1 · STOOD UP 2026-08-02 · the only instance that exists |
| ACE-Step REST | 127.0.0.1:8001 | C-10 · AUDIO lane, not yet standing |
C-1's PRIMARY DOES NOT EXIST HERE — verified 2026-08-02, twice, independently. C-1 rules the
WSL2 Puget comfy_ui container on 8188 "THE PRIMARY generation host" on the ground that "the
container is pre-rebuilt." That premise is false on milks5090: nothing listens on 8188 (netstat
and Get-NetTCPConnection agree); wsl -l -v shows Ubuntu-24.04 Stopped with a 1.4 GB
ext4.vhdx; and a live probe inside the distro returns no-docker and no-comfy-dir against an
essentially empty root. **100% of 2026-08-02's generation — the ART first light AND the KT-4
ACE-Step audio smoke — ran on the C-1 SECOND instance at 8189.** Do not read the table row above as
"8188 is up." It is a *planned* host, not a standing one. The open decision (build the container, or
re-rule the Windows-native instance as primary and retire the WSL2 leg) is carried in the day's
return for Josh.
| fastembed / HF downloader | outbound | Stage 5.4 |
|---|
C-10 THE LAW (adjudications 2026-07-29): *"no lane's service runs before its port is in the
firewall table — an unacknowledged Defender dialog at 04:00 presents as a hung editor."* 8189 and
8001 are entered above; that satisfies the table half of the law.
How the law is satisfied in practice — VERIFIED 2026-08-02, not assumed (6F.3's own instruction).
A real TCP listener was bound and connected on each of 8188 / 8189 / 8001, loopback-only:
| Port | bind 127.0.0.1 | loopback connect | firewall rule needed |
|---|---|---|---|
| 8188 | ok | ok | none |
| 8189 | ok | ok | none |
| 8001 | ok | ok | none |
Both network profiles (Wi-Fi, Tailscale) are already Private (6F.1 satisfied). Windows does not
filter 127.0.0.1 → 127.0.0.1, so a loopback-bound listener raises no dialog and needs no rule —
6F.3's assumption is now measured rather than assumed. **The operative control is therefore the BIND
ADDRESS, not a firewall rule:** every lane service must be started with an explicit loopback bind
(the ART instance runs --listen 127.0.0.1 --port 8189; Ollama was already observed bound to
127.0.0.1:11434). A service started on 0.0.0.0 *would* raise the 04:00 dialog the law is about.
Recorded honestly: a first probe reported an abort on 8001 and it did not reproduce (3/3 clean on
retry). It was a race in the probe's own socket teardown, not interference. No phantom is being
carried forward.
Not done, and deliberately: no explicit inbound Allow rules were created. They are unnecessary
given loopback binds, and adding them would *widen* exposure to the LAN and the Tailscale interface
rather than harden it. Creating firewall rules is a security-settings change and is Josh's to make;
if belt-and-braces rules are wanted anyway, that ask is carried in the day's return.
6F.3 Confirm the loopback MCP listeners need no rule at all. Windows does not firewall
127.0.0.1 → 127.0.0.1 traffic, so the two MCP channels should require nothing — but **verify it
rather than assuming**, because if a rule *is* needed and is missing, the failure is a 400/timeout
that looks like the "0 tools" false-negative documented at 6a.2 and will be misdiagnosed as a
session-id bug.
VERIFY (Stage 6F): launch the editor, both MCP channels, Ollama, and ComfyUI in one attended
sitting and confirm zero firewall dialogs appear. That silence is the observable. Anything that
prompts here would have prompted at 4 AM instead.
---
What migrates. The soak is the QA loop's endurance belt and it is the AI QA machine's own
heartbeat — under THE JOSH GATE the QA loop is the *only* player until the AAAAA slice, so the soak
running nightly on the new machine is not housekeeping, it is the evidence pipeline.
The current shape, read off the machine:
C:\dev\Humanity\Humanity\Tools\nightly_soak.cmd — cd /d C:\dev\Humanity\Humanity, `mkdirSaved\QA\Soak` if absent, then
python Tools\run_soak.py --maps greybox,flores,bali,samosir,palembang,borobudur,angkor
appending to Saved\QA\Soak\nightly_schtask.log.
HumanityNightlySoak — the shape below is the verbatim live Get-ScheduledTask / Get-ScheduledTaskInfo capture (B1). Rev 1 recorded it *selectively* and got
ExecutionTimeLimit backwards, and omitted the two settings that actually collide with Stage 0:
TaskPath : \
State : Ready
Trigger : Daily, StartBoundary 04:00
Action : C:\dev\Humanity\Humanity\Tools\nightly_soak.cmd
(no arguments, no working directory — the cmd file cd's itself)
Principal : joshu
RunLevel : Limited
LogonType : Interactive
ExecutionTimeLimit : PT72H <-- NOT "no execution time limit" (rev 1 was wrong)
DisallowStartIfOnBatteries : True <-- omitted by rev 1 — COLLIDES WITH STAGE 0
StopIfGoingOnBatteries : True <-- omitted by rev 1 — COLLIDES WITH STAGE 0
MultipleInstances : IgnoreNew
AllowDemandStart : True <-- 7.6 depends on this
WakeToRun : False
RandomDelay : (none)
run_soak.py loops the capture drive N times (default 3) in a seeded randomized map order,collecting per map run: exit code + duration, manifest teeth violations from
Saved/QA/last_run.json (missing / black-scene / bad-material / bad-chapter / scene-stack /
steep-encounter / airborne-pawn / offscope-boss / offpad-boss), crash/ensure markers grepped from
the editor log (Fatal / Assertion / LowLevelFatal / ensure / Critical error), and editor
peak memory via psutil across the whole subprocess tree → memory growth loop-over-loop. It
writes Saved/QA/Soak/soak_<YYYY-MM-DD>_<HHMMSS>.md — a timestamped filename
(run_soak.py:253: SOAK_DIR / f"soak_{started:%Y-%m-%d_%H%M%S}.md"). Rev 1 said soak_<date>.md
in the description and in two VERIFYs; it had copied the module docstring, which is itself stale
against the code (M5). **Glob Saved/QA/Soak/soak_*.md and read the newest** — never construct the
name. Exit 0 = all green, 1 = a red run / teeth violation / crash marker, 2 = setup error.
7.1 Install psutil — on the honest reason (M4). run_soak.py imports it inside a try/except
and degrades to None. Rev 1's claim that this is silent is withdrawn: run_soak.py:181 writes
a dedicated line into the body of every report —
lines.append(f"- psutil memory sampling: {'ON' if psutil else 'OFF (psutil not installed -- memory n/a)'}")
— so the degradation announces itself explicitly. What stands is that the **exit code is
unaffected**: a psutil-less soak still exits 0, so an automated green check would pass while the
memory-growth signal — the single most valuable thing a multi-loop soak produces — is missing. That
is reason enough to install it explicitly. It is not, however, in the same class as TESSERACT_DIR,
which genuinely announces nothing.
7.2 Re-create the scheduled task — and resolve the Stage-0 / Stage-7 collision deliberately (B1).
Re-create with the verbatim shape above (all fields, not a subset). Three decisions, not two:
Josh's words: "yes auto shutdown is more valuable than the flag especially since we land
everything as we go." Riders ruled with it: the battery outlets carry ONLY the PC + the primary
monitor + network gear — EXTRA MONITORS AND PERIPHERALS GO ON THE SURGE-ONLY OUTLETS so they
shut off on an outage instead of burning shutdown runtime; the repo is cold-start safe by the
land-as-you-go discipline; and the robustness mandate lands as THE WATCHERS (see the WATCHERS
stage below + task #17): boot-time self-heal services that auto-start, verify both repos clean
and pushed, confirm the scheduled tasks armed and PowerPanel alive, restart what should run, and
log durably. The decision record below is retained as the analysis trail.
*(original decision text follows)*
Stage 0.5 wires a USB data cable from the UPS to the workstation — that is exactly what makes
the UPS visible to Windows as a system power device. Under DisallowStartIfOnBatteries: True +
StopIfGoingOnBatteries: True, if Windows presents the UPS as a battery, the 04:00 soak will
refuse to start while on battery and will be killed the instant the UPS transfers. On the
old machine (no UPS) these flags were inert. On the new machine they may not be — and rev 1 never
noticed that Stage 0 and Stage 7 interact at all.
The trade-off, stated rather than hidden:
-DontStopIfGoingOnBatteries -AllowStartIfOnBatteries): the soak survivesa 4-second brownout, which is the entire point of owning the UPS. Cost: in a *real* extended
outage the soak keeps drawing from a battery whose whole job is a graceful shutdown — it burns
runtime that was budgeted for the shutdown itself. Mitigation: the UPS trigger (0.5) still
fires and PowerPanel still shuts Windows down; the soak dies with the machine, and a killed soak
is a lost night, not lost data (the report is written per-loop).
momentary flicker becomes a false red (or a refused start), and on a battery-capable power
presentation the 04:00 run may simply never fire — a silent, recurring no-op.
RECOMMENDATION: clear both flags. A UPS whose presence *prevents* the work it was bought to
protect is a self-defeating configuration, and a soak killed by a 4-second brownout is a false red
that costs a real morning of diagnosis. The runtime-conservation argument is weaker than it looks:
the shutdown trigger is set on *remaining runtime* with 2× margin (0.5), so the reserve is
protected by the trigger, not by the task flags.
First, though, MEASURE whether the collision is even live: after the PowerPanel agent is
installed, run Get-CimInstance Win32_Battery and check whether Windows reports a battery at all.
If it does not, the flags are inert as before and clearing them is a harmless belt-and-braces.
If it does, this decision is mandatory. Either way, record which way it went — a soak that
quietly never runs is the failure this whole item exists to prevent.
Interactive / RunLevel Limited,which means it only runs while Josh is logged in. For a 7-8-day 24-hour autonomous window that
may be exactly right (the UE editor capture path wants a real session), but it should be a decision,
not an inheritance. If the soak must survive a logout, it needs S4U/Password logon and a session
the editor can render into — which is its own problem. Recommendation: keep Interactive, and
make it survivable via auto-logon (1.10 / D-18) rather than by changing the logon type.
machine running an autonomous window round the clock, the soak now *competes* with whatever the
window is doing. Recommendation: keep 04:00 and treat the soak as the one serialized nightly
reservation — but if asset-gen runs are queued overnight, the two must not overlap on VRAM (see the
Stage-5 serialization rule). Note ExecutionTimeLimit: PT72H gives the run a 72-hour ceiling,
not an unlimited one — long, but a real bound worth knowing when a soak appears to vanish.
7.3 Confirm the env vars the TASK will see — both of them (C8). run_qa_pass.py probes
UE_EDITOR_CMD, then C:/Program Files/Epic Games/UE_5.8/Engine/Binaries/Win64/UnrealEditor-Cmd.exe,
then 5.7. If the engine landed elsewhere, set UE_EDITOR_CMD **as a system/user env var the
scheduled task will see** — a var set only in an interactive shell will not reach a scheduled task.
HUMANITY_QA_TIMEOUT has the identical visibility problem and rev 1 omitted it: both
run_soak.py (--timeout default, 900s) and run_qa_pass.py read it. Set both at the same scope,
at the same time, and verify both from a task-scoped context at 7.6.
7.4 Run a tractable proof first, not the full belt. `python Tools\run_soak.py --loops 3 --maps
greybox` — one fast map, three loops. This proves the whole chain (editor launch, warm-up,
single-instance lock, capture, verify, teeth parsing, report write) in minutes rather than hours. Read
the exit code; do not background it (the foreground-only rule).
7.5 Then the first FULL soak, overnight. Either trigger the scheduled task manually
(Start-ScheduledTask — this is what AllowDemandStart: True buys) or let 04:00 take it. This is
the machine's first sustained multi-hour GPU+CPU load and it doubles as a Puget thermal-validation
check under our actual workload — though the *hardware* burn-in already happened at 1.0, so a
thermal surprise here is a workload finding, not a DOA finding.
7.6 Task-environment verify. Before trusting the overnight run, confirm the task can actually
see what it needs: run the task on demand and check that nightly_schtask.log shows the editor
resolving (proving UE_EDITOR_CMD) and no premature timeout (proving HUMANITY_QA_TIMEOUT). A
quick way to prove the scope without waiting: schtasks /Run /TN HumanityNightlySoak and read the
log, rather than inferring from an interactive shell where the vars obviously resolve.
VERIFY (Stage 7): the newest Saved/QA/Soak/soak_*.md (glob it — the filename is
timestamped, never construct it) exists and its summary line reads all-green; run_soak.py exited
0; the report's psutil memory sampling: line reads ON and the per-loop peak-memory figures
are non-null with no monotonic growth across loops; Get-ScheduledTask HumanityNightlySoak reports
State: Ready and Get-ScheduledTaskInfo reports a LastRunTime and LastTaskResult 0 — and
that result must come from a run taken with the UPS agent live, not merely from the task
existing (this is what proves the D-11c battery-flag decision actually landed). nightly_schtask.log
has the run's output appended. Also confirm the machine did not sleep mid-soak (Stage 1.2).
---
The closing checklist. Every lane gets one observable that proves it live. Report at the honest tier —
this proves *lanes*, not play quality.
| # | Lane | The check | Green means |
|---|---|---|---|
| 8.1 | Power | PowerPanel event log shows part (a)'s transfer proof and part (b)'s outage → shutdown sequence; the machine powered back on and reached a logged-in desktop unattended; measured runtime recorded — and now, with real lanes installed, capture the LOADED runtime figure (0.7 deliberately deferred it) | unattended runs are authorized |
| 8.2 | Storage | three volumes present at expected capacity; cache env vars resolve in a fresh shell; each junction from 1.4 resolves to the intended drive (dir the link, check free space); model/bulk data on the intended drives | the layout landed, not just the plan |
| 8.3 | GPU | nvidia-smi: 5090, 32GB, near-zero idle VRAM with the desktop up | the iGPU rule landed → the 29GB fit is real |
| 8.4 | Canon gates | python harness/run_gates.py unpiped → exit 0, 29 gates, fresh gates_scorecard.md | the canon lane is fully operational |
| 8.5 | UE build | Engine/Build/Build.version reads BuildId 55116800; Build.bat HumanityEditor Win64 Development -project=... → success, foreground, exit code read | VS + SDK + .NET + engine + the in-repo NeoStack source all correct |
| 8.6 | UE editor + automation | editor opens the project; a NeoStack MCP execute_script round-trip spawns an actor and returns a screenshot; Epic MCP list_toolsets returns PCG | both editor seams live |
| 8.7 | Inference | 14B loads; fixed prompt completes; tokens/sec + peak VRAM recorded; the 7-8B / 3-4B / 0.6-1.7B VRAM figures measured and the unsourced estimates replaced | the local reasoning-adjacent lane is live and baselined |
| 8.8 | Embeddings / RAG | index_manifest.json shows embedding_is_real=true; query.py returns cited [SRC: ...] hits; index_freshness gate passes; the refreshed manifest is committed (5.4) | the semantic recall lane is real, not the hash fallback |
| 8.9 | Triage floor — CONDITIONED ON 5S | day one: triage_floor.py selftest passes on the stub. After 5S: a --backend local run writes a real record and its ranking is sane against the stub's | day one = the seam is intact; post-5S = the 1,873-book sweep is unblocked (the machine's headline unlock) |
| 8.10 | OCR / VLM — CONDITIONED ON 5S | day one: both candidate models installed and TESSERACT_DIR confirmed to exist. After 5S: one _needs_ocr/_vlm_only/ scan that tesseract failed comes back readable through the VLM backend | day one = models present; post-5S = the stubborn-scan queue is unblocked. Cannot go green on setup day — VLMBackend._load_model() and ocr_pdf() both still raise NotImplementedError |
| 8.11 | Image gen | one text-to-image generation writes a PNG; it is opened and looked at; peak VRAM recorded; output tagged previz (the roster + license read is benchmark day, per §8.5) | the concept-art Lane P/G substrate is live |
| 8.12 | 3D gen | one asset generates through the D-1 host path and opens in a viewer; tagged previz — a textured TRELLIS.2 output runs through non-commercial nvdiffrast and must never enter a shipped-asset path | the asset lane is installed (benchmark day is separate) |
| 8.13 | Soak | the newest Saved/QA/Soak/soak_*.md (globbed, not constructed) all-green, exit 0, psutil memory sampling: ON, non-null peak memory, no growth trend; LastTaskResult 0 from a run taken with the UPS agent live | the QA heartbeat migrated intact and the battery-flag collision is resolved |
| 8.14 | Git | both repos clean, both push successfully, LFS content real (not pointers) — note 5.4's manifest commit is what makes "clean" achievable here | the repo-is-the-memory rule holds on the new box |
| 8.15 | Session env | CLAUDE.md stack loads (global + canon + game); memory dir present; compaction hook fires | the director can actually run the window |
| 8.16 | Audio | day one: deferred, and recorded as deferred — Kokoro-82M not installed, ACE-Step/YuE benchmark-gated, libraries not staged (6c) | the deferral is visible rather than an absence. Green = the lane is scheduled, not that it runs |
| 8.17 | Firewall | editor + both MCP channels + Ollama + ComfyUI launched attended with zero firewall dialogs | no 4 AM prompt can stall the soak |
| 8.18 | Unattended chain | BIOS power-on + auto-logon (or the recorded (b) acceptance) + the soak's battery flags all recorded and demonstrated end to end | the 7-8 day window can actually survive a power event |
Landing the runbook. When 8.1-8.18 are green (8.9 / 8.10 at their day-one tier, 8.16 as a
recorded deferral), write the results into this doc as a LANDED block — the measured numbers
especially (idle and loaded on-battery runtime, idle VRAM, tokens/sec, measured per-tier VRAM,
peak VRAM per lane, soak duration, the actual .rag rebuild elapsed on this machine). Those
baselines are what every later "is this slower than it should be?" question is measured against, and
there is exactly one chance to capture them clean. **Also record every [DECISION AT SETUP] as
answered or parked** — an unrecorded decision becomes a mystery failure three weeks later. Commit,
and add the docs/DOC_MAP.md row.
---
Built during setup week (task #17), armed before the first unattended night. The principle: the
repos are cold-start safe by the land-as-you-go discipline, so recovery is VERIFICATION plus
RESTART, never reconstruction. One boot-trigger scheduled task (highest privileges, no battery
conditions) runs the watcher chain and writes a durable status log per boot.
and pushed = the guarantee held; anything dirty or unpushed = a loud line at the top of the log
and a desktop notice — never an auto-commit (the director rules on any dirty tree).
is enabled, and carries the ruled battery-flag configuration; re-arm from the checked-in task
definitions if missing (the definitions live in the game repo Tools/, exported at setup).
UPS state (charge, last transfer event).
Restore-on-AC setting), auto-logon completes (D-16), the boot trigger fires W.1-W.3, and the
next scheduled soak runs on time. VERIFY at setup by the full pull-the-plug rehearsal: outage →
graceful shutdown → power restore → boot → watcher log shows all green with zero human touches.
surge-only side = extra monitors and all peripherals (they shut off on outage by design).
Consolidated so nothing hides in a stage — and rev 2 makes that claim true. Rev 1 opened with
"consolidated so nothing hides in a stage" while three inline markers never reached the table (the
0.5 command-file hook, the 1.3 Puget boot arrangement, the 3.4 VS edition), the numbering **skipped
D-10 entirely, and D-14 appeared only in the table and never in a stage**. Rev 2 fixes all five:
the orphans are now D-15/D-16/D-20, D-10 is retired explicitly as a phantom, and D-14 has a stage.
Body markers and register rows now match.
Every row is a place the ruled stack genuinely stops short — none is a guess dressed as a ruling —
except where the row says otherwise (D-2 and D-7 are narrowed here rather than presented as open,
and D-3's *scheduling* is ruled even though its *pick* is not).
| ID | Decision | Where it bites | Recommendation |
|---|---|---|---|
| D-1 | Generation-stack host OS: WSL2+CUDA vs ComfyUI-on-Windows vs dual-boot. TRELLIS.2 is Linux-only officially; the machine is Windows. Genuinely open — "WSL" appears once repo-wide, in an unrelated citation. The biggest unbudgeted item in the setup | Stage 6b, Stage 5 | WSL2 for official-path models + ComfyUI-Windows for the image lane; decide deliberately, it costs real time either way |
| D-2 | CUDA isolation MECHANISM only — NOT the pins (narrowed, M2). 12.8 for llama.cpp is a ruling (Q3 §3.4: *"pin CUDA 12.8"*); 12.4 is TRELLIS.2's published requirement. Neither is a choice. What is open: per-lane venv/conda vs WSL2 vs ComfyUI-portable | Stage 2.4 | per-lane isolated environments; avoid 13.x on this machine; the mechanism follows D-1 |
| D-3 | The image-gen model for concept-art Lanes P/G — no brief names one (positive control sound). But the scheduling is ruled: REALM_ANALYSIS_ART_PIPELINE §8.5 folds the roster + license read into benchmark-day pre-flight | Stage 6b install / benchmark day for the pick | day one: ComfyUI as host + one previz-tagged generation. Pick + license read → benchmark day |
| D-4 | The 14B pick — Qwen3-14B / Phi-4 / Ministral-3-14B / Gemma-4 12B listed as co-equal (Q3 §3.6: the tier is ruled, the model is not) | Stage 5.3 | pull two, A/B on the triage task, keep the winner |
| D-5 | Triage-floor backend tier — 7B (fast over 1,873 books) vs 14B (better ranking); triage_floor.py:513 says only *"wire the local 7B/14B here"* | Stage 5.5 / 5S | start 7-8B, escalate only on measured noise |
| D-6 | VLM-OCR engine — briefs name a *class* (PaddleOCR-VL / DeepSeek-OCR), not a pick | Stage 5.6 / 5S | install both day one, decide on the three worst _needs_ocr/_vlm_only/ scans after the seam is wired |
| D-7 | ACE vs bespoke runtime substrate — NOT an open fork (narrowed, B7). ALTERNATIVES_MATRIX slot 5 already carries options A/B/C + RECOMMENDATION C (HYBRID) + strongest objection + what-flips-it; RESEARCHED_STACK carries it forward *"pending the weights spike"* | Stage 5.7 | Standing posture = C (hybrid). Day one reduces to the two named pre-condition reads: the bundled-weights license and whether ACE's Agent tier can be constrained to read-only token emission. Josh rules on the recommendation, not on a blank fork |
| D-8 | DDC placement — Gen5 beside the work tree vs split to Gen4 | Stage 1.4 | don't split day one; measure a week of cooks first |
| D-9 | NVFP4/MXFP4 — have the llama.cpp Blackwell kernels landed since 2026-07-15? | Stage 2.5 | cheap re-check; a memory win on the dev box if yes (~25% off Q4_K_M, Q3 §3.3 [INFERRED]) |
| ~~D-10~~ | RETIRED — this ID never existed. Rev 1's numbering skipped it. Recorded here so the gap is a decision, not a lost row | — | — |
| D-11a | Soak task logon type — Interactive vs S4U | Stage 7.2 | keep Interactive; make it survivable via auto-logon (D-18), not by changing logon type |
| D-11b | Soak hour — 04:00 vs re-timed against the autonomous window | Stage 7.2 | keep 04:00 as the serialized nightly reservation; never overlap asset-gen on VRAM. Note the real PT72H execution ceiling |
| D-11c | THE SOAK'S BATTERY FLAGS (DisallowStartIfOnBatteries / StopIfGoingOnBatteries, both True) vs Stage 0.5's UPS USB data cable, which is what can make Windows present the UPS as a system battery. Rev 1 missed this collision entirely (B1) | Stage 0.5 ⇄ Stage 7.2 | Measure first (Get-CimInstance Win32_Battery), then CLEAR BOTH — a UPS that prevents the work it protects is self-defeating, and the runtime reserve is protected by the shutdown trigger's 2× margin, not by task flags. Trade-off stated in full at 7.2 |
| D-12 | .rag/book_src migration — copy vs regenerate (large; measure first) | Stage 4.2 | copy to the slot-4 bulk drive; rebuild the .rag vector store rather than copying it (~5 min / ~10k chunks — the corrected figure) |
| D-13 | Wall circuit — dedicated 15/20A branch for the workstation | Stage 0.4 | electrical question; if the breaker trips under load, the answer is yes |
| D-14 | Gaea Indie ($99) — the ruled terrain detail leg; its CLI-automation tier is an open confirm in RESEARCHED_STACK's ENGINEERING-SPIKES | not day one — and now stated in a stage: it belongs to the terrain lane, alongside the Saved/Terrain GeoTIFF placement at 1.4 | schedule with the terrain lane, not with setup. The CLI-tier confirm is a desk read whenever that lane opens |
| D-15 | PowerPanel pre-shutdown command-file hook (Tools/on_ups_power_event.cmd) — write day one or defer? Edition-dependent (Business-class capability) and a game-repo / build-lane write | Stage 0.5 | defer to the first week — nice-to-have, not a gate, and it costs a cross-lane commit on the busiest day |
| D-16 | A different Puget boot / partition arrangement than this doc assumes | Stage 1.3 | do not re-image to match the doc — re-map the roles onto what shipped and record the actual mapping |
| D-17 | BitLocker / device encryption per volume + recovery-key escrow | Stage 1.9 | accept on C: (escrow the key — J3), leave the model and bulk drives unencrypted; verify with Get-BitLockerVolume rather than assuming |
| D-18 | Auto-logon after an automatic power-on — the third link in the unattended chain | Stage 1.10 | (a) configure auto-logon (credential = J4); option (b) accepts losing the remainder of any night with a power event |
| D-19 | Remote reach — RULED (Josh, 2026-07-28): Tailscale, promoted to a PRE-DEPARTURE GATE. Josh is abroad from 08-07 running Humanity-on-5090 + Continuo-on-Ally-X fully remote; the remote path is tested from his own devices before departure (see the D-19 ruling block) | Stage 1.11 | RULED — no longer open |
| D-20 | Visual Studio edition/year Epic pins for UE 5.8 | Stage 3.4 | read Epic's own "Setting Up Visual Studio" page for 5.8 at setup; positive control confirms no repo doc names a VS/MSVC/SDK/.NET version |
---
Rev 1 carried seven; rev 2 carries nine, and one of the original seven is half-withdrawn.
Added by the critique: 4b (a second stale doc in the same directory), 8 (the ACE license —
the one rev 1 stated flatly while listing weaker items), and 9 (the textured-PBR non-commercial
trap). Corrected: 6, whose psutil half was wrong.
Recorded because "trust content, not labels" is the standing discipline, and each of these would
otherwise mislead the next reader.
1. NeoStack-on-5.8 is NOT unverified — the build lane already closed it. RESEARCHED_STACK.md
(ENGINEERING-SPIKES), NEOSTACK_AI.md §0.3, and Q3_2026_MODELS_REFRESH.md §2.5 all carry
"5.8 support unconfirmed" as an open spike. The game repo's CLAUDE.md records NeoStackAI
installed as source, compiled against UE 5.8.0 BuildId 55116800, with the MCP channel verified
live and smoke-tested on 2026-07-19. The briefs are simply older than the evidence. **Correct them
in the canon lane — precisely: what is closed is source-compiled-on-5.8 + the MCP channel +
Agent Chat; the marketplace/Fab 5.8 tag** remains unconfirmed at source (§2.5's own point).
2. TRELLIS.2 is Linux-only, on a Windows machine. HARDWARE_DECISION.md reasons about the 3D-gen
lane purely in VRAM terms and never raises OS; LOCAL_3D_ASSET_GEN.md §1.1 states Linux-only with
Windows access "via community ComfyUI wrappers only." The ruled default geometry backend therefore
has no verified native path on the delivered machine — this is D-1 and it is the biggest
unbudgeted item in the setup.
3. The CUDA pins conflict across briefs. 12.4 (TRELLIS.2), 12.8 (llama.cpp, with 13.1 actively
harmful), cu128 torch (vLLM). No brief reconciles them because none of them was writing an install
plan. Per-lane environments are the only coherent resolution — D-2.
4. harness/rag/README.md is stale against config.json. The README calls Ollama+
nomic-embed-text the "primary (recommended)" embeddings backend; config.json ranks **fastembed
first** (real, multilingual, ONNX, daemon-free) with Ollama as the alternate. RESEARCHED_STACK
and HARDWARE_DECISION both treat fastembed as the embeddings answer. The config is operative;
flag the README for a one-line correction.
4b. **harness/check_index_freshness.py:13 is stale by ~38× — the same defect class, in the same
directory, missed by rev 1.** Its docstring reads # ~8s, updates the manifest hash, while the
live harness/rag/index_manifest.json reads chunk_count: 10084 / elapsed_sec: 309.0 — **~5
minutes for ~10k chunks.** Rev 1 copied the docstring into its Stage-4.2 cost argument rather than
reading the manifest, which is exactly the "trust content, not labels" failure this runbook's own
preamble invokes. Correct the docstring in the same canon-lane pass as the README.
5. HARDWARE_DECISION's iGPU rule will almost certainly arrive violated. The rule (monitors on the
motherboard, 5090 headless, ~full 32GB) is what makes the 29GB Hunyuan fit deliverable — but Puget
builds ship monitors wired to the GPU by default. This is a *physical* setup step (2.2), and if it
is missed, a later OOM would falsely fire the documented upgrade trigger #1.
6. **TESSERACT_DIR is a silent-degradation risk. psutil is NOT — that half of rev 1's claim is
WITHDRAWN. ocr_backends.py:48 hard-codes C:\Program Files\Tesseract-OCR with no existence
check**, so a missing install breaks the default OCR backend without announcing anything: a
genuine silent degradation. Rev 1 put psutil in the same class, asserting a missing psutil
*"produces a soak with no memory-growth data and no error"* and that *"neither failure announces
itself."* That is factually wrong. run_soak.py:181 writes
- psutil memory sampling: ON | OFF (psutil not installed -- memory n/a) into the body of every
report — the degradation is announced explicitly, in the artifact an operator actually reads.
What survives is narrower and still worth the install step: the exit code is unaffected, so an
automated green check passes while the memory-growth signal is absent. The 7.1 install step stands;
its stated reason is corrected.
7. A drive-role assignment does not exist in HARDWARE_DECISION. The doc rules the *hardware*
(32GB clears the workload math; Puget validation makes the tight fit deliverable sustained; RAM
stays 2×64; slot 2 free) and names NVMe as a UE bottleneck, but never assigns the three drives to
roles. Stage 1.4's mapping is a recommendation derived from its workload analysis, not a
quotation of it — argue with it if the first week's measurements disagree. *(Rev 1's reasoning here
was sound; only the paths were wrong — four rows named repo-relative locations that no env var
can move. Fixed at 1.4 with an explicit mechanism per row.)*
8. **The ACE SDK license is CONTESTED, not settled — and rev 1 stated it flatly while listing weaker
contradictions.** Rev 1 wrote *"the ACE Game Agent SDK (v0.5.0, 2026-06-15, Apache 2.0…)."*
ADVERSARIAL_ADJUDICATION.md overrules the unqualified form on two axes: **(a) the code license
does not cover the bundled model weights** (docket 4: *"ACE weights ≠ code license"*; the
weights-license read is a pre-adoption spike), and (b) MIT-vs-Apache is itself unsettled
(action item 5: *"re-verify the ACE SDK license directly … and split code-license from
weights-license in Q3 §3.5"*). Q3 §3.5's "License: Apache 2.0" is a code-only claim the
adjudication explicitly flags as incomplete and possibly wrong. Given this runbook opens by calling
the licensing rule *binding*, restating a contested license as settled was the highest-stakes
citation error in rev 1. Corrected at 5.7.
9. A textured TRELLIS.2 output is non-commercial. LOCAL_3D_ASSET_GEN.md §1.1 [VERIFIED]
(nvdiffrast's own LICENSE quoted) plus RESEARCHED_STACK's *"the automated textured-PBR leg is an
EMPTY SET today"* mean the textured path runs through NVIDIA non-commercial
nvdiffrast/nvdiffrec. Rev 1's Stage 6 and check 8.12 said only "one asset generates … opens in
a viewer" — the exact step where an operator produces a textured mesh and files it as a result.
Restated inline at Stage 6 and 8.12: previz-only, never a shipped-asset path.
---
Stages 0-8 executed on arrival day by the on-box session (walk-through mode: Josh's hands for
physical/auth only). Full measured baselines + decision record: C:\dev\setup_artifacts\baselines.md
(off-repo by design — box-local artifacts). The rows below are the validation table at its honest tier.
| Check | State | Evidence |
|---|---|---|
| 8.1 Power | CONFIGURED; plug-tests WAIVED (Josh ruling 2026-07-30) | PPB Business 4.12.2 reads PR1500RTXL2UC; runtime-exhaustion trigger Instant, 5-min reserve, Shutdown-UPS ON; battery date set; ~1h47-54m runtime @ ~11% load. Calibration deferred to remote. Win32_Battery empty BY DESIGN (Business agent claims HID) → soak flags doubly inert |
| 8.2 Storage | GREEN | C:/D:/E: as planned; caches env-var'd to D:; .rag→D:\rag_store + Saved\Terrain→E:\terrain junctions live |
| 8.3 GPU | GREEN | 5090 headless as shipped: 0 MiB idle VRAM, iGPU carries display; 44C, no ECC anomalies |
| 8.4 Canon gates | GREEN | 29/29 PASS exit 0 unpiped; scorecards committed (38b6ab1) |
| 8.5 UE build | GREEN w/ recorded deviation | UE 5.8.1 (Launcher serves latest patch; CompatibleChangelist 55116800 = the pin's binary-compat declaration). Build.bat HumanityEditor exit 0 in 66.7s; NeoStackAI compiled from source |
| 8.6 Editor + automation | GREEN | NeoStack MCP: session-id echo, execute_script help/open_level/actor spawn (SetupSmoke5090, discarded unsaved) + viewport screenshot (GreyboxArena frame read); Epic MCP: list_toolsets returns PCG/Editor/Logs |
| 8.7 Inference | GREEN, baselined | qwen3:14b 53.9 t/s / peak 14,388 MiB; phi4 146.8 t/s / 12,340; 8b 218.4/10,010; 4b 361.1/7,700; 1.7b 479.7/5,370; 0.6b 762.9/4,612 (Ollama default ctx — measured, replaces the unsourced estimates) |
| 8.8 Embeddings/RAG | GREEN | fastembed real (is_real=true), 10,616 chunks / 110.7s (old box: 309s); manifest committed (929a122); query.py returns cited [SRC:] hits |
| 8.9 Triage floor | GREEN (day-one tier) | stub selftest PASSED; canon pack builds (vocab=767). 5S = own task, not day one |
| 8.10 OCR/VLM | GREEN (day-one tier) | Tesseract at C:\Program Files\Tesseract-OCR (TESSERACT_DIR satisfied); DeepSeek-OCR + PaddleOCR-VL weights in D:\hf\hub. VLM seam = 5S |
| 8.11 Image gen | GREEN | ComfyUI 0.29.0 portable, torch 2.13.0+cu130 sm_120 (deviation recorded; llama lane unaffected); SDXL-Turbo 1024² gen completed, looked at, peak 7,258 MiB, PREVIZ-tagged + license sidecar |
| 8.12 3D gen | SUBSTRATE ONLY | WSL2 + Ubuntu-24.04 provisioned (D-1(a) substrate); Puget docker pack + TRELLIS = setup week; benchmark day separate |
| 8.13 Soak | FULL SOAK GREEN — Stage 8 CLOSES | First full nightly soak 2026-07-31 (soak_2026-07-31_070001.md): 3 loops x 7-zone belt = 21/21 GREEN, 0 teeth violations, 0 crash markers, psutil ON, LastTaskResult 0, UPS agent live. Memory honest read: loop-1 bali peaked 9.06 GB (first-run DDC/shader cache build), loops 2-3 settled flat ~3.4-4.3 GB — cross-loop deltas are caching, not leak (fresh editor per run; the report's own note). The report's +-4727 MB figure = warm-vs-settled spread, verdict GREEN earned. TZ NOTE: fired 07:00 ET (trigger armed pre-TZ-switch at 04:00 Pacific); re-arm to 04:00 ET recorded as the follow-up. Prior proof row superseded: 3-loop greybox proof exit 0 (soak_2026-07-30_155504.md), psutil PATH-order fix recorded |
| 8.14 Git | GREEN | both repos clean + pushed (canon 38b6ab1, game bc6effa); LFS content real |
| 8.15 Session env | GREEN | CLAUDE.md stack ×3 loads; memory dir + global config + hooks transferred from old machine; standalone CLI 2.1.220 authed; CLAUDE_CODE_EXECUTABLE set |
| 8.16 Audio | DEFERRED, recorded | Kokoro/ACE-Step/YuE ride their own lanes per 6c |
| 8.17 Firewall | GREEN | editor, both MCP listeners, Ollama, ComfyUI, soak — all launched attended, zero firewall dialogs (loopback binds) |
| 8.18 Unattended chain | GREEN by parts; end-to-end plug test WAIVED | BIOS AC-restore set (walkthrough, photographed); auto-logon proven by hands-off reboot to desktop; HumanityBootWatch logon watcher live (repo/task/PPB/Ollama self-heal, E:\qa_archives\watchers logs); soak flags cleared (D-11c) |
Decisions landed: D-11c cleared-by-ruling · D-17 all-volumes-unencrypted-as-shipped (no key to escrow)
· D-18 auto-logon (a) · D-19 Tailscale+RustDesk proven from cellular · D-20 VS 2026 18.8 (Epic's
5.8 pin) · D-7 desk reads done (code=Apache-2.0 confirmed; weights = portal-terms at install; Chat-tier
route noted) — ruling still Josh's · D-1 (a)-substrate staged · D-4/D-5/D-6/D-9 parked to benchmark/5S
with models staged. Continuo box window: staged to DRY RUN GREEN (their THURSDAY_RUNBOOK executed;
Q4 sha-verified e47ad9…c008; Friday = one --execute command). Parked: Puget posted burn-in sheet
(needs Josh's portal sign-in), NVIDIA Control Panel Store app (cosmetic), USB-selective-suspend
powercfg rejection (Device-Manager route later), runtime calibration (remote), book_src copy (books
never gate).