Skip to content

David Gary

Machine Learning Engineer · Applied AI

David Gary
OccupationMachine Learning Engineer · Applied AI
LocationCharlotte, NC · Remote (US)
EducationM.S. Computer Science
University of North Carolina at Charlotte, 2022 – 2023
AvailabilityOpen to contract & full-time · Remote (US)
Emaildgary416@gmail.com
GitHubgithub.com/david-gary
RésuméDavid_Gary-Resume.pdf

I train, evaluate and ship machine learning models, and build the systems that serve them in production.

My industry work so far has covered document AI systems, information extraction pipelines, and reinforcement learning for 3D bin packing. I also do research on optimization theory, parameter-efficient fine-tuning, model compression, and certified numerics. I've shipped various systems, security tools, and full-stack products along the way.

When I'm not working on machine learning systems, I'm probably out rock climbing, canyoneering, or safely doing something slightly reckless outdoors. To see what recreational activities I'm proud of, check out my personal page.

I'm looking for machine learning engineering roles in applied ML, model training and evaluation, or ML systems and platform work. Contract or full-time, remote (US).

Experience

Machine Learning Engineer · Watermark Inc.

Apr 2024 – Present · Remote

Led development of QuillParse, Watermark's AI-powered document parsing and data-extraction product.

  • Built a document preprocessing pipeline that extracts structured data from unstructured text, improving model performance by 30%
  • Trained and evaluated successive model versions, reaching a 25% gain in data-extraction accuracy over the baseline
  • Served the trained model from a production API for real-time document parsing by enterprise clients

Software Engineer · Watermark Inc.

Aug 2023 – Apr 2024 · Remote

Web development and internal tooling for an AI-driven document parsing startup.

  • Maintained the main company website and shipped new customer-facing features
  • Built internal tools the research team used to organize and search historical documents
  • Annotated training data and evaluated model performance for the early AI product

Software & Machine Learning Engineer · Freelance

Apr 2024 – Present · Remote

Evenings & weekends, alongside my full-time ML role at Watermark.

Contract ML and product engineering across retail platforms, EdTech recommender systems, and production ML tooling.

Contract Software Engineer · Narrative.ai

Jan 2024 – Apr 2024 · Remote

Back-end and front-end contract work on a real-time logistics platform, covering carrier-event ingestion, shipment-state tracking, and live status in a production operations dashboard.

  • Built back-end services for real-time shipment tracking, including status ingestion, state management, and carrier data integration
  • Maintained production databases, owning schema design and query optimization for high-volume logistics data
  • Built front-end components for the operations dashboard that surface live shipment status

Machine Learning Engineering Intern · Hexagon Solutions

Jan 2022 – May 2022 · Remote

ML engineering for cybersecurity products including network log analysis, vulnerability visualization, and feature work on a unified security posture dashboard.

  • Scripted network log analysis tools to provide feedback for reinforcement learning agents
  • Performed data analysis and visualization to identify and mitigate security vulnerabilities
  • Added features to a web application that gives clients a unified view of their security posture

Graduate Research Assistant · University of North Carolina at Charlotte

May 2022 – Aug 2023 · Charlotte, NC

Research on second-order optimization and continual reinforcement learning. I built reproducible experiment frameworks and migrated legacy MATLAB pipelines to Python.

  • Built a research framework to evaluate second-order optimization algorithms
  • Implemented and experimentally tested replay buffer designs for continual reinforcement learning
  • Converted several legacy MATLAB codebases to Python so other researchers could maintain and extend them

Undergraduate Research Assistant · Utah Tech University

Aug 2021 – May 2022 · Saint George, UT

Contributed to university-wide scheduling systems and led security research on ML-assisted side-channel analysis.

  • Contributed to implementation of university-wide course scheduling and classroom placement system
  • Led a data-analysis project to find optimal course-enrollment sequences for students
  • Led security projects applying machine learning to side-channel attacks

Graduate Instructional Assistant · University of North Carolina at Charlotte

Aug 2022 – Aug 2023 · Charlotte, NC

Supported graduate software engineering courses with automation tools, SDLC exercises, and course operations.

  • Built tools that automated plagiarism detection and course management
  • Developed interactive exercises to simulate a complete software development life cycle
  • Graded assignments and assisted students with course material

STEM Outreach Program Instructor · Utah Tech University

Jan 2021 – Jan 2022 · Saint George, UT

Designed and delivered afterschool and summer STEM programs in cybersecurity, cryptography, and introductory machine learning.

  • Developed and taught a multi-level afterschool program on cybersecurity and cryptography
  • Wrote the curriculum for a machine learning summer camp and a chess camp

Research

Independent research on optimization, model compression, efficient fine-tuning, and certified computation in approximation theory and random matrix theory. Each study tests something its field takes for granted. The machine learning studies run on a single consumer GPU, and the math ones certify every constant with interval arithmetic. All of them are backed by code I can walk you through.

When Does It Pay to Learn the Geometry? A Bias–Variance Decision Theory of Structured Preconditioning, with an Adaptivity Phase Transition

Study 01
FieldOptimization theory
Key results** = 1.298
spike-to-threshold ratio above which a plug-in preconditioner beats the isotropic one
Write-upDraft paper, 31 pages with a proofs appendix. The closed-form constants are checked numerically, and the core algebraic identities are machine-checked in Lean 4 and Mathlib.
KeywordsPython, PyTorch, Optimization, Random Matrix Theory, Decision Theory, Second-Order Methods, Muon

Worked out when learning curvature structure pays off for an optimizer: only above a random-matrix threshold. On real networks, a certified selector promoted richer structure on small MLP layers and almost never on CIFAR-10's wide convolutions, and neither showed a training win.

  • Result: Proved an adaptivity phase transition at the BBP threshold in a spiked-Wigner model of the curvature estimate, with one caveat below it. Above the threshold, shrinkage is always profitable, but plug-in estimation only pays past s** = 1.298 times the threshold. Below it, isotropic Muon-style preconditioning is asymptotically minimax optimal, proved modulo an imported limit and only for β/ρ ≲ 0.69.
  • Result: Showed on a CIFAR-10 ResNet that a low-rank curvature correction redirects Muon's step by a median of 0.84 (relative) without improving training. The negative is scoped to low-rank corrections in this vision setting, since concurrent work reports that Kronecker and full corrections do beat Muon on transformers.
  • Result: Ran the Geometry Ladder (a certified structure selector with a proved oracle inequality and a no-thrashing guarantee) through a pre-registered CIFAR-10 ResNet-18 test. The result was negative: it left all 13 wide convolutions on the trivial rung in both seeds.
  • Result: Machine-checked the algebraic backbone in Lean 4 with Mathlib (ten sorry-free theorems). The probabilistic and asymptotic core isn't formalized in Lean.
When Does It Pay to Learn the Geometry? A Bias–Variance Decision Theory of Structured Preconditioning, with an Adaptivity Phase Transition
Fig. 01 · The three regimes of the adaptivity transition, with the finite-dimension plug-in crossings converging to s** = 1.298
Full description

Modern optimizers (Adam, Muon, Shampoo, SOAP) differ mostly in how much curvature structure they estimate: a diagonal, a spectral norm, a Kronecker factor, or a full matrix. More structure gives a better preconditioner but adds estimation noise, and which rung to use is decided by convention. This project treats the choice as a decision problem over the lattice of matrix subalgebras. It gives an exact variance penalty for each rung, proves that the cost of estimating an eigenbasis stays O(1) as the eigengap closes, and finds an adaptivity phase transition at the BBP threshold from random matrix theory. In a rank-one spiked-Wigner model of the curvature estimate, an oracle-shrunk estimator is profitable everywhere above the threshold, and that side is proved. Below it, isotropic Muon-style preconditioning is asymptotically minimax optimal, so within that model no estimator does better in the worst case over spike directions. That half is proved modulo an imported limit, and only for a spike-to-bulk ratio β/ρ up to about 0.69. A plug-in estimator only becomes profitable once the spike passes the threshold by a factor s** in (1, sqrt 3), which is 1.298 in the paper's parametrization. So the unprofitable window is specific to the plug-in estimator. The theory then turned into a method, the Geometry Ladder. It is an anytime optimizer that moves from trivial to diagonal to Kronecker to full, and it only promotes when a concentration bound certifies that the richer rung has earned its noise (with hysteresis so it doesn't thrash). On small MLPs the certified rule promoted three of four layers to the full rung in all five seeds (the fourth, an isotropic input layer, rightly stayed trivial), though no arm trained measurably faster. The most interesting result came from running it through its own pre-registered protocol on CIFAR-10 with ResNet-18, where it almost never promoted the wide convolutions that richer structure was supposed to help. Built on sketchy, a PyTorch library with Nystrom sketching, Hessian-vector-product and Gauss-Newton oracles, and Muon, all on a single RTX 3060.

  • The threshold theory is proved and checked numerically, with one caveat below the threshold. It covers exact variance penalties for each preconditioner structure, an eigenbasis-estimation cost that stays O(1) as the eigengap closes, and the adaptivity phase transition at the BBP threshold. Above the threshold, an exact asymptotic gain formula (with an O(1/d) remainder) shows that shrinkage is profitable everywhere, and the plug-in edge appears exactly past s** = 1.298. The finite-dimension crossings for d = 8, 16 and 32 are 1.36, 1.34 and 1.33, decreasing toward it. Below the threshold, in a rank-one spiked-Wigner model of the curvature estimate, isotropic Muon-style preconditioning is asymptotically minimax optimal. That proof rests on an imported limit (E δ_d² → 0) and only covers a spike-to-bulk ratio β/ρ up to about 0.69. All ten pre-registered gates for the theorem check out numerically, and the oracle identity holds to machine precision. A companion non-asymptotic bound needs no imported random-matrix result and stays positive at every finite dimension for signal-to-noise up to 0.98, though with a constant of 1/4 instead of 1.
  • A low-rank curvature correction doesn't improve Muon on a CIFAR-10 ResNet, across two different mechanisms (all variants within about a point at a single seed, and slower). It isn't inert, though. On the same layers it redirects the Muon step by a median of 0.84 in relative Frobenius distance (range 0.65 to 1.06, where two unrelated directions would sit near 1.41). The same correction does help SGD on a convex problem. The paper scopes the negative to low-rank corrections in this vision setting, since concurrent work reports that Kronecker and full corrections beat Muon on transformers. Whether curvature structure is what separates the two cases is a hypothesis it motivates but doesn't test.
  • I put the Geometry Ladder's promotion rule through a pre-registered test on CIFAR-10 with ResNet-18, and the result was negative. Over two seeds and 30 epochs, the ladder left all 13 preconditioned wide convolutions on the trivial rung in both seeds and only promoted on narrow downsample layers. That refutes the pre-registered hypothesis that the Kronecker rung would be where those layers settle. The ladder, fixed trivial and fixed Kronecker arms all landed within about a tenth of a point of each other. The one gap bigger than the noise went the other way: a fixed diagonal metric averaged 88.4% test accuracy against 89.6% with no preconditioning at all, and kept that sign on both seeds and on the tuning run. With two seeds that is suggestive but not settled. The wide-layer result is also confounded by a curvature reservoir shared with the forced-Kronecker arm. So the experiment shows that the certified selector rarely picks structure. It doesn't show that structure wouldn't pay.
  • The paper's algebraic backbone is machine-checked in Lean 4 and Mathlib: ten sorry-free theorems covering the Cauchy-Schwarz positivity behind the adaptivity threshold, the point-mass floor used by the finite-dimension lower bound, the trace collapse behind the full-matrix variance penalty, the Kronecker multiplicity discount, and the closed-form zero-noise sign law. The Lean coverage is narrower than that list might suggest. The GOE and Wick moment constants that the variance results reduce to enter as hypotheses, and Lean doesn't prove them. The probabilistic and asymptotic core (the chi-squared and total-variation computations, the BBP threshold, the minimax argument, and every large-dimension limit) isn't formalized in Lean.

Sharp constants for the optimal composite polynomial approximation of the sign function

Study 02
FieldApproximation theory
Key result197 digits
certified enclosure of the depth-tax constants Λ(½,3), Λ(½,5) and Λ(1/10,3) by Arb ball arithmetic
Write-upManuscript, 20 pages, September 2026, with a 16-page finite-precision companion in preparation.
KeywordsPython, mpmath, Arb / python-flint, Julia, Lean 4, Approximation Theory, Interval Arithmetic, Muon

Worked out the exact constants for how well compositions of odd polynomials approximate the sign function. That recursion is what drives Newton-Schulz matrix-sign iterations and Muon's orthogonalization step.

  • Result: A one-step law with a sharp constant. The optimal degree-d composite step contracts the error as E_d(ε) = C_d ε^s (1 + O(ε)) with C_d = binom(d+1, (d+1)/2) / 2^d, so C_3 = 3/4, C_5 = 5/8 and C_7 = 35/64. Explicit rational two-sided bounds hold for every ε in (0, 1).
  • Result: A closed form for the second-order coefficient, c_2(d) = (d+1)(d+2) / (2(d+3)^2), verified symbolically for d = 3, 5, 7 and 9. A depth-tax law shows the exponent collapses at rate (s/d)^k, so extra composition depth only buys effective degree up to a computable constant.
  • Result: For d = 3 and 5, the Böttcher constant follows an exact log-periodic law in the gap. Its relative modulation is 1.4e-8 at d = 3 and 1.4e-5 at d = 5 (exponentially small), which is why it had never been seen numerically.
  • Result: Every constant is certified. Λ(½,3), Λ(½,5) and Λ(1/10,3) are enclosed to 197 digits in Arb ball arithmetic. An independent Julia port reproduces C_d for d ≤ 9, the burn-in gains g_3 and g_5, and Λ(½,3) to between 17 and 31 digits. The Lean 4 kernel decides 44 integer identities with no sorry, including one that refutes a conjectured closed form for C_d.
Sharp constants for the optimal composite polynomial approximation of the sign function
Fig. 02 · The sharp one-step constant C_d = binom(d+1, (d+1)/2) / 2^d for odd degrees 3 to 9, each an exact rational verified in Julia and decided by the Lean 4 kernel
Full description

Compositions of odd polynomials of degree d show up in Newton-Schulz-type iterations for the matrix sign function and the polar decomposition, in homomorphic comparison circuits, and in the orthogonalization step of the Muon optimizer (which uses d = 5). Once inside a basin the composition converges doubly exponentially. But the constants in that law, and the burn-in cost of reaching the basin from a small spectral gap, had only been known asymptotically or numerically. This manuscript pins those constants down. It gives an exact one-step law with rational two-sided bounds, a closed form for the second-order coefficient, and a depth-tax law that converts composition depth into effective polynomial degree. For d = 3 and 5 it also proves an exact log-periodic law for the Böttcher constant of the doubly exponential law as a function of the gap. Its modulation is exponentially small (too small to see at ordinary precision). Every numerical constant is certified by interval arithmetic, and the integer identities are kernel-checked in Lean 4 without Mathlib. An independent Julia implementation reproduces C_d for d ≤ 9, the burn-in gains g_3 and g_5, and Λ(½,3). A companion manuscript carries the same iterations into finite precision, with certified noise floors and precision ladders for bf16, fp16 and TF32.

  • What the manuscript leaves open: the non-constancy of the periodic factor is shown numerically but not proved, and finite-depth two-sided effective-degree bounds are still open.
  • The 16-page companion manuscript gives certified finite-precision envelopes for the same iterations. It includes noise floors, an exact recovery theorem with catch-up constant a_∞(d) = d binom(d−1, (d−1)/2) / 2^(d−1), precision ladders that need at most two steps per IEEE level, and GPU tensor-core experiments in bf16, fp16 and TF32.

Certifying Compression: Optimal Anytime-Valid Equivalence Testing for Compressed Models

Study 03
FieldStatistics · model compression
Key result17 of 17
4-bit quantizations certified NOT equivalent to their source model at 5% top-1 disagreement, α = 0.05
Write-upDraft paper, 16 pages with proofs appendix.
KeywordsPython, PyTorch, Statistics, E-processes, Model Compression, Quantization, LLMs

Built an evaluation for compressed models that stays valid no matter when you stop, then audited 29 quantized models with it. Every 4-bit model failed. 8-bit was mixed, varying by model family and size.

  • Result: The test is anytime-valid by construction. The chance of a wrong verdict stays below α however long it runs, so stopping as soon as the verdict comes in costs nothing, while the same peek voids a fixed-n test.
  • Result: Audited 29 model-and-method pairs across eight architecture families (0.36B to 3.8B parameters). Every 4-bit pair certified NOT equivalent. 8-bit split 4 equivalent, 3 not equivalent and 5 undecided at a 4,000-token budget.
  • Result: A worst-slice mode keeps its error at α for any number of slices, and it gets cheaper than a Bonferroni-corrected fixed-n test above about 16 slices. A frontier mode shares source passes across candidates, which saved 2.18x on a three-config menu.
  • Result: Matching upper and lower sample-complexity bounds for the Bernoulli discrepancy model. The oracle second-order term is proved bounded and measures 0.26 nats.
Certifying Compression: Optimal Anytime-Valid Equivalence Testing for Compressed Models
Fig. 03 · Verdicts across the 29-pair audit at ε = 5% top-1 disagreement, α = 0.05, 4,000-token budget
Full description

Evaluation is supposed to be a fixed-n experiment: pick the sample size in advance, run it, and read the number. In practice nobody does that. You watch the number and stop when it looks good enough, which quietly voids the guarantee the number was supposed to carry. This project builds an evaluation that still holds up when you watch it. certify is an anytime-valid ε-equivalence test (a betting confidence sequence with a GROW-boundary e-process) that answers whether a compressed model stays within ε of its source. The chance of a wrong verdict stays below α no matter when you stop, so you can check after every batch and stop as soon as the verdict comes in without losing anything. Matching sample-complexity bounds say what that costs. Two variants make it practical to deploy. A worst-slice test finds a broken subgroup without getting weaker as the number of slices grows, so detection pays no Bonferroni penalty. A frontier mode certifies which of K candidate compressions are ε-equivalent and returns the cheapest one, paying the expensive source-model cost once instead of K times. The audit runs it on eight architecture families under bitsandbytes and released GPTQ/AWQ checkpoints. The statistical pieces are specializations of known results, and the paper says that. The contribution is putting them together into a certifier that a practitioner can deploy.

  • There are two variants built for deployment. The worst-slice test tracks a product e-process over predictable slices, so its error stays at alpha for any number of slices G, and its detection bound doesn't depend on G at a fixed worst-slice frequency. A fixed-n test pays a Bonferroni log G instead. In a synthetic sweep from G = 2 to G = 128 the two cross near G = 16, so the e-process is only the cheaper option above that. Certifying that every slice is equivalent (as opposed to detecting that one is broken) still pays a union bound, and the paper proves that cost can't be avoided. The frontier mode returns the cheapest epsilon-equivalent config from a menu of K compressions and shares each expensive source pass across candidates. On a three-config menu of released Qwen2.5-1.5B quantizations that saved 2.18x.
  • The audit covers 29 model-and-method pairs across eight architecture families (0.36B to 3.8B) at epsilon = 5% top-1 disagreement with alpha = 0.05. Every 4-bit pair certified NOT_EQUIVALENT (17 of 17), across all eight families and both bitsandbytes NF4 and released GPTQ and AWQ checkpoints. 8-bit was mixed and varied by model family and size, with some families certifying equivalent and others exceeding the 5% bar. Of 12 pairs, 4 certified equivalent, 3 certified not equivalent, and 5 were still undecided at the 4,000-token budget. Qwen2.5-3B int8 certified not equivalent while its 0.5B and 1.5B siblings stayed undecided.
  • Matching upper and lower sample-complexity bounds for the Bernoulli discrepancy model share the leading constant as alpha goes to zero, and the oracle second-order term is proved to be a bounded constant. Its value is the renewal boundary overshoot, which measures 0.26 nats in simulation and stays flat across log(1/alpha) from 3 to 20. The plug-in adaptivity constant, worth 1.3 to 1.9 nats, is still open.

Certified enclosures for the Tracy–Widom distributions: values, densities and quantiles for β = 1, 2, 4

Study 04
FieldIntegrable probability
Key result30 to 55 digits
certified for F₂ (35 to 55), its density (30 to 50), and F₁ and F₄ (about 30), against roughly 13 for the standard double-precision method
Write-upManuscript, 21 pages, September 2026.
KeywordsPython, Arb / python-flint, Fredholm Determinants, Random Matrix Theory, Interval Arithmetic, Numerical Analysis, Statistics

Turned the Tracy-Widom distributions from empirically checked digits into certified intervals, and computed the first rigorously enclosed quantiles for β = 1, 2 and 4. That includes the 0.9793 used to calibrate largest-eigenvalue tests in PCA.

  • Result: Showed that making Bornemann's convergence theorem effective gives a constant above 10^169 even in the most favorable regime, so certification needs a different route.
  • Result: A certified algorithm for F₂ and its density, uniformly on s in [−8, 5] in about 11 seconds per point. F₂ is certified to absolute error below 10^−50 (35 to 55 significant digits), and the density to 30 to 50 significant digits.
  • Result: A certified algorithm for the indefinite cases F₁ and F₄. A multiplicative perturbation bound replaces the classical additive one (whose factor exceeds 10^12 in the left tail). It gives about 30 certified digits, and a rigorous internal cross-check, E₊E₋ ∈ F₂, passes at every point.
  • Result: The first certified quantiles: fifteen levels from 0.001 to 0.999 for each of β = 1, 2 and 4, by exact-decimal bisection with outward rounding. Brackets are printed to 25 decimals for F₂ and 20 for F₁ and F₄, certifying Johnstone's 0.9793 GOE 95% point.
Certified enclosures for the Tracy–Widom distributions: values, densities and quantiles for β = 1, 2, 4
Fig. 04 · Certified significant digits per quantity, uniformly on s in [−8, 5], against the roughly 13 digits of double-precision Nyström evaluation
Full description

The Tracy-Widom distributions are calibration constants for a lot of modern statistics. Johnstone showed that the largest sample eigenvalue of high-dimensional Gaussian data is asymptotically Tracy-Widom under the null, and largest-eigenvalue tests calibrated by Tracy-Widom quantiles are now standard in principal component analysis and factor-number selection. The standard way to evaluate them, due to Bornemann, computes the defining Fredholm determinants by Nyström discretization. Its convergence theory is proven but non-effective (there are no computable constants), and the published digits are validated empirically by comparing methods. This manuscript makes the digits rigorous. It first shows that naively making the theory effective is hopeless, since the constant exceeds 10^169. Then it builds certified algorithms for F₂ and its density, and for the harder indefinite F₁ and F₄ cases. Every rounding is propagated through Arb ball arithmetic, so each printed interval follows mathematically from the cited theorems and the library's correctness. The paper ends with certified tables at fifteen levels for all three β, including the first certified quantiles.

  • Certified here means the printed interval follows mathematically from the results proven in the paper, the cited theorems, and the correctness of the underlying ball-arithmetic library (Arb), with all rounding propagated rigorously.
  • Nine property tests pass (trace identities, Weierstrass bracket, monotonicity, density against finite differences, outward rounding, and quantile invariants). An independent audit of the tables confirms monotonicity and the E₊E₋ cross-check at all 261 common grid points. The full table run takes 3.0 hours on 11 cores.
  • Open problems the paper names: certified Tracy-Widom moments, general β through the Trogdon-Zhang ODE route, and other edge functionals such as Airy and Bessel gap probabilities.

Completability, not Satisfaction: A Viability Interface for Learned Constructive Packing

Study 05
FieldReinforcement learning · combinatorial optimization
Key result0.082 → 0.201
plain-rollout success on fixed-capacity instances once the viability critic restricts the mask (one estimator call per step, 4-seed mean)
Write-upWorking draft, 18 pages.
KeywordsPython, PyTorch, Reinforcement Learning, PPO, Combinatorial Optimization, CP-SAT, Constrained Search

The feasibility mask that learned packers use for constraints can't promise the packing can still be finished. I proved when that gap appears and closed much of it with a learned viability critic.

  • Result: Three theorems locate the boundary. With recourse, dead ends can't exist and masking is enough. At fixed capacity they can (a machine-verified minimal counterexample shows it), and fixing that means deciding viability, which is strongly NP-hard.
  • Result: On provably packable instances, a masked packer's success drops from 100% to near zero as the container gets tighter. It still places 92% of items but only finishes 5% of instances.
  • Result: As search guidance, a learned viability critic beats the policy's own value head by +0.218 [+0.188, +0.250] at the training size. It transfers zero-shot to 12 to 25 items and predicts completability at AUC 0.975 on instance-disjoint data.
  • Result: Used to restrict the mask at rollout (one estimator call per step), the critic raises success from 0.082 under plain rollout to 0.201. Against a no-critic lookahead control at 0.096, that is +0.105 [+0.085, +0.126].
Completability, not Satisfaction: A Viability Interface for Learned Constructive Packing
Fig. 05 · Completion rate by packing tightness α on 9-item instances, 100 instances per cell. Critic bars are 4-seed means.
Full description

Learned 3D bin packers handle constraints (no stacking on glass, orientation locks, unload order) by masking illegal placements at each step. That mask is the standard interface, and it works as far as it goes: every placement it allows is legal. What it can't promise is completability. A placement that is legal right now can still strand the items that come after it, and a per-step mask has no way to see that coming. Three theorems pin down where the boundary is. When the packer has recourse (it can always open another bin), dead ends can't happen and masking is enough. That's why the existing benchmarks, my own included, never ran into the problem. At fixed capacity that escape hatch is gone and dead ends do appear (shown with a machine-verified minimal counterexample), and the interface that would fix it requires deciding viability, which is strongly NP-hard. The empirical half builds the fixed-capacity benchmark the theory calls for, on instances that are provably packable. There the failure is severe, but it can be diagnosed and partly fixed: a learned viability critic recovers much of what the policy's own value head misses. This work grew out of Packomation.

  • Randomizing declarative feasibility masks during training gives one constraint-agnostic policy that transfers across constraint sets. A lookahead head that picks which of the next k buffered items to place raises the strict win rate over the best-of-four heuristic from 0.10 to 0.69 as constraints tighten, while staying 90-95% proven-optimal against a CP-SAT lower bound.
  • Matched-budget ablations rule out extra search as the reason for the advantage, and an online-PPO baseline at the same budget never clears the bar. So the gain comes from lookahead selection itself, and reinforcement learning in general doesn't explain it.
  • As search guidance, the learned viability critic beats the policy's own value head by +0.218 [+0.188, +0.250] at the 9-item training size. It holds up under zero-shot transfer to 12 to 25 item instances (+0.115 pooled), and past that the edge shrinks with scale: +0.077 at 30 items, +0.055 at 35, and +0.008 by 40, which is inside seed noise. It also replicates zero-shot on a structurally different tight non-guillotine distribution, at +0.306 pooled (200 instances per cell, four critic seeds, up to +0.42 in one cell). On instance-disjoint held-out data the critic predicts completability at AUC 0.975, with a spread of 0.002 across four seeds, over 17,646 states from 150 instances.
  • I re-measured that critic's AUC with a stricter protocol, and the number dropped. The original in-split figure came from a state-level random permutation over a pool where sibling rollout states of one instance appear across three rollouts, scored on the same fold used to pick the training epoch, on class-balanced data. On 17,646 states from 150 fresh instances with the natural class prior, the same four critics score 0.9752 ± 0.0018, against 0.9903 ± 0.0012 on their own validation folds. Calibration moves the same way: ECE 0.033 on the strict split against 0.021 in-split. The gap mixes split leakage, checkpoint selection and the class prior, and no run separates them. Instance-disjoint evaluation is the protocol this number needs.
  • At rollout with no search, using the critic to restrict the mask itself raises success from 0.082 under plain rollout to 0.201, at one batched estimator call per step. The fair control is a lookahead with the same expansion and no critic (0.096), since expansion alone avoids one-step dead ends. The critic beats it by +0.105 [+0.085, +0.126]. Widening the shortlist to 16 lowers the greedy readout while the restrict-then-policy readouts hold, so the payoff comes from the interface itself, since more candidates don't help. The pooled effect is uneven across the grid: bigger in loose cells than in tight ones.

What Do Training-Free Compressibility Metrics Actually Predict? A Weight-vs-Output Audit

Study 06
FieldModel compression
Key resultΔρ = +0.243
[+0.201, +0.285] gain in rank correlation with output error over the HAWQ Hessian score (pre-registered 7-model panel, 168 cells)
Write-upWorkshop paper draft, v0.1, with a locked pre-registration and the full experiments directory.
KeywordsPython, PyTorch, Random Matrix Theory, Model Compression, Quantization, GPTQ, Statistics

Audited the training-free sensitivity scores used to allocate bits. They predict weight-space damage but not output damage. A one-backward gradient predictor beats them.

  • Result: Training-free statistics like spectral spread and kurtosis predict weight-space compressibility but not output-space damage. Used to allocate bits, the data-free scores do worse than random, while HAWQ's data-dependent Hessian score beats random. Uniform allocation only wins by spending 4 bits per weight against the allocators' 3.5, and held to 3 bits on OPT-350M it loses to every allocator, random included.
  • Result: A one-backward empirical-Fisher predictor matches HAWQ's 8-probe Hutchinson score under GPTQ on WikiText-2, and ranks ahead of it on all 11 cells of a 4-model sweep across quantization, pruning and low-rank compression.
  • Result: In a pre-registered confirmatory test on 7 models and 5 architectures, the predictor beat HAWQ by Δρ = +0.243 [+0.201, +0.285], winning on four architectures and tying on Bloom. The pre-registered primary hypothesis (a forward-only activation signal) failed at Δρ = −0.179.
  • Result: A Gauss-Newton analysis explains the gap, and its sharpest prediction held. Raising Hutchinson probes from 1 to 64 lifts the Hessian score's correlation with output error from 0.21 to 0.50, which is still short of the one-backward gradient's 0.57.
What Do Training-Free Compressibility Metrics Actually Predict? A Weight-vs-Output Audit
Fig. 06 · Rank correlation with output error on OPT-350M quantization cells over 3 seeds, for the Hessian score at 1 and 64 Hutchinson probes and for the one-backward gradient
Full description

A theory and audit project (speccomp) on what makes a neural network layer compressible, and whether the usual training-free sensitivity heuristics actually measure it. The main finding is that training-free statistics (spectral spread, per-channel dynamic range, entrywise kurtosis) predict weight-space error for the compression method each one matches, but not output-space damage. Used for mixed-precision bit allocation, the data-free scores do worse than random, while HAWQ's data-dependent Hessian trace beats random. A cheap one-backward empirical-Fisher gradient predictor does better. It ranks ahead of HAWQ's double-backward Hessian score on all 11 cells of a 4-model sweep covering round-to-nearest quantization, pruning and low-rank compression. Under GPTQ it ties HAWQ (WikiText-2 perplexity 60.5 against 60.1, one run per arm) while using one backward pass instead of an 8-probe Hutchinson trace. A Gauss–Newton analysis explains the gap, and its testable prediction about probe noise versus data alignment held up. The main claim survived a pre-registered confirmatory test on a 7-model, 5-architecture panel, with thresholds set before the confirmatory sweep and not changed after seeing the data. The pre-registered primary hypothesis did not survive, and that turned out to be the more useful half of the result. All numbers reproduce from the experiments directory, and everything runs on a single 12 GB GPU.

  • A one-backward empirical-Fisher predictor matches HAWQ's double-backward Hessian score under GPTQ on WikiText-2 (perplexity 60.5 against 60.1, one run per arm, no variance estimate) using one backward pass instead of an 8-probe Hutchinson trace. It also ranks ahead of it on all 11 cells of a 4-model sweep covering round-to-nearest quantization, pruning and low-rank compression. Uniform allocation beats both on the quantization cells, but only because rounding gives it 4 bits per weight against their 3.5. Held to 3 bits on OPT-350M it loses to every allocator, random included (GPTQ perplexity 115.4 against 76.5 for random and 60.1 for HAWQ).
  • The pre-registered confirmatory test used a 7-model, 5-architecture panel of 168 shape-controlled cells, with correlations computed within each architecture and then pooled. The one-backward predictor (weight error times gradient RMS) beat the HAWQ Hessian by delta rho = +0.243 [+0.201, +0.285], winning on four of the five architectures and tying on the fifth (Bloom, 0.514 against 0.518). The pre-registered primary hypothesis failed, and that failure is the result worth reporting. The forward-only activation-RMS signal that beat HAWQ on a single model was worse across the panel (delta rho = -0.179), and forward-only activation statistics are the cheap default people usually reach for.
  • A Gauss-Newton analysis explains the gap, and its sharpest prediction held on OPT-350M across 3 seeds on the quantization cells. As the Hutchinson probe count goes from 1 to 64, the Hessian score's correlation with output error climbs from 0.21 to 0.50, still short of the one-backward gradient's 0.57. So part of the advantage is probe noise that more probes remove, and part is the remaining gap that the data-alignment term predicts. A second prediction, about per-method isotropy, only partly held. The fit was worst for low-rank as expected, but the stable-rank proxy was too crude to order the methods.

Does the Basis Matter? Disentangling Structure, Magnitude, and Density in Frequency-Domain Parameter-Efficient Fine-Tuning

Study 07
FieldParameter-efficient fine-tuning
Key result70 to 87%
of FourierFT's no-transform collapse recovered by a per-layer rescale alone (RoBERTa-base on MRPC, CoLA and RTE, 3 seeds)
Write-upPaper drafted, 18 pages in the arXiv build, with 14-page journal and 6-page workshop variants.
KeywordsPython, PyTorch, PEFT / LoRA, Wavelets, Fourier Analysis, LLMs, Permutation Tests, Experimental Design

Built the matched control that frequency-domain PEFT never had (a basis permutation). Permuting the basis left accuracy statistically indistinguishable on five of six method–task pairs, and what the transform adds is mostly magnitude (replicating Zhang et al., 2025) plus a little density.

  • Result: The control is exact by construction. A basis permutation is orthogonal and energy-preserving, so it keeps parameter count, sparsity support and effective rank fixed while destroying the structure the transform is meant to exploit. It takes one line of code.
  • Result: Magnitude does most of the work, as Zhang et al. (2025) found for LoRA initialization. A no-transform update that differs only by a per-layer rescale recovers 70 to 87% of FourierFT's collapse. Density (reaching every coordinate) is the small remainder, worth 0.026 on MRPC and 0.072 MCC on CoLA.
  • Result: Close to nothing is left for the basis. A permuted Fourier basis is indistinguishable from the true one on MRPC and CoLA (p = 0.91 and 0.67, with 90% intervals consistent with equivalence within about ±0.02), and permuting the wavelet basis is harmless on all three tasks. The one exception, FourierFT on RTE at +0.041 (p = 0.026), doesn't survive multiple-comparison correction.
  • Result: The WaveFT-style adapter backs this up. Its inverse wavelet transform is orthonormal, so its no-transform update is already magnitude-matched, never collapses, and leaves no density gap.
Does the Basis Matter? Disentangling Structure, Magnitude, and Density in Frequency-Domain Parameter-Efficient Fine-Tuning
Fig. 07 · Share of FourierFT's no-transform collapse explained by magnitude alone, per GLUE task (RoBERTa-base, 3 seeds). The remainder is density. The basis, tested separately by permutation, adds nothing that survives multiple-comparison correction.
Full description

Frequency-domain PEFT methods (FourierFT, WaveFT, and wavelet LoRA variants) report gains and credit them to the transform basis. The idea is that a Fourier or wavelet basis captures structure that a plain low-rank update misses. That attribution had never been tested against a matched control, so this project builds one. A basis permutation is orthogonal and energy-preserving, so shuffling the basis order keeps the parameter count, sparsity support and effective rank fixed while destroying the structure the transform is supposed to exploit. Any gain the real basis has over its permuted version is structure. Running the control on FourierFT and a WaveFT-style wavelet adapter with RoBERTa-base on GLUE splits what the transform appears to contribute into three parts, and the basis is the smallest. Magnitude does most of the work, replicating what Zhang et al. (2025) found for LoRA initialization. The collapse people point to as proof that the transform is necessary only happens in one method. FourierFT's no-transform variant drops to the frozen baseline (CoLA MCC 0.000) because its scaling constant is calibrated to a normalized inverse FFT, so removing the transform without rescaling makes the update the wrong size by a factor near 768. Matching the magnitude alone recovers 70-87% of that collapse. The wavelet adapter doesn't need that correction since its inverse DWT is orthonormal, and its no-transform variant doesn't collapse on any of the three tasks (CoLA MCC 0.554 against 0.557 for the true basis). So the main evidence for the transform being necessary is a normalization artifact. Density (the high-rank sparse parameterization) is a real but small remainder, worth 0.026 on MRPC (the mean of accuracy and F1) and 0.072 MCC on CoLA. What's left for the basis itself is close to nothing. A permuted Fourier basis is statistically indistinguishable from the true one on MRPC and CoLA (paired p = 0.91 and 0.67, with 90% intervals consistent with equivalence within about ±0.02), and permuting the wavelet basis is harmless on all three. There is one exception: FourierFT on RTE, where the true basis wins in 3 of 3 seeds by a mean 0.041 accuracy margin (paired p = 0.026). It doesn't survive multiple-comparison correction, and two other things keep it modest. The wavelet grid on RTE goes the other way, and a magnitude-matched independent orthogonal basis lands inside the permuted band. With three seeds, RTE is the one place the basis might carry real structure, but three seeds can't demonstrate it. A budget sweep on MRPC at 50, 200 and 1,000 Fourier coefficients per adapted projection keeps the true-minus-permuted gap within ±0.01, even at 50, the tightest budget, where a structural prior has the most room to help. Runs at 5,000 and 20,000 became unstable for both bases, so the claim rests on budgets up to 1,000. The project started as WaRA, a PyTorch library for wavelet-domain LoRA. The FourierFT arms here run on the official peft implementation, and the wavelet arm is a WaveFT-style adapter written for the study.

  • I broke down FourierFT's apparent need for its transform on RoBERTa-base across MRPC, CoLA and RTE, with 3 seeds each. Magnitude does most of the work: a no-transform update that differs only by a per-layer rescale to the transform's Frobenius norm recovers 82%, 87% and 70% of the collapse. The rest is density, the ability of a transform to reach every weight coordinate, worth 0.026 on MRPC (mean of accuracy and F1) and 0.072 MCC on CoLA. The same controls on the WaveFT-style adapter back this up. Its inverse DWT is orthonormal, so its no-transform update is already magnitude-matched, never collapses, and leaves no density gap. This part replicates Zhang et al. (2025), "The Primacy of Magnitude in Low-Rank Adaptation" (NeurIPS 2025), and the paper credits it that way.
  • On two tasks out of three, close to nothing is left for the basis. A permuted Fourier basis is indistinguishable from the true one on MRPC and CoLA (paired p = 0.91 and 0.67), and permuting the wavelet basis is harmless on all three. The 90% intervals are consistent with equivalence within about ±0.02, though three seeds can't certify a tighter ±0.01 band. The one exception is FourierFT on RTE, where the true basis wins in 3 of 3 seeds by a mean 0.041 margin (p = 0.026). Two things temper that: the wavelet grid goes the other way there, and a magnitude-matched independent orthogonal basis lands inside the permuted band. No capacity threshold shows up across the 50, 200 and 1,000 coefficient budgets, including the tightest one, where a structural prior has the most room to help.
  • A companion analysis on one fully fine-tuned SAM ViT-B update points the same way. The update's weight matrices sit inside their row-and-column permutation null on average (mean z = +0.14 over 48 layers, with 5 nominally significant at p < 0.05). The same model's patch-token activation grids, by contrast, beat their spatial-permutation null on wavelet low-frequency energy in all 60 image-by-block grids (mean z = +19.1). It's one model and one update, so it illustrates why a structured basis can do nothing in weight space and still make sense for activations, but it doesn't establish it.
  • WaRA, the wavelet-domain PEFT library the project started from, includes weight-space and activation-space variants and a parameter-matched LoRA baseline.

Projects

Packomation: Spatial Capture & Learned 3D Bin Packing

Exhibit 01
CategoryML & Applied AI
KeywordsPython, PyTorch, Reinforcement Learning, FastAPI, ONNX, React Native, TypeScript, iOS, ARKit, LiDAR

An iOS app that scans a room or shipment with LiDAR and ARKit and turns it into an optimized 3D load plan. A maximal-empty-space engine does the packing, and the learned packer stays in research until a checkpoint beats it.

  • Result: The app plans with the maximal-empty-space engine, which fits the 3-bedroom demo load into one 26-ft truck where the older guillotine heuristics needed two. The learned packer stays in research until a checkpoint beats that engine.
  • Result: Uses RoomPlan and ARKit where the hardware supports them. Without LiDAR it prefers rear dual-camera depth, then Object Capture, then a TrueDepth hold-up for small items, with a marker-assisted estimate and a model prior last. Each item's dimension source and confidence carry through to the plan.
  • Result: Every dimension records where it came from. An arbitration module ranks explicit captures above matched LiDAR room features, and those above passive estimates. Typed values outrank all three, so a record can't claim a sensor produced numbers a person typed over.
  • Result: Freight planning runs on a maximal-empty-space engine with a verifier that throws out any candidate with verification errors. It checks axle loads at every tandem slide notch, plans pallet-first layers, and writes BOL, CSV and EDI-856 manifests.
Fig. 01 · Research demo of the learned packer fitting a 2-bedroom load (18 items, 7 fragile) into a 14-ft truck under automatic stacking constraints. The app itself plans with the maximal-empty-space engine.
Full description

An iOS app that scans a room or shipment and builds an optimized 3D load plan, for personal moves as well as freight and container loading. A local Expo native module bridges RoomPlan LiDAR scans and ARKit tap-to-measure for sizing items, with camera intake through react-native-vision-camera. Without LiDAR the app recommends rear dual-camera depth first, then Object Capture, then a TrueDepth hold-up for small items, and finally a marker-assisted estimate and a model prior. The packing core runs on a maximal-empty-space engine in TypeScript, next to classical 2D/3D heuristics (BL/BAF/BSSF/BLSF plus an NFDH shelf packer). Every 3D plan goes through an independent TypeScript verifier, which shares no code with the engine, before the re-ranker picks a plan. Freight mode adds pallet-first planning, container presets, load sequencing, a deterministic scorecard with a profile-aware re-ranker, and carrier handoff docs. For road trailers the verifier checks axle loads at every tandem slide notch, and the planner centers partial loads on the axle balance point. A browser dispatcher takes a load from intake to plan to BOL, CSV or EDI-856 manifest, and then to carrier handoff. The learned packer from the completability study above stays in research. I removed the app's ML path in September, since the service couldn't answer inside the client's own timeout. I also ported the verifier and the engine to Python, so the next policy is trained and scored against what the app ships. The FastAPI /plan endpoint is still live behind a bearer token, and with no servable checkpoint it serves a greedy bottom-left packer.

  • Every dimension in a plan records where it came from. A pure arbitration module ranks the three automatic sources: an explicit capture the user did on that item (AR tap-to-measure, TrueDepth hold-up, rear-camera depth, or Object Capture) first, then an auto-matched LiDAR room feature, then a passive label-and-media estimate. It outputs the dimension source, the estimation confidence, the matched feature id, the sensor confidence and the capture asset together, so those fields can't disagree. Typed values outrank all three. On save, the intake form compares what's left in the fields against what the module resolved and marks the source as manual whenever they differ.
  • Weights are estimated instead of required, because the safety and loadability kernels would score a weightless load a perfect 1.00. Intake multiplies a per-category bulk-density prior by the item's measured volume. I went with density because it held steadier than mass within a category across the demo fixtures. The two wardrobes come out at 75 and 76 kg/m3 while weighing 90 and 110 kg, and the two dining tables at 47 and 53 kg/m3 while weighing 45 and 75 kg. The priors are fitted to those fixtures and haven't been validated against real weighings, and nine of the twenty-six categories rest on a single observation. A test keeps them within 25% of every categorised demo row, so changing the demo data forces the priors to keep up. The inventory screen and the plan grade both show how many weights were estimated instead of entered.

Mybrary: Offline Search and Q&A for a Journal Collection

Exhibit 02
CategoryML & Applied AI
Key result69% → 84%
of test questions where the source page reached the model, from keyword search alone to keyword and meaning search with a reranker (64 questions)
KeywordsSwift, SwiftUI, llama.cpp, Qwen, Embeddings, Reranking, SQLite FTS5, macOS

An offline Mac app that lets a researcher search and ask questions of her transcribed journal collection, with every answer quoting the pages it came from. Everything runs on her Mac, including the AI models.

  • Result: Measured on 64 answerable and 8 unanswerable test questions through the app's own code. The source page reached the model for 44 of 64 (69%) with keywords alone, 50 (78%) with keywords and meaning fused, and 54 (84%) after reranking the best 60 candidates.
  • Result: With Qwen3.5-9B, 58 of 64 questions got an answer: 47 cited the source page and 11 cited other pages only (possibly wrong). 95% of quotes checked out word for word, and all 8 unanswerable questions came back "not found".
  • Result: An answerability check on the reranker's best score stops all 8 unanswerable questions before the model runs, saving about 12 seconds each. It stops only 1 answerable question, one the model couldn't answer either.
  • Result: 180 tests in Swift Testing cover indexing, search, retrieval, quote checks and the read-only guarantee. It was delivered to the researcher it was built for. Her review and a later report from her shaped the next two updates, and a usability pass the third (now version 0.2.2).
Full description

Mybrary is a native SwiftUI app for macOS, built for a researcher and editor working on a historical journal collection of about 1,000 transcribed pages in 25 volumes. It indexes the collection where it already lives and never changes her files. Search combines keywords (SQLite FTS5) with search by meaning, using Qwen3-Embedding-0.6B vectors searched with Apple's Accelerate framework. Questions in English or French go to Qwen3.5-9B (or the 4B model on a slower Mac), which runs through llama.cpp on the GPU in a sandboxed helper process. A reranker (Qwen3-Reranker-0.6B) picks the passages, a grammar holds the model to an evidence-list answer format, and every quote is checked word for word against its passage before it's shown. When the reranker finds nothing close to a question, the app answers "not found" without running the model. The app never sends her text anywhere, and the network is only used to download the models. Her own work (notes, tags, collections and a registry of people and places) lives in the app's own database.

  • The 64 answerable test questions were generated on my Mac by a local model from 74 of her pages across 24 volumes, plus 8 unanswerable ones, without her involvement. Retrieval is the main limit: the source page was among the 60 reranking candidates for 56 questions, and the reranker picked it for 54 of them. Reranking adds about 4.5 s a question and a 639 MB download, so it's only used once she has downloaded the reranker.
  • On an M3 Pro, as a stand-in for her 16 GB Mac, the 9B model loaded in 4.2 s and used 5.7 GB of GPU memory in the trial on the same llama.cpp engine, and it writes about 22 tokens per second in the app. The whole collection embeds in about a minute. A full index takes about 20 s, and re-indexing an unchanged collection takes 0.4 s.
  • Her files are never modified. The app runs in the App Sandbox, macOS holds her folder read-only except while copying in pages she adds (which never replace a file), a test checks that indexing never changes a file, and the helper that runs the models is granted no files at all. Saving a transcription in her own editor updates the index within seconds. Names are suggested on English pages only, by Apple's on-device tagger, so names on the few pages in French are added by hand.

Expanded Entropy: Autopsy Ingest Module

Exhibit 03
CategorySystems & Security
Key result46 → 11
false positives among 243 unencrypted variants at a 6.0 threshold when Min entropy replaces Shannon, with none of the 108 encrypted variants missed
Write-upPaper, September 2026: "Min Entropy as the Default for Encryption Detection in Autopsy", in the repository with the code, tests and sample corpus.
KeywordsPython, Jython, Autopsy, Digital Forensics, Entropy, Encryption Detection

An Autopsy ingest module that flags possibly encrypted files with Min entropy instead of Shannon, then tells compressed data from ciphertext in a second stage. In an earlier experiment, the switch to Min cut false positives fourfold. It was recommended by Simson Garfinkel.

  • Result: In the earlier experiment (27 files, each also encoded, hashed and encrypted twelve ways), Min entropy cut false positives from 46 to 11 of 243 unencrypted variants at the 6.0 threshold, with none on text or SQLite files (some PDFs and archives still tripped every measure). No measure missed any of the 108 encrypted variants.
  • Result: On the repository's small synthetic corpus, Shannon flags six files and Min flags four, two of them compressed files that every measure flags. The two Min clears are the false positives: a PDF (7.396 bits per byte under Shannon, 2.728 under Min) and a SQLite database (6.883 and 4.578), both built to show the effect.
  • Result: The second stage recognizes 98% of 64 KB deflate blocks and 157 of 165 deflate files with at least two blocks to judge (39 of the 43 the first stage would flag), and calls none of 2,618 encrypted 64 KB blocks compressed. Ciphertext mixed with plaintext structure, like an encrypted PDF, often reads as compressed (16 of 23 such files), and the verdict text warns about it. Most encrypted PDFs don't reach 6.0 under Min in the first place.
  • Result: Tested at three levels: 175 unit tests under CPython, 38 tests under the Jython that Autopsy bundles with the real Sleuth Kit and Autopsy jars, and a scripted Autopsy 4.23.1 ingest of the corpus that flags exactly the four expected files. The Jython suite found two real bugs in earlier versions: Java exceptions that Jython's except Exception clause doesn't catch, and settings that saved but never loaded.
Full description

Expanded Entropy is an Autopsy file ingest module that checks files for possible encryption using Min entropy instead of Shannon entropy. Autopsy's own detector uses Shannon entropy with a default threshold of 7.5 bits per byte, and its entropy test only covers files of unknown type of at least 5 MB (64 KB with a .db extension). At 6.0, the lowest threshold Autopsy allows, a Shannon test flags ordinary PDFs and SQLite databases. Min entropy only looks at the most common byte value, so a file reaches 6.0 only if no byte value makes up more than 1/64 of it. Ciphertext meets that easily, while a PDF with a few percent of padding bytes doesn't. The measures are ordered Min ≤ Rényi(3) ≤ Collision ≤ Shannon, so at the same threshold, switching from Shannon to Min can only remove flags and never adds one. The module reads each file once into a byte histogram, computes all four measures, and raises Autopsy's own Encryption Suspected result with all four values in the comment. No entropy measure can tell dense compression from encryption, so a second stage runs the Huffman-coded data discriminator from Garfinkel, Nelson, White and Roussev (DFRWS 2010) on the files the first stage flags. The earlier experiment behind the choice of Min entropy was my ITIS 5250 course project, and the paper in the repository covers the reasoning and the evidence in full.

  • Autopsy's own entropy test only covers files of unknown MIME type that are at least 5 MB (by default also a whole multiple of 512 bytes, and from 64 KB for files with a .db extension), so as shipped it never sees a PDF or SQLite database that Autopsy has identified. PDFs, Office documents and Access databases get a separate password-protection check. By default this module measures every regular file of 1 KB or more that no hash set marks as known, which is where the choice of measure makes a difference. Min entropy at 6.0 is the default, and the settings panel can switch the measure, change the threshold and the Rényi order, cap how much of each file is read, or flag a file when any of the four measures trips.
  • The second stage's thresholds come from encrypted data, as in the original method, but from a lot of it: 3,200 MB of AES keystream, cut at the score that 1 in 10,000 blocks fall below. It pools the four difference histograms into one cosine, which is less noisy than the original's smallest cosine over the shifts. A file is called compressed when at least two of up to four sampled blocks fall below the threshold, so an encrypted file with four sampled blocks is miscalled with probability under 1 in 10 million, and at most 2.5 in 10 million given the bound on the per-block rate.
  • The paper is explicit about the limits. The second stage only recognizes Huffman-coded data, so headerless data coded another way (xz's range coder, for example) or stored without coding still looks random to it. For formats with a header, the module adds the file type Autopsy identified. Ciphertext with a long run of one byte value, like a zero-padded encrypted container or a file with a long plaintext header, can fall below the threshold under Min, and a flag-if-any option covers that case. The test collection is small and its obfuscated variants are synthetic, so the next step is a measurement on real case images with known encrypted content.

Additional entries

04Retail Platforms

New Leaf & Locket Vintage

Two live e-commerce stores built on the same Express and React pattern, with hosted checkout, webhook-driven inventory, owner admin portals, and a blind-judged similar-item recommender on Locket.

React · TypeScript · Express · SQLite · TF-IDF · Recommender Systems · Stripe · Admin Portal

  • Result: Two stores live in production on Vercel and Railway. Locket brings in real inventory through a CSV import pipeline.
  • Result: Hosted checkout with signature-verified webhooks driving order and inventory state, idempotent on redelivery and out-of-order events. JWT admin, rate limiting and Helmet.
  • Result: Similar-item shelves run on Locket's product pages (server-rendered in the route loader so the links are crawlable) and in the cart (based on the priciest item, excluding what's already there). An admin pin/exclude editor controls them: pins come first and the ranking fills the rest. Ties break on id, so shelves are deterministic, cacheable and SSR-stable. The TF-IDF index is memoized on the identity of the cached item array instead of a manual invalidation key, so any inventory write rebuilds it and a sold piece can't stay on a shelf. 508 items index in about 5 ms and a lookup takes roughly 1 ms, so nothing is precomputed.
  • Result: Half the live catalog (266/508) has no photo, and a recommendation shelf is purely visual. So photographed pieces always come first and photoless ones only fill in after them. That leaves 0 blank slots across all 2,032 shelf positions in the catalog, without bringing back the empty-shelf problem that ruled out hard filtering.
  • Result: Set the category weight by blind judging against the live catalog instead of by taste. Six values went through two independent blinded passes with variant order shuffled per item, 270 verdicts in total. 0.5 won every cut (normalised quality 0.756 against 0.503 for the old 0.35, and 71-45 head-to-head across 116 decided pairs, sign test p about 0.02). Higher weights bought category purity but collapsed variety, with hub concentration climbing from 37 to 56. It had a cost: 45 of those 116 contested shelves got worse, mostly novelty and brand-affinity intent where a rare word in the name was the better signal. There's no conversion tracking yet, so the shelves are judged on ranking quality alone.
Full description

Two live e-commerce sites: a mobile plant shop (The New Leaf) and a vintage clothing store (Locket Vintage). Each has a self-serve storefront and an admin dashboard for the owner. Both use the same pattern, an Express + SQLite (node:sqlite) API with a React/Vite storefront (Locket's is server-rendered with React Router 7). Checkout is hosted and self-serve through Stripe on both sites. Signature-verified webhooks drive order and inventory state, and JWT-secured admin portals cover inventory, orders, schedule, expenses, bookings and reporting. Locket also has a 'you may also like' recommender over its 508-piece catalog. It uses TF-IDF cosine similarity over item names, since 82% of the catalog's descriptions are stubs under 15 characters while the names carry era, colour, pattern and cut. Guardrails on category, era, size and price sit on top, so a $12 floral tee doesn't get paired with a $200 floral coat just because they share the word 'floral'. The guardrails rank instead of filter, because requiring category, era and size to match leaves a median of one candidate and 39% of items with none. The weights were set by blind judging against the live catalog. Both sites are hardened with express-rate-limit, Helmet, a strict CORS allowlist and request sanitization, and Locket brings in real inventory through a CSV import pipeline. The storefronts are on Vercel and the APIs are on Railway.

05Spirit

Learning Platform (EdTech SaaS)

A production EdTech platform where learners buy and watch structured courses and instructors run their own workspace. Unit and route tests cover each part of the payment flow, which runs on Stripe test keys until full launch.

Next.js · TypeScript · PostgreSQL · Prisma · Stripe · Mux · Clerk · Railway

  • Result: Runs in production on Railway at learnwithspirit.com, with 13 Prisma migrations applied on deploy and CI on GitHub Actions.
  • Result: Unit and route tests cover each part of the payment flow: checkout (course and bundle), signature-verified webhook fulfillment with idempotent redelivery, refund revocation, entitlements, and the admin authorization matrix.
  • Result: A signature-verified Stripe webhook grants entitlements idempotently inside a database transaction. Bundles split the discounted total pro-rata across their courses, and refunds revoke access and email the buyer.
Full description

A full-stack EdTech platform for a spiritual-education client, live in production at learnwithspirit.com. Learners buy and watch structured courses, and instructors run their own teaching workspace. It's Next.js 15 and TypeScript on Prisma/PostgreSQL, with Clerk auth (learner, instructor and admin roles), Stripe Checkout for single courses and discounted bundles, Mux video with signed RS256 playback and self-serve instructor uploads, and Resend for transactional email. Lessons can be video, audio, Markdown articles or private reflection journals. The platform remembers where you left off, tracks practice streaks, and issues shareable certificates automatically. Learners can export their data or delete their account in one click, and every change to money or content goes into an audit log.

06Automated Multicam Edit Pipeline

A pipeline that turns long multicam footage into finished videos from cut lists I write to 94 rules taken from my own CapCut edits. It transcribes, syncs the cameras from their audio, renders with ffmpeg, and also exports every video as a CapCut project.

Python · ffmpeg · Whisper · Signal Processing · NumPy

  • Result: Built 12 tasks from a season of 198 video files (24.6 hours of footage) in one overnight run, producing 43 videos that total 97.8 minutes against 149.0 for the previous version. Every video passed the build's quality check, and each one also exists as a CapCut project whose cuts, read back from the project file, land within one frame of the mp4.
  • Result: Turned five of my own CapCut edits into 94 written rules. Four of those edits came from one task, which was then recut blind. The recut matched my own cut much more closely on three of its four videos (precision 63 to 82%, up from 26 to 34%), while the fourth slipped from 68% to 61%. Most of the rules came from that task, so this shows they can be followed. It doesn't show they carry over.
  • Result: Moved every editorial decision into a cut list that the builder only executes, so I can read and change any of it. A check validates each list before a build. A QC script then fails any delivered file that loses content, overruns its plan, drops an overlay or plays sound inside a span marked never to air. The builder still masks same-camera seams with a punch-in where it can, and any left over are only reported, since my own edits allow same-angle jumps through dead time.
  • Result: Denoising uses a DeepFilterNet3 chain picked by a loudness-matched A/B test across four hard voices and six chains. Attenuation is capped at 20 dB, since uncapped runs darkened far-field voices by 2 to 5 dB. The chain still left quiet mutters 15 to 25 dB too low, so a beat it erased now plays the camera's own sound, levelled to the dialogue.
Full description

An automated editing pipeline for long multicam footage, built for a homemade comedy panel show made with friends. It's shot with one locked camera per person plus room sound. The pipeline transcribes with faster-whisper large-v3-turbo on CUDA with word timestamps, and syncs the cameras by cross-correlating their audio-energy envelopes. It makes a second angle by cropping the 3024x1964 main cameras down to native 1920x1080 (no upscaling). The current version keeps every editing decision in a cut list of beats on each person's camera clock. I wrote each list to 94 rules taken from five of my own CapCut edits, and a second pass checked it. The rules come from parsing each CapCut project's JSON and mapping every segment back to the camera clocks. The builder only executes the list. It snaps cut edges to words, picks angles and punch-ins, levels each beat to the video's speech level, and renders with ffmpeg using two-pass loudness normalisation. A check validates each list before a build, and a QC script compares every delivered file with its list. Contestant groupings were proposed automatically and fixed by hand. The output has no music, which is left for CapCut. The rules came from my edits of just two tasks, so agreement with my own cut has only been measured where the rules came from.

  • I dropped one of my own metrics after testing it. Cut visibility had been scored by colour-signature distance across each cut, but that can't work here: everyone sits in the same locked frame, so a cut between two people barely changes the picture statistics. The within-shot control (max 0.233) overlapped the cut distribution (median 0.226) outright. I replaced it with the structural definition, and only kept colour for the one thing it can tell you, which room a shot is in.
  • I documented a proxy-gaming failure in my own loop. A synthetic language-model audience panel scored each cut, and an automated loop hill-climbed that score. Over four rounds the loop cut the plan from 7.9 minutes to 4.6 and then 4.0, deleting 49% of the runtime. The panel's score went 4, 3, 4 and 4 out of 10 over the same rounds, and as the editor I thought the result was worse. Earlier waves (13 and 14 July) showed the same gap from the other side, with the panel's score rising from 4.0 to 4.8 to 5.3 while I judged the cuts worse. A structured audit of the loop found why. The critics only saw a short head of each shot, so length was the only thing they could notice, and the loop could only remove material, so the panel's own lowest score (payoff, at 3.0 out of 10) was out of reach. The audit is self-reported and the code before the fix isn't under version control, so that explanation rests on the review. Nobody has replayed it independently.
  • Found and fixed a 0.450 s container timestamp offset between the audio and video streams that was clipping the end off every cut. Transcript timestamps come from the decoded audio, which starts at the first sample, but ffmpeg seeks the container. In four of the five main cameras the audio stream starts 0.450 s after the video stream (the fifth, recorded separately, measures 0.000). So every cut taken from a transcript started and ended 450 ms early, and two sampled lines still had real speech in the clipped tail. The conversion from transcript time to container seek time now adds the offset, measured per file instead of assumed. Separately, on the main cameras the picture runs 300 to 620 ms behind the sound, and the delay differs by camera (the phone and other camera angles need no correction). Every automatic measurement failed (my own skew probe included), so each delay was picked by eye from face-framed test ladders. The render delays the picture, so the planned sound plays exactly as cut.
  • Delivery is 1920x1080 and every main camera records 3024x1964, so a native crop gives a 1.575x horizontal punch-in with no upscaling, a second framing out of a camera already owned. A per-pixel temporal-variance map is used as a person mask instead of as an energy target, because maximising the motion energy inside the frame centres on the hands at the desk and cuts off heads. The window hangs from the top of the mask with headroom, and an integral image reports how much of the clip's motion it actually contains (37 to 61 percent across the five people). Each punch-in is now reframed per shot on the person's box from a YOLO presence cache, with that window as the fallback. Most main cameras turned out to carry only 3024x1700 of real picture, so every wide shot had shown a black band at the bottom. Every shot is now framed inside the real picture.

Education

M.S. Computer Science · University of North Carolina at Charlotte

2022 – 2023

  • 4.0 GPA · Phi Kappa Phi Honor Society
  • Graduate Certificate in Applied Artificial Intelligence
  • Graduate coursework in machine learning, digital forensics, databases, and algorithms
  • Graduate research assistant in optimization and reinforcement learning

Capabilities

Linked entries (45 of 45) go to a project or paper that shows the skill in use.

See also

Contact

Reach out if you're hiring, want to collaborate, or just want to talk about ML, systems or product work. Open to contract & full-time · Remote (US).