Verification — P2.1.2 Score Computation

Task ID: fcce8362-60c1-492b-aef3-9546a4e63ce6 Branch: feature/p2-1-2-score-compute Step: 5 of 5 (audit ✓ → contract ✓ → packet ✓ → implement ✓ → verify) Date: 2026-05-12

Test evidence + acceptance-criteria checklist for the λ score-computation slice.

§1. Gates (CLAUDE.md §5)

All three Phase 0 gates pass in the worktree.

PS .worktrees/claude/p2-1-2-score-compute> npm run build
> colibri@0.0.1 build
> tsc

> colibri@0.0.1 postbuild
> node scripts/copy-migrations.mjs

copy-migrations: copied 7 migration(s) src/db/migrations -> dist/db/migrations
PS .worktrees/claude/p2-1-2-score-compute> npm run lint
> colibri@0.0.1 lint
> eslint src
PS .worktrees/claude/p2-1-2-score-compute> npm test
...
Test Suites: 50 passed, 50 total
Tests:       2466 passed, 2466 total
Snapshots:   0 total
Time:        44.617 s
Ran all test suites.

Test-count delta

Metric Value
Baseline at main @ 994db1e4 (post-P2.1.1) 2444 tests, 48 suites
Post-P2.1.2 2466 tests, 50 suites
Delta +22 tests, +2 suites
Regressions 0
Flakes 0 (full suite passed on first try)

The +2 suite count breaks down as:

  • src/__tests__/domains/reputation/compute.test.ts — 16 unit + 4 property = 20 tests
  • src/__tests__/domains/reputation/determinism.test.ts — 2 tests

20 + 2 = 22. Matches the delta exactly.

Coverage on new code

File                | % Stmts | % Branch | % Funcs | % Lines |
src/domains/reputation/compute.ts |  100  |   100   |   100  |   100  |

100% statement / branch / function / line coverage on compute.ts.

§2. Acceptance-criteria coverage (contract §6)

ID Criterion Evidence
AC-1 compute_score exported with locked signature src/domains/reputation/compute.ts:105–115 exports the function with (node_id, domain, events, ack_lookup, scar_lookup) → bigint shape. Type-checked by tsc. Imported by name in test file.
AC-2 ack_capped ≤ BPS_100_PERCENT before bps_mul U-3 (ack=50000n → result equals event.delta, not 5×), P-3 (1000 iter: per-event score ≤ |delta|). Code site: compute.ts:138–142.
AC-3 Arithmetic via integer-math.ts only compute.ts:52 imports only bps_mul; scanner test confirms zero forbidden patterns.
AC-4 Ceiling = BPS_100_PERCENT - scar; clamp scar to [0n, 10000n] U-5 (scar=2000n → ceiling=8000n), U-6 (scar=50000n clamped to 10000n → ceiling=0n), U-14 (scar=10000n exactly → ceiling=0n), U-15 (scar=-500n clamped to 0n → ceiling=10000n). Code: compute.ts:155–166.
AC-5 Floor = 0n; negative aggregate clamps U-11 (one negative-delta event → 0n). Code: compute.ts:151–153.
AC-6 Monotonicity under positive-only events P-1, 1000 iter, pinned seed 0x1f9bc0deafn. Each prefix score asserted previous.
AC-7 Determinism P-2, 1000 iter, pinned seed 0xfa1afe1n. Two-call equality on identical inputs.
AC-8 Ack-cap holds — no contribution exceeds \|delta\| magnitude P-3, 1000 iter, pinned seed 0xc0ffeebabe1n. Lookup returns up to 1_000_000n; per-event score ≤ BigInt(delta).
AC-9 No Math., Date., Math.random in src/domains/reputation/compute.ts src/__tests__/domains/reputation/determinism.test.ts corpus self-scan (mirrors κ P1.1.2 pattern manifest).
AC-10 Empty events → 0n U-1.
AC-11 Out-of-domain events skipped U-8 (passes 1× execution + 1× commissioning; only execution counted).
AC-12 Out-of-node events skipped U-9.
AC-13 Sort total + stable across shuffles U-10 (same delta sum from shuffled vs sorted input; includes same-epoch / id-tiebreak case).
AC-14 Return type is bigint U-12, P-4 (1000 iter typeof === 'bigint').

All 14 acceptance criteria met.

§3. Forbidden-op scanner — proof of extension

The κ P1.1.2 determinism scanner is now extended to src/domains/reputation/** via a parallel scoped test file (rather than modifying the κ scanner test in-place). This preserves κ test independence while satisfying the source prompt’s “extend globs” requirement.

Scanner test location:

src/__tests__/domains/reputation/determinism.test.ts

Pattern manifest mirrors κ contract r83-a-determinism-contract.md §4: Math.* · Date.* · new Date · timer · network · require(fs) · import fs · crypto.* · process.time · await · async fn · float literal.

Exclusion: schema.ts

src/domains/reputation/schema.ts (P2.1.1 shipped code) uses Math.max / Math.min on number for offset / limit clamping in selectHistory. The exclusion is documented in three places:

  1. Audit §5.7 (risk + mitigation)
  2. Contract §5.3 (test-contract clause)
  3. Scanner test file header (in-code comment)

This exclusion is symmetric with the κ scanner’s own self-exclusion of determinism.ts (the scanner can’t include its own pattern library). The exclusion list is a ReadonlySet<string> initialized with exactly one entry: 'schema.ts'. Any future file added under src/domains/reputation/ is scanned by default.

Belt + suspenders test

A second test (compute.ts is present in the reputation directory and gets scanned) explicitly pins both compute.ts and schema.ts as present. This guards against the scenario where someone renames compute.ts without updating the exclusion list — the first test would still pass with zero files scanned (modulo the expect(scannedFiles).toBeGreaterThanOrEqual(1) guard, but that fires only if every .ts ends up excluded). The second test makes the failure mode unambiguous.

§4. File inventory

Path Lines Type
src/domains/reputation/compute.ts 177 TypeScript
src/__tests__/domains/reputation/compute.test.ts 431 Jest
src/__tests__/domains/reputation/determinism.test.ts 133 Jest
docs/audits/p2-1-2-score-compute-audit.md 247 Doc
docs/contracts/p2-1-2-score-compute-contract.md 283 Doc
docs/packets/p2-1-2-score-compute-packet.md 312 Doc
docs/verification/p2-1-2-score-compute-verification.md (this file) Doc

No edits to:

  • src/server.ts, src/config.ts, or any existing TS module
  • src/domains/reputation/schema.ts (P2.1.1 surface frozen)
  • src/__tests__/domains/rules/determinism.test.ts (κ scanner unchanged)
  • package.json (zero new deps — hand-rolled LCG instead of fast-check)

Greenfield function add + scoped scanner test extension; no refactor.

§5. Commit chain

Step SHA (HEAD-relative) Subject
1 audit e020c555 audit(p2-1-2-score-compute): inventory surface
2 contract ad0ae11f contract(p2-1-2-score-compute): behavioral contract
3 packet a0f4c25f packet(p2-1-2-score-compute): execution plan
4 implement 94249ee6 feat(p2-1-2-score-compute): Σ-aggregation with ack-weight cap + monotonicity property test
5 verify (this commit) verify(p2-1-2-score-compute): test evidence

Branch is rooted at origin/main @ 994db1e4 (post-P2.1.1 PR #226).

§6. Risks tracked → resolution

Risk (audit §5) Status Resolution
bigint × number TypeError Resolved BigInt(event.delta) bridge applied at function boundary; covered by U-2 / U-4
schema.ts has Math.max/min Resolved Documented in-file exclusion in scanner test
event_id as acker key is convention Locked Compute uses event.event_id verbatim; P2.5.1 decides encoding
Sort stability Resolved Total comparator (epoch, id); V8 stable since Node 12; U-10 asserts
bps_mul overflow Non-issue Worst case 1000 × 10000 = 10_000_000n ≪ MAX_INT64
scar_bps > 10000 from lookup Resolved Defensive if (scar > BPS_100_PERCENT) scar = BPS_100_PERCENT; at compute.ts:163
Self-scan exclusion symmetry Resolved Mirrors κ pattern; documented in audit §5.7
No fast-check Non-issue Hand-rolled LCG with pinned seeds; reproducible across CI

§7. Phase 0 surface impact

  • MCP tool count: 14, unchanged (P2.1.2 is library-only).
  • Database schema: unchanged (no migration, no new table).
  • Public TypeScript surface adds compute_score, AckLookup, ScarLookup from src/domains/reputation/compute.ts. Consumers (P2.4.1 capability gates, P2.5.1 reputation_get) will import these in subsequent waves.
  • κ scanner contract: untouched. The parallel scoped scanner test in src/__tests__/domains/reputation/determinism.test.ts is the canonical extension to src/domains/reputation/** per AC-9.

§8. Phase 0 / Phase 2 posture

  • λ Reputation per docs/3-world/social/reputation.md §Phase 0 posture: “The reputations, experience_tokens, and penalty_events tables exist in the schema but are not populated.” This task does not change that — it ships the pure function that a future Phase 2 tool (P2.5.1) will call.
  • ADR-005 §Decision: no multi-model routing in Phase 0; P2.1.2 has zero interaction with the δ router surface.
  • ADR-006 graduation: λ stays colibri_code: none until P2.5.1 mounts an MCP-tool surface. P2.1.2 is a library-only graduation toward partial.

§9. Sign-off

All five steps of the executor chain complete. All three CLAUDE.md §5 gates green. Twenty-two new tests landed; zero regressions; zero flakes. 100% coverage on the new function. Ready for PR open.


Back to top

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

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