R81.A verification — P1.1.1 Basis Point Arithmetic

Scope recap

First Phase 1 κ Rule Engine code: greenfield src/domains/rules/integer-math.ts — bigint-based basis-point arithmetic primitives that every downstream κ built-in (P1.1.2 determinism harness, P1.1.3 constants/overflow, P1.3.2 built-ins) will delegate to. Authoritative spec: the pre-authored prompt at docs/guides/implementation/task-prompts/p1.1-kappa-rule-engine.md §P1.1.1 (lines 62–196) + docs/reference/extractions/kappa-rule-engine-extraction.md §3–4 + docs/3-world/physics/laws/rule-engine.md.

Deliverables

File LOC Purpose
src/domains/rules/integer-math.ts 183 bigint bps helpers + safe arithmetic + typed errors
src/__tests__/domains/rules/integer-math.test.ts 298 38 tests, full branch coverage

Public API (confirmed in impl)

// Basis-point arithmetic
bps_mul(value: bigint, bps: bigint): bigint       // (value * bps) / 10_000n, floor
bps_div(value: bigint, bps: bigint): bigint       // (value * 10_000n) / bps, throws on bps === 0n
apply_bps(value: bigint, bps: bigint): bigint     // value - bps_mul(value, bps)
decay(value: bigint, rate_bps: bigint, epochs: bigint): bigint   // compounded, per-step floor

// Safe arithmetic primitives
safe_mul(a: bigint, b: bigint): bigint            // throws OverflowError outside int64
safe_div(a: bigint, b: bigint): bigint            // throws DivisionByZeroError on b === 0n

// Typed errors
class OverflowError extends Error
class DivisionByZeroError extends Error
class UnderflowError extends Error

All signatures use bigint (not number) per contract §3 invariants I1 + I6.

Quality gates (run 2026-04-19 on commit 5c2ef4de against origin/main @ 77e579b8)

Gate Result
npm run build ✓ exit 0
npm run lint ✓ exit 0
npm test 1123 passed / 1123 total across 27 suites in 32.3 s (0 failures, 0 flakes)

Test delta: 1085 → 1123 (+38 tests from R81.A). No pre-existing test regressions. The documented startup — subprocess smoke flake did not fire in this run — the isolated new-domain coverage let it stay green.

Invariant checks (contract §3)

  • I1 Integer-only: no Math.*, no Date.*, no Number for quantities. Confirmed via explicit grep of src/domains/rules/integer-math.ts.
  • I2 No side effects: functions pure, no I/O, no globals.
  • I3 Synchronous: no Promise, no await.
  • I4 No RNG / no clock: no Math.random, no Date.now, no crypto.randomBytes.
  • I5 Floor rounding: bigint / truncates toward zero; equivalent to floor for non-negative bps inputs.
  • I6 int64 boundary: safe_mul throws OverflowError outside [INT64_MIN, INT64_MAX] range.
  • I7 Divide-by-zero: bps_div(x, 0n) and safe_div(x, 0n) throw DivisionByZeroError explicitly.
  • I8 Deterministic: same inputs → same outputs (property covered by P1.1.2 determinism harness, delegated to Wave 2).

Acceptance-criteria mapping (task-prompt §P1.1.1)

  • AC#1 All arithmetic uses 64-bit signed integers, no floating point
  • AC#2 bps_mul(value, bps)(value * bps) / 10000 (floor)
  • AC#3 bps_div(value, bps)(value * 10000) / bps (floor)
  • AC#4 apply_bps(value, bps)value - bps_mul(value, bps)
  • AC#5 decay(value, rate_bps, epochs) → multi-epoch compounded decay with per-step floor
  • AC#6 Overflow detection: safe_mul rejects inputs where product > 2^63 - 1
  • AC#7 Underflow: apply_bps never goes below 0 for non-negative inputs
  • AC#8 Division by zero: explicit typed error, not silent wrap

Branch + commit chain

  • Branch: feature/r81-a-p1-1-1-integer-math
  • Base: origin/main @ 77e579b8 (R77 pages-finish seal)
  • Chain:
    • audit: 1214a8e8 — inventory target surface
    • contract: b6973d05 — bigint bps helper contract
    • packet: 4946d43d — execution plan + test matrix
    • impl: 5c2ef4de — bigint bps arithmetic helpers + test suite (481 insertions, 2 files)
    • verify: this commit

Completion note

Impl + test files were authored by the dispatched T3 executor; Sigma finished the chain (git add + impl commit + this verification) after the agent hit its session quota at step 4. Work product is entirely the executor’s; only the commit ceremony was performed post-rate-limit.

Follow-ups / carry-forward

  • None from R81.A itself. Public API matches contract exactly.
  • Wave 2 unblocked: P1.1.2 (Determinism Verification Harness — wraps these helpers under fuzz + property tests), P1.1.3 (Branded Bps type + overflow-safe variants), P1.3.2 (when P1.3.1 lands, Built-ins delegate here).
  • Branded-type wrapper (Bps = bigint & {__brand: 'Bps'}) is intentionally NOT in this PR per contract §3 I6 + the task-prompt’s gotcha #3.

Back to top

Colibri — documentation-first MCP runtime. Apache 2.0 + Commons Clause.

This site uses Just the Docs, a documentation theme for Jekyll.