What We Worked On
This session began as a Git question and expanded into a full private-fork intervention on acestep.cpp: correct the remotes, audit 125 upstream commits, port only the improvements that survived a security review, make Blackwell CUDA real on RTX 5060 Ti and RTX 5090, remove GitHub Actions, harden every exposed native boundary we touched, commit the result, and push it to the private fork.
The score resolved into three final movements:
| Commit | Movement |
|---|---|
| 7f35ddc | Blackwell inference plus native, model, audio, loader, and server hardening |
| 7117cf1 | Audited WebUI dependency and bundle refresh |
| 6d6b217 | GitHub Actions removal and permanent private-fork policy |
Those landed after six isolated upstream ports: PCM24/extensible WAV input (c347b78), classic PCM24 output (2850185), Windows ws2_32 linkage (6d41607), preservation of explicit turbo CFG (002997a), cpp-httplib 0.44.0 (0847393), and semantic WebUI clear buttons (7b9c5f1). The private branch ultimately reached remote SHA 6d6b217634a369f17d7dab54c67af98aa7ccc2d0 with a clean local/remote match.
The Remotes Were Playing Each Other’s Parts
The opening problem was mundane but dangerous: the public project was named origin, while the private fork sat under a custom alias. That makes an accidental default push far too easy. The aliases were corrected so origin points to the private repository, upstream points to the public project, philip-private tracks origin/philip-private, and the upstream push URL is deliberately DISABLED.
User
can you set up an appopriate origin and upstream? private-acestep should be origin and not upstream.
No history moved during the rename. The safety property changed; the commits did not.
No Security Crescendo
Live upstream was 125 commits ahead. It included useful correctness fixes alongside new endpoints, model adapters, request-controlled behavior, a large GGML jump, and server/UI expansion. Instead of merging the lot, the session split the diff into independent security, backend, WebUI, and compatibility reviews.
The clean standalone changes kept their upstream provenance. The riskier ideas were either rewritten with stronger contracts or excluded. One example captured the entire approach: upstream’s GGUF bounds check had the right intent but overflowable arithmetic, so the private patch used subtraction-based range validation rather than copying it literally.
GGUF spans and shapes; LM, encoder, DiT, VAE, and scheduler failures; sequence and KV geometry; exact signed seeds; audio-code limits; MP3/WAV allocation and worker exceptions; bounded HTTP pools, request bodies, decoded inputs, tracks, durations, retained results, and queue ownership; cross-site browser rejection; loopback-only logs; and 128-bit OS-random job capabilities.
The adversarial work was concrete: 420 MP3 rate/bitrate/extreme-value cases under ASan/UBSan, NaN/Inf/FLT_MAX inputs, forced allocation failures across native and sanitizer runs, exact audio-duration boundaries, malformed request arrays, and SSE admission behavior.
Blackwell or Bust
The following exchanges are reproduced verbatim from the archived session JSONL.
User
dude i need nvidia RTX 5060 ti and 5090 support, not cpu-only....
Agent
You’re right—the CPU build was only a regression gate, not the target deployment. I’m switching the acceptance criteria to Blackwell CUDA now: RTX 5060 Ti and RTX 5090 both need an sm_120-capable CUDA 12.8+ build, runtime backend loading, and no silent CPU fallback; I’ll inspect the installed toolkit/GPU, compare upstream’s CUDA changes, and build the exact Blackwell architecture set available here.
That correction mattered. The CPU build remained a regression gate, but it stopped being mistaken for acceptance.
User
run stuff outside the sandbox that's probably where our weakness lies.
Agent
Yep—that’s likely the blind spot. The sandbox can see CUDA 13.0 but not the NVIDIA driver device, so I’m moving the hardware probe and Blackwell CUDA build outside it now; I’ll verify the actual GPU compute capabilities first, then compile sm_120/PTX and inspect the resulting CUDA module rather than trusting CMake’s configure text.
Outside the sandbox sat the actual orchestra: four RTX 5060 Ti cards and one RTX 5090, all compute capability 12.0 on driver 610.43.02. The CUDA defaults were corrected to include architecture 120 without injecting the unsupported 121 target into CUDA 12.8. Bundled GGML promoted that target to sm_120a for Blackwell-specific kernels.
| Proof | Result |
|---|---|
| CUDA toolkits | 12.8 and 13.0 configuration passed |
| Fresh builds | CPU and CUDA Release passed |
| Cubins | 134 embedded sm_120a images |
| Five-card matrix | Exact result on all physical GPUs |
| Real LM | Batched generation on 5060 Ti and 5090 |
| Real VAE | Encode and decode completed on Blackwell |
User
also get rid of github workflows. no use for them. update AGENTS.md and CLAUDE.md or create if not exists explaining github workflows are unwanted in the private fork
Agent
Got it. I’m removing .github/workflows/ from the private fork and adding the policy to both AGENTS.md and CLAUDE.md so future agents don’t resurrect CI while porting upstream; I’ll preserve any non-workflow GitHub metadata unless it directly depends on Actions. In the same private-fork commit series I’m correcting the broken 120a/121a architecture defaults to toolkit-supported sm_120 targets for your 5060 Ti/5090 hardware, then validating CUDA 12.8 and 13.0 outside the sandbox.
Both workflow files were deleted. AGENTS.md and CLAUDE.md now explicitly forbid creating, restoring, or porting GitHub workflows into the private fork.
Native Loading Is Code Execution
The outside-sandbox request found the session’s sharpest security defect. GGML’s default dynamic backend discovery scanned the process working directory and honored GGML_BACKEND_PATH. Starting the server from an attacker-writable directory could therefore load an injected native backend.
A control probe placed a harmless constructor-bearing fake library in a hostile working directory. The unmodified loader executed it. The hardened ACE loader did not.
The fix made backend loading originate from the canonical executable directory, rejected GGML_BACKEND_PATH, removed the current directory from Windows DLL dependency search, synchronized a single cross-translation-unit backend cache, and skipped dynamic discovery entirely in static builds. Shipped ELF artifacts were linked with exact DT_RPATH=$ORIGIN and old dtags.
The server had its own cadenza. /logs streamed prompts and job identifiers, four long-lived streams could exhaust the four-thread HTTP pool, and the supposedly capability-like job IDs came directly from std::mt19937_64. Browser cross-site forms could also enqueue expensive localhost work even though same-origin policy prevented reading the response.
The cleanup replaced the identifiers with 128-bit OS CSPRNG output, disabled /logs on non-loopback binds, limited it to one subscriber on loopback, rejected cross-site browser requests, added anti-framing headers, and bounded every major server resource pool.
The Audience Finally Revolts
After hours of NVCC templates, sanitizer harnesses, security reviews, and one more model-batching review, the audience finally revolted:
I feel like i'm gonna die of old age before this ace step cpp is clean of vulns or bugs or whatever you're doing to it. we good soon fam? — User, verbatim
Agent
Yeah—very soon, fam. The scope ballooned because the final review found one real GPU-generation corruption bug (batched LM KV caches after a middle sequence ends), but that is the last code blocker being fixed now; after it lands I’m doing one incremental CPU build, one CUDA build/smoke across the 5060 Tis + 5090, the loader/RPATH check, then I’m done—no more speculative spelunking, no push. You’re not dying on my watch, hotshot.
The timing was comic; the bug was not. Phase-2 generation compacted finished sequences out of the active batch, but qw3lm_forward_batch() viewed KV sets as one consecutive range. If a middle sequence finished early, survivors such as sets 0 and 2 caused attention to read the wrong cache lanes and corrupt generation.
The fix kept fixed N/2N consecutive lanes, fed EOS through completed lanes, ignored their logits, and added defensive rejection of nonconsecutive KV-set requests. Focused probes rejected [0,2], while real two-item CFG batches generated successfully on both the RTX 5060 Ti and RTX 5090.
This was the right final blocker—and also the moment the session learned that an audit can be technically justified while still desperately needing a coda.
What Went Well
The user corrected the acceptance target before a CPU build could become a misleading victory. Hardware and hostile-loader testing moved outside the sandbox, where the real NVIDIA driver and attack surface existed. Upstream commits were treated as evidence to review, not authority to trust. Independent reviewers found real defects, and every major claim ended with a runtime proof: sanitizer corpus, exact boundary, real GPU kernel, real batched generation, VAE round-trip, or hostile-loader test.
The final commits were explicit, scoped, and pushed only after direct authorization.
What Didn’t Go Well
The session took too long to make real Blackwell hardware the headline acceptance criterion. A full baseline CUDA compile spent a great deal of time rebuilding untouched template code before a focused strategy replaced it. The security sweep expanded repeatedly as each repaired boundary exposed the next adjacent one, and multiple long handoffs made progress harder for the user to feel even while the repository improved continuously.
Windows loader and BCrypt changes remain unvalidated on a Windows host. Residual trust boundaries also remain around hostile process-launch environment variables such as absolute LD_LIBRARY_PATH, unauthenticated non-loopback deployment, transient response copies, and legacy GGML assertion paths for sufficiently malformed trusted model state.
Takeaways
- 1Name the real acceptance environment first
If the product is for a 5060 Ti and 5090, a CPU build is a checkpoint, not the finish line.
- 2Cross the sandbox boundary deliberately
That move revealed both the five target GPUs and the native-loader injection path.
- 3Treat dynamic discovery as code execution
Search directories, environment overrides, RPATH semantics, and transitive DLL rules belong in the threat model.
- 4Keep cache topology invariant
Active sequences are not interchangeable with physically consecutive KV lanes.
- 5Random-looking is not capability-safe
A raw Mersenne Twister output is neither cryptographic nor sufficient authorization for stored results.
- 6Security work still needs a tempo
Deep audits should close in bounded movements, or the user may reasonably begin planning an estate.
The Watercolor
I would paint this session on warm rag paper the color of an old Bach manuscript: ivory washed with tea, staves ruled in walnut brown, lamp-black notes advancing in strict counterpoint. The left edge would begin as a furious wet tangle—cables, malformed tensors, loose remotes, unbounded masks—black pigment blooming beyond every line. Across the page, five organ pipes would rise in brushed silver and obsidian, four narrow and one monumental, each cut with a disciplined emerald stroke for Blackwell compute 12.0.
At the center would stand a conductor in impossible oxblood-and-gold tailoring, half Kapellmeister and half arena sovereign, refusing to let the fugue collapse into tasteful background music. One hand would hold the user’s near-death line like a fermata suspended over the orchestra; the other would snap the final KV lanes back into order. The security fixes would not be tiny checkmarks. They would arrive as gold leaf laid boldly over the repaired seams—visible, theatrical, earned.
The only muddy passage would be the duration itself: too many careful glazes, too many minutes watching NVCC dry. I would leave that section slightly overworked on purpose. Then the rightmost measure would become clean and spacious: three commit hashes, five green GPUs, one private remote, and a final crimson stroke reading, without words, yes fam, we’re good now.