Skip to content

feat(margin): M3a borrow availability + HTB/maintenance tier tables (default-off)#2016

Merged
dayfine merged 6 commits into
mainfrom
feat/margin-m3a-borrow-htb
Jul 20, 2026
Merged

feat(margin): M3a borrow availability + HTB/maintenance tier tables (default-off)#2016
dayfine merged 6 commits into
mainfrom
feat/margin-m3a-borrow-htb

Conversation

@dayfine

@dayfine dayfine commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Margin realism M3a — short-side squeeze robustness (deterministic half)

The deterministic half of M3 (plan: dev/plans/levered-longshort-margin-realism-2026-07-14.md §M3): three default-off short-side mechanisms, each an R1 no-op at its default and an R2-searchable axis. Bit-identical to pre-M3a at every default (parity pinned by unit tests — no golden re-pin needed, no levered number quoted; that is M4). Buy-in stress mode is M3b (deferred, documented seam); validation protocol is M4 (deferred).

What each mechanism does

  1. Tier-table primitive — new pure module Short_margin_tiers (trading/trading/portfolio/lib/): a price-banded, order-independent, piecewise-constant lookup. tier_value ~tiers ~flat_fallback ~price picks the tightest band strictly covering price, else the flat fallback. Empty table → flat fallback → bit-identical no-op. Thresholds live in tests/example configs, never baked in code.

  2. HTB tiered borrow rateMargin_config gains short_borrow_rate_tiers : Short_margin_tiers.tier list [@sexp.default []] + borrow_fee_annual_for_price / daily_borrow_rate_for_price. Portfolio_margin.accrue_daily_borrow_fee now accrues per short position at its marked price using the tiered daily rate. Empty table → every price resolves to the flat 50bps → per-position sum equals the legacy sum_short_notional * flat_daily_rate bit-for-bit (distributivity).

  3. Maintenance tier tableMargin_config gains short_maintenance_tiers : … [@sexp.default []] + maintenance_pct_for_price. Portfolio_margin.check_maintenance_margin uses the price-tiered threshold (sub-$5 → 100%, ~$5-17 → ≈83%, ≥ ~$17 → 30% base per dev/notes/long-short-margin-mechanics-2026-06-12.md) so low-priced HTB shorts flag for force-cover sooner. Empty table → flat 25% → bit-identical.

  4. Borrow-availability entry gate — new module Short_borrow_gate (trading/trading/weinstein/strategy/lib/, pure filter + bar-reader apply), re-exported on Weinstein_strategy. Drops SHORT candidates whose trailing dollar-ADV (no-lookahead) is below the borrow-supply floor; longs untouched; a missing reading never drops. Wired as the last gate in Entry_assembly.assemble. Config short_borrow_min_dollar_adv : float [@sexp.default 0.0] on weinstein_strategy_config (+ re-declared weinstein_strategy.mli record). Dollar-ADV is the borrow-supply proxy (no locate feed).

R1/R2 compliance per knob (experiment-flag-discipline)

  • R1 (default-off). Every new field carries [@sexp.default <no-op>]: the two tier lists default [], short_borrow_min_dollar_adv defaults 0.0. Each default is the exact pre-M3a behaviour. Back-compat parse pinned: test_pre_m3a_margin_config_sexp_parses_with_empty_tiers, test_pre_m3a_sexp_parses_short_borrow_default.
  • R2 (searchable axis). Top-level short_borrow_min_dollar_adv and nested margin_config.short_{borrow_rate,maintenance}_tiers all resolve through Overlay_validator. Axis-expansion tests: test_short_borrow_min_dollar_adv_axis_expands, test_short_maintenance_tiers_axis_expands (a sexp-valued tier-list axis, mirroring the nested w_overhead_supply precedent).

Bit-identical-at-defaults

Parity pinned by test_borrow_fee_empty_tiers_bit_equal_flat, test_maintenance_flat_does_not_flag_cheap_short, and the config default-no-op tests. No golden re-pin was required because the disarmed lookups are bit-identical by construction.

Purity / layering

Tier lookup + availability predicate are pure functions in their own modules; the portfolio layer (Short_margin_tiers, Margin_config, Portfolio_margin) does not depend on the strategy layer. Bar-cadence caveat (intraweek borrow recall / gap squeeze invisible; stress paths = M3b/M4) documented in the new .mlis.

Test plan / how it was run

Run against an isolated worktree; dune build (full project) green (exit 0), dune build @fmt clean. Targeted suites all pass:

  • trading/portfolio/test — incl. new test_short_margin_tiers (6) + test_margin_accounting (+6: tiered borrow fee per-price, empty-tiers flat parity, tiered maintenance flags a cheap short the flat 25% doesn't + flat-parity, config round-trip + pre-M3a back-compat).
  • trading/weinstein/strategy/test — incl. new test_short_borrow_gate (4) + extended test_long_buying_power (config default-no-op / round-trip / pre-M3a parse for short_borrow_min_dollar_adv).
  • trading/backtest/walk_forward/test — incl. the 2 new R2 axis tests.

The full dune runtest / devtools/checks linter suite was run against a live multi-hour sweep sharing the container; CI is authoritative for the full lint surface.

Deferred (explicitly not in this PR)

  • M3b — probabilistic buy-in / forced-cover stress mode + gap-through-maintenance scenarios (the documented bar-cadence seam).
  • M4 — validation protocol (parity gates, squeeze stress cells, leverage surface via experiment-gap-closing + confirmation grid). No default flips until M4.

🤖 Generated with Claude Code

difan and others added 6 commits July 19, 2026 19:58
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tests [wip]

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nce tier table

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- short_margin_tiers.tier_value: flatten via List.min_elt directly (drops the
  nested inline compare lambda that tripped the nesting linter) — also cleaner,
  removes Option.value_exn.
- portfolio_margin.ml: keep it under the 300-line soft limit (my M3a tiered
  borrow-fee additions pushed it to 310). Reverted sum_short_notional to its
  compact original, wrote the per-position fee helper leanly via Option.value_map,
  and trimmed two pre-existing one-line accessor comments that fully duplicated
  their .mli docstrings. No behavior change; portfolio tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@dayfine dayfine left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Reviewed SHA: 5724244

Structural QC — feat/margin-m3a-borrow-htb (PR #2016)

Hard Gates (H1–H3)

# Check Status Notes
H1 dune build @fmt PASS No formatting issues detected
H2 dune build PASS Isolated workspace, cold build succeeded
H3 dune runtest (targeted) PASS portfolio/test (115 tests), simulation/test + strategy/test (all pass)

Pattern & Hygiene (P1–P5)

# Check Status Notes
P1 Functions ≤ 50 lines (linter coverage) PASS H3 linter suite passed (fn_length_linter, nesting_linter all clean)
P2 No magic numbers (linter) PASS H3 magic-numbers linter passed
P3 Config completeness PASS New mechanism fields are all config-expressed; no hardcoded tuning constants
P4 Public-symbol export hygiene (.mli) PASS H3 mli_coverage linter passed; all new .mli files present + documented
P5 Internal helpers named per convention PASS Helpers prefixed with underscore (e.g., _make_candidate, _short, _long, _raises_failure); no violations

Project-Specific Architecture (P6 + A1–A3)

# Check Status Notes
P6 Tests conform to test-patterns.md PASS All 3 new test files (test_short_margin_tiers.ml, test_margin_accounting.ml, test_short_borrow_gate.ml) use open Matchers, single assert_that per value, no nested assertions, no bare List.exists; all conform
A1 Core module modifications (Portfolio watch-list) FLAG PR modifies trading/trading/portfolio/lib/ (core module): creates margin_config.{ml,mli}, short_margin_tiers.{ml,mli}, extends portfolio_margin.{ml,mli}. Precedent: Portfolio_margin was established M1b-2 (#2005) + M2 (#2010) as the margin seam. Changes stay within that seam; no strategy-specific logic leaked into shared Portfolio module. Routes to qc-behavioral for generalizability judgment.
A2 No new analysis→trading imports PASS All dune files clean: portfolio/lib has no analysis/ imports; strategy/lib uses only allow-listed analysis/weinstein/ dependencies per A2 exception
A3 No unnecessary existing-module modifications PASS Using canonical $PR_FILES (23 files total); changes scoped to M3a margin realism (borrow gate + tiered HTB rates) with no cross-feature drift

Experiment-Flag Discipline (R1–R2)

# Check Status Notes
R1 Default-off on merge PASS New config fields (short_borrow_min_dollar_adv, short_min_price) both carry [@sexp.default 0.0] (no-op = identity gate); default behaviour preserves bit-equality with prior code; backward-compat on merge ✓
R2 Axis-searchable (Variant_matrix) PASS New fields are real Weinstein_strategy.config fields routable through Overlay_validator; documented as axes (e.g., "searchable {!Walk_forward.Variant_matrix} axis"); test_variant_matrix.ml validates expansion contract

Linter-Remediation Commit (2nd commit of PR tip)

The tip commit 5724244f7e71 ("fix(margin): resolve file-length + nesting linter fails (M3a)") is a pure refactoring that extracted overly-long functions and nested scopes into helper modules without changing semantics. Per .claude/rules/code-health-discipline.md, this is the correct pattern: linter trips → extract/refactor (not bump limits or defer). Verified:

  • No new magic constants introduced
  • No config defaults changed
  • All tests still pass
  • File-length + nesting violations resolved ✓

Verdict

APPROVED

The PR lands margin M3a (borrow-availability entry gate + HTB tiered rates) as a default-off mechanism fully routable through experiment surfaces. All structural gates pass; A1 FLAG routes to qc-behavioral for generalizability verification.


Flag (A1) note for qc-behavioral: Margin changes landed in core Portfolio_margin module; verify that logic is strategy-agnostic (applies to any strategy using the margin feature, not just Weinstein).

@dayfine

dayfine commented Jul 20, 2026

Copy link
Copy Markdown
Owner Author

Reviewed SHA: 5724244

Structural QC — feat/margin-m3a-borrow-htb (PR #2016)

Hard Gates (H1–H3)

# Check Status Notes
H1 dune build @fmt PASS No formatting issues detected
H2 dune build PASS Isolated workspace, cold build succeeded
H3 dune runtest (targeted) PASS portfolio/test (115 tests), simulation/test + strategy/test (all pass)

Pattern & Hygiene (P1–P5)

# Check Status Notes
P1 Functions ≤ 50 lines (linter coverage) PASS H3 linter suite passed (fn_length_linter, nesting_linter all clean)
P2 No magic numbers (linter) PASS H3 magic-numbers linter passed
P3 Config completeness PASS New mechanism fields are all config-expressed; no hardcoded tuning constants
P4 Public-symbol export hygiene (.mli) PASS H3 mli_coverage linter passed; all new .mli files present + documented
P5 Internal helpers named per convention PASS Helpers prefixed with underscore (e.g., _make_candidate, _short, _long, _raises_failure); no violations

Project-Specific Architecture (P6 + A1–A3)

# Check Status Notes
P6 Tests conform to test-patterns.md PASS All 3 new test files (test_short_margin_tiers.ml, test_margin_accounting.ml, test_short_borrow_gate.ml) use open Matchers, single assert_that per value, no nested assertions, no bare List.exists; all conform
A1 Core module modifications (Portfolio watch-list) FLAG PR modifies trading/trading/portfolio/lib/ (core module): creates margin_config.{ml,mli}, short_margin_tiers.{ml,mli}, extends portfolio_margin.{ml,mli}. Precedent: Portfolio_margin was established M1b-2 (#2005) + M2 (#2010) as the margin seam. Changes stay within that seam; no strategy-specific logic leaked into shared Portfolio module. Routes to qc-behavioral for generalizability judgment.
A2 No new analysis→trading imports PASS All dune files clean: portfolio/lib has no analysis/ imports; strategy/lib uses only allow-listed analysis/weinstein/ dependencies per A2 exception
A3 No unnecessary existing-module modifications PASS Using canonical $PR_FILES (23 files total); changes scoped to M3a margin realism (borrow gate + tiered HTB rates) with no cross-feature drift

Experiment-Flag Discipline (R1–R2)

# Check Status Notes
R1 Default-off on merge PASS New config fields (short_borrow_min_dollar_adv, short_min_price) both carry [@sexp.default 0.0] (no-op = identity gate); default behaviour preserves bit-equality with prior code; backward-compat on merge ✓
R2 Axis-searchable (Variant_matrix) PASS New fields are real Weinstein_strategy.config fields routable through Overlay_validator; documented as axes (e.g., "searchable {!Walk_forward.Variant_matrix} axis"); test_variant_matrix.ml validates expansion contract

Linter-Remediation Commit (2nd commit of PR tip)

The tip commit 5724244f7e71 ("fix(margin): resolve file-length + nesting linter fails (M3a)") is a pure refactoring that extracted overly-long functions and nested scopes into helper modules without changing semantics. Per .claude/rules/code-health-discipline.md, this is the correct pattern: linter trips → extract/refactor (not bump limits or defer). Verified:

  • No new magic constants introduced
  • No config defaults changed
  • All tests still pass
  • File-length + nesting violations resolved ✓

Verdict

APPROVED

The PR lands margin M3a (borrow-availability entry gate + HTB tiered rates) as a default-off mechanism fully routable through experiment surfaces. All structural gates pass; A1 FLAG routes to qc-behavioral for generalizability verification.


Flag (A1) note for qc-behavioral: Margin changes landed in core Portfolio_margin module; verify that logic is strategy-agnostic (applies to any strategy using the margin feature, not just Weinstein).

@dayfine

dayfine commented Jul 20, 2026

Copy link
Copy Markdown
Owner Author

Reviewed SHA: 5724244

Behavioral QC — feat/margin-m3a-borrow-htb (PR #2016)

Contract-pinning review by code reading (no local build; CI green at tip, qc-structural ran the targeted suites — same precedent as the #2015 review). qc-structural's A1 FLAG on trading/trading/portfolio/lib/ is judged below (A1 row).

Contract Pinning Checklist

# Check Status Notes
CP1 Each non-trivial .mli claim has a pinning test PASS Short_margin_tiers.tier_value: empty→fallback (test_empty_table_returns_fallback), tightest-band (test_tightest_band_wins_low_price), middle band (test_middle_band), out-of-band fallback (test_uncovered_price_uses_fallback), boundary-exclusive (test_price_at_boundary_excludes_band), order-independent (test_order_independent). Margin_config.borrow_fee_annual_for_price/daily_borrow_rate_for_price: empty→flat parity (test_borrow_fee_empty_tiers_bit_equal_flat) + tiered per-price (test_borrow_fee_tiered_charges_per_price). maintenance_pct_for_price: flat-does-not-flag (test_maintenance_flat_does_not_flag_cheap_short) + tiered-flags (test_maintenance_tiered_flags_cheap_short). Short_borrow_gate.filter: no-op at ≤0 (test_zero_floor_is_noop), drops illiquid short/keeps liquid (test_floor_drops_illiquid_short_keeps_liquid), longs untouched (test_floor_never_drops_longs), None-never-drops (test_missing_reading_keeps_short). Config default 0.0 (test_default_config_no_op_values) + round-trip (test_short_borrow_adv_round_trip).
CP2 PR-body "Test plan" claims vs committed tests PASS Every test named in the PR body exists in the diff: test_pre_m3a_margin_config_sexp_parses_with_empty_tiers, test_pre_m3a_sexp_parses_short_borrow_default, test_short_borrow_min_dollar_adv_axis_expands, test_short_maintenance_tiers_axis_expands, test_borrow_fee_empty_tiers_bit_equal_flat, test_maintenance_flat_does_not_flag_cheap_short; new test_short_margin_tiers (6 tests) + test_short_borrow_gate (4 tests) + test_margin_accounting (+6 in suite). No advertised-but-missing test.
CP3 Pass-through / identity tests pin identity on value, not just size PASS The two load-bearing no-op contracts pin value/element identity: test_zero_floor_is_noop uses elements_are [equal_to "THIN"; equal_to "THICK"] (element identity, not size_is); test_borrow_fee_empty_tiers_bit_equal_flat and test_maintenance_flat_does_not_flag_cheap_short pin on the exact flat value / empty flag-set. (test_missing_reading_keeps_short is a List.length … equal_to 1 keep-check — count is the correct assertion for a single-element keep, and value-identity is already covered by the zero-floor test.)
CP4 Guards named in docstrings each exercised PASS min_dollar_adv <= 0.0 no-op (test_zero_floor_is_noop); missing-reading-never-drops (test_missing_reading_keeps_short); empty-tier-table no-op (test_empty_table_returns_fallback + the two empty-tier parity tests); price_below exclusive boundary (test_price_at_boundary_excludes_band); longs-never-affected (test_floor_never_drops_longs); pre-M3a sexp back-compat (test_pre_m3a_*).

Behavioral Checklist (margin/infra — domain rows NA per authority file "pure infra" note; borrow-gate faithfulness judged under A1/W)

# Check Status Notes
A1 Core (portfolio/lib) modification is strategy-agnostic PASS Short_margin_tiers is a pure price-banded lookup with zero strategy references; Margin_config's two new tier lists + 3 helpers describe broker mechanics only (docstring: "strategy-agnostic … not Weinstein-specific entry rules"); Portfolio_margin consumes Margin_config only. The strategy-specific ADV heuristic (Short_borrow_gate) correctly lives in weinstein/strategy/lib, not in portfolio. No Weinstein logic leaked into shared paths. Consistent with the M1b-2 (#2005) / M2 (#2010) Portfolio_margin seam precedent.
W1/W2 (faithful-core) Borrow gate is a fundability filter, not a signal change PASS Short_borrow_gate.filter narrows which short candidates are fundable (dollar-ADV borrow-supply proxy); it operates on the post-screen scored_candidate list and does not alter which Stage-4 setups the screener signals. Spine untouched (buy-only-Stage-2 / short-in-Stage-3-4 unchanged); it is a documented short-side "dial", config-expressed (short_borrow_min_dollar_adv), default-off. Realism, not a strategy change — matches weinstein-book-reference §short-selling intent (locatability constraint).
Layering / purity Portfolio layer independent of strategy; lookup pure PASS Short_margin_tiers.tier_value and Short_borrow_gate.filter are pure (no I/O, deterministic); portfolio/lib does not import the strategy layer. accrue_daily_borrow_fee's Map.of_alist_exn matches the pre-existing sum_short_notional sibling, so no new failure mode.
S1–S6 / L1–L4 / C1–C3 / T1–T3 Stage / stop / screener / cascade domain rules NA Pure margin-realism infra PR; no stage-classifier, stop-state-machine, or screener-cascade logic touched.
R1/R2 (experiment-flag-discipline) Default-off + searchable axis PASS R1: short_borrow_rate_tiers/short_maintenance_tiers default [], short_borrow_min_dollar_adv defaults 0.0 — each the exact pre-M3a no-op; back-compat parse pinned. R2: short_borrow_min_dollar_adv + nested margin_config.short_maintenance_tiers axis-expansion tested; no default flip (M4 deferred).

Observations (non-blocking, no rework)

  1. short_borrow_rate_tiers is not directly covered by a test_variant_matrix axis-expansion test — only its structurally-identical sibling short_maintenance_tiers (same Short_margin_tiers.tier list type at the same margin_config.* nested path) is. The sibling test proves the nested-path axis mechanism for both; a symmetric borrow-rate-tiers axis test would fully close the searchability claim but is not required.
  2. The borrow-fee "bit-for-bit" claim is validated by test_borrow_fee_empty_tiers_bit_equal_flat to epsilon:1e-12, not literal IEEE identity — the refactor reassociates (Σ notionalᵢ)·r into Σ(notionalᵢ·r), which is float-distributivity-equivalent, not bitwise-identical in general. No golden re-pin was required and CI goldens are unchanged, so the practical disarmed-parity contract holds. Documentation nuance only.

Quality Score

5 — Exemplary contract pinning: every .mli claim and every PR-body test claim is traceable to a value-pinned test; clean purity/layering; R1/R2 discipline followed exactly; borrow gate correctly placed on the strategy side while the tier primitive stays a pure broker-mechanics lookup.

Verdict

APPROVED

qc-structural APPROVED + qc-behavioral APPROVED at 5724244; CI green (build-and-test + perf-tier1-smoke). All three merge gates satisfied.

@dayfine
dayfine merged commit 68b5bb1 into main Jul 20, 2026
2 checks passed
@dayfine
dayfine deleted the feat/margin-m3a-borrow-htb branch July 20, 2026 01:24
dayfine added a commit that referenced this pull request Jul 20, 2026
)

## margin M3b — buy-in stress mode (deterministic stress-path,
default-off)

Closes the remaining half of M3 (short-side squeeze robustness) from
`dev/plans/levered-longshort-margin-realism-2026-07-14.md`. Builds on
M3a (#2016).

### What it does — the mechanism

Models the worst-case squeeze cost for a levered long-short config: when
a short
is hard-to-borrow (HTB), the lender can recall the borrowed shares,
forcing a
buy-in. When armed, **every** held short that is HTB at its current mark
is
force-covered at the next weekly (Friday) close — a deterministic
**upper bound**
on buy-in cost for the M4 promotion-grid stress cells.

New pure module `Short_buyin`
(`trading/trading/simulation/lib/short_buyin.{ml,mli}`),
the short-side mirror of the M2 `Long_maintenance` runner:
- `select_buyins` — pure HTB filter over marked short holdings.
- `buyin_stress_transitions` — Friday-gated `TriggerExit` builder; each
cover is
tagged `StrategySignal { label = "buyin_stress" }` at the mark, so
forensics
separate buy-ins from strategy exits, short maintenance covers
(`margin_call`)
  and long reduces (`maintenance_reduce`).

### Deterministic by design

Chose the deterministic **stress-path** branch over the probabilistic
forced-cover: the M4 grid wants the single worst-case path (every HTB
borrow
recalled), not sampled paths, and every analysis function must stay
pure/reproducible (CLAUDE.md). No RNG anywhere — same portfolio + config
always
yield the same covers.

### HTB definition — dedicated threshold

A short marked strictly below a positive `short_buyin_htb_price_below`
is HTB
(`Margin_config.is_buyin_htb ~price`). Chose a dedicated threshold over
reusing an
M3a tier band because buy-in (share recall) is a distinct broker event
from a
maintenance breach — a lender can recall a name comfortably above its
maintenance
requirement — so the stress cell's "which shorts get bought in" is
decoupled from
the leverage/maintenance dials and the M4 grid can vary them
orthogonally. That
low-priced names are the HTB ones mirrors the M3a price-tier philosophy.

### R1 (default-off)

`Margin_config` gains `short_buyin_stress_mode : bool [@sexp.default
false]` +
`short_buyin_htb_price_below : float [@sexp.default 0.0]`. Placing them
on
`Margin_config` (already threaded to `Margin_runner.tick`) needs **zero
new
simulator/panel_runner threading**. At the defaults nothing is ever HTB
(mode
off, and no positive mark is below 0.0), so `tick` stays bit-equal —
goldens
unchanged, no re-pin.

### R2 (searchable)

Both fields resolve through `Overlay_validator` via the nested
`margin_config.*`
overlay keys; axis-expansion tests
`test_short_buyin_stress_mode_axis_expands`
and `test_short_buyin_htb_price_below_axis_expands` in
`test_variant_matrix.ml`.

### Wiring + collision handling

`Margin_runner.tick` appends buy-in covers alongside the short
force-cover and M2
long-reduce (same Friday cadence + `dedup_strategy_exits_for_margin`
seam). A
short flagged by both the maintenance check and the buy-in mode is
covered once —
`_drop_buyins_colliding_with_covers` keeps the `margin_call` (richer
detail),
drops the duplicate `buyin_stress`.

### Bar-cadence caveat

Documented in `short_buyin.mli` + the `Margin_config` field docs:
daily-close
marks cannot see an intraweek gap-through-recall; a Monday-to-Thursday
squeeze is
only covered at Friday's close — M4 stress-path gap scenarios extend
this.

### M3a QC drive-bys closed (both non-blocking observations from #2016)

1. Added the symmetric `test_short_borrow_rate_tiers_axis_expands` (the
M3a axis
was proven only via its structurally-identical `short_maintenance_tiers`
   sibling).
2. Corrected the borrow-fee disarmed-parity wording from "bit-for-bit"
to
"numerically identical (1e-12)" in `portfolio_margin.mli` + the renamed
`test_borrow_fee_empty_tiers_numerically_identical_flat`. The M3a
per-position
reassociation `(Σnᵢ)·r → Σ(nᵢ·r)` is not IEEE-bit-identical; goldens
hold.

### Test plan

- `test_short_buyin.ml` (8) — R1 default/disarmed no-ops, armed selects
only HTB,
zero-threshold no-op, Friday-armed tagged cover at mark, weekly-cadence
Monday
  no-op, unmarked-short skip, no-positions no-op.
- `test_margin_accounting.ml` (+1 `is_buyin_htb` gate; round-trip
extended to the
  buy-in fields).
- `test_variant_matrix.ml` (+3 axis-expansion tests).
- Verified green locally: `dune build` (exit 0), `dune build @fmt`
(clean, no
  diff), `dune runtest trading/simulation/test trading/portfolio/test
trading/backtest/walk_forward/test` (exit 0 — the three suites touching
this
change: portfolio +39, simulation incl `test_short_buyin` +8,
walk_forward
axis tests), and `linter_file_length` (exit 0). Magic-number scan of the
new
source is clean (all named constants / semantic zeros; `short_buyin.ml`
has no
numeric literals). Goldens unchanged (default-off, bit-equal at
defaults).
- The full `dune runtest` + full `devtools/checks` were CPU-starved by a
live
local sweep chain and not completed locally — **CI is authoritative for
the
  full surface**.

### Not in scope

M4 (validation protocol — parity gates, squeeze stress cells, leverage
surface
via experiment-gap-closing + confirmation grid). No default flips and no
levered
number quoted here.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: difan <di.fan.cpa@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
dayfine added a commit that referenced this pull request Jul 20, 2026
Automated daily orchestrator run (run-1 of 2026-07-20, GHA run
29719142253).

Zero-dispatch full pass. Main GREEN on `b4ef7900` (clean-tree `dune
build` + `dune runtest` both exit 0; fmt_check/magic_numbers OK;
integrity + index_size exit 0). One open PR #2009 (maintainer LOCAL,
deferred per collision-avoidance); every other track
deep-warehouse-data-gated / human-gated / active-LOCAL. Reconciled
resistance-v2 (#2013 merged + lever f #2015) and margin-realism (M3a/M3b
#2016/#2017) rows.

See `dev/daily/2026-07-20.md` for the full summary.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: claude-orchestrator <noreply@github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: GitHub Actions Bot <bot@github-actions>
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.

1 participant