{"_id":"@animakit/sprt","name":"@animakit/sprt","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@animakit/sprt","version":"0.1.0","description":"Sequential Probability Ratio Test (Wald 1947) — Bernoulli SPRT gating in <1ms, 0 deps. Extracted from 53 production sprints.","license":"MIT","author":{"name":"Justine Serna"},"repository":{"type":"git","url":"git+https://github.com/animakit-ai/anima.git","directory":"packages/sprt"},"keywords":["llm","agents","sprt","wald","sequential-testing","hypothesis-testing","statistics","gating","evolution"],"type":"module","main":"./dist/index.cjs","types":"./dist/index.d.ts","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"sideEffects":false,"engines":{"node":">=20"},"scripts":{"build":"tsup src/index.ts --format esm,cjs --dts --clean","test":"vitest run --coverage","typecheck":"tsc --noEmit","bench":"node --import tsx benchmarks/latency.ts"},"publishConfig":{"access":"public"},"gitHead":"c829594442fe6db4f75bf9d9e324a8463c1d05c7","_id":"@animakit/sprt@0.1.0","bugs":{"url":"https://github.com/animakit-ai/anima/issues"},"homepage":"https://github.com/animakit-ai/anima#readme","_nodeVersion":"24.14.0","_npmVersion":"11.11.1","dist":{"integrity":"sha512-1zraeaZh3lxily4FQwA9SLl8kwq+5+NqjNm3omwFiDOR+0UziFKfd7py02CDr5afsq2csFHX3I8r10NNAysiWw==","shasum":"6b2065215b2669c80e44b7f63b091deebf7d499c","tarball":"https://registry.npmjs.org/@animakit/sprt/-/sprt-0.1.0.tgz","fileCount":6,"unpackedSize":17281,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCARizdsgnC6gbAzqs4p9COa/teCluCSu35FMYgFeAV5QIgQBYjX8aG3OtXvnTOlwdKorNVXqVYvbHsxctrOS62y54="}]},"_npmUser":{"name":"andrrewcorp","email":"andrew.corpdesing@gmail.com"},"directories":{},"maintainers":[{"name":"andrrewcorp","email":"andrew.corpdesing@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sprt_0.1.0_1783306658424_0.04541545142262393"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-06T02:57:38.281Z","0.1.0":"2026-07-06T02:57:38.561Z","modified":"2026-07-06T02:57:38.912Z"},"maintainers":[{"name":"andrrewcorp","email":"andrew.corpdesing@gmail.com"}],"description":"Sequential Probability Ratio Test (Wald 1947) — Bernoulli SPRT gating in <1ms, 0 deps. Extracted from 53 production sprints.","homepage":"https://github.com/animakit-ai/anima#readme","keywords":["llm","agents","sprt","wald","sequential-testing","hypothesis-testing","statistics","gating","evolution"],"repository":{"type":"git","url":"git+https://github.com/animakit-ai/anima.git","directory":"packages/sprt"},"author":{"name":"Justine Serna"},"bugs":{"url":"https://github.com/animakit-ai/anima/issues"},"license":"MIT","readme":"# @animakit/sprt\n\n> **Sequential hypothesis testing in <1ms with zero dependencies — before you evolve your agent's config.**\n\nWald (1947) Bernoulli SPRT: accumulate log-likelihood ratio per boolean sample, stop at upper/lower boundaries. Pure functions, zero runtime deps, zero I/O. Extracted from the production agent of [ANIMA](https://github.com/animakit-ai/anima) — **53 sprints**, three verbatim copies of the same math (source + two test files that re-implemented it inline). This package is the single source of truth.\n\n```bash\nnpm install @animakit/sprt\n```\n\n```ts\nimport { createSprt, computeSprt, presets } from '@animakit/sprt';\n\n// Streaming accumulator (freezes after terminal decision)\nconst sprt = createSprt(presets.animaProduction);\nfor (const success of [true, true, false, true, /* … */]) {\n  const { llr, decision } = sprt.update(success);\n  if (decision === 'accept') break;  // production: 'apply'\n  if (decision === 'reject') break;  // production: 'reject'\n}\n\n// Batch mode (parity with AgentConfigEvolver's trace loop)\nconst state = computeSprt(\n  traces.map((t) => t.quality_proxy > 0.70),\n  presets.animaProduction,\n  previousLlr,\n);\n```\n\n## Why this exists\n\n`@animakit/neuromorphic-router` applies score multipliers from statistically approved adjustments. `@animakit/sprt-evolution` (future) will compute those adjustments from traces. Both need the **same** SPRT core and the **same** `KeywordWeightAdjustment` type. Extracting `@animakit/sprt` first (PACKAGE_INVENTORY order 0) unblocks both without coupling them.\n\n## Production preset — honest asymmetry\n\n`presets.animaProduction` uses the **exact** constants from `AgentConfigEvolver.evaluatePendingRecommendations()`:\n\n| Boundary | Value | Meaning |\n|---|---|---|\n| `upperLlr` | `log(19) ≈ +2.944` | Accept H1 — matches Wald α=β=0.05: `log((1-β)/α)` |\n| `lowerLlr` | `log(0.2) ≈ -1.609` | Reject H1 — **faster than symmetric Wald** |\n\nThe upper boundary is textbook Wald with α=β=0.05. The lower boundary is **not** the symmetric partner (`log(β/(1-α)) ≈ log(1/19) ≈ -2.944`). Production chose faster rejection — we preserve that exactly via explicit `lowerLlr`, not by silently re-deriving from α/β.\n\nFor new deployments, pass `alpha` + `beta` to get symmetric Wald boundaries:\n\n```ts\ncreateSprt({ p0: 0.5, p1: 0.62, alpha: 0.05, beta: 0.05 });\n// upperLlr ≈ +2.944, lowerLlr ≈ -2.944\n```\n\n## Decision mapping\n\n| Anima Core | `@animakit/sprt` |\n|---|---|\n| `apply` | `accept` |\n| `reject` | `reject` |\n| `gathering_data` | `continue` |\n\n## Shared type for router + evolver\n\n```ts\nimport type { KeywordWeightAdjustment } from '@animakit/sprt';\n\nconst adj: KeywordWeightAdjustment = {\n  agent: 'JEFE',\n  direction: 'boost',\n  delta: 0.05,\n};\n```\n\n## API\n\n```ts\ninterface SprtConfig {\n  p0: number;\n  p1: number;\n  upperLlr?: number;\n  lowerLlr?: number;\n  alpha?: number;\n  beta?: number;\n}\n\ntype SprtDecision = 'accept' | 'reject' | 'continue';\n\ninterface SprtState {\n  llr: number;\n  samples: number;\n  decision: SprtDecision;\n}\n\nfunction createSprt(config: SprtConfig): {\n  update(success: boolean): SprtState;\n  updateMany(successes: boolean[]): SprtState;\n  state(): SprtState;\n  reset(): void;\n};\n\nfunction computeSprt(\n  successes: boolean[],\n  config: SprtConfig,\n  startLlr?: number,\n): SprtState;\n\nconst presets: { animaProduction: SprtConfig };\n```\n\n**Accumulator vs batch:** `createSprt` freezes after the first terminal decision (streaming). `computeSprt` always processes the full array (batch parity with production's trace loop).\n\n## Latency\n\n100k iterations (Node 20+, consumer CPU):\n\n```\ncreateSprt().update(true)          p99 << 1ms\ncomputeSprt(20 samples)            p99 << 1ms\n```\n\nRun `pnpm bench` in the package directory.\n\n## Parity\n\nThe test suite reproduces every scenario from:\n- `Anima_core/tests/sprint48-sprt.test.ts` — LLR within 1e-12, identical decisions via `presets.animaProduction`\n- `Anima_core/tests/sprint48-router-multipliers.test.ts` — `KeywordWeightAdjustment` structural contract\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-9434efc0b161bb43fddb7077a6ddf5a9"}