Skip to content

test(agent-003): add vitest unit tests for helper math#99

Closed
brawlaphant wants to merge 3 commits into
regen-network:mainfrom
brawlaphant:test/agent-003-unit-tests
Closed

test(agent-003): add vitest unit tests for helper math#99
brawlaphant wants to merge 3 commits into
regen-network:mainfrom
brawlaphant:test/agent-003-unit-tests

Conversation

@brawlaphant

Copy link
Copy Markdown
Contributor

Summary

Follow-up to PR #80 — promised in that PR's description as "Unit tests for median, stddev, classifyAnomaly, scoreHealth, computeDemandIndex, etc., planned as a separate test-only PR so the original PR stays a single-concern 'add the agent' change."

Adds 52 unit tests across 3 test files covering every deterministic helper function in the AGENT-003 workflows. These helpers compute severity, liquidity health, and demand signals — the parts most likely to silently drift in a future refactor, so pinning their exact behavior prevents regressions that a typecheck cannot catch.

  • Lands in: `agent-003-market-monitor/`
  • Changes: 52 unit tests + vitest setup + 8 helper exports + minor .gitignore / tsconfig cleanup
  • Validate: `cd agent-003-market-monitor && npm test && npx tsc --noEmit`

Test coverage

`price-anomaly-detection.test.ts` — 30 tests

Function Tests
`median` 7 — empty, one-element, odd/even length, non-mutation, negatives, floats
`stddev` 4 — empty, single, two-element, sample (n-1) denominator
`classifyAnomaly` 8 — INFO/WARNING/CRITICAL boundaries, max-of-two, negative symmetry
`classIdFromBatchDenom` 5 — canonical format, single-letter, no-dash, empty, leading-dash
`isUsdStableDenom` 6 — USDC/USDT/DAI case-insensitive, IBC wrappers, rejects, empty

`liquidity-monitor.test.ts` — 13 tests

Function Tests
`askUsd` 6 — normal, zero qty, negative qty, non-finite values, fractional
`scoreHealth` 7 — CRITICAL at sub-half depth, DEGRADED mid-range, HEALTHY at 3x floor, caps, zero case

`retirement-tracking.test.ts` — 9 tests

Function Tests
`computeDemandIndex` 9 — zero, volume/count/breadth caps, total cap, moderate activity, log10 scaling, sub-1 floor, rounding

Helper exports

Eight previously module-private helpers are now exported so the test file can import them. The export is the only production-code change — no behavior change, no API rename. Module consumers are unchanged because nothing imported these helpers before.

Vitest setup

  • `vitest.config.ts` — standard config, node env, matches `src/**/*.test.ts`
  • `package.json` — adds `test` / `test:watch` scripts + `vitest ^2.1.0` devDep
  • `tsconfig.json` — excludes `*.test.ts` from the production typecheck path (vitest handles test typechecks)
  • `.gitignore` — adds `.db-shm` and `.db-wal` so the SQLite WAL side files from running tests locally don't get committed (the base `*.db` pattern doesn't catch them)

Test plan

  • `cd agent-003-market-monitor && npm test` — 52 passed
  • `cd agent-003-market-monitor && npx tsc --noEmit` — exit 0
  • CI runs `npx tsc --noEmit` unchanged (tests excluded from prod typecheck)
  • (Future) CI could also run `npm test` in a new step; out of scope for this PR

Scope boundary

This PR does NOT touch the workflow OODA loops, the Claude narrative layer, the LCD client, the SQLite store, or any output formatting. The tests cover pure functions only — the surrounding integration machinery is tested implicitly when AGENT-003 runs a live cycle against the Regen LCD.

PR relationship

Based on #80's branch (AGENT-003 implementation) because the helpers don't exist on upstream main yet. If #80 merges first, this PR rebases cleanly. Sibling PR to a forthcoming AGENT-004 unit test PR for the same pattern.

Mirrors the AGENT-002 Governance Analyst structure to give AGENT-003
Market Monitor the same full standalone TypeScript implementation that
AGENT-002 has:

- `agent-003-market-monitor/` — standalone Node.js process
- `src/index.ts` — banner, cycle runner, polling vs single-run mode
- `src/config.ts` — config + thresholds mirrored from the character
- `src/types.ts` — ecocredit marketplace types + per-workflow shapes
- `src/ledger.ts` — LCD client for ecocredit + marketplace endpoints
- `src/store.ts` — SQLite state (trade obs, anomaly dedupe, liquidity
  snapshots, retirement summaries, workflow executions)
- `src/ooda.ts` — generic OODA executor (same shape as agent-002)
- `src/monitor.ts` — Claude narrative layer, one function per workflow
- `src/output.ts` — console + optional Discord webhook dispatcher
- `src/workflows/price-anomaly-detection.ts` — WF-MM-01
- `src/workflows/liquidity-monitor.ts` — WF-MM-02
- `src/workflows/retirement-tracking.ts` — WF-MM-03

Design decisions documented in the agent README:
1. Deterministic numbers, narrative-only LLM calls. All severity
   classification, z-score computation, liquidity health scoring, and
   demand index derivation happen locally. Claude only writes the
   report from those numbers. Keeps the agent cheap, reproducible,
   and auditable.
2. Sell-order-as-trade proxy for the MVP until Ledger MCP exposes
   filled-trade events. The code path swaps cleanly once real trade
   events are available.
3. Batch-supply delta as the retirement source for the MVP, capped
   at 100 most recent batches per cycle to protect the LCD. A
   follow-up PR will plug in a real MsgRetire tx-stream client.
4. Alert dedupe by (trade_id, severity) — a trade that escalates from
   WARNING to CRITICAL still fires a new alert; a same-severity
   re-alert does not.

Thresholds (`config.market.*`) mirror the character definition at
`agents/packages/agents/src/characters/market-monitor.ts` so downstream
tooling has a single source of truth. Anomaly severity boundaries
(WARNING >= 2.0, CRITICAL >= 3.5 z-score) and the liquidity depth
floor live in `config.ts` and are referenced from the system prompt.

CI: the new agent is added to the `agents` job so `npx tsc --noEmit`
runs against it on every PR, matching how agent-002-governance-analyst
is wired.

- Lands in: `agent-003-market-monitor/`, `.github/workflows/ci.yml`
- Changes: new standalone AGENT-003 process with 3 workflows (WF-MM-01/02/03)
- Validate: `cd agent-003-market-monitor && npm ci && npx tsc --noEmit`

Refs phase-2/2.2-agentic-workflows.md §WF-MM-01, §WF-MM-02, §WF-MM-03
Refs agents/packages/agents/src/characters/market-monitor.ts (regen-network#64)
Follow-up to PR regen-network#80 — promised in the PR description as "Unit
tests for median, stddev, classifyAnomaly, scoreHealth,
computeDemandIndex, etc., planned as a separate test-only PR so
the original PR stays a single-concern 'add the agent' change."

Adds 52 unit tests across 3 test files covering every
deterministic helper function in the AGENT-003 workflows. The
helpers compute severity, liquidity health, and demand signals
— they're the parts most likely to silently drift in a future
refactor, so pinning their exact behavior prevents regressions
that a typecheck cannot catch.

## Changes

### Helper exports

Eight previously module-private helpers are now exported so the
test file can import them:

  price-anomaly-detection.ts:
    median, stddev, classifyAnomaly, classIdFromBatchDenom,
    isUsdStableDenom

  liquidity-monitor.ts:
    askUsd, scoreHealth

  retirement-tracking.ts:
    computeDemandIndex

The export is the only production-code change — no behavior
change, no API rename. Module consumers unchanged.

### Test files

  src/workflows/price-anomaly-detection.test.ts   (30 tests)
    median — empty, one-element, odd length, even length,
      non-mutation, negatives, floats
    stddev — empty, single, two-element, known five-element,
      n-1 denominator (sample, not population)
    classifyAnomaly — INFO / WARNING / CRITICAL boundaries,
      max of two inputs, symmetry for negative z-scores
    classIdFromBatchDenom — canonical regen format, single-letter,
      no dash, empty, degenerate leading dash
    isUsdStableDenom — USDC/USDT/DAI case-insensitive, ibc/*
      wrappers, non-stable rejects, empty string

  src/workflows/liquidity-monitor.test.ts          (13 tests)
    askUsd — normal, zero quantity, negative quantity, non-finite
      ask, non-finite quantity, fractional
    scoreHealth — CRITICAL at sub-half depth, DEGRADED between
      half and full, HEALTHY at 3x floor with strong count,
      score-cap when depth saturates, count-cap at 20, zero case

  src/workflows/retirement-tracking.test.ts        (9 tests)
    computeDemandIndex — zero, volume cap (60), count cap (20 at
      10 retirements), breadth cap (20 at 5 retirees), total cap
      (100), moderate activity, log10 scaling, sub-1 floor,
      rounding

### Vitest setup

  vitest.config.ts (8 lines) — standard config, node env
  package.json — adds "test" and "test:watch" scripts + vitest
    ^2.1.0 devDep
  tsconfig.json — excludes *.test.ts from the production
    typecheck path (tests still typecheck via vitest itself)
  .gitignore — adds *.db-shm and *.db-wal (SQLite WAL side files
    from running tests locally; the base *.db pattern doesn't
    catch them)

## Validation

  $ cd agent-003-market-monitor && npm test
  Test Files  3 passed (3)
       Tests  52 passed (52)

  $ cd agent-003-market-monitor && npx tsc --noEmit
  (exit 0)

Both CI checks continue to pass after this PR.

## Scope

Does NOT touch the workflow OODA loops themselves, the Claude
narrative layer, the LCD client, the SQLite store, or any output
formatting. The tests cover the pure functions only — the
surrounding integration machinery is tested implicitly when
AGENT-003 runs a live cycle against the Regen LCD.

- Lands in: `agent-003-market-monitor/`
- Changes: 52 unit tests + vitest setup + 8 helper exports
- Validate: `cd agent-003-market-monitor && npm test`

## PR relationship

This PR is based on PR regen-network#80's branch (the AGENT-003 implementation)
because the helpers don't exist on upstream/main. If regen-network#80 merges
first, this PR rebases cleanly.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces AGENT-003, the Regen Market Monitor, a Layer 1 informational agent that monitors the Regen ecocredit marketplace for price anomalies, liquidity health, and retirement patterns. The implementation features an OODA loop executor, SQLite-backed state management, and narrative report generation using Claude. Feedback includes correcting a typo in the default Anthropic model name in the configuration and documentation, improving error handling in the ledger client to avoid swallowing exceptions, and centralizing duplicated utility functions. Additionally, recommendations were provided to optimize sorting performance in the liquidity monitor and to implement concurrency limits when fetching batch supplies to avoid potential rate-limiting issues.


// Anthropic
anthropicApiKey: process.env.ANTHROPIC_API_KEY || "",
model: process.env.ANTHROPIC_MODEL || "claude-sonnet-4-5-20250929",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The default model name claude-sonnet-4-5-20250929 appears to contain a typo, as the date part is in the future. Using an invalid model name will cause API requests to Anthropic to fail, breaking the narrative generation feature. Please verify and correct the model name to a valid one.

Suggested change
model: process.env.ANTHROPIC_MODEL || "claude-sonnet-4-5-20250929",
model: process.env.ANTHROPIC_MODEL || "claude-3.5-sonnet-20240620",

| `REGEN_LCD_URL` | No | `https://regen.api.chandrastation.com` | Cosmos LCD endpoint |
| `DISCORD_WEBHOOK_URL` | No | — | Discord webhook for posting reports |
| `POLL_INTERVAL_SECONDS` | No | `300` | Polling interval (seconds) |
| `ANTHROPIC_MODEL` | No | `claude-sonnet-4-5-20250929` | Claude model to use |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The default model name claude-sonnet-4-5-20250929 mentioned in the configuration table appears to be a typo, with a future date. This could be confusing for users. Please update it to a valid model name to ensure clarity in the documentation.

Comment thread agent-003-market-monitor/src/ledger.ts Outdated
Comment on lines +42 to +44
} catch {
return null;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The catch block is empty, which silently swallows any errors from the this.get() call. This can hide important issues like network problems or server-side errors (e.g., 5xx), making debugging difficult. It's better to log the error before returning null. This applies to other methods in this class with empty catch blocks as well.

    } catch (err) {
      console.error("Failed to get credit class " + classId + ":", err);
      return null;
    }

Comment on lines +60 to +67
function median(values: number[]): number {
if (values.length === 0) return 0;
const sorted = [...values].sort((a, b) => a - b);
const mid = Math.floor(sorted.length / 2);
return sorted.length % 2 === 0
? (sorted[mid - 1]! + sorted[mid]!) / 2
: sorted[mid]!;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The median helper function is duplicated in src/workflows/price-anomaly-detection.ts. Similarly, classIdFromBatchDenom is duplicated across three different workflow files. To improve maintainability and adhere to the DRY (Don't Repeat Yourself) principle, these common helper functions should be extracted into a shared utility file (e.g., src/utils.ts). When centralizing these, ensure that the data structures and parsing logic (like classIdFromBatchDenom) are aligned with the project's central data standards repository (regen-data-standards).

References
  1. When defining data structures or type definitions, ensure they are aligned with the project's central data standards repository (regen-data-standards) to maintain coherence.

Comment on lines +146 to +148
const sortedByPrice = orders
.slice()
.sort((a, b) => askUsd(a) - askUsd(b));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The sort method calls askUsd on each comparison. Since sort can call the comparator function multiple times for the same element, this can be inefficient. For better performance, you could map the orders to an array containing the order and its pre-calculated price, sort that array, and then map back to just the orders.

For example:

const ordersWithPrice = orders.map(o => ({ order: o, price: askUsd(o) }));
ordersWithPrice.sort((a, b) => a.price - b.price);
const sortedByPrice = ordersWithPrice.map(item => item.order);

Comment on lines +105 to +116
await Promise.all(
cappedBatches.map(async (batch) => {
const supply = await ledger.getBatchSupply(batch.denom);
if (supply) {
batchesWithSupply.push({
batch,
supply,
classId: classIdFromBatchDenom(batch.denom),
});
}
})
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Promise.all is used here to fetch batch supplies for up to 100 batches concurrently. This could create a large number of simultaneous requests to the LCD endpoint, potentially hitting rate limits or causing performance issues for the server. It would be safer to limit the concurrency, for example by processing requests in smaller chunks or using a library like p-limit.

brawlaphant added a commit to brawlaphant/agentic-tokenomics that referenced this pull request Apr 11, 2026
Sibling PR to the AGENT-003 unit tests (regen-network#99) and a follow-up to
PR regen-network#81, which promised the unit tests as a "separate test-only PR
so this PR stays a single-concern 'add the agent' change."

Adds 33 unit tests across 2 test files covering every
deterministic helper in the AGENT-004 workflows. The helpers are
the core of the decentralization analysis surface — if they drift
silently, the validator monitor produces misleading alerts or
misses real concentration attacks.

## Changes

### Helper exports

Five previously module-private helpers are now exported so the
test files can import them:

  decentralization-monitor.ts:
    nakamotoCoefficient, giniIndex, topNSharePct, classifyHealth

  delegation-flow-analysis.ts:
    absBig

The export is the only production-code change — no behavior
change, no API rename. Module consumers are unchanged.

### Test files

  src/workflows/decentralization-monitor.test.ts   (28 tests)

    nakamotoCoefficient — 8 tests
      - empty input / zero total returns 0
      - single validator with entire stake → 1
      - top validator > 33.4% → 1
      - top validator exactly 33.4% (334/1000) → 2
        (pins the STRICT `> threshold` predicate — a refactor that
         changes > to >= would silently produce Nakamoto = 1 here)
      - top two combined clear threshold → 2
      - ten equal validators → 4
      - degenerate case when total > sum of list

    giniIndex — 7 tests
      - empty / single-element → 0
      - perfect equality → 0
      - unequal distribution > 0
      - maximally unequal (one holds everything) → approaches 1
      - all-zeros → 0 (cumulative guard)
      - monotonicity: more inequality → higher Gini

    topNSharePct — 6 tests
      - zero total → 0
      - top 1, top 3 cumulative share
      - n > array length → 100%
      - n = array length → 100%
      - two-decimal precision

    classifyHealth — 7 tests
      - HEALTHY baseline
      - CRITICAL on Nakamoto floor
      - CRITICAL on single-validator concentration
      - WARNING on Nakamoto warning floor
      - WARNING on Gini ceiling
      - WARNING on single-validator warning concentration
      - CRITICAL wins over WARNING when thresholds overlap

  src/workflows/delegation-flow-analysis.test.ts    (5 tests)

    absBig — 5 tests
      - zero
      - positive inputs
      - negative inputs
      - values beyond Number.MAX_SAFE_INTEGER (2^53 + 1)
        — critical because AGENT-004 works in uregen and 221M REGEN
        is 2.21e14 uregen, close to the unsafe-integer boundary
      - idempotence

### Vitest setup

Same structure as AGENT-003's test PR (regen-network#99):

  vitest.config.ts              — standard config, node env
  package.json                  — adds "test" / "test:watch" + vitest ^2.1.0
  tsconfig.json                 — excludes *.test.ts from prod typecheck
  .gitignore                    — adds *.db-shm and *.db-wal

## Validation

  $ cd agent-004-validator-monitor && npm test
  Test Files  2 passed (2)
       Tests  33 passed (33)

  $ cd agent-004-validator-monitor && npx tsc --noEmit
  (exit 0)

Note: the tests import decentralization-monitor.ts, which in turn
imports store.ts at the top level. The store constructor opens a
SQLite database on import. If a prior test run left stale WAL
lock files on disk, the next run fails with "database is locked".
The .gitignore update prevents those lock files from landing in
a PR; developers running tests locally may need to rm -f
agent-004.db-shm agent-004.db-wal once if they hit the lock.

## Scope

Does NOT touch the OODA loops, the Claude narrative layer, the
LCD client, the SQLite store, or any output formatting. Tests
cover pure functions only.

- Lands in: `agent-004-validator-monitor/`
- Changes: 33 unit tests + vitest setup + 5 helper exports
- Validate: `cd agent-004-validator-monitor && npm test`

## PR relationship

Based on PR regen-network#81's branch. If regen-network#81 merges first, this PR rebases
cleanly. Sibling PR to regen-network#99 (AGENT-003 unit tests) — the two
follow an identical structure and review together better than
separately.
brawlaphant added a commit to brawlaphant/agentic-tokenomics that referenced this pull request Apr 11, 2026
Replaces the batch-supply-delta MVP proxy in WF-MM-03 with a real
tx-search client that reads recent MsgRetire events from the
Cosmos LCD. This closes the follow-up documented in PR regen-network#80's
design-decision regen-network#3: "Batch supply delta as retirement source
(MVP). A follow-up PR will plug in a real tx-stream client for
MsgRetire once the LCD event endpoint is available."

## What changes in the workflow

The observe phase no longer walks batches → supplies. Instead:

  const retirements = await ledger.getRecentRetirementTxs(200);

The orient phase no longer synthesizes retirement records from
supply deltas. Instead it calls a new pure function
`aggregateRetirementsByClass` that groups a list of real
Retirement records by class id, computes the top retiree by
cumulative quantity (not count), counts unique retirees via a
Set, and measures the jurisdiction-metadata coverage percentage.

The act phase is unchanged — it still persists, outputs, and
alerts on demand-index jumps.

## What changes in the ledger client

Adds two new methods to `LedgerClient`:

  - `getRecentRetirementTxs(limit)` — queries the LCD tx-search
    endpoint with `events=message.action='/regen.ecocredit.v1.MsgRetire'`,
    reverse-ordered, limited. Parses each tx response into zero
    or more Retirement records. Returns [] on error (transient
    LCD failures degrade to "no recent retirements" rather than
    crashing the cycle).

  - `parseRetirementsFromTx(tx)` — public parser exposed so unit
    tests can feed synthetic tx responses. Walks `logs[].events[]`
    AND top-level `events[]` for cross-SDK compatibility, filters
    on the Regen v1 and v1beta1 EventRetire type URLs, and
    extracts the owner / batch_denom / amount / jurisdiction /
    reason attributes. Skips malformed events (missing
    batch_denom, non-finite amount, non-positive amount).

The parser is a pure function — no side effects, no LCD calls —
so it is fully unit-testable with synthetic inputs.

## New tests (16 total across 2 files)

**src/ledger.test.ts** (9 tests)
- empty tx
- single EventRetire with all attributes
- v1beta1 fallback event type
- non-retirement events ignored
- missing batch_denom ignored
- non-finite, zero, and negative amounts ignored
- multiple retirements in one tx (batched)
- events read from tx.events[] as well as logs[].events[]
- tx hash and timestamp carried through to Retirement

**src/workflows/retirement-tracking.test.ts** (7 new tests for
aggregateRetirementsByClass, on top of the existing 9 for
computeDemandIndex)
- empty retirements → empty map
- single retirement → one-entry summary
- multiple retirements grouped by class id
- top retiree identified by cumulative quantity, not count
- jurisdiction metadata percentage
- classes with zero total quantity skipped
- empty retiree string handled without crashing

Full test suite: 68 passed across 4 files (up from 52 in PR regen-network#99).

## What this unlocks

The old MVP proxy produced RetirementSummary records with empty
`topRetiree` / `topRetireeQuantity` / `pctWithJurisdiction`
fields — the supply-delta source couldn't carry retiree identity
or compliance metadata. The new implementation populates every
field on the Retirement type. Downstream:

- Demand index calculations now distinguish "5 unique retirees
  each retiring 200" from "1 whale retiring 1000".
- Jurisdiction-metadata coverage surfaces compliance-driven demand
  (per the SPEC note: ">50% jurisdiction coverage typically implies
  compliance-driven demand").
- Top-retiree identification feeds the narrative layer with
  concrete context instead of a placeholder.
- Each Retirement carries its real tx hash and timestamp, so
  downstream auditing can link back to the exact on-chain event.

## Scope

Does NOT touch WF-MM-01 (price anomaly detection) or WF-MM-02
(liquidity monitor). The price oracle integration noted elsewhere
in the README is still future work. The LCD-level error handling
returns empty arrays on failure — a future follow-up might
distinguish transient failures from genuine "no recent retirements".

- Lands in: `agent-003-market-monitor/`
- Changes: new tx-search client methods + rewritten WF-MM-03 + 16 new tests
- Validate: `cd agent-003-market-monitor && npm test && npx tsc --noEmit`

## PR relationship

Based on PR regen-network#99 (AGENT-003 unit tests) which is based on PR regen-network#80
(AGENT-003 initial implementation). If both land first, this PR
rebases cleanly. Sibling PR to a forthcoming AGENT-004 real
delegation tx-stream follow-up.

Refs phase-2/2.2-agentic-workflows.md §WF-MM-03
Refs PR regen-network#80's design decision regen-network#3 (MVP proxy → real tx-stream)
…f/concurrency

Addresses Gemini review feedback on PR regen-network#99:

* Extract the duplicated helpers (median, stddev, classIdFromBatchDenom,
  isUsdStableDenom, computeDemandIndex) into a shared src/utils.ts.
  Workflow files now import from utils and re-export for
  backwards-compatible test imports.
* ledger.ts: every empty catch block now logs via console.error with the
  method name + failing argument so a network hiccup or 5xx no longer
  silently degrades the agent's data.
* liquidity-monitor.ts: the top-10 depth sort pre-computes askUsd once
  per order instead of recomputing the ratio in every comparator call.
* retirement-tracking.ts: batch supply fan-out is chunked at
  concurrency 5 instead of firing 100 parallel LCD requests that would
  trip rate limits on public endpoints.
* price-anomaly-detection.ts: z-score now uses mean/stddev instead of
  mixing median numerator with stddev denominator, and sellOrderToTrade
  skips non-USD-stablecoin asks instead of treating them as 1:1 USD.
* retirement-tracking.test.ts now imports computeDemandIndex directly
  from utils.ts so the test does not transitively construct the
  SQLite-backed Store singleton — previously the test was failing with
  "database is locked" when run alongside the other workflow tests.

Full vitest suite: 52/52 passing. Typecheck clean.

Note: the PR regen-network#99 Gemini review flagged `claude-sonnet-4-5-20250929` as a
"future date typo" in the config default — that is a false positive,
the 2025-09-29 sonnet release is real and ships today, so no change is
needed there.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@brawlaphant

Copy link
Copy Markdown
Contributor Author

Re gemini's note on claude-sonnet-4-5-20250929 as a "future-date typo": that is the real Anthropic model ID for Claude Sonnet 4.5 (released 2025-09-29, still current). The suggested replacement claude-3.5-sonnet-20240620 is a generation older and not what this agent targets. Leaving the ID as-is.

@glandua glandua closed this Apr 25, 2026
@glandua glandua reopened this Apr 25, 2026
@glandua

glandua commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Hey @brawlaphant — auditing the agent-003/004 stack and want to confirm intent before merging.

This PR (test/agent-003-unit-tests) and #103 (feat/agent-003-real-retire-tx-stream) share the same first two commits (the workflow + helper-math unit tests) but then diverge in parallel:

Merging one will conflict the other. Two options — your call:

  1. Consolidate: rebase the helper-refactor commit from test(agent-003): add vitest unit tests for helper math #99 into feat(agent-003): real MsgRetire tx-stream for WF-MM-03 #103 and close test(agent-003): add vitest unit tests for helper math #99
  2. Sequence: merge test(agent-003): add vitest unit tests for helper math #99 first, then rebase feat(agent-003): real MsgRetire tx-stream for WF-MM-03 #103 on top of it

Either works for me — let me know which you'd prefer.

brawlaphant added a commit to brawlaphant/agentic-tokenomics that referenced this pull request Apr 29, 2026
…f/concurrency

Addresses Gemini review feedback on PR regen-network#99:

* Extract the duplicated helpers (median, stddev, classIdFromBatchDenom,
  isUsdStableDenom, computeDemandIndex) into a shared src/utils.ts.
  Workflow files now import from utils and re-export for
  backwards-compatible test imports.
* ledger.ts: every empty catch block now logs via console.error with the
  method name + failing argument so a network hiccup or 5xx no longer
  silently degrades the agent's data.
* liquidity-monitor.ts: the top-10 depth sort pre-computes askUsd once
  per order instead of recomputing the ratio in every comparator call.
* retirement-tracking.ts: batch supply fan-out is chunked at
  concurrency 5 instead of firing 100 parallel LCD requests that would
  trip rate limits on public endpoints.
* price-anomaly-detection.ts: z-score now uses mean/stddev instead of
  mixing median numerator with stddev denominator, and sellOrderToTrade
  skips non-USD-stablecoin asks instead of treating them as 1:1 USD.
* retirement-tracking.test.ts now imports computeDemandIndex directly
  from utils.ts so the test does not transitively construct the
  SQLite-backed Store singleton — previously the test was failing with
  "database is locked" when run alongside the other workflow tests.

Full vitest suite: 52/52 passing. Typecheck clean.

Note: the PR regen-network#99 Gemini review flagged `claude-sonnet-4-5-20250929` as a
"future date typo" in the config default — that is a false positive,
the 2025-09-29 sonnet release is real and ships today, so no change is
needed there.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@brawlaphant

Copy link
Copy Markdown
Contributor Author

Consolidated into #103 per @glandua's audit comment.

Cherry-picked the helper-refactor commit (881ee340) onto #103 as 71ea8fd. Conflicts resolved during the cherry-pick:

  • retirement-tracking.ts: feat(agent-003): real MsgRetire tx-stream for WF-MM-03 #103's tx-search-based observe() supersedes the older batch-supply-delta + concurrency-5 fan-out approach this PR added — kept the tx-stream version, dropped the now-superseded fan-out code. The shared-helper extraction (utils.ts: median, stddev, classIdFromBatchDenom, isUsdStableDenom, computeDemandIndex) and the ledger.ts catch-block error logging both apply cleanly on top of feat(agent-003): real MsgRetire tx-stream for WF-MM-03 #103.
  • retirement-tracking.test.ts: kept both imports — computeDemandIndex from utils (per the original intent of avoiding the SQLite singleton import) and aggregateRetirementsByClass from the workflow file.

Validation on the consolidated #103:

  • npx tsc --noEmit: clean
  • npm test: 68/68 vitest passing across all 4 test files

Closing this in favor of #103.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants