Skip to content

R5 documentation wave: doc guards, complete Pine-to-native map, LLM onboarding, native reference and ADR re-derived, Doxygen over the whole public surface - #272

Merged
luisleo526 merged 22 commits into
mainfrom
r5/int12-docs
Sep 21, 2026
Merged

luisleo526 merged 22 commits into
mainfrom
r5/int12-docs

Conversation

@luisleo526

Copy link
Copy Markdown
Collaborator

What

The R5 documentation wave — the last lane group before release, run after the code lanes so it documents the tree as it is. Twenty-one lane commits + one integration commit on main 0a47cbf7:

Lane Commits Content
L14-A 5 documentation infrastructure: scripts/check_doc_anchors.py (every file:line citation resolves to its symbol; --fix moves digits only when the answer is read; 992 anchors, 474 were wrong), scripts/check_doc_lint.py (lane labels, stale negatives, epochs derived from the tree, dead links), Doxygen over the kernel headers, the C header, examples, design and ADR documents (INPUT 26 → 96, layer groups, a scoped warning gate in docs/build.sh), 1021 header comment lines promoted so Doxygen reads them, docs/ci.md "Documentation guards"
L14-B 7 docs/pages/pine-to-native.md complete: 131 offered Pine names / 131 rows (113 native, 18 ruled none with the reason and where the behaviour lives), C++ symbol + anchor + C spelling + runnable host per row, "One strategy, three ways", the margin map, the six-feature worked migration EXECUTED against the kernel-only archive; scripts/check_pine_to_native_coverage.py as a binding preflight stage; two new examples (auxiliary finer feed; open lots with marked equity); docs/pages/contributing-llm.md; CONTRIBUTING.md rewritten; README front doors; site indexes
L14-C 9 docs/pages/native-engine.md re-derived section by section (every false negative replaced; new sections: policies, the intrabar path, spec validation, reading the run back, close causes); ADR-0001 rewritten with rule 2 amended to a two-part test (generic mechanism; no hash-visible knob) and every TradingView-justified kernel site ruled; design §1 closure markers held by scripts/check_design_inventory.py (fail-closed); 140 declarations documented
integration 1 the two doc guards become ordinary fail-closed stages (--strict-docs removed — the pages are clean), floors recomputed (kernel 193, release 558), Doxyfile inputs, the two page anchors restored, 30 read-resolved anchors, one lint false positive fixed

Engine untouched: 8 headers changed in comments only (comment-strip byte comparison), src/ unchanged. Epochs unchanged.

Evidence

  • Anchors 1545/1545 across every page, lint 0 offenders, coverage 131/131, design inventory 0 findings, kernel residuals 0 findings, rulings guard OK, Doxygen 0 warnings.
  • Integrated tree: preflight 25 stages with doc-anchors and doc-lint binding, release 558 (floor 558), debug 542, kernel 193 ran of 194 (floor 193), build-on 542; full corpus parity 312/312 with the pinned headline and the 30-probe subset (executor and supervisor runs).
  • Campaign sweep exp-r5-int12-docs-wave-20260922 on this head: execution pineforge-experiment-run-kssz4, 72/72 cases, 0 failed; 4190 graded, 0 coverage lost, band1 +0/−0, band2 +0/−0, hard regressions 0, leavers 0 — net 0 vs baseline snapshot e5e887ed / population dd8841c9 (candidate snapshot 97784230); pineforge-pr-gate-v4c5j reports target.not-positive, the neutral outcome at net 0 (a documentation wave cannot move a trade).

Merge with rebase.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Lg1KP7RXkwcEP2wFxXooy9

luisleo526 and others added 22 commits September 21, 2026 23:33
…ints at (R5 lane L14-A, item 1)

The pages cite the tree by `file:line`. Every header edit moves those lines,
so the citations rot silently: the second claimed-vs-actual audit found 108-115
of ~304 anchors wrong after a single campaign, and a reader who follows a stale
anchor lands on an unrelated declaration and concludes the page is lying. One
more hand re-derivation buys one more campaign; a gate is the durable fix.

scripts/check_doc_anchors.py reads the anchor grammar the pages already use -
bare name, explicit path, range, and the bare `:line` continuation - resolves
it through a stated search order, and, when a backticked symbol precedes the
anchor in the same table cell or sentence, requires that symbol on the cited
line. The scope rules are what make the claim honest: a Pine column never
lends its spelling to a Native column's anchor, a `strategy.risk.*` name is
never read as a symbol the tree declares, and the `closed_trade_*` and
`/ _exit_id` elisions are matched as the pages mean them.

`--fix` rewrites digits and nothing else, and only where the answer is read
rather than guessed: one occurrence of the symbol in the file's code (comments
stripped, because a paragraph about a name is not the name), or exactly one
type declaration of it. Everything else is reported with its candidate lines
and left for whoever rewrites the sentence.

The gate runs in ci_preflight as `doc-anchors`, advisory: it prints today's
drift without failing the integration branch before lanes L14-B and L14-C
remove it. `--strict-docs` makes it binding, which is how those lanes will
leave it. Its self-tests are not advisory - a guard that cannot fail is
decoration - and register as the `test_doc_anchors` CTest row; the row count
moves, and the integrator recomputes the floors.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit de0a860c71072b07d9380219faa143263b7a297c)
…lane L14-A, item 2)

`scripts/check_doc_anchors.py --fix` moved 257 of the 474 stale anchors onto
the line their own cited symbol occupies today. Every one was read, not
guessed: the symbol has exactly one occurrence in the resolved file's code, or
exactly one type declaration there. The drift is the gap waves' own growth -
`on_native_input` 440 -> 673, `native_marked_equity` 499 -> 913, `initial_capital`
159 -> 516 - so the pages' prose was right and only their coordinates were not.

The diff is line numbers and nothing else, and it is checkable: 179 removed
lines against 179 added, each pair identical once `:<digits>` is normalised
away. No sentence, row or claim changes here; that is the work of lanes L14-B
and L14-C, which now start from a 217-anchor residue instead of 474.

The 217 left are the ones a script must not decide: a symbol on several equally
plausible lines, a symbol that has vanished from the file it is cited in, and
eleven citations of files the tree no longer has (`runner/examples/…` after the
examples move, `include/pineforge/market_admission.hpp` after N14's header
move). They are listed per page in the lane report.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 21b9745f05addfa6668559f3da36ca86cac81d77)
…is live (R5 lane L14-A, item 3)

The anchor gate catches a coordinate that moved. It cannot catch a sentence
that became false: fifteen `lane L…` rows in pine-to-native.md name work that
landed campaigns ago, four "there is no … in this slice" claims in
native-engine.md are contradicted by symbols the same page documents, and
`engine_script_run_v17` survives where the tree is at v18. Those are prose, so
they get their own guard with its own report.

scripts/check_doc_lint.py holds four rules. A `lane L<n>` on a published page
is an offender: the migration guide says what the tree does, the roadmap lives
in the campaign. A "there is no … yet / in this slice / today" claim is an
offender unless its line carries `<!-- verified HEAD -->`, an explicit claim
that somebody checked it - and the real pages wrap those sentences over a line
break, so the rule reads the page, not one line at a time. A relative link
whose file or `#anchor` is missing is an offender, with both anchor spellings
the pages use resolved: Doxygen's `{#id}` and a heading slug.

The epoch rule is derived rather than listed. The live set is read out of the
tree - every `inline namespace <family>_v<n>` and every `"pineforge-…/v<n>"`
hash domain - and only another version of a LIVE family is stale. A hardcoded
`native_order_v[1-5]` would have flagged `native_order_v1`, which is the live
identity epoch even though native_order.hpp is at v6; and a derived set needs
no edit the next time an epoch bumps.

41 offenders on HEAD across 9 files, which is the point: this guard is
expected red until lanes L14-B and L14-C rewrite those sentences, so
ci_preflight runs it advisory beside `doc-anchors` and `--strict-docs` makes
both binding. Its self-tests are binding now and register as `test_doc_lint`.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit da5f7d83a7f167beb4646211eee3a84852ceb9b8)
…ad it (R5 lane L14-A, item 4)

The published site was one header and 25 pages. native_c_api.h — the whole C
host surface — was outside INPUT, ADR-0001 and the 944-line design document
never published at all, and the three native C++ headers were invisible: they
carry ~1000 lines of accurate, mechanism-level prose written as plain `//`
comments, which Doxygen does not read. A contributor arriving at the site
found a C ABI reference and no native API.

Four changes.

INPUT now covers the whole public surface: every header under
include/pineforge (kernel, source layer and compat/pine), the ten native
examples, the adapter's implementation units, the pages, the design document,
the ADR and the settlement note that fill-model.md already links. 26 inputs
became 96.

pineforge.h is named FIRST, before the directory that also contains it, for
the reason engine.hpp:37 already states about translation units: engine.hpp
defines PINEFORGE_NO_STRATEGY_DECLS and Doxygen carries a define across the
whole run, so parsed second, pineforge.h loses strategy_create / strategy_free
/ run_backtest / run_backtest_full / report_free and ~50 references to them
resolve to nothing. Ordering is the same fix src/c_abi.cpp uses.

docs/groups.dox declares the boundary the include graph cannot show: "Kernel /
native API" and "Pine adapter (TradingView-parity policy layer)", 19 and 16
files, each with the paragraph that says which one a given reader wants. It
groups files from one place rather than adding @InGroup to fifty headers.

The doc comments themselves: the declaration-leading `//` blocks of
native_host.hpp, native_run_spec.hpp and native_order.hpp are promoted to
`///` — 1021 lines, 165 declarations — so the prose that was always there is
now the API documentation. On top of that, the five parameters and two return
contracts that native_c_api.h's submit, replace, cancel_where and
execute_current never documented are written out, each naming
tests/test_native_c_api.c, and three `*`-inside-backticks spellings that
Doxygen parses as unbalanced markup are respelled.

Nothing under include/ changed but comments: strip the comments from all six
touched files at origin/main and at HEAD and the code is byte-identical.

The gate is scoped, because Doxygen's WARN_AS_ERROR is global and a stale
comment in a legacy adapter header must not stop the site from building.
docs/build.sh reads WARN_LOGFILE and fails only on a warning in the guarded
set — the kernel / native API headers, the C API header, the C ABI header, the
layer map, the examples — and prints the rest. Warnings went 3 over 26 inputs
to 0 over 96; injecting one broken @ref into native_host.hpp fails the build,
so the gate is not decoration. build.sh also feeds doxygen a config file
rather than stdin, which doxygen 1.18 aborts on.

Two anchors in pine-to-native.md moved with native_c_api.h's new comments and
were re-anchored by the checker; line numbers only, as before.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 67f3a44c60ee0adb11e29a101de350663866ab74)
…ne L14-A, item 5)

docs/ci.md gains a "Documentation guards" section: what each of the three
guards reads, the command to run it, what `--fix` will and will not do, and
why `doc-anchors` and `doc-lint` are advisory in the preflight until lanes
L14-B and L14-C clear the offenders they report.

The section's own description of the "there is no …" rule trips that rule, so
it carries the `<!-- verified HEAD -->` marker — which is the clearest possible
demonstration of what the marker is for, in the one place a reader learns about
it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 7485a40ad077809c67c4073d635e5b08c6086cfa)
…lane L14-B, item 1)

The second audit named two landed kernel features with no runnable host:
NativeRunSpec::auxiliary_feed (gap lane N7) and native_open_lots() (gap lane
N18). The migration page has to name an example for every row it claims, so
both get one, built exactly as lane P6 built its three.

native_auxiliary_feed_strategy.cpp runs 15-minute inputs over a 1-minute
auxiliary feed and declares a "5" series on it -- a series finer than the
input, which is refused by name without the feed
(NativeRunSpecError::SubscriptionWithoutAuxiliaryFeed). It checks each of the
twelve buckets against the hand aggregation of its own five minutes, checks
the routing rule by time (three buckets ride on the input whose period they
opened in, oldest first, before its calculation) and then decides on the
bucket the pull side answers.

native_open_lots_strategy.cpp pyramids a long three times on flat bars with
AfterCalculation close execution, so every number is exact, and reads the book
lot by lot: ordinals oldest first, one row per physical_position().lot_count,
native_marked_equity(mark) == balance + sum(unrealized_pnl) at every
calculation, a NaN mark that keeps the booking facts and computes nothing, and
a FIFO partial reduce that takes its share of the entry fee with the slice
(L2 keeps 1.5 units and 1.5 of its 2.00 ticket). It then reads Pine's report
namespace through the protected BacktestEngine accessors a host inherits, and
runs the same tape twice to show who folds the extremes: KernelRecorded folds
max_drawdown / max_runup / max_contracts_held_*, HostRecorded folds none of
them, and both runs close the same trades for the same money.

Registered as lane P6 registered its own: PINEFORGE_NATIVE_EXAMPLES, a
_pf_example_line_<name> for the CTest row's assertion, and the manifest of
scripts/check_native_include_independence.py. Two comments that counted the
examples are made count-free rather than re-numbered, so the next example does
not falsify them again.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit f4739a672d36c6fab8736d480cf01a15efa69d15)
…ete (R5 lane L14-B, item 2)

Both audits measured docs/pages/pine-to-native.md against the tree and found
the same two defects: 43 of 96 offered `strategy.*` names had no row at all
(the whole trade-statistics namespace, strategy.margin_liquidation_price,
strategy.default_entry_qty, the oca / direction / commission constants), and
15 rows routed a reader to a roadmap lane for a feature that shipped
campaigns ago. The page is re-derived here against HEAD.

Every offered Pine name now has a row: 131 of them -- the 96 `strategy.*`, 11
`request.*` and 4 `barmerge.*` rows of the repository's own Pine v6 inventory,
`strategy()` itself, and the 19 named arguments of the declaration that the
inventory collapses into one row. 113 map to a kernel symbol; 18 are ruled
`none`, which is a decision with its reason and the place the behaviour lives
instead, not a gap. Each row carries the C++ symbol with its file:line, the C
spelling through native_c_api.h or pineforge.h, and a runnable host under
examples/native/ (or the test) that exercises it.

No row names a lane. Where a mapping is not one-to-one the row says which way
it differs and cites the ruling of record -- ADR-0001's "Kernel capabilities
the Pine adapter does not declare" and the design record's section 3.6 -- so a
reader can tell a boundary decision from an omission.

New sections the audits asked for: a coverage table with the three counts and
how to recount them; "One strategy, three ways", the same trivial strategy in
Pine, in C++ and in C, pointing at hello_kernel.cpp and hello_kernel_c.c with
the three rules that make the C door behave (size-prefixed structs, a callback
that must return 0, on_recalculate replacing on_bar); a full margin and
liquidation map; and a six-feature worked migration -- cash sizing with a fee
reserve, a bracket on a price grid, a trail in ticks, a maintenance-only
margin model, a risk limit and a higher-timeframe series -- migrated end to
end reading only this page.

One fact the page states that no page stated before, found by writing
examples/native/native_open_lots_strategy.cpp: the equity extremes and the
position-size peaks are folded at the kernel's own report point, so they stand
at zero under the default HostRecorded policy and are the host's own. The
example runs the same tape under both policies and prints the difference.

scripts/check_pine_to_native_coverage.py derives the offered set from the
inventory and the covered set from the page's own first table column, checks
that the page's printed totals are the counted ones, and runs as a
non-advisory ci_preflight stage: a name added to the inventory without a row
fails the gate. The anchor checker reports 550 anchors, 0 bad, on this page.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 6ce318ce83d234bfd5ff44425941719b8f3e3dca)
…(R5 lane L14-B, item 3)

An agent handed a brief in this repository fails in two ways a human reader
does not: it writes a plausible sentence that is not true of this tree, and it
makes a test green without making it prove anything. docs/pages/contributing-llm.md
is CONTRIBUTING.md's ground rewritten so that neither is easy.

The boundary is ten numbered invariants, each paired with the script that
enforces it and the ADR section that rules it, so an agent can check a rule
rather than recall one. The repo map is a table of directory, purpose and the
guard that watches it. The lane recipe is the worktree and corpus setup, the
fail-before recipe against the previous header closure, the verification order
with the four traps that have cost other lanes a cycle (ci_verify re-pins the
corpus; never sweep beside a build; never checkout the LFS feed; ctest rebuilds
nothing), one commit per step, and the report shape.

Two sections exist only because agents get these wrong. The "never" list makes
the expensive habits explicit -- never cite a symbol from memory, never loosen
a pin without "expectation corrected", never change a lane's semantics in a
merge, never widen a guard's scope to pass, never claim an unexecuted run. And
"the places that look like duplicates but are ruled" names the nine pairs an
agent reading this tree concludes are dead code, each with its ruling of
record, because deleting one is a regression the guards catch late.

A glossary closes it: kernel, adapter, front door, twin, ledgered assertion,
floor, receipt, epoch, corpus pin, sweep, band 1 / band 2.

Registered in the Doxyfile INPUT beside pine-to-native.md. The anchor checker
reports 16 anchors, 0 bad, and the lint is clean on it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 9d2d59c43b0d590bbdc1f745d4bcebc35aa961c5)
…epository (R5 lane L14-B, item 4)

The previous file answered "how do I build and run ctest". It did not say what
the repository is for, where the boundary is, what the parity corpus actually
proves, or what a pull request has to show -- and three of its claims had gone
stale: a 30-binary suite "under a second", a 10-second ctest budget, and three
named functions that no longer exist.

The rewrite is the whole workflow. What the repo is, in a paragraph. The two
layers and the ONE rule, with the mechanical test for it ("if justifying the
change needs the word TradingView, it does not belong in the kernel") and the
two consequences that are easy to miss: every kernel capability is opt-in, and
a field the adapter never declares carries a ruling. A table saying where each
kind of change goes and what else it obliges. The test-first loop, with the
four shapes of non-evidence named. The gates as a checklist with the exact
commands and, for each, the specific way of being wrong it refuses. The floors
and the rule that adding rows means raising them in the same commit.

The parity contract gets its own section because it is the thing a newcomer
most reliably misunderstands: the corpus is a byte oracle at a pinned gitlink,
"moved" means any byte changed, the baseline rather than the corpus's own
trades is the oracle, and a refresh carries its evidence. Beside it, the
"expectation corrected: <old> -> <new>, because <mechanism>" rule for any
pinned number, spelled exactly so it stays greppable, and a pointer to the
epoch procedure for the internal C++ namespaces.

Commit and pull-request conventions are read off the history rather than
invented, and the campaign merge rule is stated in the terms it is actually
decided in: no individual regression, net movement >= 0, with the documented
net-0 exception and its recorded FAIL.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 7e6e2db9f42dd37e657369b705e07297ef7346fa)
…B, item 5)

Two claims the second audit measured as false are removed. Line 38 said "one
header, 65 extern "C" functions"; the surface is 97 across two headers, 65 to
run a compiled strategy and 32 to drive the kernel yourself. The architecture
bullet said a bare host "cannot size orders", that "the equity curve is
recorded by the host", and that "request.security() feeds have no native
registration API" -- all three false at HEAD, and each demonstrated by a
shipped example.

In their place the README states what is true and why it is true: every kernel
capability is opt-in, which is what lets adapter runs stay byte-identical by
construction, and a spec field the adapter never declares is a recorded
decision held by scripts/check_native_feature_rulings.py rather than dead code.

A new "Three front doors" section gives each way in its own short example --
Pine through codegen, C++ through NativeStrategyHost, C through the callback
table -- with the example source referenced by path rather than pasted, so the
README cannot drift from a file that compiles. It links the migration page the
goal names, which the README never linked before.

A new "Building, testing and the gates" section gives the commands as they
are (ci_verify.py release and kernel, ci_preflight.py, plain CMake), the CMake
options that matter including PINEFORGE_BUILD_SOURCE_LAYER=OFF and
PINEFORGE_BUILD_EXAMPLES, and the gates a pull request passes as one line each
with its script name and what it refuses: parity subset, row floors, kernel
residuals, feature rulings, the two C surfaces, twin parity and the three
documentation guards. It closes by pointing at CONTRIBUTING.md and the LLM
onboarding page.

The repository layout gains examples/native/ and the docs/design and docs/adr
directories, and the scripts/ line names the verifier and the guards rather
than only the corpus tooling.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 7dc3ae67a21a3d96244bc6642d8edae3012627d1)
…, item 6)

docs/pages/index.md carried four defects the second audit measured. Its @note
called the internal C++ headers "deliberately omitted ... not recommended for
direct external consumption" while the migration page tells a native author to
include native_host.hpp; it claimed "the entire public surface fits in one
header and 65 public PF_API declarations" when it is 65 plus 32 across two;
its worked-examples table had zero examples/native/ rows though the tree ships
fifteen with CTest rows; and it had no index of its own pages.

The page now opens on the two layers and the three front doors, and the @note
says what is actually internal: the Pine adapter's own headers. The API
section gives both inventories with the guard that pins each. The worked
examples are split into driving a compiled strategy and driving the kernel
yourself, the second listing every host under examples/native/ with what it
demonstrates. A closing index lists all 31 pages under docs/pages/ once, in
five groups, each with a one-line description -- including the two that carry
no Doxygen label and are therefore named by path.

docs/README.md described a docs/ tree that had moved on: a pages/ list of
fourteen files (there are 31), no design/ or adr/, no groups.dox, no ci.md,
and nothing about the guards a page has to pass. It now describes the tree as
it is, says which loose docs/*.md are published and which are engineering
records, explains build.sh's scoped warning gate, gives the anchor grammar an
editor needs with a worked example, and lists the three documentation guards
with their commands and their current binding state.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit a05208056a3da392c8b1c99f63478690a928484c)
…(R5 lane L14-B, item 7)

The audit's acceptance for G3 is that a reviewer can migrate a six-feature
strategy reading only the migration page. I did that: assembled the host from
the page's own sections 1-6, compiled it against libpineforge_kernel.a alone
and ran it. Three statements did not survive the exercise, and they are
corrected here rather than explained away.

1. The margin rule was stated backwards. The page said `initial_short = 0.0`
   is legal "because maintenance_short is unset"; the header says the opposite
   -- `initial_* == 0.0` is the maintenance-only spelling and is legal only
   where that side's `maintenance_*` IS set. A side with neither states
   nothing at all, and configure_native refuses the whole spec with
   MarginSideUndeclared, which is what the assembled host hit first. The
   long-only example now declares an ordinary short requirement and the prose
   explains the waiver rule as the header has it.
2. An anchored trail needs its arm_price present, holding the placeholder 0.0.
   The page's snippet passed std::nullopt, and the leg was rejected with
   RequestRejectReason::InvalidTrigger while the rest of the strategy ran --
   the worst kind of error, silent in the summary line. The snippet carries
   the placeholder and the comment that says why.
3. SubmitResult::handle is an optional, so the bracket owner is `*entry.handle`.

With those three, the host runs: the entry sizes 24.5096 units from 2500 of
cash net of the 0.1 % fee at the signal price on the 0.25 ladder, the
take-profit arms at fill + 40 ticks = 112.00 and fills there, the trail and the
stop are cancelled with it by their OCA group, the margin model admits the
opening and never liquidates, and the risk limit is declared and not breached.
The run and its output are recorded beside the lane's report.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit b4353d0bfc36cad4f2339db1d8c903e285bbf5b7)
…ection (R5 lane L14-C, item 1)

Every sentence of docs/pages/native-engine.md re-read against the header or
test it cites, and rewritten where the tree contradicts it.

The false negatives are gone, each replaced by what HEAD offers: there IS a C
request API (strategy_native_submit_v1 and its four siblings), there IS a
partial-bar view (current_partial_bar, NativeOpenBarView::OpenOnly), there IS
a native subscription API (the whole "Higher-timeframe series" section two
screens above the sentence that denied it), there IS a kernel-only target
(PINEFORGE_KERNEL_SOURCES, add_library(pineforge_kernel)), and generated Pine
code has not been on a "compatibility route" since PineStrategyHost became a
NativeStrategyHost. src/compat/pine/market_admission.cpp is in the source
layer's own list, not outside it. A C host submits on a stream like any other.
The host epoch is engine_script_run_v18 and the source-adapter hash domain is
pineforge-source-adapter/v3.

The "interim" self-aggregation recipe was true and mislabelled: a host that
wants the running aggregate and none of a series' delivery rules still writes
it. It moves next to the subscriptions it is an alternative to, says what it
does not give you, and stops pretending the subscription API is unbuilt.

New sections for the surface the page never named: the feed-shape and
path-order policies, the intrabar path and its three alternatives, spec
validation and its two result types, "Reading the run back" (every const
query with its C spelling), the closed row's close cause, and cohorts.

Roadmap labels are out. A published reference tells a reader what the tree
does; "lane L8b" tells them nothing they can look up. The examples table's
lane column is now the suite that pins the same surface.

check_doc_anchors: 102 anchors, bad=0. check_doc_lint: clean.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 97926eadfa30046c49ed271cf4a7177d1874e79f)
…dard the waves applied (R5 lane L14-C, item 2)

The seven false sections describe a tree that no longer exists, so they are
gone: there is a kernel-only target and the two source sets are disjoint (no
"boundary bug"); the C API trades (submit / replace / cancel / cancel_all /
cancel_where / execute_current, and streaming needs no new symbol); the
examples are a gated target whose rows assert exit code AND output; the run
spec is no longer narrow; request.security series ARE reachable from a bare
host; the equity curve is a report-policy choice, not a host chore; the
domain is pineforge-broker-state/v18; there are six intents, not five; there
are four margin seams, not one.

Two of the "four rules" earlier drafts named are also gone, and saying so
took reading the code rather than the comment: there is no
set_margin_call_enabled in the tree, and closed_trade_close_cause compares no
string — it reads a typed execution::CloseCause and answers 3 for a KERNEL
liquidation. What is live is one hashed pair, the intrabar-fill excursion
mask. The 1051-line path resolver is gone too; the repository holds one fill
simulation.

Rule 2 said "if justifying it needs the word 'TradingView' it belongs in the
adapter", and the tree does not pass that. It never could: a calibrated
number has to say what calibrated it. The amended rule asks two things
instead — is the mechanism drivable for another venue by data, a spec field
or a hook (else it is the adapter's), and would the alternative be a
hash-visible knob over a choice the run already made (else it is a hook, not
a field) — which is the standard that ruled the feed partition and the
SymInfo::type vocabulary generic while the per-order-kind tick rules and
strategy.risk.* stayed adapter-side.

A new section accounts for every TradingView-justified kernel site against
the amended rule. Taking that population found something the audits missed:
of the ~20 sites they named as "compiled kernel", eight document functions
the lowerings deleted — from engine_orders.cpp:560 to :697 the file has no
code at all — so the deferred-flip growth rule, the opening margin guard, the
same-tick sequencing, process_orders_on_close, the signal-bar sizing freeze
and the intrabar liquidation are rule-5 comment residue, not rule-2
questions. The rest are live, each generic with its calibration recorded, and
each pinned. No site is left unaccounted for; two are recorded as open
questions rather than violations.

The residual tables N14/P2/P6 wrote are byte-for-byte unchanged.
check_kernel_residuals: 109 archive hits, 0 findings. check_native_feature_rulings:
10 ruled fields, exit 0. check_doc_anchors: 217 anchors, bad=0.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit d496afd14dba8e038b058126a04d5897dcda0cb9)
…them there (R5 lane L14-C, item 3)

Thirty-eight §1 rows read **no** or **partial** for capabilities a passing
kernel-profile test drives. The audit named five; reading the table against
the tree found the rest — every sizing basis, the whole margin model, every
risk limit, the calculation triggers, the subscriptions, the auxiliary feed,
the price grid, the recorded curve, the per-bar hashes, the host hash
extension, the C order API.

The repair is the convention the table already used for N6 and N7, not a
verdict rewrite: a row keeps the finding it recorded — that is the audit's own
record of what the campaign found — and appends "**Closed:** <what landed>
(`tests/…`)". Flipping the verdicts would have destroyed the record; leaving
them alone left the document lying.

Row g is rewritten: the legacy path resolver's move happened and then the
thing itself was deleted, so engine_path_resolve.cpp is 95 lines of three
generic functions and the repository holds ONE fill simulation. §2.ii items e,
f, j, k and l are done too — the dead helpers, the dead stream path, four of
five Pine-shaped lot flags, the margin-call toggle and the string-sentinel
decoding are all gone from the tree — and §2.vi's correction list has been
applied, which this lane did.

§3.2 gains the twelve audit lanes that landed on main, each with the last
commit of its own.

scripts/check_design_inventory.py holds the convention. "Runs in the kernel
profile" is not a heuristic: it is tests/CMakeLists.txt's own decision,
transliterated — the TEST_SOURCES list operations replayed, then
pineforge_test_reaches_source_layer's transitive quoted-include walk, plus the
add_executable targets the reach filter does not cover. --ctest-list
cross-checks that reimplementation against `ctest -N` from a real kernel build
dir, in both directions, so a drift from CMake is reported rather than
believed; on this tree the two agree, 125 TUs against the kernel profile's 192
rows.

22 self-tests: six must-fail (a no row with a kernel witness, a partial row,
a qualified partial, a marker whose only witness is source-bound, a cited
test that is not in the tree, and a ctest listing that disagrees each way),
eight must-not-fire (the two marker spellings, an adapter-only gap, a
transitive reach through a local header, a quirk row, a waiver row, a pure-C
target, a REMOVE_ITEM'd member) and five shape cases that exit 2 rather than 0.

Wired into ci_preflight as design-inventory plus its self-test stage, and
fail-closed from the start: it holds a convention every row already follows,
so it has no drift to report and nothing to wait for.

ci_preflight --output-dir build-ci-preflight: PASS, 24 stages, both new ones
passed. check_doc_anchors: 654 anchors on this page, bad=0.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit ab5b2ecc8114773f933eb427fc6841a18a457688)
…so in its own header (R5 lane L14-C, item 5)

The docs build's warning count for the native headers was already zero, before
this lane and after it: docs/Doxyfile sets WARN_IF_UNDOCUMENTED = NO
deliberately, so an undocumented declaration is not a warning and there were
none left to close. What there was instead: 132 top-level public declarations
in the five headers the reference page's own sections describe, carrying no
doc comment at all — the lifecycle and failure model, the whole query surface,
every command, the FX curve, the feed-shape policies, the intrabar path, spec
validation, the driver coordinate, and the request values a host actually
writes.

Each now carries a /// block in the standard L14-A set: what it is, when the
kernel consults or answers it, what the return means, the C spelling beside
the C++ one, and the test that exercises it. A reader who jumps from the page
to the header lands on prose rather than on a bare signature, which is the
point.

Comment lines only, proven two ways: the diff of non-comment lines since this
lane's base is empty, and stripping every comment from each touched file at
origin/main and at HEAD leaves the code byte-identical. The kernel archive
rebuilds and the docs build stays at 0 warnings.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 45101edc909d796bf1280262b82aaea6c7c00554)
… (R5 lane L14-C, item 4)

Item 5's doc comments moved every line the three pages cite in native_host.hpp,
native_run_spec.hpp, native_order.hpp, native_fx_curve.hpp and
market_driver.hpp. 247 anchors re-anchored, digits and nothing else: 230 by
check_doc_anchors.py --fix, which moves a citation only when the claimed
symbol has one occurrence or one type declaration in the resolved file, and 17
by reading — twelve of them the `on_native_bar`, `cancel_where` and `replace`
overload pairs, where the declaration is the first of the two and the second is
its body or its options form.

With this, every `file:line` in the three pages this lane owns names its
symbol on this tree: native-engine.md 102/102, ADR-0001 217/217,
native-feature-parity.md 654/654, bad=0 on all three. The lane's own repairs
included the three NOFILE citations N14's header move created — the
market_admission.hpp observation fields now cite
include/pineforge/source/market_admission.hpp — and the historical citations
into files the campaign deleted, which are spelled as
`git show ab9714b:<path>` rather than as a coordinate no reader can follow.

docs/pages/pine-to-native.md is L14-B's and is untouched here; 63 of its
anchors moved for the same reason and `check_doc_anchors.py --fix` repairs
them mechanically.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit bf6d607453ef3b8c90368d21e77df6299f310fb1)
…4-C, item 2 follow-up)

"Roughly 250" was an estimate. Measured: engine_orders.cpp :200-224 and
:556-697, engine_run.cpp :162-186, engine.hpp :1262-1381 — 312 lines, with
zero code lines inside any of the four spans.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 6b8776599ca6e374a3a9fe49ebf9f64cba3b8245)
… to say (R5 lane L14-C, item 1 follow-up)

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit cbf91a99101b353b6bcddcdfbe2b6033908c291d)
…a risk flatten carries (R5 lane L14-C, item 5 follow-up)

Comment line only. The enumerator is set at native_execution_consumer.cpp:3332
and read back by tests/test_native_risk_limits.cpp:392.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit d0581cdc9debec86af35e4ce59d1a578780641d9)
…R5 lane L14-C, item 4 follow-up)

Digits only. Every anchor of the three pages this lane owns names its symbol
again: native-engine.md 102/102, ADR-0001 217/217, native-feature-parity.md
654/654.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit dc8b57f9eb2ebe6bc929edef16052803a6f0532d)
…12, documentation wave)

The three documentation lanes are cherry-picked above this commit. Each one
passed its own gates on its own base; this is what the union of the three
needs, and nothing else.

The guards go binding. `--strict-docs` was L14-A's ruling that a guard may
report rather than fail while the drift it names is exactly what the next two
lanes exist to remove. Those lanes have landed: the anchor checker reports
bad=0 on every page and the lint 0 offenders, so the flag is removed rather
than flipped -- a guard that can be asked not to bind is decoration. The
advisory *mechanism* stays in `ci_preflight.py`, with its self-test, for the
next guard that lands before its drift is gone; no stage uses it today.
`CONTRIBUTING.md` joins both guards' globs: L14-B rewrote it whole and checked
it by hand, and nothing kept it true.

The anchors. L14-C's 528 header comment lines moved 307 of the anchors in
L14-B's rewritten `pine-to-native.md`, which is what happens when two lanes
branch from the same tip and one of them edits the headers the other cites.
`--fix` re-anchored 277 of them; the remaining 30 are symbols the checker
refuses to guess at (`side` on eight lines, `Cancel` on two). Each was
resolved by mapping its line through the 7485a40a..HEAD diff of the header it
cites and reading both texts: all 30 old lines survive verbatim, so the
coordinate moved and the claim did not. Two of the 30 differ from the
checker's first candidate -- `cancel_where` is the `NativeRequestField`
overload, not the one-argument one, and `FromOwnerFill::ticks` is the flag,
not `TrailTicks::ticks`.

The two page anchors `native-engine.md` links to, `{#pine_to_native_map}` and
`{#pine_to_native_map_trades}`, were dropped by L14-B's rewrite (it split the
one "Concept map" section into ten). Restored as `@anchor` commands so that
L14-B's per-section ids are kept as well.

Doxygen builds at 0 warnings over all inputs, not only over the guarded set.
Four references from L14-B's pages pointed at files outside `INPUT`. The
front doors are now published -- `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`,
`LEGAL.md`, `SECURITY.md` -- and the two engineering records they also named
are cited by path instead, because `docs/README.md` states that split and a
record is not a page.

The lint's last offender was its own false positive: `Series<T>::operator[](k)`
inside a code span reads as a markdown link to a file named `k`. An inline code
span is not a link, for the same reason L14-A ruled that a fenced block is not
a citation; only the span's content is masked, so a real link whose label is
code is still read. Two self-tests, one each way. The fourteen other offenders
name their epoch correctly -- historical baselines, frozen providers, and P2c's
`lifecycle_v2` removal epoch, which is forward, not stale -- so each carries
the `<!-- verified HEAD -->` marker the rule provides.

P2c landed on main after all three lanes branched, so the migration page still
offered the deprecated spelling as the primary one: its `risk_free_rate` row
now names `sharpe_monthly` / `sortino_monthly` and records `sharpe_tv` /
`sortino_tv` as the deprecated aliases of the same two doubles, with the
serialized report key unchanged. ADR-0001 keeps both sections whole -- P2c's
"Deprecated public spellings" table and L14-C's rewritten feature-gate rulings
-- which `check_kernel_residuals.py` (109 archive hits against 119 ruled
identifiers and 11 ruled texts, 0 findings) and `check_native_feature_rulings.py`
both still parse.

The floors, recomputed on this tree under lane Q12's ran-rows rule:
`KERNEL_MIN_TESTS` 189 -> 193 (194 registered, the WebSocket row still skips)
and `RELEASE_MIN_TESTS` 554 -> 558. Both +4, the same four rows: L14-A's
`test_doc_anchors` and `test_doc_lint`, and L14-B's two example hosts.

Cross-lane corrections the union tree still needed: `native-engine.md`'s
"all thirteen sources" is fifteen (L14-B added two examples), `docs/ci.md`'s
"three guards" is four and its "ten native examples" fifteen, and the kernel
row floor the page quotes is the recomputed one. The three L14-C flagged in
L14-B's pages -- README's opt-in sentence and `index.md`'s two counts -- were
already true here: L14-B's later commits fixed them after L14-C read them.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Comment thread scripts/check_doc_lint.py

import argparse
import re
import sys
@luisleo526
luisleo526 merged commit 9b50973 into main Sep 21, 2026
13 checks passed
luisleo526 added a commit that referenced this pull request Sep 22, 2026
The pages cite the tree by line number and both doc guards are binding since
the documentation wave (PR #272). Wave D moves those lines a long way:
`include/` loses 411 net lines to lanes E6 and E10 (engine.hpp alone -400),
`native_c_api.h` gains E7's two enums, E11's symbol, E13's readout tail and
E14's request tail, `native_order.hpp` and `native_execution_consumer.cpp`
both grow, and `src/source/pine_adapter.cpp` moves under E5, E9 and E14. On
the picked tree 574 of 1553 anchors were bad; none of that is a claim
changing, only where the claim lives.

Three passes, in this order:

1. `python3 scripts/check_doc_anchors.py --fix` until it converged
   (358 anchors re-anchored, 216 left that it refuses to guess at).
2. The 216 it refuses are ambiguous only to a symbol search. They are not
   ambiguous to the diff: every one of them was correct at origin/main, which
   the wave's own gate proved (bad=0), so each was mapped through
   `git diff -U0 origin/main..HEAD` for its own file and rewritten to the line
   the wave moved it to. 159 doc lines.
3. Five anchors survived that, because they were not line drift but claims the
   wave made false. Each is corrected by reading:
   - `native-engine.md` cited `record_script_report_point` at the call site
     lane E2 moved; it now cites the definition.
   - `native-feature-parity.md` row (e) cited `apply_slippage` "in the comment
     at engine.hpp:2129" — lane E10 deleted that comment; it now cites
     `src/native_matching.hpp:240`, where the function is.
   - `native-feature-parity.md` rows (j) and 7 and ADR-0001's "current state"
     bullet said the excursion mask pair is "written only by the adapter" at
     `pine_strategy_host.cpp:471`. Since lane E6 no host writes it: the
     excursion owner declares where its fill sat and the kernel derives the
     pair. The three citations now name `declare_opened_lot_entry_bar_mask`.

Four citation corrections the lanes asked the integrator for, in files main
owns after PR #272:

- The ten-significant-digit money residue was `engine.hpp:918-952`, not
  `:73-180` — measured by lane E6, which deleted it; `:73-180` is and was live
  code (`ClosedLotExcursionFacts`, `PyramidEntry`, `Trade`). Corrected in all
  four places that carried the wrong span: ADR-0001's "current state" bullet
  and its residue-table row 8, `docs/pine-adapter-kernel-notes.md:16`, and
  `native-feature-parity.md` rows (d) and 7.
- ADR-0001 said `<pineforge/native_c_api.h>` implements **32** additive
  symbols. Lane E11 added the 33rd.
- ADR-0001 recorded two rule-2 open questions. The wave closed both: the C
  delivery words are typed (lane E7's `pf_native_lookahead_e` /
  `pf_native_gaps_e`), and the excursion mask pair has no host writer (lane
  E6, with E11's C spelling and E15's declared-order derivation). Both bullets
  now say so, and say what is left: the pair is still durable hashed lot
  state, so removing it is still an epoch decision.

Also folded in, from the picks themselves rather than from a lane's own file
list: lane E14's new `##` ADR section was moved into the documentation wave's
"TradingView-calibrated kernel mechanisms" table B (a standalone section
beside the residual vocabulary reads as stale to
`scripts/check_kernel_residuals.py`), and the header's two asymmetry notes
were reconciled — `pf_native_working_v1` did grow a readout tail (E13), and
the trail seed is still deliberately not read back (E14).

Gates: `check_doc_anchors.py` 1555 anchors, bad=0 on every page;
`check_doc_lint.py` 0 offenders; `check_pine_to_native_coverage.py`
offered=131 covered=131; `check_design_inventory.py` 0 findings;
`check_native_feature_rulings.py`, `check_kernel_residuals.py` and
`check_native_c_api_surface.py` all clean.

One header edit rides here because it is the same kind of rot, caught by
`bash docs/build.sh` rather than by the anchor gate: lanes E7 and E11 wrote
their doxygen cross-references against the enum TAG (`#pf_native_lookahead_e`,
`#pf_native_gaps_e`, `#pf_native_opened_lot_fill_point_e`), while this header
indexes and every other row cites the typedef (`#pf_native_intent_t`,
`#pf_native_size_price_t`). Doxygen could not resolve the three, and E11's
block left `@param s` undocumented while documenting the other three
parameters. Four warnings; with the references pointing at `..._t` and `s`
named, `docs/build.sh` reports **0**.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@luisleo526
luisleo526 deleted the r5/int12-docs branch October 5, 2026 02:43
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