Skip to content

Lighter PR CI: slow rows run only on push and dispatch, proof jobs start with preflight, and the merge gate is the maintainers' verification statuses (lane CI-LITE) - #288

Merged
luisleo526 merged 4 commits into
mainfrom
r5/ci-lite
Sep 25, 2026
Merged

luisleo526 merged 4 commits into
mainfrom
r5/ci-lite

Conversation

@luisleo526

Copy link
Copy Markdown
Collaborator

Lighter PR CI, and the merge gate described as it now works

PR CI stops waiting on the slowest rows. Every test stays in the tree, and the full set still runs on every push to main, on manual dispatch, and in the maintainers' own pre-merge verification.

What changes

  • 27 slow CTest rows get the label slow, declared in one place (tests/CMakeLists.txt).
    • A row qualifies if it took more than 60 s under the INT23 or INT24 sanitizer job, or more than 30 s in either INT24 Debug job.
    • The heaviest are test_ci_verify (485–986 s under sanitizers) and the native batteries (test_native_direct_mutation, test_native_match_band_precheck, test_native_match_row_reuse, test_native_command_after, …).
  • On pull_request only, the sanitizer, Debug and native jobs pass --exclude-label slow.
    • Push to main and the new workflow_dispatch trigger run every row.
    • The excluded run stays exact: ci_verify.py counts rows with CTest's own ctest -N, with and without -LE slow, and requires ran == registered − labelled, with PR registration floors. A row that silently loses its registration still fails.
  • Proof jobs start alongside preflight instead of waiting about 9 minutes for it. The aggregate build context still requires every job.
  • Merge gate: the ruleset now requires the commit statuses pineforge/verify and pineforge/parity, posted from the maintainers' own verification, instead of GitHub Actions' build/sanitizers. GitHub Actions CI is advisory.
    • promote-baseline.yml now confirms both statuses on the merged PR head, taking the newest status per context.
    • docs/ci.md, AGENTS.md, the README and the workflow comments describe the new gate.

Measured

before after (estimate)
PR wall time ~60 min (9 min serial preflight, then sanitizers ~50) ~30–35 min

Most of the remaining time is the sanitizer build itself: 29–30 min from build start to CTest on the hosted 4-core runner. The ≤25-minute target is not reachable without build changes; that is noted for later.

Verification

  • ci_preflight passes locally: 32/32 stages, 143 verifier tests, 8 preflight tests.
  • ctest -N counts:
profile registered labelled slow selected
release 672 27 645
debug 653 27 626
sanitizers 653 27 626
native 662 27 635
kernel 272 22 250
  • Maintainer verification on this head: lab remote jobs rj-20260925t114243-6e5abd and rj-20260925t105637-45e625 on head 53d3655 (tree ce3a1ba8afb6): ci_preflight: passed (exit 0, 32 stages, 0 advisory reported);ctest ran 672 rows (floor 672);100% tests passed out of 672;100% tests passed out of 653;==> Doxygen warnings: 0; 100% tests passed out of 653;ctest ran 272 rows (floor 271);kernel residuals: libpineforge_kernel.a: 173 archive hits (170 identifiers, 3 texts), 269 installed-header hits and 8 kernel-source hits against 202 ruled ident;100% tests passed out of 272;corpus_trades_identity: 312 probes at corpus eede4a22978051f5f13d791e99b2151fbbbfa073 — baseline match=312, moved=0, unrecorded=0, missing=0, schema violations=;Verified 312 strategies — excellent=311, strong=0, moderate=0, weak=0, minimal=0, anomaly=1, engine_only=0, missing=0
  • No file under src/, include/ or corpus/ changes, so engine behaviour and TradingView parity cannot move.

Report: exec/CI-LITE-final.md under the R5 evidence root.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LifAW9e5J6gFx7gatuxETE

@luisleo526
luisleo526 merged commit 1a0e7ea into main Sep 25, 2026
17 checks passed
luisleo526 added a commit that referenced this pull request Sep 26, 2026
…-rc.1 candidate) (#290)

* H-MEASURE: measure the margin retentions against the kernel and TradingView

AUDIT4 X14 rows G2-09 (M7), G2-10 (M8), G2-12 (M10), G2-13 (M11) and the
E20 f1 probe-tail pin. tests/test_adapter_margin_schedule_differential.cpp
runs the same bars and orders through the Pine adapter and through a bare
kernel host whose margin hooks answer TradingView's money and slice (the
twin's), so only the kernel's own scheduling, check kinds and opening gate
differ; every section prints both sides and pins the measured difference:

- M7: the kernel's AfterApplied point after a leveraged opening or a
  mid-bar add, and its BarOpen point on a carried commissioned POOC short,
  are points margin_check_allowed refuses.
- M8: a gap-open breach is a market execution at the open, sized on the
  open's money; no kernel check kind books that row.
- M10: the pre-open slice's own x4 parts from the kernel's AfterApplied
  point (and from ab9714be) on the one-contract band, the +1e-6 restore
  floor and the frozen signal-time units.
- M11: AdmitWithHostMargin and initial_margin_fraction part both ways.
- E20 f1 (ruled 2026-09-22): the probe-suppressed tail books the kernel's
  path liquidation and the adapter's post-script margin call.

M7 is also measured against TradingView: four lab tv tapes
(tests/fixtures/margin_entry_bar, BINANCE:ETHUSDT.P 15m, rangeProof
covered) book the margin call of a leveraged opening ON ITS ENTRY BAR at
that bar's low, as the kernel's AfterApplied point does; the adapter books
it a bar late or not at all. That is a TradingView-visible divergence,
pinned as recorded (not fixed here: the lane measures).

Docs made true: ADR-0001 "Margin" (the pre-open slice does have a kernel
point beside it) and its initial_margin_fraction row, native-engine.md's
margin paragraph, pine-to-native.md and contributing-llm.md (M11),
live-surface.md §3.2 (the tail's two routes; the dispatch_bar paragraph
named helpers that no longer exist), design rows MG4 and MG15; two design
anchors into native-engine.md re-anchored for the moved lines.

No src/ or include/ change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit bafefba06cebfc6989313e91c4a97e1a815a7239)

INT26 pick note: the ADR and design pages conflicted on citation digits
only (int16_digit_merge: 5 blocks, no text refused). The resolution is
PAR-MARGIN's 6574de6d, the same pick onto the same tree (83d1ca7f): its two
design citations of native-engine.md carried through the exact line map
(2941-3009 -> 2963-3031). hunkcheck: every hunk of bafefba0 carried; the
two pages differ from its diff in anchor digits only.

* H-MEASURE: tape the pyramiding count, the sibling stop and pending-entry trails

AUDIT4 X14 rows G2-15 (M13), the M16 sibling stop (G2-18), E14's
anchored-leg seed (AUDIT3 H6 tapes) and E5's pending-entry arm, each
measured against the kernel on the same bars and against TradingView's own
trades (lab tv, NYSE:F 15m, ws-report-v1, rangeProof covered; each fixture
README names its tapes and sha256):

- tests/test_pyramiding_count_differential.cpp (M13): fifteen pyramiding=2
  scenarios through the adapter, a bare host with max_open_lots=2 and the
  tapes. TradingView checks an entry once, at its first eligible point,
  against the trades then open; max_open_lots books 14 of 15 as TradingView
  does, the adapter's per-cycle count 8 (it counts a resting entry, admits
  three market entries on a flat bar, keeps a slot another entry's exit
  drained). A default strategy.exit(from_entry) under FIFO closes the
  book in the adapter and one lot in TradingView (P10). All pinned as
  recorded divergences; the retention reason in ADR-0001 is refuted.
- tests/test_zero_trail_sibling_stop.cpp (M16): the bare host with both
  legs is the adapter bit for bit; the Trail alone rides past the open.
  TradingView books the touch at the open on 16 of 16 taped trades.
- tests/test_pending_entry_trail_tapes.cpp (E5, E14): a trailing exit
  written while its entry is pending. The quantized arm holds, 28 of 28
  (E5's claim, taped); TradingView's running best starts at the activation
  13 of 13 while the adopted anchored child names no best_seed and exits 1
  to 24 bars later -- recorded divergences, the adoption compare leaving
  best_seed out.

Docs: ADR-0001's max_open_lots row, design MG3 and the rulings summary, the
sibling-stop and anchored-leg paragraphs (the latter no longer "an open
measurement"), native-engine.md and pine-to-native.md on adoption and the
sibling stop, contributing-llm.md's pyramiding row; two design anchors
into native-engine.md re-anchored.

No src/ or include/ change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 99d3b9506af49a3c9bdfc5bfd947c12fd9988839)

INT26 pick note: the ADR, design and pine-to-native pages conflicted on
citation digits only (int16_digit_merge: 5 blocks, no text refused). The two
design citations of native-engine.md both sides moved are carried through
the exact line map from the pre-pick tree (2963-3031 -> 2970-3038,
1642-1643 -> 1647-1648). hunkcheck: every hunk of 99d3b950 carried; the
three pages differ from its diff in anchor digits only.

* H-MEASURE: measure excursions, short-seed swaps, the dust sweep, ismarket

AUDIT4 X14 rows E19 (the excursion model, G2-22), G2-21 (short-seed
report swaps), G2-32 (the 1e-10 dust sweep) and G2-36 (session.ismarket,
the CME weekend and 0000-2400 classes), each measured against the kernel
on the same fills and against TradingView's own trades (lab tv,
ws-report-v1, rangeProof covered; each fixture README names its tapes):

- tests/test_e19_excursion_tape.cpp (E19): a corpus probe's own script
  re-exported (1580 trades, its excursion cells equal to the corpus
  tape's) and a calc_on_order_fills scratch tape. Where the host-owned
  model (RULING A48) and the kernel sampler differ, the kernel's number is
  TradingView's: entry-bar over-mask, exit-bar over-fold after an at-open
  exit, the COOF scratch TradingView reports as 0/0. One trade per class
  pinned; corpus-wide the kernel is TradingView's on 315 of the 326
  identified disagreements and the host on none. Recorded divergences.
- tests/test_short_seed_report_swap.cpp (G2-21): the swap relabels two
  rows' entry_incarnation into ab9714be's numbering, read against the
  kernel's own lot identities in the same run; TradingView exports no
  incarnation, and the Pine host books the collision tape's 13 rows.
- tests/test_pine_dust_sweep_paired.cpp (G2-32): the sweep erases a dust
  lot inside a live book, unlike ab9714be's whole-book reset; TradingView's
  decimal quantities leave no remnant row, which the Pine host books and a
  bare host does not (four 2.8e-17-unit rows).
- tests/test_session_ismarket_tape.cpp (G2-36): six tapes (ES1!, EURUSD,
  XAUUSD, ETH; both 2025 DST switches, Thanksgiving) flag every bar in
  market; the kernel's in_session matches every spelling, the generated
  predicate misses every Sunday open under a :23456 mask and every bar of
  0000-2400. Routing session.ismarket is a codegen change, not made here.

Docs: ADR-0001 (the excursion seam, the dust sweep as a quirk, the
session.ismarket selection, the excursion columns being report-only),
design RP1, RP5 (its "measured in §3.7 part 2" named no short-seed row)
and the excursion-mode alternative, native-settlement.md's sweep
paragraph ("restates" the legacy rule, it does not), pine-to-native.md
and pine_v6_coverage_detail.md on session.ismarket.

No src/ or include/ change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit fd3c72e2d6cc22a77b86a73d2efc36aeed7c968f)

INT26 pick note: docs/native-settlement.md conflicted in text. INT25
(K-ULP4) had appended the sentences on the adapter not declaring the kernel's
quantity tolerance to the paragraph this commit rewrites; the merged
paragraph is this commit's measured text followed by those INT25 sentences
unchanged. The ADR, design and pine-to-native pages conflicted on citation
digits only (int16_digit_merge, digits carried from the pre-pick tree).
hunkcheck: every hunk of fd3c72e2 carried; design and pine-to-native differ
from its diff in anchor digits only.

* H-MEASURE: F1(e) tape row, F1's magnified residual, request.security routes

AUDIT4 X14's aggregation rows, measured on the K-IDX tree (the kernel now
books lots, rows and interval_index in script-bar space):

- F1(e), tests/test_aggregated_entry_bar_index_tape.cpp: TradingView's own
  tape of a process_orders_on_close script whose every exit reads
  strategy.opentrades.entry_bar_index / closedtrades.exit_bar_index (lab
  tv hm-f1e-ebi-pooc-eth and its magnifier-on twin, BINANCE:ETHUSDT.P 15m),
  replayed on the chart, the plain aggregated (corpus 1m -> 15m) and the
  magnified path: 26 checks, 0 failures. With the four booking sites of
  e362bc4b reverted in a scratch build (the kernel books input slots again,
  and nothing re-stamps them) it fails 10 of 24 checks: no held exit
  fires, A/B/C close at their timeouts, D never enters. No corpus probe
  runs an aggregated process_orders_on_close script that reads a bar
  index; this engine row is the parity witness until the supervisor adds
  one.
- F1's magnified residual, tests/test_magnified_aggregated_tape.cpp:
  instrumented, the three entry-bar tests of a magnified aggregated run now
  compare script bars with script bars (0 of 5170 out of space, 4996 on
  91d65ad6); sixteen lab tv tapes of lane F1's differential script book
  its 12 rows as this engine does on every path (ab9714be's 9 were its own
  error). The variants the magnified run books exactly are asserted at
  chart-bar granularity; TradingView dates a magnified fill at its chart
  bar's open (218 of 218), a recorded presentation divergence.
- M20 / G2-23, tests/test_adapter_security_route_conditions.cpp: every
  condition that keeps request.security on the source evaluator, each
  reachable one tripped alone against a control site, and where a kernel
  subscription spells the same site, the evaluator's value against a bare
  kernel host's on every chart bar. ADR-0001's row named four classes; the
  predicate has sixteen conditions, now listed and measured.

Docs: design §3.8 (the gate that can now see F1's regression, AG1's
TradingView proof, AG2's magnified dating, the magnified residual closed),
ADR-0001's subscriptions row and native-engine.md's route paragraph; one
design anchor into native-engine.md re-anchored.

No src/ or include/ change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 206a739d2d9a997ae0516064e668ea48979a89ca)

INT26 pick note: the ADR conflicted on citation digits only
(int16_digit_merge, digits carried from the pre-pick tree). hunkcheck: every
hunk of 206a739d carried; the ADR differs from its diff in anchor digits
only.

* H-MEASURE: the G1 acid composite as a C++/C witness row

AUDIT4-codex A4-ACID-COVERAGE. tests/test_native_acid_composite.cpp is one
source-free strategy on NativeStrategyHost (kernel headers only) that
exercises every feature of the G1 acid test and prints PASS per feature:
F01 fee-reserved Sized entry, F02 anchored bracket legs on a price grid,
F03 a keep_binding re-issue, F04 a trail in ticks, F05 a maintenance-only
margin model and its liquidation seen through the open lots, F06 an FX
step, F07 a risk limit and an opening refused with RiskLimit, F08
calc-on-fills, F09 an hourly subscription plus an auxiliary 5m->30m series
that is actually delivered (44 buckets; the audit's copy wiped its own
series with an empty begin-time declare and so read aux=0), F10
session-day flags, F11 a FIFO partial close across lots and an exact-sum
close that leaves no dust lot (K-ULP3), F12 typed refusals, F13 magnifier
counters, F14 the kernel-recorded report with per-bar hashes.

The C half (tests/test_native_acid_composite_c.c, native_c_api.h only)
configures through strategy_configure_native_ext_result_v1 on a handle it
first refuses (GRID_REQUIRES_PRICE_TICK, stays UNCONFIGURED, then Ready,
then WRONG_PHASE), runs the same commands in batch and stream, and prints
the same FIELD lines: the C++ half compares the two sets in process, 915
of 915 identical, every C++-only family named by an EXCLUDED line (the
four C-SURFACE-2 items ruled to 1.1.0, closes_session_day_open_ended, the
protected broker fold, quote_origin_ordinal and driver_statistics).

The batch/stream comparison is explicit: trades, fills, curve, series
deliveries, check points and the broker half agree; the per-bar hash rows,
the final hashes and the forming bar's closes_session_day are
driving-mode keyed, each rule printed with its documented source.
Findings printed, not asserted: under IntrabarPath::lower_tf the margin
model is checked at the bar's first sample and after fills only, never
per sample, contrary to native-engine.md's "re-evaluates at each
delivered sample".

Source-free: registered like test_native_c_api, so it runs in the kernel
profile and in release. native-engine.md records the C port's measured
exclusions beside the COVERAGE block.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 58e0f16275ea57148f3385d564df88ae7cc2e70c)

* H-MEASURE: H12 mutation battery; the PR parity subset covers what the sweep catches

AUDIT3-opus2 H12 (carried by AUDIT4 X14): measure the 30-probe
pull-request subset against mutations. 44 single-line mutations (22
kernel: matching, fees, sizing, path order, sessions, timeframe
aggregation; 10 adapter; 12 ta) plus 17 designed afterwards as a holdout,
each built on spark and run over all 312 corpus probes, the unmutated tree
312/312 moved=0 before, between and after: the full sweep caught 39, the
30-probe subset 19. Escaped: ten ta.* arithmetic mutations, the AUTO
path-order tie, an HTF aggregation low, strategy.risk.max_position_size's
equality gate and the stop-limit entry (the last two with one corpus
witness each, outside the 40-item scan the subset was built from).

- scripts/corpus_parity_subset.txt: 24 probes appended (the original 30
  untouched): the greedy cover of the escapes, one witness per ta class a
  generated strategy constructs, and the two holdout witnesses. The 54
  catch all 39; subset-only reruns of the escaped mutations detect them.
  Its header no longer claims every one-witness mechanism by construction.
- scripts/corpus_parity_mutation_battery.tsv: the 39 caught mutations with
  the probes that caught them.
- scripts/test_corpus_parity_subset_cover.py, a new ci_preflight stage:
  fails when the subset stops witnessing a recorded mutation (it reports 20
  escapes against the original 30).
- docs/ci.md records the battery and the full-sweep timing it measured
  (19-24 s ten-wide, 113 s serial, after a 99 s build); the "30 probes"
  counts in docs/ci.md, CONTRIBUTING.md, README.md, check_corpus_parity.sh
  and the two workflows' comments now read 54, the historical timings are
  labelled as the first 30's.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 9c0579d2b332eaebe579a9b5baa7aa8dcedb8be6)

INT26 pick note: the two workflow comments this commit re-counts were
rewritten on main (57c89ff5, the advisory PR subset and the maintainers'
parity status). The merged comments are main's text with this commit's
count: corpus-parity.yml's "PR EARLY SIGNAL" and "advisory PR subset"
sentences name the 54 probes; ci.yml's rewritten comment names no count.
No other hunk differs from 9c0579d2 (hunkcheck).

* H-MEASURE: put N12's seeded corpus experiment on the tree

AUDIT4 X14 row "N12's corpus half" (DONE-CLAIMED-ONLY: design §3.6.1
cited an uncommitted, env-gated experiment). Ruled, with its pin and a
committed reproduction:

- It cannot be a CTest row. Pine's strategy.risk statements reach the
  adapter on script bar 0, after project() built the run spec and
  configure_native digested it; prepare_native_begin is final and a second
  configure_native while Ready is refused, so no in-process test can seed
  the kernel's NativeRunSpec::risk for a Pine run without a source change.
  The pins stay the five probes' baseline rows and test_adapter_risk_relower's
  SW check.
- scripts/check_seeded_risk_experiment.sh applies
  tests/fixtures/seeded_risk/n12-experiment.patch (N12's own experiment,
  recovered from its session record and ported; inert without
  PF_N12_ROUTE) to a throwaway copy, builds the runtime and the five risk
  probes, checks the unseeded runs still hash to the parity baseline, runs
  them with the kernel's rule seeded in the adapter's place and compares
  expected.tsv. On this tree (spark, 29 s) it reproduces every count the
  design states: 1502/1502 and 1464/1464 identical, 3840 of 3916, 312 of
  604, 2370 of 2386 (two extra rows) on the ten TradingView-recorded
  columns. Exit 1 when the measurement moves, 2 when the patch no longer
  applies.

Docs: design §3.6.1's acceptance evidence and ADR-0001's risk row cite the
script; one contributing-llm.md anchor into the design re-anchored.

No src/ or include/ change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit bf5a11fbb4248d3f3bfbf5fcce1c610705c12f41)

INT26 pick note: the ADR conflicted on citation digits only
(int16_digit_merge, digits carried from the pre-pick tree). hunkcheck: every
hunk of bf5a11fb carried; the ADR differs from its diff in anchor digits
only.

* H-MEASURE: the ctest floors count the lane's rows -- release 672 -> 684, kernel 271 -> 272

Counted with ctest -N on this tree, configured as ci_verify's release and
kernel profiles: release registers 684 rows (the twelve H-MEASURE rows on
top of 672, no row skips), kernel 273 (test_native_acid_composite is the
lane's one source-free row; the WebSocket row still skips on a system
libcurl, so 272 run). Each row is named beside the floor it raises.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 2b494497c8707c3365218cac4ae8d9548dc3c67b)

INT26 pick note: scripts/ci_verify.py's two floors conflicted with INT25's
(wave G: KERNEL 277, RELEASE 678). The merged floors add this lane's rows to
INT25's -- KERNEL 277 + 1 = 278, RELEASE 678 + 12 = 690 -- with both
comments kept; INT26 item (iv) recounts every floor with ctest -N per
profile on the integrated tree. The four floor citations in CONTRIBUTING.md
and contributing-llm.md name the merged lines (ci_verify.py:247 and :371).

* Gates: the residual gate rules a text by its exact words and reads Pine's dotted namespaces (R5 lane H-DOCGATES, X12)

AUDIT4-opus X12 (kres K4, K5, K11) found check_kernel_residuals blind in
three ways. Its own probe battery, copied and re-run on this tree's macOS
kernel archive, flagged 16 of 51 probes at 21bdc2e8; it flags every Pine
probe now, on all four surfaces (strings, nm, header literals, kernel
literals).

- A ruled name never covers a text. The bare words `Pine` (the PineMap
  row) and `syminfo` passed "match Pine semantics exactly" and
  "syminfo.tickerid must be set", and any ruled name passed any text
  around it. A text is now ruled by its exact words; a name by its name.
- The vocabulary reads Pine's other dotted namespaces (timeframe., input.,
  str., math., matrix., map., line., xloc., syminfo., format., currency.,
  dayofweek., ...; the namespace must open the run, so a compiler's
  l_switch.table.<symbol> label stays silent), the camel-case Tv/TV
  spelling, bare islastbar/isfirstbar, heikinashi, renko, tradingday and
  the word Pine in a text.
- A row whose second column says "no archive symbol" is held to it:
  PineMap or a matrix text in the archive or a kernel literal fails.
- The key line counts the rulings the vocabulary reads (174 identifiers,
  45 texts), not every first-column token (202/25 counted 27 + 22
  mechanism-table names), and ci_verify.py floors both counts
  (ADR_RULED_IDENTIFIERS_MIN / ADR_RULED_TEXTS_MIN), passed as
  --min-ruled-identifiers / --min-ruled-texts.

The 57 installed-header literals are ruled, not reworded (rewording a
generated strategy's runtime diagnostic is the GAP-15 codegen decision):
one new ADR row holds the 32 distinct dotted argument-check texts of
generic_matrix.hpp, map.hpp and drawing.hpp; the PineMap row holds
map.hpp's four static_assert texts in place of `Pine`; the
deprecated-alias row holds its six alias texts. No source, header or
object changes: scripts, tests and docs only.

Mac kernel archive: 21bdc2e8's checker "146 archive hits ... against 202
ruled identifiers and 25 ruled texts: 0 findings"; this commit "146
archive hits ... 326 installed-header hits ... against 174 ruled
identifiers and 45 ruled texts (floors 174/45): 0 findings ... OK".
test_check_kernel_residuals: 39 -> 46 cases (ReachTests), all pass.
A symbol a compiler split or cloned (GCC's `.cold` / `.part.N` /
`.isra.N` / `.constprop.N`, clang's `.cold.N` / `.llvm.N`) is still one
name: x86-64 GCC 13's archive prints `strategy_set_syminfo_type.cold`
and six more ruled exports that way (first NTU run of this change:
7 findings, all of that shape).

Doc deletions this commit names (rewritten, not dropped):
- ADR residual intro, "a text by a phrase it contains" (lane F6's rule)
  -> "a text by its exact words";
- ADR PineMap row, "where the bare word `Pine` is read" (lane F6);
- native-engine.md "What the kernel-only archive still names": the
  vocabulary list and "requires every match to be listed, by name"
  (gap lane P2's wording, pre-F6).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit d5b6583119d321e3c6d41a2dc4e1d2ccb5c86fe1)

INT26 pick note: scripts/ci_verify.py conflicted where INT25 and H-MEASURE
rewrote the floors this commit sits beside; its ADR ruled-count floors are
inserted after the merged RELEASE_MIN_TESTS, every floor and comment of
both kept. hunkcheck: every hunk of d5b65831 carried unchanged.

* Gates: a published sentence leaves only when its commit names it -- the doc-revert stage (R5 lane H-DOCGATES, X13)

AUDIT4-opus docs-a (f)/N7: no silent doc revert reached main between
fd785928 and 91d65ad6, but nothing would have caught one. Lane
B-C-SURFACE's rebase kept its own base's pages, dropping V19-D's
keep_handle / keep_binding row and putting D2-C's runtime-block wording
back; the integration caught it by reading.

scripts/check_doc_reverts.py compares each commit with its parent,
sentence by sentence (paragraphs, list items, table cells of README.md,
CONTRIBUTING.md and docs/**/*.md; anchor digits and content pins
normalised). A deleted sentence, or older wording restored over newer
(a sentence the page held before its parent), must be named by the
commit's message: the lane label or hash of the commit that introduced
it, six consecutive words of it, or its table row's key. Fresh rewrites
and re-anchors need no name. Range: non-merge commits since the merge
base with main; with no main ref (the lab's remote hosts) it walks back
from HEAD; a commit whose tree predates the gate is never judged.
--base/--head/--message-file judge one replayed change.

Acceptance (both run on this tree):
- 597a4367's nine pages replayed onto db98990c with 597a4367's message:
  "17 unnamed sentence deletions or reverts ... FAIL" -- V19-D's
  keep_handle rows (introduced by c619f5f) and D2-C's ambient-block
  wording reverted to "thread-local";
- e3e20cb5 with its own message: "0 unnamed ... OK"; the same change with
  the message "docs: tidy" fails on the 11 PERF-P1 sentences it deleted
  (introduced by 36a6a7e, cherry-picked from 3bd72fb).

Preflight stages doc-reverts and doc-reverts-tests (binding); CTest row
test_doc_reverts (10 cases over throwaway git repositories), so the
floors rise: KERNEL_MIN_TESTS 272 -> 273, RELEASE_MIN_TESTS 673 -> 674.
docs/ci.md, README.md, CONTRIBUTING.md and contributing-llm.md name the
gate; the floor citations re-anchored (ci_verify.py:229 -> :231,
:332 -> :336). No sentence is deleted by this commit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 34ae339e3488c2ec22e6724643d65d2ecea73a48)

INT26 pick note: the floors conflicted with INT25's and H-MEASURE's; each
floor adds this commit's one row to the merged value (KERNEL 278 -> 279,
RELEASE 690 -> 691), both comments kept, and the four floor citations name
the merged lines (ci_verify.py:249 and :375). hunkcheck: every other hunk
of 34ae339e carried unchanged.

* Gates: a content pin accompanies a claim, never replaces it; a comma-borrowed citation claims nothing (R5 lane H-DOCGATES, X13)

AUDIT4-opus docs-a N1/N2 (GAP-1, GAP-5): a backticked sha256 pin before
an anchor dropped the symbol claim and was compared alone, so whatever
the cited line held passed -- a wrong line (P09), a blank line (P10), a
garbage hash before a real one (P11), a ruling row pinned over unrelated
code (P16) -- and 44 of the tree's 92 pins held something other than
what their sentence claimed. In a citation list, a citation that prose
introduced after a comma ("FX curve c_abi.cpp:882, probe c_abi.cpp:882")
borrowed the list's first symbol.

check_doc_anchors.py:
- the nearest non-pin span before a pin is still the claim and is still
  checked; a ruling row needs its symbol or fragment, pinned or not;
- PINLINE (a pin on a single line), PINEMPTY (a pin over blank lines),
  PINDOUBLE (two pins before one anchor); a pinned comment-only window is
  COMMENTONLY unless the sentence says it cites a comment;
- a citation that prose words introduce after an earlier citation's
  comma is NOCLAIM until it carries its own backticked symbol.
Self-tests 45 -> 53: PinMustFail (P09, P10, P11, P16, the comment window,
a pinned range with its claim) and BorrowedClaim. Against 21bdc2e8's
checker the six must-fail cases fail and the two controls pass
(anchor_selftests.before.txt in the lane scratch).

The pages: on HEAD the new rules raised 64 findings (23 PINLINE, 2
PINDOUBLE, 8 COMMENTONLY, 1 SYMMISS, 30 NOCLAIM). Every pin was
re-derived on this tree (claim, window, verdict, true location) and
re-cited as a symbol claim at its declaration, or as a pinned range
whose sentence names the comment it cites; every comma-borrowed citation
now names its own symbol at its true line (e.g. design OT5: FX curve
`strategy_configure_native_fx_curve_v1` c_abi.cpp:940, probe
`strategy_execution_contract` c_abi.cpp:873; FP1's fill_through
enforcement `protect_limit` :6103-6113 and InvalidTerms :4958-4976).
The anchor gate reads 1657 anchors, 0 bad. docs/ci.md and the checker's
docstring state the new rules.

Doc sentences this commit deletes or rewrites as history (named for the
doc-revert stage). Most of the pins it removes are B-DOCS' (d3cca9e,
cherry-picked from 5c3c9ae), so the unpinned wording that returns in
pine-to-native.md's `open_profit` rows and `strategy_create` row, and in
design E2's margin sentence, is that commit's pins undone on purpose:
- design §2.vi claim rows 2, 3, 6, 8 and 9: their plan-era anchor lists
  (B-DOCS' pins, 91d65ad6's re-cites) become "at 73817c1 (overtaken ...)";
  row 1 is re-cited to today's Trigger/OrderIntent/Owner/Group/PointBudget;
- design §2.i "Today: one static library always compiles the source
  layer" -> "Before L1" plus the tree's current CMake lines (the
  sentence 1dd5430 wrote, "sits in the *main* list", now "sat");
- design "Its callers were the adapter only (pine_adapter.cpp:2605, ...)"
  for the deleted admission_retention -> its history (73817c1d);
- design "The dead helpers engine.hpp:1255, engine.hpp:1265, ... are the
  reference arithmetic" -> they are deleted; the kernel's own step is
  native_matching::apply_slippage;
- design P6 "(`sha256` `sha256` native-engine.md:421-435)" -> the page
  section "Stream limitations (current)";
- design "degenerate equity metrics (engine_metrics.cpp:3)" drops its
  anchor (pre-L2 behaviour).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 85910410f08abac32922125b4c3b0e2a01db598e)

INT26 pick note: the four pages conflicted where INT25 and H-MEASURE had
moved or rewritten the rows this commit re-cites. Each merged row keeps both
intents:
- ADR "Margin": this commit's three claimed citations, then H-MEASURE's
  measured paragraph unchanged.
- design rows 1-3, 5, 6, 9 and P4: this commit's re-citations (symbol claims,
  or "at `73817c1` (overtaken ...)"); INT25 had only moved their digits or
  re-hashed their pins. Rows 7 and 8 keep INT25's text (row 8 is
  C-SURFACE-1's current C-surface statement with its pins); this commit left
  row 7 alone and marked row 8's old statement overtaken.
- design (a) NEUTRALITY: this commit's `PASS` claim; main rewrote the
  AGENTS.md section it cited (116c461b), so the pin now covers main's
  "A campaign PASS verdict still binds the exact engine and codegen HEADs"
  (AGENTS.md:139-140).
- OL14 and pine-to-native's `pyramiding` row: word-level merges, INT25's and
  H-MEASURE's words with this commit's claims.
Every other hunk of 85910410 is carried (hunkcheck); citation digits are
re-anchored once on the integrated tree (INT26 item vii).

* Gates: the doc lint reads native-*/v<n>, the ABI numbers, VERSION and src/include paths (R5 lane H-DOCGATES, X13)

AUDIT4-opus docs-a GAP-6 (probes P19, P20, P29-P32): the lint was blind
to a dead `src/` or `include/` path, to a stale `native-consumer/v8` or
`native-driver/v4` domain, to "`PF_ABI_VERSION` is 3" and to "PineForge
0.13.1, the current release".

- rule 3's live hash domains also read every "native-<name>/v<n>"
  literal the tree declares (market_driver.hpp: native-driver/v5,
  native-consumer/v9, native-calendar/v1); rule 7 judges a marker on one;
- rule 5 reads `src/` and `include/` paths to a C/C++ file or directory;
  a `git show <ref>:path` object path and a file its clause calls
  generated are not dead;
- rule 8 (new): a stated PF_ABI_VERSION / PF_NATIVE_API_VERSION must be
  the header's #define; a higher number is a forward reference unless
  stated as current, a lower one needs the marker and a history framing;
- rule 9 (new): a PineForge release stated as the current one must be
  VERSION's.
Self-tests 55 -> 67 (MustFailH: P19, P20, P29, P30, P31, P32, a marker on
a native domain stated as now, a forward ABI number stated as current;
MustNotFireH: live values, forward/historical numbers, git object paths,
a generated header, a foreign crate's src/main.rs, a native domain as
history). Against 21bdc2e8's lint the eight must-fail cases fail and the
four controls pass (lint_selftests.before.txt in the lane scratch).

The tree had three offenders under the new rules, all in the design
record: row o (§2.ii) now says the admission journal "was"
include/pineforge/market_admission.hpp + src/market_admission.cpp until
N14 moved both under source/ (marked history), and §2.iii's O proposal is
spelled `c_native_host.cpp` like S's, not as a tree path. The lint reads
0 offenders; docs/ci.md lists the new families.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 845b07a5a345312bfa85a71fbfd9b5aeab514724)

* Tests: one random draw per statement at the fifteen sites the compiler ordered, and a lint that keeps the class out (R5 lane H-DOCGATES, X17)

AUDIT4-opus perf N-2: XPLAT1's bug class (e8bc3237) came back. C++ leaves
a call's argument order unspecified and a binary operator's operands
unsequenced; GCC on x86-64 draws right to left, AppleClang left to right,
so ten call sites in five test files (P7's and L2's fixtures, TA1's tests)
built a different random battery on each compiler. The lint finds five
more, in unsequenced `*` operands (test_adapter_live_state_equivalence,
test_native_direct_mutation x2, test_native_handle_stable_replace x2).

Each of the fifteen sites now takes one draw per statement into a named
local, in the order the arguments are written (AppleClang's), so no Mac
output moves:
- the 15 affected test executables, Release, AppleClang 17 (arm64):
  stdout before vs after identical in every non-timing byte (15/15);
- the same 15 in Docker xplat1-gcc13:amd64 (GCC 13, x86-64): before, the
  printed batteries differed from the Mac's in 7 tests
  (test_adapter_purge_index "14844 commands" vs 14575,
  test_native_settlement_carry, _fused_settlement, _in_place_reads,
  _precommit_hook, _quiet_point, _direct_mutation); after, x86-64 prints
  the Mac's bytes in all 15. Every test passes on both, before and after.
So the only output that moves is x86-64's random battery, onto the one the
Mac already runs; no pinned value, hash or fixture moves (nothing in these
tests pins a draw-dependent count, or x86 CI would have failed before).

scripts/check_rng_draw_order.py (binding preflight stages rng-draw-order
and rng-draw-order-tests): a draw is a call that advances a std:: engine
or a class whose members apply a PRNG step, found transitively through
drawing helpers and lambdas; it reports ARG (two draw-bearing arguments of
one call), OPERAND (two draw-bearing operands of an unsequenced operator)
and BYVALUE (a generator parameter copied while other arguments are
evaluated), and leaves the sequenced forms alone (one per statement or
declarator, braced-init lists, && || ?: and the comma, C++17's << >> []
= orders, lambda bodies). 21bdc2e8's tests: 15 findings; this tree: 0;
self-test 5 cases (a must-fail fixture of XPLAT1's three shapes and each
kind, a must-pass fixture of every sequenced form). CONTRIBUTING.md
lists the gate.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 7536bf01e0a4cbfdb32141b9065891048f4366a6)

* Tests: the runtime blocks' LIFO check gets a death row, and the chart-day memo a witness that reads it (R5 lane H-DOCGATES, X17)

AUDIT4-opus perf N-7 and D-17: two INT23 witnesses proved nothing.

1. uninstall_runtime_ambient's debug-build LIFO check (09ced53e, INT23)
   had no row: a mutant deleting it survived every profile.
   tests/test_native_runtime_ambient_lifo.cpp holds the legal order in
   process (each block's writes copied back down to the thread's own) and,
   in a forked child, the outer block leaving first: a library built with
   its debug checks (PINEFORGE_LIBRARY_DEBUG_CHECKS=$<CONFIG:Debug>, from
   tests/CMakeLists.txt; the TU strips NDEBUG like every test) must die of
   SIGABRT inside the call; any other library must return, leaving the
   thread's own block in force with the inner block's write lost -- the
   silent state loss the check exists to stop. Measured on a scratch copy
   of this tree: Debug "ok (16 checks)", Release "ok (19 checks)", Debug
   with UBSan ok; with the check deleted, Debug fails 2 of 16 (the child
   returned). This tree's Release kernel build: "ok (19 checks)".
   Source-free, so it runs in the kernel profile too: KERNEL_MIN_TESTS
   273 -> 274, RELEASE_MIN_TESTS 674 -> 675 (recorded below both floor
   lines so the pages' citations of them do not move).

2. test_chart_day_memo's `CHECK(pair.kept.holds_cache())` became vacuous
   with D2-C: the consumer holds the adapter's lookup index on every chart,
   so INT23's mutant cd5 (a memo never kept or read) passed. The new
   memo_witness reads the memo in place and plants keys in it (test-only:
   the index's day_lo / day_hi / day_key offsets come from a layout mirror
   of AdapterLookupIndex, held to the whole days UTC reads keep before
   anything is planted, so a drifting layout fails instead of writing over
   another member): on each UTC spelling a read keeps its whole floor day
   and key and a planted key answers exactly that day; on each chart
   timezone nothing is kept and a planted key is never answered.
   Mutants on a scratch copy: cd1-cd4 still fail; cd5 (never read), cd6
   (kept, never read) and cd7 (a zoned chart consults the memo) now fail
   where the old check passed all three. No source change: tests only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit d5ead4d5893e175f431bbd9b8d25f138fe6d5706)

INT26 pick note: the floors conflicted with the merged ones; each adds this
commit's LIFO death row to the merged value (KERNEL 279 -> 280, RELEASE
691 -> 692), with this commit's comment kept below RELEASE_MIN_TESTS so the
cited floor lines stay put. Every other hunk of d5ead4d5 carried.

* Docs: the deferred-performance inventory, the witness drift and the next script-ABI epoch's schedule are written down; three comments say what the code does (R5 lane H-DOCGATES, X17)

AUDIT4-opus X17 (perf N-1, N-4, N-5, N-6, N-9, N-10; K1-9; L4-10), the
documentation half. Comment-only for the three C++ files: their code and
literals are token-identical to HEAD's (scripts/cxxlex.py), and the
Release objects of src/native_calendar.cpp (which includes
native_calendar.hpp) and src/source/pine_strategy_host.cpp (which
includes pine_adapter.hpp) are byte-identical before and after
(sha256 ccd2c0b06f48..., c9ce59093717...).

- TLS wording: pine_strategy_host.cpp said D2-C left "no thread-local
  access per bar"; it left no thread-local WRITE. The comment now names
  the readers that still reach the block through the thread's pointer
  once per call (the extremum rings behind ta.highest / lowest /
  highestbars / lowestbars / stoch / wpr / range; the day partition behind
  the default ta.vwap, crosses_boundary(DAY) and the session-period
  helpers), measured 1.000 access a bar per call by AUDIT4.
- K1: native_calendar.hpp claimed every instant a held session day
  holds() keys to its ordinal; America/Sitka and America/Juneau in
  October 1867 under "2330-2300" hold 30 and 45 instants (all out of
  session) whose own session_day_at carries another ordinal. The comment
  states the guarantee where the cycles tile and names the exception.
- L4: the two retired receipt-reader slots and their waivers are
  scheduled for the next engine_script_run epoch (slot comment, both
  waiver rows, and the progress page).
- docs/native-refactor-progress.md "Deferred performance work": D2-B, the
  PERF-D3 S1a / S1b / S1c / S2 / S2e rows and the quiet-run loop, PGO,
  L3's compact records, checked-values handoff and chunked trades_ store,
  the zoned chart-day memo, and the thread-local readers that remain --
  each with its measured size (lane, host, tool), the ledger ruling that
  deferred it, where its prototype lives (perf-d2/proto-throwaway
  92e85571, perf-d3/proto-throwaway a820b7df, r5/l3 b33ea659) and what
  reopens it; "audit-off mode", "LTO" and "data-oriented layout" are
  struck until a design note defines them.
- "Recorded witness drift": K24's pre-size is dormant under Window
  retention; PERF-L4 reads the receipts 3.09 times a bar, not once
  (test_adapter_quiet_bar_probe on this tree: ReceiptRead asked 40996,
  81.8 % stopped at the gate, against 13248 for a once-per-bar gate);
  D2-C's carry counts moved 479/397 -> 489/412 at dbcca850 (bisected on
  macOS), and x86-64 now prints the Mac's numbers after this lane's
  one-draw-per-statement fix.
- The page joins check_doc_anchors.py's published set, so its 28 new
  citations are held; the pages' anchors that the comment lines shifted
  are re-anchored (native-engine.md, the ADR, the design record).

No sentence is deleted: the pages gain sections, and the re-anchors
change digits only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 2201c1ac15ef463a8f75867651ee96c45e993f04)

INT26 pick note: the ADR, design and native-engine pages conflicted on
citation digits only (int16_digit_merge per line, digits carried from the
pre-pick tree; one ADR citation of pine_strategy_host.cpp both sides moved
taken additively, 1925 -> 1931, re-judged at INT26 item vii). hunkcheck:
every hunk of 2201c1ac carried; two pages differ in anchor digits only.

* Docs+Gates: every kernel seam and every kernel member the source layer writes gets an ADR-0001 row, the account of TradingView-justified comments is complete, and a gate holds the inventory (R5 lane H-DOCGATES, X10)

AUDIT4-opus X10 found the ADR contradicting itself and the tree. Each
sentence was re-derived on this tree:

- The examples sentence claimed every C++ host includes only
  native_host.hpp. Three include native_toolkit.hpp or native_module.hpp
  (both include native_host.hpp) and the two C hosts include pineforge.h;
  "each including only `<pineforge/native_host.hpp>` (or `native_c_api.h`)"
  is rewritten to say so.
- The build_close_trade_with_costs row still said "One question stays
  open, recorded at the site: the net basis is applied to a host-owned
  excursion's magnitudes too (RULING A48's hook)". R5 lane F3 closed it in
  684800bf; the row now says so and scopes the net basis to the kernel's
  own sampled excursions.
- The neutral-spellings row said map.hpp and drawing.hpp are neutral names
  with deprecated pine_* aliases, "already ruled: "Neutral spellings" above"
  -- a section that does not exist, contradicting the residual table's
  PineMap row (primaries with no neutral alias). The row now names both
  cases and cites the two residual rows.
- "They do not yet account for the whole population" (the paragraph ending
  "until each gets a row or moves") and the Consequences bullet "Not yet
  fully accounted for" contradicted rule 2's "no site left unruled". Four
  Section B rows close the eighteen unruled lines the audit's closure grep
  found (the chart-day partition, the bar-time accessors, the offset sign,
  the grid and lot helpers); the paragraph now records the re-taken census
  (369 comment lines in 44 of 92 files, none unruled) and the bullet says
  the count is held by reading, not by a gate. Rule 2 pointed at "the
  section below"; the section is above.
- Rule 1 now names the generated-code language runtime and its admission
  test, which the three category rows apply.
- The subscriptions row listed four exclusions ("the sites the predicate
  leaves out (lower timeframe, lookahead, auxiliary, streams) keep the
  source evaluator"); declare_security_sites_to_kernel has fifteen and
  declares every site or none. The row lists them.
- Fourteen new rows in "Kernel state the adapter sets" cover every seam
  and member the new gate finds, including the two whole-struct
  current_bar_ writes (E21 check e), broker_fill_event_seq_, the dead
  source_stream_entry_comment (scheduled for the next script-ABI epoch in
  docs/native-refactor-progress.md), fold_exit_trail_peak_, NativeHostCache
  and the rows AG1/AG2 re-date. The dust sweep is recorded OPEN for lane
  H-THIN (A4-DUST); the position_entry_count_ overwrite is recorded OPEN.
- Design row RP5 said the short-seed swaps are "measured in §3.7 part 2";
  no row there measures them, and it now says so. The second "### 3.8"
  (lane F9) is §3.9, and RP9's "§3.8 records the old quadratic adapter fold"
  now points at it.
- Two engine.hpp comments were false: "Generated code reads them for Pine's
  bare ``hour``" (the transpiler emits pine_hour(..., syminfo_.timezone);
  no corpus strategy names a _bar_* accessor) and script_tf_'s writers
  "(both sites live in engine_run.cpp)" (the one writer is the Pine host).
  Comment-only, line-count preserving: all 86 library objects are
  byte-identical with and without the edit.

scripts/check_kernel_seam_rows.py (a binding ci_preflight stage, with its
must-fail suite as ci_preflight stage and CTest row test_kernel_seam_rows)
fails when a kernel `virtual source_*` seam, a BacktestEngine member the
source layer writes, or a Trade / PyramidEntry field written through the
kernel's rows has no ADR-0001 row naming it in its first cell. Over this
commit's parent it reports 43 without a row; here 0. It reads class bodies
itself: check_broker_state_hash_coverage.py loses a member declared right
after an inline function body (current_bar_, bar_magnifier_enabled_,
trace_buffer_). KERNEL_MIN_TESTS 274 -> 275, RELEASE_MIN_TESTS 675 -> 676.

Sentences deleted or rewritten, by the commit that wrote them: ca0aac5
(INT16's examples sentence), 2757095 (P2's lead-in of the mechanism
table), 5691220 (L14-C's neutral-spellings row), 2dd9834 (F2's "The rows
above account" paragraph and its "Not yet fully accounted for" bullet) and
d3cca9e (the gates paragraph's closing sentence, now naming the seam-row
gate beside the review record).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 4cbc6ab6c1d8925d2d9353fc030ab511665252f9)

INT26 pick note: the merged pages keep both sides.
- ADR-0001 inventory: INT25's K-ULP4 and K-ULP5 rows stay after the journal
  window row (its V19-FIX wording kept), then this commit's fourteen rows.
- ADR `subscriptions` row: this commit's all-or-nothing predicate list, plus
  the one clause it left out (`declare_security_sites_to_kernel` also
  refuses a registry whose `sec_id`s are not dense from 0), then H-MEASURE's
  measured sentence on what each reachable clause changes (c77ee9f9).
- ADR close-trade row: this commit's closed A48 question and H-MEASURE's
  report-only excursion columns (word merge).
- ADR rule-2 paragraph: this commit's gate list, then INT25's C-SURFACE-1.0
  transport ruling section unchanged.
- design RP5: H-MEASURE's measured short-seed sentence stays; this commit's
  "unmeasured: §3.7 has no row for them" was true only before H-MEASURE's
  `tests/test_short_seed_report_swap.cpp` (37090e19).
- floors: this commit's seam-row self-test adds one row to the merged
  values (KERNEL 280 -> 281, RELEASE 692 -> 693).
check_kernel_seam_rows on the merged tree: 3 seams, 44 written members,
0 without a row.

* Docs+Gates: the 1.0 C boundary -- every C++ capability the C surface does not expose, its reason and the checker row that fails when the gap closes; no page claims C/C++ parity beyond it (R5 lane H-DOCGATES, C-surface 1.0)

Supervisor ruling 2026-09-26: C-SURFACE-2 moves to 1.1.0, so the 1.0
docs list every C++ capability the C surface does not expose, each with
its reason and checker row, and nothing claims C/C++ parity beyond that
list.

docs/pages/native-engine.md "The 1.0 C boundary" replaces "What is not
exposed, and why", which named the five excluded host members and said
of the preview that "`strategy_native_execute_current_v1` answers the
same verdicts" -- it applies the command, so it is no preview. The table
has 27 rows: the five COVERAGE `[--]` members, the deprecated
hash_source_extension seam, the KernelRecordedAtHostMarks exclusion
(reworded: the kernel's mark is reached only by the Pine source host; a
C++ host records its own points), and 21 C_V1_EXCLUSIONS rows -- the
replace options, the applied event's tail, a closed row's entry comment,
closed rows in place, the working request's whole definition, the
open-ended session-day fact and the rest of the callback contexts,
host-sized openings, the terms hook's units answer, the excursion facts'
rate, the hash sink, the entry-bar mask outside on_applied,
timeframe_undetected, the inherited statistics, the hook views, the
command events' payloads, the command results, native_state()'s spec and
failure context, trace rows and hook re-declaration, the C++ library
around the host, and native_toolkit.hpp. The four C-SURFACE-2 items say
1.1.0; the rest say they have no lane.

scripts/check_native_c_api_surface.py: each C_V1_EXCLUSIONS row pins its
C++ declaration (a whole-word match) and one or more (C record, pattern)
pairs whose pattern must stay absent; every pattern tolerates a prefix
and a suffix (`\w*`), because the old draft's pins caught only the plain
spelling and let strategy_closed_trade_entry_comment_v1, a
keep_handle-carrying replace call, strategy_native_submit_bracket_v1 and
a request_origin / request_label applied tail through. The page must
cite every row exactly once and no row the checker lacks. Ten new
self-tests: those four spellings, a pf_native_applied_ext_v1 beside v1,
an input interval on the decision, a C++ declaration that goes, and a row
missing, doubled or made up on the page. Against this commit's parent
checker all ten fail (7 failures, 3 errors); here 29/29 pass.

Parity claims narrowed where they went past the boundary: native-engine
"`<pineforge/native_c_api.h>` is the C spelling of all of it", the
reading table's state / working / events / current-point rows (partial),
native_sized_units's C cell (it has one), the preview's C cell, the
report mark "the host calls the kernel's report mark", the spec
extension's "The one field of `NativeRunSpec` it deliberately does not
carry is `identity`" (also timeframe_undetected), on_close_units "the only
half this header exposes"; pine-to-native "needs no C++", the host-sized
answer "A C host answers the same question through `on_close_units`",
"Three rules make the C door behave like the C++ one" and the "Five
members have no direct C spelling" paragraph; README's three front doors
("so they match trigger, price fills, book lots and settle identically")
and "to its C++ **and** C spelling" (also index.md and contributing-llm);
the ADR's C API bullet, its route-or-ruling sentence and the
KernelRecordedAtHostMarks row; design §2.iii marked as the L13 plan.

Header comments (comment-only, line-count preserving; all 86 library
objects byte-identical with and without them): native_c_api.h's opening
("It is the C spelling of ... NativeStrategyHost"), the
inspect_current_execution COVERAGE row, the spec extension's omission,
on_close_units; native_host.hpp's C spellings of native_state, events,
current_execution_point, resolve_execution_terms, inspect_current_execution
and the two configure calls; native_order.hpp's HostSized note ("the C
surface refuses HostSized under any owner but BindCohort" -- a Book-scoped
WaitForApplied close is admitted too).

Sentences deleted or rewritten, by the commit that wrote them: f22a34e
(N8's "What is not exposed, and why" lead), d3cca9e (its five-member
list and the market-only note), 69228e6 (L14-C's native_sized_units and
preview C cells), 074f648 (F4's KernelRecordedAtHostMarks row reason),
2fcbb52 (F2's "Not every member of the C++ host has a C spelling"),
ca0aac5 (INT16's five-member sentence on the migration page) and 4fb9db3
(L14-B's CONTRIBUTING row for a C kernel-driving export).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 77a3eacb6e24fec8d98c1d074bfaf8943cdfdb9a)

INT26 pick note: this commit was written before INT25's KERNEL-EDGE
(409ebad1), which made the kernel's report mark installed C++ API
(`NativeStrategyHost::mark_native_report_point`, a COVERAGE `[--]` row of
native_c_api.h). Its sentences "The kernel's mark is reached only by the Pine
source host (it is not installed API); a C++ host records its own points
instead" are false on the merged tree, so:
- the ADR's KernelRecordedAtHostMarks row keeps INT25's text (a C++ host
  reaches the kernel producer through mark_native_report_point);
- native-engine.md's report-mark paragraph keeps INT25's text and adds this
  commit's C half: "A C host has no call that marks one (the 1.0 C boundary
  table).";
- the boundary table's KernelRecordedAtHostMarks row states the C++ mark
  route and cites COVERAGE `[--] mark_native_report_point` beside its
  ENUM_TWINS exclusion (the sixth excluded NativeStrategyHost member).
The C configure paragraph keeps INT25's "a second extended configure of a
Ready handle is refused without changing it" and takes this commit's two
omitted fields (`identity`, `timeframe_undetected`). The ADR paragraph on
report ownership keeps INT25's digits and takes this commit's boundary
pointer. check_native_c_api_surface: 64 members, 58 with a C spelling,
6 excluded; 21 C++ capabilities outside the 1.0 C surface, each pinned and
in the boundary table.

* Gates: a sanitizer build's quoted type name is judged as the name, and Eigen's assert text a debug archive carries has its own row (R5 lane H-DOCGATES, X12)

The sanitizers profile's run of the X12 vocabulary (lab remote job
rj-20260925t190344-64918a, NTU2, x86-64 GCC) failed test_kernel_residuals
on two strings a release archive does not carry:

- `'struct SymInfo'`: UBSan's type descriptor quotes a type's name. The
  line IS the name `SymInfo`, which is ruled, but X12 judged it as a text
  naming a ruled identifier. check_kernel_residuals.py now reads a quoted
  type name (GCC's `'struct X'`, clang's `'pineforge::X'`) as its names.
- `matrix.cols() == matrix.rows()`: the eigen_assert text of Eigen's
  eigenvalue solvers, which src/matrix.cpp instantiates, compiled in only
  when NDEBUG is off. X12's dotted-namespace vocabulary reads `matrix.`.
  It gets an ADR-0001 row by its exact words ("not residue": Eigen's
  parameter, not Pine's namespace), and a row whose second column says
  "absent under NDEBUG" is no longer called stale when no surface carries
  it, so the same row holds in release, debug and sanitizers.

ADR_RULED_TEXTS_MIN 45 -> 46. Five self-tests: both quoted spellings
pass as the ruled name and an unruled quoted type still fails, a quoted
Pine text is still a text, the debug-only text is not stale when absent
and covered when present, only a marked row may be absent, and an
unruled assert-shaped text still fails. Dropping the type-name rule fails
the first; dropping the debug-only rule fails the release table.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 68b974f2d2921fbe79c72d1b9642ad393cc67d66)

INT26 pick note: scripts/ci_verify.py conflicted beside INT25's PR-only
floors and ctest bound; ADR_RULED_TEXTS_MIN takes this commit's 46 and every
INT25 line stays. The residual gate on the merged tree: 174 ruled identifiers,
46 ruled texts, 0 findings.

* Kernel+C: the four deprecated public spellings are removed for 1.0 (lane REL10, item 1)

ADR-0001 "Deprecated public spellings" scheduled pf_equity_stats_t::sharpe_tv /
sortino_tv for removal at the next PF_ABI_VERSION and
exit_legs::Domain::Coof / MagnifierCoof at the namespace after lifecycle_v1.
They are removed for 1.0 without either epoch: an alias shares its storage or
its value with the primary spelling, so no offset, size, value, hash fold or
mangled name moves. PF_ABI_VERSION stays 4 and lifecycle_v1 stays
lifecycle_v1; the PF_DEPRECATED and PF_ANONYMOUS_UNION helpers leave
pineforge.h with them.

ADR-0001 rule 2: the kept spellings are the generic ones, named for the
resampling period and the fill-recalculation pass, not for a Pine or
TradingView setting.

- test_removed_public_spellings (F6's deprecation row, renamed; still one
  row): the 1.0 spellings compile clean under -Werror in strict C99 and in
  C++17, and each removed spelling alone fails with the unknown-member
  diagnostic that names it.
- Tests and the Python mirrors name the 1.0 spellings; the twin-parity guard
  matches the renamed CHECKs by literal signature, counts unchanged.
- The JSON report keys stay sharpe_tv / sortino_tv: docker/run_json.py writes
  the two C fields under them (EQUITY_REPORT_KEYS), pinned by
  scripts/test_report_schema_keys.py, a new ci_preflight stage.
- Every page that named an old spelling says what is true now; the ADR
  section keeps its heading and records the removal. Anchor digits follow in
  the lane's re-anchor commit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 38e8ad1e0f6a022e03d91e82f31d43ea66bef652)

INT26 pick note: dropping the four spellings drops their ADR residual row,
which H-DOCGATES (33aaf0b9) had widened to rule each alias's six texts by
their exact words; the row leaves whole, as this commit removes it, and the
residual gate's ruled-count floors in scripts/ci_verify.py fall with it
(ADR_RULED_IDENTIFIERS_MIN 174 -> 170, ADR_RULED_TEXTS_MIN 46 -> 40; the
gate on the merged kernel archive counts 170 / 40, 0 findings).
ci_preflight.py keeps H-MEASURE's subset-cover stage and adds this commit's
report-schema-key stage. pine-to-native.md takes this commit's text (line
141 on its tree), digits carried.


The sentences the removal retires, by the commits that wrote them: lane
P2c's deprecation ruling and its page notes (329e021), lane F4's strict-C99
anonymous-union note (0a46b45), the int12 guard pass's migration sentences
(9b50973) and INT16's wave-F reconciliation of the same pages (ca0aac5).

* Build: a release-candidate VERSION configures, builds and installs, and every surface names it (lane REL10, item 3)

VERSION may be X.Y.Z-rc.N (N >= 1). CMake's project(VERSION), the package's
PineForge_VERSION, PINEFORGE_VERSION_MAJOR / _MINOR / _PATCH / _STRING and
pf_version_get() stay the numeric X.Y.Z; PINEFORGE_VERSION_FULL,
pf_version_string() and the package's new PineForge_VERSION_FULL carry the
full version, -rc.N included. AUTO keeps git describe first (it already
resolved a vX.Y.Z-rc.N tag); FILE and AUTO's no-describe fallback now keep the
file's -rc.N instead of dropping it, and any other suffix fails configure.
version.h.in keeps its six placeholders: codegen's test harness renders
exactly those.

The installed-package smoke consumer prints pf_version_string() and exits 1
unless the package, the installed header and the linked library name one
version. scripts/ci_verify.py compares its print with VERSION, so the numeric
print it replaced would have failed every profile on an -rc.N VERSION.
test_cmake_version_source adds the candidate's archive, tag and
past-the-tag cases, the final release after its candidate, and the refused
prerelease spellings. No pkg-config file is added: integration-cmake.md says
the CMake package is the one that ships. That page now pins 1.x: the package
is SameMajorVersion, so a 0.x minimum does not find a 1.x install.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit dd6e9d843e24156e49be35ac4883f11ea2668116)


INT26 pick note: clean pick. Two sentences are rewritten rather than kept:
lane F2's statement of what the generated <pineforge/version.h> exposes for
0.14.0 (2fcbb52) now states the full and numeric versions, and lane FPC's
smoke-consumer sentence (4c9404c) keeps its -ffp-contract=off check inside
the rewritten smoke paragraph.

* Release: release.yml takes an exact override, a dry run and release candidates; its version arithmetic is a tested script (lane REL10, item 4)

scripts/release_version.py `next` computes current / next / tag / prerelease
/ previous from VERSION and the tags, and refuses anything but X.Y.Z or
X.Y.Z-rc.N, a version that does not sort above VERSION, an existing tag, and
a bump from a release candidate (its successor is always an exact override).
`previous`, the release-notes base, orders tags by semver precedence: the
YAML's `git tag --sort=-v:refname` put vX.Y.Z-rc.N above vX.Y.Z, so v1.0.1's
notes would have started at a candidate. `check-install` verifies a staged
install's version.h and package files before a tarball is packed.
scripts/test_release_version.py holds all of it as a ci_preflight stage.

release.yml:
- `override` (exact version) and `dry_run` inputs beside `bump`; `override`
  reaches only the script, through env.
- A release candidate is a GitHub prerelease, and the hub dispatch carries
  client_payload {version: vX.Y.Z[-rc.N], prerelease: true|false, run_id}.
- The prebuilt job configures with PINEFORGE_VERSION_SOURCE=FILE and verifies
  the staged version; the tarball keeps its pineforge-vX.Y.Z[-rc.N]-<triple>
  name.
- A dry run computes the version, builds, installs, verifies and packs every
  tarball (kept as workflow artifacts), and commits, tags, releases, uploads
  and dispatches nothing.
- The App-token commit / tag / push step is unchanged; a dry run skips it.
- The workflow publishes no container image, and its header no longer says it
  does: the GHCR image is the hub's.

ci_preflight's workflow-lint stage now lints release.yml too (the prebuilt
configure's intentional word split carries its shellcheck annotation).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 2bd8e2f3fb9307571b57167d20f892a25f53cd42)

INT26 pick note: ci_preflight.py conflicted beside H-MEASURE's subset-cover
stage; both stages stay and this commit's comment covers its two stages.

* Docs: the public contract for 1.0 (lane REL10, item 2)

docs/pages/public-contract.md states what the version number covers from
1.0.0, mirroring codegen's docs/PUBLIC_CONTRACT.md: versions and where the
full X.Y.Z-rc.N appears; the C ABI (PF_ABI_VERSION 4 for 1.x, frozen layouts,
append-only functions and enumerators); the native C++ API (source-compatible
within 1.x, not binary-compatible); the script ABI epoch engine_script_run_v19
and the stability of its state-hash values; the 1.0 C-surface boundary (the
exclusions listed in the native-engine page's "Driving the kernel from C",
where lane H-DOCGATES's 1.0 table lands; C-SURFACE-2
planned for 1.1.0); and the pairing rule -- engine and codegen share one version
number, the same X.Y.Z prerelease included, and the hub enforces it. Each rule
names the checker or CTest row that holds it on this tree, and the parts no
checker holds (a C signature kept by name, a C enumerator value against the
previous release, pf_report_t against a 1.0.0 baseline, C++ source
compatibility against a 1.0.0 baseline, the stream fingerprint's value) are
named as such.

Linked from README, docs/README, the site index, the CMake integration page
and CONTRIBUTING's new release step. pineforge.h's two hash comments no
longer say a fingerprint may change between builds: its recipe is the
epoch's.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 5f423b54fa8954c705fafde171f98ec0adf577f6)

* CHANGELOG.md: the 1.0.0 entry (lane REL10, item 5)

What 1.0 means -- the kernel runs without any Pine adapter, and Pine is an
adapter over it -- and what a 0.x user must act on since v0.13.1, the last
tag (VERSION read 0.14.0 from 439bd520 on, never tagged): C ABI 4 and the
grown pf_report_t, the renamed equity fields (JSON keys unchanged), the
regenerate-and-relink rule of the v19 script ABI epoch and the codegen
pairing, the new state hashes, the event-retention window default,
-ffp-contract=off reaching consumers, the moved pine_float_compare.hpp, the
0.x find_package pins a SameMajorVersion package no longer satisfies, and
prerelease versions; then the behaviour that moves results. Read from the
tags, the merged PRs #232-#288 and the public headers' diff between v0.13.1
and 1a0e7ea1, with each commit and PR cited checked against the history.
README points to it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit bda36e1fe578221727afff65883823f92d0b83c5)

* Kernel: a group's receipts follow its drain's queue order, so a re-price that keeps its handle inside a group no longer stops the run (R5 lane K-OCA-KEEP)

Ruling (ADR-0001 rule-2 row "the order of one cause's group-effect
receipts"): a drain applies a group's effect in queue order, whatever the
handles' numbers, and the receipts record that order. Generic, no knob.

Root cause (K-ULP5's finding 1, HIGH, pre-existing). A member's fill reaches
its live siblings through WorkingRequestCore::group_recipients, which walks
the book in queue order -- ascending LiveRequest::priority. A re-price with
ReplaceOptions::keep_handle (R5 lane V19-D) keeps the request's incarnation
and takes a fresh priority, so it moves behind younger siblings: queue order
and incarnation order part. The receipt store was bisected by (cause,
recipient incarnation, effect), and prepare_group_effect / apply_group_effect
refused any receipt that sorted before receipts_.back(). So the second
recipient of one cause -- the re-priced request, drained behind a younger
sibling -- was refused CoreFailure::InvalidCause and the consumer failed the
run (Contract, discriminator 1) after the member's fill was booked, staged
and direct, under Cancel and Reduce. K-ULP5's probe on 2a03c658: book
[inc 2 prio 2][inc 1 prio 3], recipients 2 then 1, receipt (21,2) committed,
(21,1) refused.

Which order is right: V19-D's contract is that a keep_handle run records the
plain replace's run -- every journal event, ordinal for ordinal. The plain
successor is the newest request and is drained last, i.e. in queue order.
Sorting the recipients by incarnation instead would drain the re-priced
request first and swap the group events' ordinals against the plain run.
So the walk's order stands and the receipt store follows it:
- receipts_ stays append-only in commit order (the consumer folds each once,
  by index, at its commit), ordered by cause alone;
- receipt_lookup bisects the cause and walks that cause's receipts (a drain
  of k recipients makes about k*k/2 comparisons);
- the order check refuses only a cause older than the newest receipt's.
A completed run's receipts were already in incarnation order within each
cause, and the lookup answers such a store as before, so no completed run
changes and no hash value moves. receipt_cmp is gone. The other walks
(waiting_children, bound_close_handles, the parent-terminal and owner-applied
drains) read no receipt order; the cohort rosters and the opening rows sort
by handle, which a keep_handle re-price does not change.

Tests: test_native_gro…
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