Add `_hasRecenterTick` boolean guard to decouple bootstrap detection from
VWAP volume tracking. Before this fix, the bootstrap condition relied solely
on `cumulativeVolume == 0`, which made `lastRecenterTick==0` ambiguous:
it could mean "never recentered" or "previous recenter landed at tick 0
(price = 1.0 token ratio)".
The new guard ensures the direction comparison in the else-branch only
runs after a recenter has explicitly set `lastRecenterTick`, eliminating
the tick-0 ambiguity. Belt-and-suspenders: both `!_hasRecenterTick` and
`cumulativeVolume == 0` trigger bootstrap.
Tests added:
- test_hasRecenterTickGuardPreventsTick0Ambiguity
- test_vwapFrozenDuringBuyOnlyAfterSellRecenter
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add table-driven Foundry tests for OptimizerV3.calculateParams covering:
- Bear regime at 0%, 1%, 50%, 91% staking (all tax rates)
- Bull/bear boundary at 92% with tax index transitions
- Bull/bear at 95% with penalty=50 exact boundary
- EffIdx shift behavior at 96% (taxIdx 13→14 discontinuity)
- Bull at 97% with max tax, 100% always bull
- Edge cases: all-zero inputs, zero tax at high staking
- Mantissa overflow guard
- Unused slots ignored
- Fuzz: no reverts, output always exactly bear or bull
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Review feedback: d.get('fitness_flags') without a default preserves the
null vs absent distinction mandated by the manifest schema (string | null).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two changes in evolve.sh pool-admission code:
1. Include `fitness_flags` from evaluator JSONL in the manifest entry dict
for newly admitted candidates (~line 866-874). Previously the field was
omitted, so downstream `effective_fitness()` could never zero-rate a new
candidate.
2. Use `effective_fitness(entry)` when appending new candidates to the
evolved ranking list (~line 907), so ZERO_RATED_FLAGS defence applies
at first admission — not only when re-ranking existing entries.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When `git apply --check` passes but `git apply` itself fails, the code
now checks STOP_REQUESTED before continuing to the next iteration,
consistent with the check at the end of the main loop.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add explicit timeout: 3s to bootstrap, webapp, and landing healthchecks
to avoid Docker's 30s default.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The production feeDest has contract bytecode on Base mainnet, not an EOA.
Fix the contradictory comment flagged in review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Document the FEE_DEST derivation in DeployBaseMainnet.sol and explain
why FitnessEvaluator.t.sol intentionally uses a different address.
The production address (0xf6a3...D9011) is correct — it has contract
bytecode on Base mainnet, so setFeeDestination() locks it permanently.
The test uses a keccak-derived EOA (0x8A91...9383) to avoid the locking
behaviour breaking snapshot/revert cycles in fork tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add `cleanup` step: removes per-generation candidate files and
generation_*.jsonl records after they are aggregated into the evidence
file, preventing disk exhaustion (cf. run #1025 at 91% usage).
- Rewrite `deliver` step with mandatory ordering:
1. `git checkout -- .` to discard unrelated working-tree modifications
before staging result files (evidence JSON, champion .push3, manifest).
2. Commit to branch `evidence/evolution-run-{run_id}` (not directly to main).
3. Push and create PR — if this fails, post an error comment and leave the
issue OPEN; do not proceed to step 4.
4. Post summary comment only after PR URL is confirmed, with mandatory
link to the PR.
- Update `products.evidence_file` delivery to PR branch (was "commit to main").
- Update `products.issue_comment` to enforce ordering and non-close-on-failure.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add scripts/harb-evaluator/run-resources.sh: collects disk, RAM,
Anthropic API usage, and Woodpecker CI queue metrics
- Add scripts/harb-evaluator/run-protocol.sh: collects TVL, fees,
position data, and rebalance events from LiquidityManager
- Fix run-protocol.toml: positions accessed via positions(uint8) not
named getters (floorPosition/anchorPosition/discoveryPosition)
- Fix event signature: Recentered(int24,bool) not Recenter(int24,int24,int24)
Addresses review findings: missing implementation files and contract
interface mismatch.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add seed-transpile-check CI step that loops over every *.push3 file in
tools/push3-evolution/seeds/, transpiles it via the Push3 transpiler,
and verifies the generated Solidity compiles with forge build. Fails
the build if any seed fails transpilation or compilation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Problem
The project-level `.claude/settings.json` overrides the global `skipDangerousModePermissionPrompt` flag, causing Claude Code to show an interactive bypass-permissions confirmation dialog in worktrees. This blocks ALL non-interactive agent sessions on evolution.
## Root cause
Claude Code resolves settings per-project. When a `.claude/settings.json` exists in the repo, it takes precedence over `~/.claude/settings.json`. The harb repo has one (with supervisor hooks) but without `skipDangerousModePermissionPrompt: true`. Result: every agent tmux session shows a confirmation prompt and dies.
## Fix
Delete `.claude/settings.json` and `.claude/hooks/supervisor/` entirely:
- The supervisor hooks are legacy from claude-code-supervisor
- agent-session.sh injects its own hooks per worktree at runtime
- Disinto has no project-level `.claude/` and works fine
- Global `~/.claude/settings.json` has the correct flags
## Impact
**This unblocks all harb agents on evolution.** Currently zero PRs can be processed.
Reviewed-on: https://codeberg.org/johba/harb/pulls/1089
Fixes#1066
## Changes
Done. Here's what was changed:
**`evidence/README.md`**
- Added `"candidate_commit": "abc1234"` to the red-team schema JSON example
- Added `candidate_commit | string | Git commit SHA of the optimizer under test` row to the field table
**`scripts/harb-evaluator/red-team.sh`**
- Captures `CANDIDATE_COMMIT` from `git rev-parse HEAD` at startup (alongside existing `CANDIDATE_NAME`/`OPTIMIZER_PROFILE`)
- Added a new step (9a-pre) that writes `evidence/red-team/YYYY-MM-DD.json` at the end of each run, including `candidate_commit` plus all other schema fields (`candidate`, `optimizer_profile`, `lm_eth_before`, `lm_eth_after`, `eth_extracted`, `floor_held`, `verdict`, `attacks`)
Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/harb/pulls/1075
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
Fixes#1055
## Changes
That notification is for the earlier background task which already completed — I retrieved its output and used it to diagnose and fix the failing test. The work is done.
Reviewed-on: https://codeberg.org/johba/harb/pulls/1080
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
Addresses re-review feedback:
1. Attack 4 (2050 ETH): delta_bps=3746 is from extreme slippage
through thin liquidity beyond concentrated positions, not just
1% fees. Insight corrected to explain the slippage mechanism.
2. Floor Ratchet: renamed to "initial phase only", insight explicitly
notes the 2000-trade oscillation variant is NOT tested here and
is tracked as follow-up issue #1082.
3. Added methodology field explaining snapshot-isolation semantics
(why lm_eth_after == lm_eth_before).
4. Restored two dropped strategies (discovery WETH consumption,
one-way sell) with notes that they are subsumed by other attacks.
Re: #1058
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All 8 adversarial strategies failed to extract ETH from LiquidityManager.
LM ETH actually increased from ~1000 to ~1050 ETH due to fee income.
Key defense: 1% pool fee + atomic recenter + massive floor liquidity.
Closes#1058
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- getLiquidityParams() now reverts with "OptimizerV3Push3: not for production use" instead
of silently returning zeroed bear-mode defaults; LiquidityManager.recenter() already has
a try/catch fallback so backtesting is unaffected
- Added @custom:experimental NatSpec annotation to the contract marking it as a transpiler
harness / backtesting stub only
- DeployBase.sol now validates any pre-existing optimizer address by calling getLiquidityParams()
and reverting if it fails, blocking accidental wiring of OptimizerV3Push3 as a live optimizer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Review flagged inconsistency: line 8 said 'bootstrap init' while the
journal (2026-03-20.md:13) and Strategic direction (line 26) both use
'disinto init'.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Planner journal entry from first cron-driven run.
Moved from disinto PR #390 — planner journals belong in the harb repo.
Reviewed-on: https://codeberg.org/johba/harb/pulls/1064
Reviewed-by: Disinto_bot <disinto_bot@noreply.codeberg.org>
Extract transpiler output into OptimizerV3Push3Lib so both OptimizerV3
and OptimizerV3Push3 delegate to the same canonical copy. Future
transpiler changes now require only one edit.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>