Skip to content

Enforce strict count parity and fix Pine semantics gaps - #60

Merged
luisleo526 merged 7 commits into
mainfrom
campaign/strict-parity-fixes
Jul 4, 2026
Merged

luisleo526 merged 7 commits into
mainfrom
campaign/strict-parity-fixes

Conversation

@luisleo526

Copy link
Copy Markdown
Collaborator

Seven engine fixes from the TV-parity validation campaign:

  • 7427720 Enforce absolute count parity in corpus verifier — excellent now requires count_abs_delta == 0 (percentage count thresholds demoted to display/strong-tier only)
  • b3d2fac Fix equity sizing and POOC re-entry semantics
  • 2ba047e Fix first-valid Pine cross edges
  • c467113 Support Pine bar index offsets
  • a20ac1f Normalize TradingView GMT offsets for timezones
  • 56ab02f Materialize relative exit ticks after entry fills
  • 222eb7d Support unbiased stdev and variance

Gates at HEAD: ctest 78/78 passed; corpus sweep run_corpus.sh ran 252 ok=252 fail=0 (under the new strict verifier: excellent=228, strong=21, moderate=2, anomaly=1 — the stricter gate reclassifies, it does not regress runtime).

🤖 Generated with Claude Code

Bugs solved:
- Honor the Pine ta.stdev/ta.variance biased argument.
- Use sample denominator length - 1 for biased=false and preserve the default biased denominator.

Validation:
- cmake --build build -j4
- ctest --test-dir build -R test_ta_indicators_extras --output-on-failure
- scripts/verify_corpus.py --all --quiet
Store strategy.exit profit/loss tick offsets on pending exits and materialize their limit/stop prices from the live position entry price. This lets retained brackets attached to pending entries fill on the same bar as the entry, matching TradingView TP/SL behavior without strategy-specific logic.
TradingView fixed-offset labels such as GMT+1 use the human-readable sign convention, while POSIX TZ uses the reverse sign. This caused session/time gates to fire in the wrong UTC window for strategies using explicit GMT/UTC offsets.\n\nAdd a shared timezone normalizer, route ScopedTimezone through it, expose it for generated code, and cover session and calendar bucket behavior.
Add a syminfo metadata bar_index_offset for validation feeds whose local OHLCV starts after TradingView's hidden chart-history origin.

Expose pine_bar_index() and pine_last_bar_index() helpers so codegen can shift Pine-visible indices while engine internals remain zero-based.
@luisleo526
luisleo526 merged commit ae4fe48 into main Jul 4, 2026
5 checks passed
@luisleo526
luisleo526 deleted the campaign/strict-parity-fixes branch July 4, 2026 16:11
luisleo526 added a commit that referenced this pull request Sep 27, 2026
…irst extreme gap-fills there as a forced fill (R5 integration INT27, round 2: the gate sweep's regressed probe)

INT27's gate sweep (exp-r5-int27-20260927, engine d3b753c + codegen
a4259656, against rebaseline exp-rebaseline2b-20260926 on engine d093560)
refused the merge on one script,
officialjackofalltrades-aureate-market-architecture-strategy-joat, on four
lanes: OANDA:XAUUSD 15m (count +1), OANDA:EURUSD 15m (+3), BINANCE:BTCUSDT
15m (+7) and the scraped BINANCE:ETHUSDT.P lane (+4), every one excellent on
the baseline. On XAUUSD the entry price moves from trade #60 on (3266.82 ->
3261.29).

Bisect (the probe's own feeds and the pinned Lab verifier on spark, one
library per pick boundary): 0631e04 (the INT27 merge fix) and c54f939
(PAR-ORDERS-3 findings 1-2) book the baseline trades (e8107dece428);
e5efd18 -- PAR-ORDERS-3 finding 4, bc5f7a21: after the matcher's fill at a
resting request's own level on a bar's first extreme, the recalculation's
orders act from that extreme -- books 477b4cca24af, as every later commit.

Mechanism, on the XAUUSD bar 2025-04-16 00:30 UTC (O 3261.715, H 3266.82,
L 3261.29, C 3263.885, low first), traced in a scratch copy of the adapter:
the strategy.exit limit leg carried from the previous bar (below the
price) fills at the open; its recalculation re-enters, filled at the open
too (the refill); that entry's recalculation re-places the exit, whose limit
3260.5585 is already through, so exit() arms it at the first extreme
(later_same_open: StopLimit{W1 3261.29, 3260.5585}), where the path
gap-fills it at 3261.29 -- TradingView's trade #59 exit. Its placement
carries no forced_execution_price, so begin_coof_recalc left
coof_fill_forced_ false, and finding 4's rule in coof_next_waypoint read the
fill as the matcher's at the limit's own level ON the extreme: the market
re-entry filled at W1, 3261.29. TradingView books it at the second extreme,
3266.82 (#60), as it books a market order after the control's forced fill
(pa3-f4-point-w1-mkt-*). Main advanced every such fill to the next waypoint,
which is why it matched.

Fix, in finding 4's own classification: begin_coof_recalc counts the fill
of an exit limit armed as a StopLimit whose stop satisfies its level (for a
long, stop >= limit: exit()'s endpoint_satisfies, read through the
placement's projection_position_side as closing_long was) AT that stop
(coof_fill_at_path_point) as forced. Such a fill is a gap fill onto the
point, not the matcher's at the limit's own level -- even with that level
exactly on the extreme, which TradingView answers the same way. A StopLimit
whose stop does not satisfy its level fills later at the level itself and
stays a level fill. No state is added; the flag is the recalculation's
transient.

Tapes (lab tv --no-note, NYSE:F 15, 2025-07-01 .. 07-08, ws-report-v1,
rangeProof covered; tests/fixtures/second_extreme_orders/int27-*): lot E's
exit limit X, placed at bar j-1's close beyond bar j's first extreme, fills
at bar j's open; X's recalculation re-enters E at the open; E's
recalculation places X2 at X's level, already through, which the path
gap-fills at the first extreme; X2's recalculation re-enters E. Long j = 28,
61 (low-first), short j = 13, 44 (high-first); the level beyond the extreme
(int27-open-xlimit-w1-reentry-*), exactly on it (-xlimit-at-w1-) and as the
limit leg of a bracket with a far stop, the probe's form (-xbracket-w1-).
TradingView books the re-entry at the second extreme on all six (long
11.90 / 11.58, short 11.66 / 11.67; tvTradesSha256 d713d16b long,
3fe435c0 short).

Rows: tests/test_second_extreme_order_tapes.cpp, six variants, 36 rows,
342 checks. Fail-before, against d3b753c: 12 fail -- rows 3 and 6 of every
int27 tape re-enter at the first extreme (long 11.84 / 11.55, short 11.68 /
11.72). After: 342 of 342 pass, every pa2 and pa3-f4 row unchanged.

The probe (spark, the lane templates' feeds and environment facts, the
Cloud Run runner's case environment), engine trade-set sha256:
  XAUUSD 15m   d093560 e8107dece428, d3b753c 477b4cca24af, fixed e8107dece428
  EURUSD 15m   d093560 c139231711f4, d3b753c 78c241198232, fixed c139231711f4
  BTCUSDT 15m  d093560 30a00613d41f, d3b753c 39e944861bc0, fixed 30a00613d41f
  ETHUSDT.P    d093560 163550bd8f95, d3b753c 0374608317dc, fixed 163550bd8f95
every fixed lane excellent 100.0 with count delta 0, the baseline sweep's
own trade sets (lab trades show).

Hash: the eleven v19 witness harvests on this tree are byte-identical to
INT27's (f-09dafee5); no pinned value moves, so there is no re-pin.
Docs: the design page names the boundary; the test and fixture README
describe the tapes. The +17 lines in pine_adapter.cpp move 121 of 1725
anchors, carried by the exact line map from d3b753c (0 stuck);
check_doc_anchors 1725 1725 0, stale-carried 0, doc lint clean.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
luisleo526 added a commit that referenced this pull request Sep 27, 2026
…fills at extremes, O(bars) drawing checkpoints, dynamic TA lengths, finer-than-feed security, zoned session speed (#291)

* Read a request.security finer than every supplied feed as na instead of stopping the run

TradingView reads a lower timeframe from that timeframe's own bars and keeps
the last 2,000,000 of them. On BINANCE:ETHUSDT.P 15m and 1D over
2025-04-01..2026-05-01, request.security(tickerid, "5S", close) is na up to
2026-01-04 22:45 UTC and "15S" up to 2025-05-18 03:15 UTC; the 1m series
(568,783 bars) is whole. A gaps_on read is na on the 27 chart bars that hold
no 5S bar. A chart bar holding no loaded bar of the requested timeframe reads
na (lab tv pf-krunerr-ltf-horizon, -ltf-values, -ltf-count2, 2026-09-26).

The campaign lanes' finest bars are 1m, so a "5S" or "15S" site has no loaded
bar anywhere, yet validate_security_timeframes refused it: "request.security:
requested timeframe '5S' is finer than input '1'". That stopped all 14 rows of
karmasantosh773-growwithcare-final-5s-master-strategy (baseline e69aa1f7).

Where the host already supplied bars finer than the chart -- the auxiliary
slice, or an input finer than the script timeframe -- such a site is now
marked no_loaded_bars and never fed, so it and its TA read na throughout. A
chart fed without intrabar bars (input_tf == script_tf) keeps the refusal,
unchanged: it asks the host for finer bars, and the verifier's split-feed
retry keys on it. This is Pine request.security semantics, so it lives in
the source adapter (ADR-0001 rule 1); the kernel is untouched.

The flag is folded into the source security hash only when set, so every
site that loads bars keeps the digest it had: no witness moves.

tests/test_security_finer_than_feed.cpp (release-only, floor 678 -> 679):
15m chart + 1m slice with "5S"/"15S"/"30S" beside a served "1" site, a 1D
chart, a 1m input aggregated to 15m, and the unchanged refusal of "5S" and
"5" on a chart fed alone. At 0d76a099 the first three stop with the
population's own error (9/22 checks). test_pine_security_state_hash carries
the new field's mutation row. Doc anchors into the header and ci_verify.py
move with the inserted lines.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
(cherry picked from commit d82fb6f04b07e6922fd406abc4968d7dd1fb5788)

INT27 pick note: every source, header and test hunk applied unchanged. The
docs conflicts were citation digits only (the lane's header and ci_verify.py
insertions against INT26's re-anchored pages), merged token by token; INT27's
single re-anchor pass sets every digit on the integrated tree. The release
floor is INT26's 703 plus this row, 704.

* Keep an after-close Muhurat session's own slice on the calendar split feed

The nifty-1d lane's chart feed -- TradingView's own NSE:NIFTY 1D bars --
holds Muhurat sessions held after the regular close: Monday 2022-10-24
18:15 IST and Sunday 2023-11-12 18:15 IST. prepare_aux_security_chart_ranges
keys a calendar bar by the session it covers (11febbc7, for OANDA's
break-stamped dailies), and such a bar covers the NEXT regular session, the
key of the native bar after it. The strictly-increasing key guard then
stopped every split-feed run on the lane: "native chart feed trading-period
identities must be unique and strictly increasing with an auxiliary security
feed". karmasantosh773-growwithcare-final-5s-master-strategy on nifty-1d
reached it once its "5S" sites stopped refusing.

The calendar route partitions the auxiliary bars by the native timestamps,
[chart_ts[i], chart_ts[i + 1]), which are strictly increasing (checked just
above), so the Muhurat bar and the next regular bar keep their own slices.
The guard now refuses only a calendar key that runs backwards; intraday keys
are the routing labels themselves and stay strictly increasing. Only runs
that stopped here change.

tests/test_security_finer_than_feed.cpp gains the scenario: Friday, the
Sunday Muhurat and Monday as three native bars with two 1m bars each read
12 / 22 / 32 from a "1" site, and a "5S" site stays na. Before this commit
it stops with the duplicate-identity error (27/30 checks). Doc anchors into
pine_aux_security.cpp move with the inserted lines.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
(cherry picked from commit 281186653c29b74a55137449c41685e17e2aad44)

INT27 pick note: the source and test hunks applied unchanged; the one docs
conflict was citation digits only, merged token by token (INT27's single
re-anchor pass sets every digit on the integrated tree).

* Kernel: session-day facts on a certified cycle of an exchange zone resolve no calendar interval per bar (R5 lane PERF-ZONED)

PERF-KEDGE recovered KERNEL-EDGE's per-bar cost on UTC calendars only. On
every other zone present_session_day still resolved the bar's script interval
through the calendar memo at every bar, and read the label and both neighbours
through it: a New York 5-minute FeedTolerant run cost 1.73x the instructions of
1a0e7ea1 (+2,443 Ir a bar), a Tokyo 1-minute run 1.22x (+3,439).

native_calendar::cycle_certificate certifies the session day holding an
instant when the zone makes its cycle read from that day alone: UTC or a fixed
offset, or, under glibc or macOS, a TZif v2+ zone whose 64-bit table covers the
reach (22 days around the cycle, widened by the spacing) and whose transitions
there move the offset by at most 3 hours, between offsets within 14 hours of
UT, never backwards while keeping the daylight-saving flag, and at least 8 days
apart, each read back from libc (localtime on both sides, chained). Then every
civil time in reach resolves to the first instant the wall clock reaches it,
whatever was resolved before: one reading is found from any start; the two
readings of a fold that flips the flag are both found (glibc's mktime probes a
week at a time for the flag asked, and the spacing puts that probe on the
fold's own side; macOS's mktime keeps no state) and resolve_stamp keeps the
earlier; a gap resolves to the move itself inside the 14-hour search. So the
cycles tile, each instant's local date is within a day of its cycle's open
date, the memo's candidate lookup finds exactly that day, and no other day
holds its instants. The zone is asked first, around the instant, and a day is
resolved only where it holds: a refused certificate asks the calendar nothing.

On a certified cycle present_session_day reads an instant in one of the day's
spans in session on the day's ordinal, and an instant whose fixed bucket
(fixed_bucket_ms, the calendar's own unit) meets no span out of session,
resolving nothing. A bucket that reaches a span from outside one, every
instant a certificate refuses, the walk and the scheduled close make the calls
they always made. Measured on spark (instructions:u, A725 core 12):

- zoned configs, 3000 bars idle, main 1a0e7ea1 / f1f3febd / this commit:
  NY 5m tolerant 1.7294x -> 1.0000x, NY 1m tolerant 1.7648x -> 0.9993x,
  Tokyo 1m tolerant 1.2201x -> 1.0003x; every canonical and tolerant config
  of NY, Tokyo, Chicago, London, Kolkata and UTC at most 1.0008x main;
- the 100 public slots against f1f3febd: median 0.9952 (magnifier on),
  0.9942 (off), no slot above 1.0; against main 1.0013 / 1.0001;
- the budget workload: +0.41% over main at f1f3febd, +0.32% here.

Identity (spark, f1f3febd against this commit, byte for byte): 100 slots x
magnifier off/on with trade digests, equity and broker_state_hash; the
132-configuration battery on 8 host variants with every hash column; the
KERNEL-EDGE probes and the AUDIT4 acid tests; PERF-KEDGE's facts battery (9,216
rows); a new 60-window zoned facts battery (45,600 rows: 2024 changes of New
York, Chicago, Denver, Los Angeles, St John's, Havana, Santiago, London,
Berlin, Dublin, Sydney, Lord Howe, Auckland, Chatham, Casablanca, Troll; Sao
Paulo 2018/19, Tehran 2021, Apia and Tongatapu at +14, Caracas, Pyongyang;
constant zones; and the refused folds and jumps of Tokyo 1887, Sitka and
Juneau 1867, Apia 2011, Kwajalein 1969, Moscow 2011/2014, Recife 2000, New
York 1883 and 2040, Amsterdam 1937, Manila 1844); the Pine witness replay.

- native_calendar.cpp / native_calendar_memo.hpp: cycle_certificate,
  fixed_bucket_ms, SessionDayMemo::libc_local_reads() (a derived cost
  reading), the TZif v2+ table reader, and tz_read_resource shared with the
  identity digest.
- native_execution_consumer: the certified-cycle cache (four entries, the
  last hit first), certified_point, certified_interval_meets_span; the
  PERF-KEDGE UTC member calendar_is_utc() is gone (a UTC calendar certifies
  every cycle).

ADR-0001 rule 2: a generic capability of the run's own calendar -- its zone
is data, the same for every venue -- with no spec field, switch or Pine
vocabulary, and no answer moves. The only platform condition picks the libcs
whose mktime the proof reads; elsewhere TZif zones take the exact path.
Nothing is hashed: the facts fold into no digest and the new members are
derived memos.

Witness, tests/test_native_session_day_zoned.cpp (kernel-only):
certificates at real transitions (New York, Chicago, London, Sydney, Lord
Howe 2024 certified where the host's table lists them; Tokyo, Kolkata, a
fixed offset, Apia at +14, Sitka's +14:58:47 and Moscow 2015 certified; Tokyo
1887, Sitka 1867, Apia 2011, Kwajalein 1969, Moscow 2014, Recife 2000, New
York 2040 and POSIX zones refused, a refused certificate reading nothing),
each certified cycle checked against the memo-free session_day_at; the same
tapes under each TZif zone and its POSIX twin (never certified) present
identical facts at every decision point over 8 windows, 7 sessions and 12
runs each, plus the magnifier, seconds and undetected paths (700 runs, 0
mismatches); and New York and Tokyo FeedTolerant batches resolve no interval
for their facts where their twins resolve one a bar. Fail-before at f1f3febd:
"no member named 'libc_local_reads' in
'pineforge::native_calendar::SessionDayMemo'". 17 of 19 mutants fail it; the
two that survive loosen guards no zone in the host's database reaches (the
14-hour offset bound, the libc chain check). The PERF-KEDGE witness's probe
reads the memo's UTC decision directly and its header records the change.

Floors: kernel 278 -> 279, release 679 -> 680, PR registration 660/660/669
-> 661/661/670 (ci_verify.py, its self-test pin and docs/ci.md). 24 doc
anchors carried through the exact line map from f1f3febd; the 6 that cite the
two rewritten floor lines set by hand (ci_verify.py:253, :365).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
(cherry picked from commit 27e1f384f1063c13efe3961ff58b8a0c6410c425)

INT27 pick note: the lane's base f1f3febd is PERF-KEDGE's tip, which INT26
carries as a3b4b971/debbd7f1. Every source, header and test hunk applied
unchanged against INT26's text (each file's patch is byte-identical to the
lane's), and no other caller of PERF-KEDGE's calendar_is_utc() is left on
the merged tree. The floors are INT26's plus K-RUNERR's plus this lane's row:
kernel 287 run (288 registered), release 705, PR registration 686/686/695
(ci_verify.py, its self-test pin and docs/ci.md). The docs conflicts were
citation digits, merged token by token (INT27's single re-anchor pass sets
every digit on the integrated tree), and the one floors paragraph, rewritten
with the merged counts.

* Pine v6 strategy() defaults: TradingView's tapes, replayed under the configuration the generated constructor declares

TradingView changed three Pine v6 strategy() defaults around
2026-09-24T20:45Z. For a v6 script that omits them it now uses
initial_capital = 100000, default_qty_type = strategy.percent_of_equity and
default_qty_value = 100 (100 whatever the type: 100 contracts under
strategy.fixed, 100 of the account currency under strategy.cash), where it
used 1000000 / strategy.fixed / 1. Pine v5 keeps the old three, and none of
the other strategy() defaults moved: lane TV-DEFAULTS exported 244 controlled
lab-tv tapes of synthetic probes (Pine v5 and v6; BINANCE:BTCUSDT, NYSE:F,
BINANCE:ETHUSDT.P and CME_MINI:ES1! 15; each parameter omitted, at its old
default and at a value that moves the tape).

The defaults are Pine policy -- what an omitted strategy() argument means, by
language version -- so the kernel does not learn them (ADR-0001 boundary
rules 1 and 2: a default capital or order size means nothing to a venue that
states its own account, and a kernel knob would be hash-visible surface for a
value every host already declares in its NativeRunSpec; engine.hpp's
initial_capital_ member default is overwritten from the spec at every run
begin). PineStrategyConfig's member defaults stay 1000000 / fixed / 1 -- Pine
v5's, and what every hand-built source host relies on -- and pineforge-codegen
(cg/tvdefaults d7e095f) declares the v6 values in the generated constructor
for a script that omits them.

test_tv_strategy_defaults replays seven of those tapes (BINANCE:ETHUSDT.P 15,
2025-04-01..05-01, byte-for-byte in tests/fixtures/tv_strategy_defaults)
through the Pine adapter over 521 corpus 15m bars (bars.inc), under the
configuration the generated constructor declares for each probe, and requires
every trade the tape closes inside them -- 6 of 42 or 8 of 58, two v6 margin
refusals among the six -- to be the engine's on TradingView's 0.01 tick and
0.0001 lot: an omitted capital (100% of 100000), an omitted type (1% of
equity), an omitted value (100 contracts; 100 USDT), all three omitted, and
two probes that declare every one, which run the same configuration either
way. Under the configuration the pre-lane constructor declared, the host's
defaults for the omitted arguments, each of the five omitted-argument probes
misses its tape. The row pins the engine side; codegen's
test_e2e_strategy_defaults pins the emission end to end on the same tapes and
fails on codegen a4259656.

Floors: the row is source-bound, so RELEASE_MIN_TESTS 678 -> 679 and the PR
registration floors debug/sanitizers/native 659/659/668 -> 660/660/669 (the
kernel floor stays 277); the floor notes are folded into the comment lines
already there, so no line the documentation anchors moves. No hash witness
moves and no engine source changes; the cheatsheet and configuration page
state the v6 defaults.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
(cherry picked from commit 4b457291ab1100c812384923e8de7eb442a6a3f8)

INT27 pick note: the engine half of lane TV-DEFAULTS only -- the row, its
seven tapes, the docs and the floors. The lane's second commit, 1320b01d
(the corpus gitlink f989e36 -> b73f8d6 and its baseline line), is not
picked: its six initial_capital pins wait for the next corpus regeneration,
and the corpus stays at b40aa8e. The test, fixture and docs hunks applied
unchanged; the floors are INT26's plus K-RUNERR's and PERF-ZONED's plus this
row: release 706, PR registration 687/687/696 (ci_verify.py, its self-test
pin and docs/ci.md); the kernel floor does not move.

* Kernel: a retained lower bar walks its own four turning points, and a bar that traded nothing at one price is one point (R5 lane MAG-INTRABAR)

- NativeExecutionConsumer::deliver_intrabar_script: a lower bar the direct
  four-sample path declines (a leg of zero length, an open at its own low) is
  walked through its four corners, the repeated one included, instead of the
  general ENDPOINTS sampler's uniform fill -- every sample is a margin check
  point since PAR-MARGIN, so the fill measured a price the bar never printed
  there; a bar with volume 0 and open = high = low = close is one discrete
  sample, walked once.
- ADR-0001: the rule-2 row (a mechanism correction, no knob).
- tests/test_native_intrabar_turning_points.cpp (kernel-only, new row): the
  open-at-its-low sub-bar's marks are 60 60 90 85 and the call armed at that
  open is booked at 60; a volume-0 one-price sub-bar gives one mark. Against
  3ea143e5's library 4 of its 21 checks fail (the uniform 77.5, no call, 12
  marks on bar 3); against the v18 closure the TU does not compile ("no member
  named 'IntrabarSample'").
- tests/test_magnifier_ordered_sampler.cpp: a lower sub-bar with a
  zero-length leg is expected at its corners.
- Floors: kernel 279 -> 280, release 681 -> 682 (the new row registers in
  both); docs/ci.md and the floor citations follow; published anchors
  re-anchored to the moved kernel lines.

No witness value moves; the 65 ctest rows that run a lower path or the
magnifier pass unchanged on this commit.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
(cherry picked from commit 4a89056ce2faba4605db1b79e97d7178640aecb4)

INT27 pick note: the lane's base 3ea143e5 is PAR-MARGIN-2's tip, which
INT26 carries under other shas. The kernel, test and CMake hunks applied
unchanged (each file's patch is byte-identical to the lane's). The ADR-0001
rule-2 row sits after PAR-MARGIN-2's margin_segment_origin row, above
H-DOCGATES' inventory rows, where INT26 put the other mechanism rows. The
floors are INT26's plus the earlier INT27 picks plus this row: kernel 288
run (289 registered), release 707, PR registration 688/688/697 (the lane
counted no PR registration floor; its kernel row registers in all three
excluded profiles). The other docs conflicts were citation digits, merged
token by token (INT27's single re-anchor pass sets every digit on the
integrated tree).

* Adapter: the bar magnifier walks TradingView's own intrabars -- its table's timeframe, each owned by the chart bar of its last minute (R5 lane MAG-INTRABAR)

TradingView's magnifier does not walk the host's 1-minute feed: its help-centre
table picks the intrabar per chart timeframe (1 -> 10S, 5 -> 30S, 10 -> 1,
15 -> 2, 30 -> 5, 60 -> 10, 240 -> 30, 1D -> 60, 3D -> 240, 1W -> 1D), each
intrabar is the symbol's regular bar anchored at the session day's open and
cut at its close, and it belongs to the chart bar that holds its LAST minute.

- source::tradingview_intrabar_timeframe / tradingview_magnifier_bars
  (include/pineforge/source/magnifier_intrabars.hpp, src/source/
  magnifier_intrabars.cpp): build that path from the input feed on its own
  grid -- the chart bar's open as a volume-0 print when its first intrabar
  straddles into it, each owned intrabar aggregated and stamped at its first
  input (a straddler one millisecond after the print), the chart bar's close
  as a print when its last minute belongs to the next bar's intrabar. The
  input comes back unchanged when the intrabar cannot be built from it (a 1-
  or 5-minute chart needs 10S / 30S bars) or a calendar interval is
  unresolved.
- PineExecutionAdapter::project hands that path to IntrabarPath::lower_tf.
- calc_on_order_fills on that path (72 of 72 TradingView cascades): the open
  point is the walked intrabar's own Open, re-admitted at every intrabar
  (PineStrategyHost::on_native_sub_bar -> PineScheduler::sub_bar_complete);
  next_input_waypoint looks the bar up on the lower path and returns the
  intrabar's open, first and second extreme, then the next intrabar's open
  (never its close; a print goes straight to the next open), with the
  adapter's own same-point rule (coof_fill_at_path_point) for a booked tick;
  a market entry or close whose next point is the next intrabar's open stays
  a plain market order (coof_waits_for_next_sub_bar), which the kernel fills
  there even at the price the recalculation stands at. broker_bar reads the
  walked intrabar.
- Tests: test_magnifier_tradingview_intrabars (the table, grids, sessions,
  ownership; 168 checks) and test_adapter_magnifier_intrabar_tapes
  (TradingView's request.security_lower_tf intrabars for 1m..1D on ETH,
  NSE:NIFTY and NYSE:F; three bracket tapes; the two refill tapes; 1160
  checks), new rows, fail-before "magnifier_intrabars.hpp file not found".
  The differential's intrabar rows now assert TradingView's rows on all 20
  magnified tapes (0130 no longer recorded). Re-pinned to TradingView's
  cascade: the calc_on_order_fills twin's adapter lots and
  test_adapter_coof_relower's refill trace -- 100 @900000, then the straddler
  100, 100, 99, 101 @900001, then 100.1 @960000 (were 100, 100, 99, 101,
  100.25 @900000, 100.1 @960000).
- Fixtures: tests/fixtures/magnifier_intrabars (13 lab tv exports of the
  lane's own scripts, bars_1m.inc, README); intrabar_margin README updated.
- Docs: magnifier page (the intrabars a Pine strategy walks), pine-to-native
  use_bar_magnifier row, native-engine margin passages, ADR-0001 (the
  adapter's path and refill points; the kernel row's writer), design rows
  CT9 and E4; anchors re-anchored.
- Floors: release 682 -> 684 (two source-bound rows).

No witness value moves (the release ctest's witness rows pass unchanged).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
(cherry picked from commit 9df16c24b6186b9adadaedfd2d467e76ecffe9e3)

INT27 pick note: the lane's base 3ea143e5 predates INT26's PAR-ORDERS and
PAR-ORDERS-2 picks, which rewrote the same recalculation code. Composed,
each lane's intent kept:
- PineExecutionAdapter::close keeps PAR-ORDERS-2's second-extreme rule on
  the chart path (coof_close_at_second_extreme) and gains this lane's
  next-intrabar rule on a lower path (coof_close_next_sub_bar); entry()
  merged cleanly the same way.
- test_adapter_coof_relower's refill lots and test_native_calc_timing_twin's
  adapter lots take this lane's prices (TradingView's cascade on the
  2-minute intrabars: 100, then 100, 100, 99, 101, then 100.1) at
  PAR-ORDERS' instants (every magnified fill dated at its chart bar's open,
  900000); both rows pass on the merged tree, and both lanes' sentences are
  kept.
- tests/CMakeLists.txt: git's clean merge closed H-MEASURE's fixture list
  twice and repeated its margin row; the list is closed once, with this
  lane's tape row inside it.
- Floors: release 709, PR registration 690/690/699 (the lane counted no PR
  registration floor; its three rows register in all three excluded
  profiles).
- Docs: the design rows CT9 and E4 keep INT26's re-anchored text and gain
  this lane's sentences; the ADR row of the kernel's lower-bar samples takes
  this lane's text above H-DOCGATES' rows; the rest were citation digits,
  merged token by token.
On this commit H-MEASURE's test_magnified_aggregated_tape, a row the lane's
base did not carry, fails: its v3 row 2 now books TradingView's fill (a move
toward the tape), and v2/v3 row 5 moves away from it -- the next commit
(INT27 merge) settles both.

* INT27 merge: a magnified recalculation's market order after the matcher's fill at an intrabar's second extreme fills there

R5 lane MAG-INTRABAR's base (PAR-MARGIN-2's tip) did not carry INT26's
PAR-ORDERS-2 picks or H-MEASURE's test_magnified_aggregated_tape, so the two
lanes' rules met first on this tree.

- PAR-ORDERS-2 (H-MEASURE Finding 6d): the matcher's fill of a resting
  request at its own level AT a bar's second extreme ends the leg there, and
  the recalculation's market order fills at that extreme; a fill the adapter
  forced there advances. It is written for the chart path
  (PineExecutionAdapter::coof_fill_at_second_extreme); on a lower path the
  magnified run met it only by accident: the old next_input_waypoint took an
  off-grid extreme's booked tick for a fill short of it and returned the
  extreme.
- MAG-INTRABAR: a magnified run walks TradingView's 2-minute intrabars, and
  after an intrabar's second extreme the next fill point is the next
  intrabar's open (mi-coof-refill*, 72 of 72 cascades, every one a market
  order's -- forced -- fill), with the same-point rule that no longer
  mistakes a booked tick for a fill short of its print.

Together, on hm-mag-diff-v2 and -v3 bar 19 (NYSE:F, 14:15 ET) PX's limit
fills at its own level on the high of the 14:26 intrabar (11.715, booked
11.72), its second extreme, and the ML entry its recalculation places went
to the 14:28 intrabar's open, 11.71; TradingView books 11.72 on both tapes.
PineScheduler::next_input_waypoint now returns the second extreme itself
for the matcher's own (unforced) fill there, so the market order fills at
it, and keeps the next intrabar's open for a forced fill: row 5 of both
magnified replays is TradingView's again, and every cascade, bracket and
margin tape of MAG-INTRABAR still passes (test_adapter_magnifier_intrabar_
tapes, test_adapter_coof_relower, test_native_calc_timing_twin, and the 95
magnifier / intrabar / lower-path / margin / calc_on_order_fills / POOC /
extreme-order rows all pass). No hash witness moves (the eleven witness
rows pass unchanged).

The same test's v3 row 2 (magnified), a recorded divergence (11.58 where
TradingView books 11.54), flipped to TradingView's with MAG-INTRABAR's
kernel commit alone: PX's limit fills on the leg to the high of a sub-bar
that opens at its own low (bar 6, the 11:01 ET minute), and the kernel now
walks such a bar through its four turning points instead of the sampler's
uniform fill, so the entry books that high, 11.54. It stays exact on the
2-minute intrabars. The row is no longer recorded, and the file's header
says why.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Adapter: an exit a recalculation places on a fill at a bar's extreme reads that fill -- a level fill leaves no leg in flight, a forced one is read from the extreme itself (R5 lane PAR-ORDERS-3, findings 1 and 2)

exit()'s calc_on_order_fills classification took the recalculating fill's
remaining leg from next_source_path_waypoint(point) alone:

- a fill AT the bar's first extreme -- the matcher's fill of a resting
  request at its own level there -- read the whole next leg as the in-flight
  remainder of its own (9f7a025c pine_adapter.cpp:9026-9048), so a priced
  exit born there was forced onto the second extreme (Limit{endpoint});
  TradingView books it at its own level on the leg to that extreme (lab tv
  pa2-i2-level-w1-{long,short}{,-pooc});
- a fill forced onto an OFF-grid first extreme books its tick (11.425 ->
  11.43, 11.645 -> 11.65), which next_source_path_waypoint read as a fill
  short of the low, so the exit was a plain limit and the next entry filled
  at the second extreme; TradingView starts the next leg at the extreme
  (lab tv pa2-i2-point-w2-long{,-pooc}).

The classification now reads the fill as 4985dcaa does for entries and
strategy.close: at_own_extreme (coof_fill_at_path_point on the phase's own
extreme) and coof_fill_forced_ tell a level fill, which ends its leg and
leaves no remainder in flight (fill_ends_leg), from a forced one, whose next
waypoint is read from the extreme itself.

Rows (tests/test_second_extreme_order_tapes.cpp; 25 of its 132 checks fail
on the base): every RECORDED boundary row flips to exact --
pa2-i2-level-w1-long rows 1-6 (both variants), -short rows 1, 2, 5, 6,
-short-pooc rows 1, 2 (still compared on its first cycle: finding 3), and
pa2-i2-point-w2-long rows 2, 3, 5, 6 (2, 3, 5 under
process_orders_on_close). The exit tapes' rows 5 and 7 / 1 stay RECORDED
(finding 4).

Hash: publication witness ConfigFlags103 moves (its X limit, placed by the
recalculation on a limit entry's level fill at bar 24's low 99.75, fills at
its level 100.75, not at the high 103.00); re-pinned once in the lane's hash
commit.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
(cherry picked from commit fe50e34118c7bb20a342198e3137a2193a968da6)

INT27 pick note: the adapter and test hunks applied unchanged (each file's
patch is byte-identical to the lane's); the docs conflicts were citation
digits, merged token by token (INT27's single re-anchor pass sets every digit
on the integrated tree). The lane's hash values (publication ConfigFlags103)
fold into the single INT27 v19 hash re-pin, not this commit.

* Adapter: after the matcher's fill at its own level on a bar's first extreme, the recalculation's orders act from that extreme (R5 lane PAR-ORDERS-3, finding 4)

coof_next_waypoint advanced every order a non-first-open recalculation
placed to the waypoint AFTER its fill's point (fe50e341
pine_adapter.cpp:5834), so after a fill AT a bar's first extreme a market
entry, strategy.close, close_all or a market strategy.order waited for the
second extreme or the next open, and an exit stop already through was held
to the leg's end or deferred to the next open. H-MEASURE Finding 6d and
4985dcaa had settled the second extreme; the first was predicted, not
taped. The lane exported the tapes that decide it (lab tv, NYSE:F 15m,
2025-07-01..08, 20 tapes, tests/fixtures/second_extreme_orders/pa3-f4-*):

- after the matcher's fill of a resting request at its own level ON the
  first extreme (a limit entry A there), TradingView fills a market entry B,
  strategy.close("A"), close_all and a market strategy.order AT that extreme
  (pa3-f4-level-w1-{mkt,close,closeall,order}-*), fills A's exit stop,
  already through, AT it (-xstop-*), and fills a stop entry B between the
  extremes at its own level on the leg to the second extreme (-bstop-*);
- the two shapes ab9714be's rows pinned hold the same: a STOP entry exactly
  on the extreme then the market add (pa3-f4-stop-w1-mkt-*), an EXIT limit
  exactly on it then the market re-entry, whose own exit limit, already
  through, fills where the path next re-crosses its level
  (pa3-f4-xlimit-w1-reentry{,-tp}-*);
- a fill forced onto the first extreme still starts the next leg: the
  control pa3-f4-point-w1-mkt-* fills B at the second extreme.

coof_next_waypoint returns the point itself for a matcher's (not forced)
fill at an extreme (pine_adapter.cpp:5841); exit() fills a stop already
through at the point the fill ended its leg on (pine_adapter.cpp:9118-9127),
never staged behind the recalculation or deferred as a wrong-side stop
(:9379, :9391). That leg is a stop AT the point, not a market leg: the
recalculation executes market newborns in place, which a cohort-bound leg
(close_entries_rule "any": Owner BindCohort, refused by current execution
since af7618d0) cannot take, and a market leg would then book the point's
price on a later bar (the xstop tapes replayed under "any": bar 5 @11.46
for TradingView's bar 4 @11.46; with the stop, exact).

The same reading moves the second-extreme exit tapes: a stop B's
recalculation places on the second extreme, reached on the leg to the close,
fills at its own level there instead of the close's tick.

Rows: tests/test_second_extreme_order_tapes.cpp 285 checks (54 fail on
fe50e341, 79 on the base): pa2-i2-exit-w2-long{,-pooc} rows 5, 7 and
-short{,-pooc} row 1 flip RECORDED -> exact; the 20 pa3-f4 tapes, 93 rows,
exact (48 of them fail on fe50e341).
Frozen rows moved with their notes, toward the tapes:
- test_calc_on_order_fills EndpointMarketAddProbe chart row, and its frozen
  twin test_calc_on_order_fills_l4c: the add's lot 90 (second extreme) ->
  105 (the first extreme the stop entry's fill ended its leg on;
  pa3-f4-stop-w1-mkt-*); tests/twin_parity_inventory.json pins it as an
  observable rewrite, INVENTORY_SHA256 264aef4a -> cb035ede;
- the L0 oracle tests/oracle/test_oracle_coof.cpp (twin
  test_native_oracle_coof_l2) and its copy test_coof_cascade_eligibility,
  row R1: the cascade re-entry 90 (W2) -> 101 (W1) and its tp exit bar 2 ->
  1 (pa3-f4-xlimit-w1-reentry{,-tp}-*); tests/oracle.sha256
  test_oracle_coof.cpp 647f8a24 -> e006f064, tree f39b54fe -> f25b1dd2.
CHECK counts unchanged (census 791).

Hash: quiet-bar CalcOnFills, Random10, Random20 (chart, both runs each),
publication ConfigFlags103 (X's stop, 99.75 at the point its entry's level
fill ended the leg on, fills there) and seven live-state digests move;
re-pinned once in the lane's hash commit.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
(cherry picked from commit bc5f7a212050f2dd97f03e6da201f7d8def9bc0e)

INT27 pick note: every adapter, test, oracle and fixture hunk applied
unchanged (each file's patch is byte-identical to the lane's). The twin
inventory merged cleanly with INT26's; its pin in check_twin_parity.py is the
merged file's own sha256 (b0066ba1, the lane's cb035ede being its own
inventory's), and check_twin_parity.py and check_oracle_sha256.py pass. The
docs conflicts were citation digits, merged token by token (INT27's single
re-anchor pass sets every digit on the integrated tree). The lane's hash and
behaviour pins (quiet-bar, publication, live-state) are harvested on the
integrated tree: its behaviour half lands after this lane's picks, its hash
values in the single INT27 v19 hash re-pin.

* Adapter: a process_orders_on_close limit entry fills at the close that placed it when the close's tick reaches it, with or without calc_on_order_fills (R5 lane PAR-ORDERS-3, finding 3)

The post-calculation close pass (fill_pooc_close_entries) tested a pure
limit entry placed by the bar's close calculation against the RAW close,
and skipped every limit under calc_on_order_fills (bc5f7a21
pine_adapter.cpp:16649-16671). TradingView reads the close's TICK, as the
pass already did for a stop, with or without calc_on_order_fills (lab tv
pa3-f3-pooc-limit-{long,short}{,-coof}, NYSE:F 15m, 2025-07-01..08,
tests/fixtures/pooc_limit_close): a sell limit at 11.76 over a raw 11.755
close (tick 11.76) and at 11.86 over 11.855 fill at that close; a buy limit
at 11.65 over a raw 11.655 close (tick 11.66) and at 11.74 over 11.745
rest, and so does every limit only the bar's range reached -- each fills on
the next bar's touch. PAR-ORDERS-2 recorded the short case on
pa2-i2-level-w1-short-pooc, cycle 2 (bar 31: TradingView fills A's sell
limit at the close its high already reached, the engine on bar 32).

pure_limit no longer excludes calc_on_order_fills, and at_close compares
the close's tick for a limit as for a stop (pine_adapter.cpp:16654-16675).

Rows: tests/test_pooc_limit_close_tapes.cpp (new, 28 checks; 4 fail on
bc5f7a21 and on the base: both short tapes' j = 22 and j = 31 entries a bar
late); tests/test_second_extreme_order_tapes.cpp compares
pa2-i2-level-w1-short-pooc whole again, rows 1-5 (was its first cycle, rows
1-2): 288 checks, 3 fail on bc5f7a21, 82 on the base.
Release floor 682 -> 683 (+1 test_pooc_limit_close_tapes, source-bound;
the ci_verify.py:359 citations in CONTRIBUTING.md and
docs/pages/contributing-llm.md follow the line).
No hash witness moves beyond the lane's earlier commits.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
(cherry picked from commit 1550a694e859e7606bee7fad6081fe54594a4307)

INT27 pick note: the adapter and test hunks applied unchanged (each file's
patch is byte-identical to the lane's). tests/CMakeLists.txt: git's clean
merge closed H-MEASURE's fixture list after MAG-INTRABAR's row and left this
lane's row outside it; the list is closed once, with both rows inside. The
floors are the earlier picks' plus this row: release 710, PR registration
691/691/700 (ci_verify.py, its self-test pin and docs/ci.md). The design
page's close-pass paragraph keeps both insertions -- this lane's limit
sentence, then INT26 round 2's re-entry bracket sentences; the other docs
conflicts were citation digits, merged token by token. The lane's b65cee22
(its hash re-pin) is not picked: its behaviour half follows, and its hash
values fold into the single INT27 v19 hash re-pin.

* PAR-ORDERS-3: the trades and transcripts its fixes move, pinned (INT27: the behaviour half of b65cee22)

R5 lane PAR-ORDERS-3's own re-pin, b65cee22 ("PAR-ORDERS-3 v19 hash
re-pin"), moves hash values and behaviour together. INT27 folds its hash
values into the single INT27 v19 hash re-pin, whose tool refuses any
non-hash change, so the behaviour it pins lands here, with the fixes that
move it.

Harvested on this tree with each TU's own switch (PINEFORGE_QUIET_BAR_HARVEST,
PINEFORGE_D2D_PUBLICATION_HARVEST, PINEFORGE_V19E_HARVEST and the other
eight), at the pick boundary before the lane (0631e045, which reproduces
every pinned value) and after each of its three commits, and compared field
by field with the pins before the picks, the lane's b65cee22 and its base
1550a694:
- fe50e341 (findings 1 and 2) moves publication ConfigFlags103's digest only;
  bc5f7a21 (finding 4) moves it again, and the quiet-bar and live-state rows
  below; 1550a694 (finding 3) moves nothing -- the lane's own attribution.
- test_adapter_quiet_bar: the trade digests of CalcOnFills/0/*, Random10/0/*
  and Random20/0/* (CalcOnFills keeps every trade and renumbers
  Trade::entry_incarnation), and the boundary counts Random10/0/* 69 -> 67
  and Random20/0/* 70 -> 69, equal to the lane's. The same runs the lane
  moved; INT26's picks had moved their trade digests too, so the digests are
  this tree's. The list sits in the pinned file.
- test_adapter_live_state_equivalence: 6 of 108 transcript digests (the
  transcript holds no hash value) -- reversals seeds 314187, 1780393 and
  3246599, brackets 314188 and 1780394, chains 314189, the lane's seeds;
  INT26's picks had moved each of them before, so the digests and counts are
  this tree's (reversals 314187: 168 -> 196 trades, 3246599: 147 -> 149;
  brackets 314188: 144 -> 134, 1780394: 95 -> 96; chains 314189: 62 -> 75).
  The lane's seventh, chains 1780395, a digest-only move on its tree, does
  not move here. The list sits in the data file.
- test_publication_witness: ConfigFlags103's digest only, a hash value;
  nothing lands here.
Until the INT27 v19 hash re-pin, test_adapter_quiet_bar and
test_publication_witness fail on those hash values only (15 values over the
6 quiet-bar runs, ConfigFlags103's digest); every other witness row passes.

(behaviour half of commit b65cee223f1839df0989da9fba24501788417c01)

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Drawing arenas: share records between checkpoint copies so a COOF run costs O(bars)

calc_on_order_fills checkpoints the generated script state at every script
bar (pine_scheduler_native.cpp: snapshot at the bar open, restore before the
close execution, commit after it, two restores per fill recalculation), and
the generated hooks copy each DrawingArena by value. A record is never
forgotten -- delete and max_*_count eviction only tombstone it -- so every
copy cost O(every drawing ever created) and a drawing COOF run was quadratic
in bars (job-2892: ~239 s CPU on NYSE:F 15, ~12,950 s on ETH 15).

DrawingArena's records now live in a store that is a vector until the arena
is copied, exactly as before, and nothing in a vector is ever shared. A copy
is built as blocks of 32 under a 32-way radix trie plus a tail block, and a
copy of a block store -- or a store assigned from one -- shares every block;
a write clones only the blocks and nodes on its path that another copy still
shares. Under the scheduler's sequence the first snapshot copies the vector
(O(records), once, at the first bar) and the restore assigns the copy back,
so from then on a checkpoint copy or restore is O(1) for records plus O(live)
for the order_ deque (at most max_*_count ids), and a script execution pays
for the blocks it writes. The generated by-value checkpoint needs no codegen
change. An arena that is never copied keeps the vector and inlines only the
vector paths; every block path is out of line.

Every observable -- ids, liveness, every field of live and dead records,
order() (the *.all and eviction order), every pf_* result and exception --
is unchanged. Getters read through a const path that never unshares.
Eviction tombstones a record before it leaves order_, so a refused
allocation in that write leaves the arena consistent; a moved-from arena is
empty and a self-move keeps the arena.

Rows:
- test_drawing_checkpoint: differential against the pre-lane vector arena
  (verbatim) over random create/delete/eviction/set_* and every pf_*
  getter/setter/copy, interleaved with snapshot/restore/commit and arbitrary
  copy graphs, past three trie levels, every checkpoint compared whole before
  it is dropped; the scheduler's sequence across a run reset; refused
  allocations, including partway through copying a block of labels; the cost
  pins (after the first bar an unchanged checkpoint copies no record and
  allocates the same for 10,000 and 40,000 records; synth-label-coof's churn
  copies <= 64 records per execution and the checkpoint steps' bytes stay
  per-step bounded, N -> 2N ratio <= 2.25). Under AddressSanitizer the random
  and cost rows run fewer steps (its fake stack made the row take 575 s).
- test_coof_drawing_checkpoint_cost: synth-label-coof through the Pine host
  with calc_on_order_fills and fills, 4,000 vs 8,000 bars, the same bounds on
  record copies and on what the checkpoint hooks allocate.
- test_coof_drawing_rollback_tape: TradingView's coof-drawing-rollback tape
  (CG-POPFIX, 41 trades) replayed through the Pine host: all 41 trades
  identical in times, prices, quantities and both comments (x2 == n).

Fail-before (the three rows against the old drawing.hpp): every cost pin
fails (30,000,000 record copies for an unchanged 10,000-record arena;
ratio 4.000), every exactness row passes.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
(cherry picked from commit 52f0395087ac6b8d9e83475ab1e664c71df058aa)

INT27 pick note (late pick, accepted 2026-09-26 22:47, placed after the last
scheduled pick and its behaviour half; the list names no place): drawing.hpp, the three rows
and the fixture applied unchanged. git's clean merge put this lane's
fixture-dir block inside TV-DEFAULTS' `if(TARGET test_tv_strategy_defaults)`
block, before its endif(); each block stands on its own. The lane's floors
and doc anchors (0d651058) are not picked: INT27's floors item recounts the
floors (this lane: kernel +1, release +3, each PR registration floor +3) and
INT27's single re-anchor pass sets the digits.

* Compute ta.* calls with a simple or series length as TradingView does

TradingView accepts a length that is neither a constant nor an input.
PineForge refused every such call at transpile time. This adds the Pine
runtime those calls lower onto, in the source layer
(include/pineforge/source/pine_ta_length.hpp, src/source/pine_ta_length.cpp):

- A simple length (fixed for the run: a syminfo preset, an input-string
  ternary) is answered exactly as the constant. FirstCallBound builds the
  fixed-length class from the call's first execution; simple_ta_length
  stops the run on 0, a negative length or na, with TradingView's text.
- A series length for ta.highest / ta.lowest / ta.highestbars /
  ta.lowestbars re-windows every call over the site's own bar history
  (skipped bars hold the last executed source), through a cached extremum
  whose growth, poison and late-first-execution rules fit 5,647 recorded
  TradingView calls of 35 synthetic call sites with no mismatch
  (SeriesHighest, SeriesLowest, SeriesHighestBars, SeriesLowestBars).
- ta.supertrend compiles a series factor but reads it once: PineSupertrend
  is the Pine reference with the first execution's factor, warm-up
  included (1,200/1,200 recorded bars).

TradingView refuses a series length for ta.rma / ema / rsi / atr / dmi /
macd / kc / hma / tsi / rci and supertrend's atrPeriod at compile time, so
those only ever see a simple length.

Three rows replay the lab tv tapes (test_ta_series_length_extremes,
test_ta_series_length_supertrend, test_ta_simple_length); the release floor
moves 678 -> 681. No kernel translation unit changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
(cherry picked from commit ea7021ac08529bbecc54f41364af2b23ebd142cd)

INT27 pick note (late pick, accepted 2026-09-26 23:20, placed after the late
pick K-DRAWSNAP): the source-layer runtime, the library's source list and
the three rows applied unchanged (each file's patch is byte-identical to the
lane's). Its floor hunk (release 678 -> 681 on its base) is not applied:
INT27's floors item recounts the floors with its three rows (release and the
three PR registration floors +3; the kernel floor does not move, its TUs
reach the source layer). The paired codegen commits land in the codegen
integration.

* INT27 (iii): the lower-lookup shape witness times user CPU, so the allocator's page faults no longer decide it

test_native_intrabar_lower_lookup bounds the cost of 16,000 script bars
(and a four times longer lower feed) by 6x that of 4,000 bars; a scan of the
whole feed per script bar reads 16-18. It timed process CPU (std::clock),
and on the lab's x86 cloud hosts it read 6.19-6.28 where NTU and spark read
about 5.9 -- and on this tree it fails on spark too.

The excess is not the code the row times. Split on spark (gcc 13, one
pinned X925 core, 4,000 / 16,000 bars x64, best of three):
- process time: 0.15 s / 0.98 s, ratio 6.12-6.61 (main d0935605: 0.10 s x32
  / 0.59-0.61 s, 5.71-5.88);
- of the large leg's 0.98 s, 0.38-0.41 s is SYSTEM time; the small leg's is
  0.00-0.004 s. The allocator maps the large leg's buffers afresh on every
  run -- a first-touch page fault per page -- where the small leg reuses
  its heap;
- user time: 3.88-4.00 on this tree, 3.91-3.95 on main.
R5 lane PERF-ZONED exposed it: its certified fixed-offset cycles (this spec
runs at UTC+5) took the per-bar calendar cost out of both legs, so the fixed
fault cost weighs more (6b601ef0, right after that pick: 6.50-6.63).

tests/ratio_timing.hpp gains ratio_timing::user_cpu_seconds() (getrusage
RUSAGE_SELF's ru_utime; std::clock where getrusage does not exist), the
lane CI-FLAKE helper file every ratio row shares, and this row samples it.
The legs, the calibration (100 ms of the same clock, the doubling of
tests/ratio_timing.hpp) and the x6 bound are unchanged.

The guarded property still fails on a real quadratic regression: with
deliver_intrabar_script's lower_bound replaced by the pre-K24 scan of the
whole feed (scratch copies only, never committed), the row reads
- 18.11 on spark under user time (18.19 under the old process time),
- 17.04 on the M4 Max,
and fails "ratio < kShapeBound" on both; unmutated it reads 3.88-4.00 on
spark and 3.88-4.36 on the M4 Max. The value half and every pin are
untouched.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* INT27 (iv): the effective-strategy report reads the configuration the generated constructor declares

The provenance's "strategy" block (scripts/run_strategy.py's
--fingerprint-json and docker/run_json.py's "fingerprint") is the seed of
strategy() defaults, then what the TU's constructor declares, then the
run's strategy_overrides. Its parser read only pre-R4-C member writes
(`initial_capital_ = ...;`), and pineforge-codegen has since filled a
source::PineStrategyConfig (`cfg.initial_capital = 100000.0;`,
`cfg.default_qty_type = static_cast<int>(QtyType::PERCENT_OF_EQUITY);`)
and handed it to configure_pine_strategy, so every report showed the seed
whatever the script declared (R5 lane TV-DEFAULTS, follow-up 3) -- and with
TradingView's new Pine v6 defaults declared in the constructor, a v6
script's report named capital and sizing it did not run with.

parse_strategy_params now reads the constructor's PineStrategyConfig
assignments (the variable its declaration names; enum members stored as
int, `static_cast<int>(...)` unwrapped, an integer index mapped too) and,
for older TUs, the member writes as before. The seed is
PineStrategyConfig's member defaults (the values it already held; its
comment named engine.hpp's pre-R4-C members). The block's keys are
unchanged, so the margins and calc_on_order_fills the constructor also
declares stay out of it. Both copies are the one helper block, byte for
byte.

- scripts/fingerprint_self_test.py: two fixtures in the constructor's
  current form -- every field declared, including a decoy
  StrategyOverrides line outside the constructor, and a sparse one whose
  undeclared fields are the struct's defaults. 284 checks pass; against the
  previous helpers 6 of them fail (every cfg-form field read, the declared
  values, the sparse defaults).
- Over the corpus's 312 TUs at b40aa8e (pure parsing, both copies agree):
  before, 311 reports equal the seed exactly (the other only by its
  inputs.json overrides); after, 88 change -- pyramiding 81, default size 63,
  capital 62, commission 61, slippage 59, sizing type 25,
  process_orders_on_close 4, commission type 3 -- and every numeric literal
  a constructor declares equals its report's value unless an override
  replaces it. analyzer-anvil-percent-costs-01, for one: fixed / 1 /
  1000000 / 0 / 0 -> percent_of_equity / 7.5 / 100000 / 0.08 / 2.

Provenance only: nothing the run executes reads the block, so no trade
moves (the corpus parity step runs this harness).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* INT27 (i): the 1.0.0 entry says what INT27's picks change for a user

Added to "Behaviour that moves results against 0.13.1", each a sentence a
user can act on:
- Pine v6's current strategy() defaults for an omitted initial_capital,
  default_qty_type or default_qty_value (100000, percent_of_equity, 100),
  which pineforge-codegen 1.0.0 declares; v5 and a hand-built
  PineStrategyConfig keep 1000000 / fixed / 1; declare the three to keep the
  old sizing.
- calc_on_order_fills after a resting order's own-level fill on a bar's high
  or low: the recalculation's market orders, closes and passed exit stops
  fill at that point, an exit limit placed on the first extreme's fill is
  live at its level on the leg to the second, a forced fill still moves on,
  an off-grid extreme's booked tick is that extreme, and under the bar
  magnifier a market order after such a fill at an intrabar's second extreme
  fills there (the existing second-extreme sentence, widened).
- process_orders_on_close: a limit entry at the placing bar's close fills
  there when the close's tick reaches it, with or without
  calc_on_order_fills.
- The bar magnifier walks TradingView's own intrabars, built from the finer
  feed, and what a 1/5-minute chart and an exchange-listed daily chart still
  walk; a zero-length-leg lower bar walks its four turning points and a
  volume-0 one-price bar is one point.
- A request.security finer than every supplied feed reads na instead of
  stopping the run; a daily run with an auxiliary feed no longer stops on an
  after-close session (NSE Muhurat).
- A ta.* call with a simple or series length (the late pick's runtime,
  which pineforge-codegen 1.0.0 lowers onto) and what is still refused.
A new "Performance" section: a calc_on_order_fills strategy that draws no
longer slows with every drawing it made -- the late pick's shared checkpoint
copies; codegen has checkpointed the script state, drawings included, on
every fill recalculation since codegen v0.9.0, which 0.13.1 paired with.
A new "Reports and tools" section: the provenance's strategy block records
what the generated constructor declares, so such fingerprints change and the
trades do not (INT27 item iv).

The session-day speedup on exchange-zone charts has no line: it removes a
cost introduced after 0.13.1, and no answer moves. The lower-lookup timing
witness is a test change. No lane name is cited.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* INT27 (ii): the ctest floors are the integrated tree's own counts

Counted with `ctest -N` per profile, each build dir configured with
ci_verify.py's own configure argv (no compiler launcher, as CI has none), on
this tree and on main d0935605:

  profile     main d0935605      INT27             floor
  release     703                716               RELEASE_MIN_TESTS 716
  kernel      287 reg / 286 run  290 reg / 289 run KERNEL_MIN_TESTS 289
  debug       684                697               EXCLUDED 697
  sanitizers  684                697               EXCLUDED 697
  native      693                706               EXCLUDED 706

The thirteen rows, and the lanes that moved each floor (no row left):
- K-RUNERR: test_security_finer_than_feed (release and the three PR
  registration floors);
- PERF-ZONED: test_native_session_day_zoned (source-free: kernel, release,
  PR registration);
- TV-DEFAULTS: test_tv_strategy_defaults (release, PR registration);
- MAG-INTRABAR: test_native_intrabar_turning_points (source-free: kernel,
  release, PR registration), test_magnifier_tradingview_intrabars and
  test_adapter_magnifier_intrabar_tapes (release, PR registration);
- PAR-ORDERS-3: test_pooc_limit_close_tapes (release, PR registration);
- K-DRAWSNAP (late pick): test_drawing_checkpoint (source-free: kernel,
  release, PR registration), test_coof_drawing_checkpoint_cost and
  test_coof_drawing_rollback_tape (release, PR registration) -- the deltas
  the late-picks list names (kernel +1, release +3, each PR floor +3), its
  own floors commit 0d651058 not picked;
- K-TA-DYNLEN (late pick): test_ta_series_length_extremes,
  test_ta_series_length_supertrend and test_ta_simple_length (release, PR
  registration; their TUs reach the source layer, so the kernel floor does
  not move) -- the lane's own floor hunk (release 678 -> 681 on its base)
  not applied.
K-RUNERR and MAG-INTRABAR had counted no PR registration floor on their
branches; the picks added them, and this commit folds the per-pick floor
notes into one INT27 block per floor. The self-test's EXCLUDED pin and
docs/ci.md's floors paragraph say the same numbers.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* INT27 v19 hash re-pin

Inside the unreleased v19 epoch; no epoch token moves. Every witness pin
harvested once on the integrated tree, each pinned TU compiled with its own
harvest switch against the tree's library (INT26's harvest set: the eleven
witnesses PINEFORGE_R1/F9/P1/P4/QUIET_BAR/L5/P7/D2D_PUBLICATION/K1/V19E
_HARVEST and PF_HOST_VIEW_MEMO_DUMP), and at every pick boundary that could
move one, so each moved value names its pick:
- 0631e045 (after K-RUNERR, PERF-ZONED, TV-DEFAULTS, MAG-INTRABAR and the
  INT27 merge) reproduces every pinned value: those picks move none;
- c54f939e (PAR-ORDERS-3 findings 1-2), e5efd189 (finding 4), 9dc3fc08
  (finding 3, which moves none);
- 4160b3e3 and 6fa516ec, the late picks K-DRAWSNAP (after the lane's
  behaviour half) and K-TA-DYNLEN: their eleven harvests are byte-identical
  to 9dc3fc08's;
- this tree (INT27's items (iii), (iv), (i), (ii)): identical again.

16 hash values over 7 rows move, all by R5 lane PAR-ORDERS-3; the trade
digests, counts and live-state transcripts its fixes move were pinned with
them (5c6988c2, the behaviour half of the lane's own re-pin b65cee22, which is
not picked):
- test_adapter_quiet_bar: 15 of 816 values, CalcOnFills/0/*, Random10/0/*,
  Random20/0/* (the chart-path runs; finding 4, the first-extreme rule);
- test_publication_witness: 1 of 156, ConfigFlags103's digest (findings 1-2,
  then 4: its X limit placed on a limit entry's level fill at bar 24's low
  fills at its level, and X's stop, already through at the point that fill
  ended the leg on, fills there);
- 0 moved: report_relower 72, recording_hash_witness 267,
  continuation_view 227, receipts_in_place 334, command_allocations 32,
  lookup_index_witness 948, host_view_memo 13, calendar_hash_witness 12;
  live_state holds no hash value.

Old -> new (each pinned file carries the same list):
  test_adapter_quiet_bar CalcOnFills/0/1: boundary 0xbd9feba11a355c84ull -> 0x109b8bbd2db3c39cull, rows 0xbd62a54cd2c27075ull -> 0x4990637dd008c142ull, final_hash 0x8e716ca55979f5e4ull -> 0x23caae4465e49b8dull [PAR-ORDERS-3 f4]
  test_adapter_quiet_bar CalcOnFills/0/0: boundary 0xbd9feba11a355c84ull -> 0x109b8bbd2db3c39cull, final_hash 0x8e716ca55979f5e4ull -> 0x23caae4465e49b8dull [PAR-ORDERS-3 f4]
  test_adapter_quiet_bar Random10/0/1: boundary 0x82933908492fe6aeull -> 0x53a92b8342582407ull, rows 0x839a10fa6478c692ull -> 0x337fd61947e125a0ull, final_hash 0x6907e89e2f502bd7ull -> 0xfb592dc1ad328c0bull [PAR-ORDERS-3 f4]
  test_adapter_quiet_bar Random10/0/0: boundary 0x82933908492fe6aeull -> 0x53a92b8342582407ull, final_hash 0x6907e89e2f502bd7ull -> 0xfb592dc1ad328c0bull [PAR-ORDERS-3 f4]
  test_adapter_quiet_bar Random20/0/1: boundary 0xad83f25bfdab1b50ull -> 0x6d39d123fcb64c3cull, rows 0x103b25042e1313deull -> 0x4350e4a911697ba6ull, final_hash 0xb27d00f43fad75a1ull -> 0x2fff8a1132834fe4ull [PAR-ORDERS-3 f4]
  test_adapter_quiet_bar Random20/0/0: boundary 0xad83f25bfdab1b50ull -> 0x6d39d123fcb64c3cull, final_hash 0xb27d00f43fad75a1ull -> 0x2fff8a1132834fe4ull [PAR-ORDERS-3 f4]
  test_publication_witness ConfigFlags103: digest 0x9e412b4fb357ae55ull -> 0x275174bdfd481a1bull [PAR-ORDERS-3 f1-2, PAR-ORDERS-3 f4]

The tool (INT26's repin_int26.py with this epoch's notes) refuses any
non-hash change: 7 of 7 mutated harvests stop it (a quiet-bar trade digest
and boundary count, a publication trade count, a live-state transcript, a
host-view-memo fingerprint field, a calendar witness row field, a
report_relower curve statistic). After the write the same harvest
reproduces every pin (0 moved) and the eleven witness rows pass.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* INT27: the doc-revert gate starts after main's newest merged pull request when a checkout has no main ref

INT27's lab remote preflight failed doc-reverts on a tree whose own commits
pass it: "21 commits since this gate landed: 5 unnamed sentence deletions or
reverts". The lab's remote hosts check out a bundle with no branch refs, so
default_base() found no origin/main or main and the walk ran back from HEAD
to the gate's first commit -- which, on main's squashed history, is the
squash merge of INT26 itself, d0935605 (#290). It carries the whole branch's
deletions under the pull request's title: H-THIN's `owns_lot_excursions()`
sentence (introduced by e7350f7), PAR-ORDERS' two F7 E14 sentences (39cc605)
and two E20 probe-tail sentences (b80a082). Each was named by its own commit
on r5/int26, whose remote preflight passed; the squash cannot name them again.
`check_doc_reverts.py --base 0d76a099 --head d0935605` reproduces the 5; CI,
which has origin/main, never judges the squash (its merge base with a branch
is the squash itself). Every lane based on main after INT26 hits the same
failure on a lab remote host.

With no branch ref, default_base() now takes the newest first-parent ancestor
of HEAD whose subject ends in a pull request number (` (#N)`, the subject
GitHub writes for a merged pull request on main), HEAD included: the merge
base CI would find. Every commit after it is judged as before; with none,
the walk still starts at HEAD and stops before the gate's first commit.
--base, PINEFORGE_DOC_REVERT_BASE and the origin/main / main merge base keep
their precedence, and the replay mode is unchanged.

- scripts/test_check_doc_reverts.py: a squash-titled commit that deletes an
  unnamed sentence is the base without a main ref (the walk judges the one
  commit after it, and the squash judged alone still fails), and an unnamed
  deletion after a merged pull request still fails. 12 tests pass.
- docs/ci.md states the rule.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* INT27 (v): every doc anchor re-anchored once, on the integrated tree

One pass over every page check_doc_anchors.py scans, after the last pick,
the behaviour pins and the hash re-pin, so the digits are the final tree's.
Digits only: with every citation's digits blanked, each of the 8 pages is
byte-identical to its parent (181 lines change).

How, in order:
1. The multi-origin exact map (INT24's int24_exact_reanchor.py with
   --exclusive-first): main d0935605 first, then each lane's tip in pick
   order (K-RUNERR 28118665, PERF-ZONED 27e1f384, TV-DEFAULTS 4b457291,
   MAG-INTRABAR 9df16c24, PAR-ORDERS-3 1550a694; the late picks K-DRAWSNAP
   and K-TA-DYNLEN touch no page): each anchor carried through an exact difflib line map from the
   tree its digits were written against. 1725 anchors: 293 moved, 1394 kept,
   38 stuck (digits a pick's digit merge composed, which no origin carries).
2. INT26's anchor_origin_fix.py --relaxed over every INT27 commit and the
   lane tips: 15 anchors by the same line and position on main's page,
   carried through the exact map and re-judged by the gate here -- e.g. the
   design page's OL10 `exit()` pine_adapter.cpp:8527 (main 8485; the merge
   had composed 13134).
3. By hand, each checked against the code it names: the floor citations
   `KERNEL_MIN_TESTS` ci_verify.py:274 and `RELEASE_MIN_TESTS`
   ci_verify.py:429 (the assignment lines; CONTRIBUTING.md and
   contributing-llm.md); design row E4's `PineScheduler::recalculate`
   pine_scheduler_native.cpp:636 and `coof_next_waypoint`
   pine_adapter.cpp:5742 (the row this lane merged by hand kept main's
   digits); design row CT9's `volume_weighted_cap` pine_adapter.cpp:2282-2338
   (MAG-INTRABAR's own span, the retained lower-timeframe branch through the
   spec's validation, carried exactly from 9df16c24; main's 2281-2337 had
   drifted into cohort_for) and `deliver_confirmed_script`
   native_execution_consumer.cpp:7549-7815 (main's span carried exactly).

Results on this tree:
- check_doc_anchors.py: 1725 anchors, 1725 OK, 0 bad.
- stale_scan.py against d0935605: 0 stale-carried anchors.
- verify_carry.py over the same origins: 1707 EXACT, 9 EDITED (the six floor
  citations, whose cited assignment lines the floors item rewrote, and three
  design spans whose code a pick rewrote -- each passes the gate's claim), 9
  NEW (prose the picks wrote).
- check_doc_lint.py: no offenders. docs/build.sh: Doxygen warnings 0.
- check_doc_reverts.py over d0935605..HEAD (20 commits), and in a
  checkout with no branch refs as on a lab remote host: 0 unnamed deletions
  or reverts.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* INT27 (vi): the engine's merge-gate hook entry runs for MCP tool calls too, and blocks when it cannot start

pineforge-workflow's docs/VERIFY.md ("Open decisions") records two gaps in
the product repos' .claude/settings.json: the entry ran pr-gate.mjs for Bash
only, so an MCP merge tool in an engine session met no hook, and without
`|| exit 2` a hook that could not start (the file missing, a syntax error,
node's own exit 1) let the call through, since Claude Code blocks only on
exit 2. campaign/README.md's wiring closes both.

The entry's matcher `Bash` becomes `Bash|mcp__.*`, and its pr-gate command
gets `"timeout": 120` and a trailing `|| exit 2`, as the workflow repo's own
entry has them. pr-gate.mjs reads only `tool_input.command`, so an MCP
payload reaches it as an empty command and it answers "no opinion"; the
same entry therefore also runs campaign/hooks/merge-gate.mjs (the file
campaign/README.md wires for `mcp__.*`, with the same timeout and
`|| exit 2`), which reads `tool_name` and `tool_input` and judges an MCP
merge of an engine PR. On a Bash call it repeats the merge gate pr-gate.mjs
runs first; both are deny-only.

Checked through `sh -c` with the payload on stdin, as Claude Code runs a
command hook: a benign Bash call and a benign MCP call exit 0 for both
commands; with the hook file missing each exits 2.

This is the last commit before the final lab remote: a session loads its
project hooks at start, so the session that wrote this commit keeps running
the previous entry.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>

* Adapter: an exit limit the open's refill recalculation armed at the first extreme gap-fills there as a forced fill (R5 integration INT27, round 2: the gate sweep's regressed probe)

INT27's gate sweep (exp-r5-int27-20260927, engine d3b753c1 + codegen
a4259656, against rebaseline exp-rebaseline2b-20260926 on engine d0935605)
refused the merge on one script,
officialjackofalltrades-aureate-market-architecture-strategy-joat, on four
lanes: OANDA:XAUUSD 15m (count +1), OANDA:EURUSD 15m (+3), BINANCE:BTCUSDT
15m (+7) and the scraped BINANCE:ETHUSDT.P lane (+4), every one excellent on
the baseline. On XAUUSD the entry price moves from trade #60 on (3266.82 ->
3261.29).

Bisect (the probe's own feeds and the pinned Lab verifier on spark, one
library per pick boundary): 0631e045 (the INT27 merge fix) and c54f939e
(PAR-ORDERS-3 findings 1-2) book the baseline trades (e8107dece428);
e5efd189 -- PAR-ORDERS-3 finding 4, bc5f7a21: after the matcher's fill at a
resting request's own level on a bar's first extreme, the recalculation's
orders act from that extreme -- books 477b4cca24af, as every later commit.

Mechanism, on the XAUUSD bar 2025-04-16 00:30 UTC (O 3261.715, H 3266.82,
L 3261.29, C 3263.885, low first), traced in a scratch copy of the adapter:
the strategy.exit limit leg carried from the previous bar (below the
price) fills at the open; its recalculation re-enters, filled at the open
too (the refill); that entry's recalculation re-places the exit, whose limit
3260.5585 is already through, so exit() arms it at the first extreme
(later_same_open: StopLimit{W1 3261.29, 3260.5585}), where the path
gap-fills it at 3261.29 -- TradingView's trade #59 exit. Its placement
carries no forced_execution_price, so begin_coof_recalc left
coof_fill_forced_ false, and finding 4's rule in coof_next_waypoint read the
fill as the matcher's at the limit's own level ON the extreme: the market
re-entry filled at W1, 3261.29. TradingView books it at the second extreme,
3266.82 (#60), as it books a market order after the control's forced fill
(pa3-f4-point-w1-mkt-…
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