Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ endif()
# === pineforge library =================================================
add_library(pineforge STATIC
src/c_abi.cpp
src/compat/pine/order_birth.cpp
src/compat/pine/order_priority.cpp
src/engine_aux_security.cpp
src/engine_fills.cpp
Expand Down
32 changes: 17 additions & 15 deletions docs/pages/abi-stability.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,30 +112,32 @@ notice:
- The shape of internal log lines (use them for humans, not parsers).

Rebuild generated and native C++ objects against matching engine headers and
runtime. The cap and priority extractions change the v2/v3 object layouts and
therefore use the internal `engine_script_run_v4` inline namespace. An object
built from base `38dc73e` headers references v2 out-of-line members and must
fail to link to this v4 runtime. The source-pairing check compiles frozen exact
base headers separately before testing the link, so a missing include or
compile failure cannot masquerade as mismatch protection. Frozen f864/v3 headers are also rejected by this v4 runtime. Both generated-style
and native-style current callers must still link.
runtime. The integrated quantity, predecessor and order-birth representation
changes `PendingOrder` and uses internal `engine_script_run_v5`. Exact frozen
c45/v4 headers are compiled before link tests: both native and generated-style
v4 callers must fail to link to the v5 archive, while matched v5 callers link.
Earlier exact base38/v2 and f864/v3 mismatch controls remain. A compile failure
cannot masquerade as mismatch protection; no pairing executable is run.

`PINEFORGE_HAS_SCRIPT_RUN_PREPARE_V1` remains 1: it describes the existing hook
capability, not the class layout version. Regenerate and rebuild a strategy
module to obtain complete script-state reset; replacing an archive does not
retrofit an old module. Public C function signatures, POD layouts,
`PF_ABI_VERSION` (4), and `strategy_stream_api_version()` (1) are unchanged.
retrofit an old module. Public C function signatures, `PF_ABI_VERSION` (4),
and `strategy_stream_api_version()` (1) are unchanged. The pending-order v1
mirror keeps all 108 existing field names/types/offsets and its full old prefix;
new typed facts append, and removed native booleans survive only as read-only
derived outputs. Size-limited reads keep old callers within their buffers.

Namespace versioning protects referenced internal C++ symbols; it does not
validate an erased `pf_strategy_t` handle. Use a handle only with functions from
its creating strategy module. A fully self-contained old module can still use
its own matching runtime; this check does not turn it into a v4 module.
its own matching runtime; this check does not turn it into a v5 module.

The cap and priority boundaries advance the broker fingerprint domain to
`pineforge-broker-state/v4` and stream fingerprint version to 4. These identify
changed serialized state, including Pine priority attachment/configuration, cap quota/cause and
separate generic close request. The Pine component schema remains 1; it is
independent of the aggregate fingerprint version. Prior v2/v3 fingerprints are
The integrated representation advances the broker fingerprint domain to
`pineforge-broker-state/v5` and stream fingerprint version to 5. These identify
changed serialized quantity/reservation, predecessor and birth facts, alongside
existing Pine policy state. The Pine component schema remains 1; it is
independent of the aggregate fingerprint version. Prior v2/v3/v4 fingerprints are
not comparable. Fingerprints are replay checks, not serialized checkpoints or
complete hashes of private strategy state. The native runner already binds
its strategy-library SHA; its ledger format and Python provenance fingerprints
Expand Down
61 changes: 61 additions & 0 deletions docs/pages/quantity-intent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
`PendingOrder::quantity_request` separates an exit's original requested amount
from the numeric reservation made for that request. It replaces two stored
booleans that mixed those lifetimes.

`QuantityIntent` contains exactly one of `Units(amount)`,
`Fraction(numerator, denominator)` or `All`. Fractional requests retain their
original representation; the Pine boundary supplies percentages as `P / 100`
without a floating-point divide/multiply round trip. An absent request belongs
to pending commands outside this exit-request contract. These are request
descriptors, not an additional numerical-admission policy.

`QuantityReservation` records admitted units and the exposure basis used when
reserving them. A new request clears the old reservation; a reservation cannot
exist without an original request. Deferred exits acquire this receipt when a
live owner is bound. Additional per-entry bindings copy the original request
and record their own admitted amount and basis. Copying is by value.

`qty` and `qty_percent` retain their current executable/reserved meaning in the
existing order paths. OCA can reduce executable quantity without changing
the original intent or its prior reservation receipt. Whether that receipt
covered less than its basis is a derived numerical comparison, using the
existing caller-supplied tolerances. A deferred fraction can be classified
before resolution; an unbound Units request cannot infer coverage without a
numeric basis.

Consequently, a half-position request rounded to a minimum one-unit slot may
have `Fraction(50, 100)` intent and a full `1 / 1` reservation. Conversely an
`All` request clipped behind another reservation may hold only `3 / 4` of its
basis. Neither case can be represented correctly by one “partial” label.

Deferred market-close instructions are another producer: `strategy.close`
has already resolved its source amount to a placement target before
`queue_deferred_close_order` runs. The request records that resolved source
target as `Units(qty_to_close)`, without an exposure reservation until a later
layered binding occurs. This is not a fixed executable-quantity promise: the
preserved Pine ANY-relative rule can turn target 1 on E2 into reservation 2
with basis E4 after reversal. The initial target remains 1 while executable
`qty` and the later reservation are 2. It does not claim to retain the original
Pine percentage expression; that conversion already occurred. This preserves
the old initial nonpartial classification without fabricating a basis.

The Pine percentage rounding, minimum-slot, reservation retention, one-shot
exit-ID and deferred/replacement policies remain explicit compatibility debt
in their existing callers. This change does not generalize those policies or
change their thresholds, financial assertions or execution order.

The public `pf_pending_order_v1_t` retains its complete existing field prefix.
Its `requested_partial` and `full_percent_exit_request` fields are deprecated
read-only projections derived from the new authoritative values; native
decisions never read those output fields. New fields append:

- `quantity_intent_kind`: 0 absent, 1 Units, 2 Fraction, 3 All.
- The relevant units or fraction numerator/denominator; inactive values are 0.
- Reservation presence, admitted units and basis units.

All new facts and optional-presence discriminators participate in broker
hashing and mirror output. They are not waived. C ABI version 4 and stream
API version 1 remain unchanged, and size-limited mirror reads preserve older
callers. The internal C++ layout changes, so all consumers require a matching
rebuild and the integrated representation change requires a new internal
namespace/fingerprint epoch before publication.
53 changes: 53 additions & 0 deletions docs/pending-placement-receipts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Pending-order placement and replacement facts

`PendingOrder::replaced_order_incarnation` identifies the immediate live
predecessor whose priority slot the newly accepted order retains. Zero means
fresh construction. The new order still receives its own fresh `incarnation`;
`created_seq` remains its scheduling priority, not identity.

The receipt is populated by high-level MARKET/ENTRY, RAW, and primary EXIT
replacement. Named cancel followed by recreation is fresh; its separate
cancel/recreate receipt does not become a replacement. When a Pine exit
reissue materializes multiple legs, the primary leg inherits the preceding
primary's priority and predecessor; additional legs are fresh. This receipt
does not claim to enumerate all sibling objects erased by that reissue.

The former native `created_by_same_id_replacement` Boolean and redundant
`replaced_exit_order_incarnation` scalar are removed. Replacement readers use
the authoritative predecessor. The conditional
`replaced_default_market_incarnation` remains a Pine qualification receipt:
it records additional predecessor kind, sizing, side, source-bar and cycle
conditions that generic replacement identity alone cannot establish later.

The former `created_while_in_position` Boolean is also removed. Its production
meaning was EXIT-only: `strategy.exit` derived it from the same `effectively_flat`
calculation used for `created_position_side`; a positive deferred close used the
nonflat side it targeted. EXIT consumers now read that existing placement side.
The two non-EXIT checks were vacuous because their producers always left the
old Boolean false; those checks are removed without requiring flat placement.

`created_position_side` is not renamed or reinterpreted as a universal physical
snapshot. MARKET/ENTRY/RAW capture physical exposure; a Pine EXIT captures
exposure after earlier same-evaluation close claims. The physical position can
still be open when such an EXIT captures FLAT. Existing cycle/carry fields and
their scopes are unchanged. A complete physical placement/close-claim model is
separate work.

The public size-aware `pf_pending_order_v1_t` retains every existing field at
its original offset. Its old replacement Boolean, EXIT predecessor scalar and
in-position Boolean are deprecated derived **output projections**, never core
state or inputs. The legacy RAW projections remain false/zero; the appended
`replaced_order_incarnation` reports the true RAW predecessor. Dynamic-layout
readers can discover the new field; older prefix readers retain their layout.
The generator emits these projections explicitly without native storage or a
readback path. Native hashing includes the predecessor once and placement side
once; removed redundant fields need no independent hash state.

This removes two of the 32 direct PendingOrder Boolean members, leaving 30 in
this component. It replaces one bit with factual identity and removes one
duplicate placement value; it is not a Boolean wrapper or a renamed policy
mask. Existing Pine priority/admission/close policies still read these facts
and retain their existing qualification rules. Public C ABI version 4 and
pending mirror version 1 remain unchanged. Final aggregate internal C++/hash
versioning and stale-object pairing are owned by the integrated refactor;
this component must not be published separately without that boundary.
21 changes: 21 additions & 0 deletions include/pineforge/compat/pine/order_birth.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once
#include "../../order_birth.hpp"

namespace pineforge { inline namespace engine_script_run_v5 { struct PendingOrder; } }
namespace pineforge::compat::pine {

// Historical Pine permissions remain policy, not physical birth facts.
enum class HistoricalBirthReach : int32_t { Standard, ExtremeWaypoints };
inline bool first_open_fill_evaluation(const OrderBirth& birth) {
return birth.from_fill() && birth.evaluation_ordinal() == 1
&& birth.cursor().first_point();
}
HistoricalBirthReach select_historical_birth_reach(const OrderBirth& birth,
bool requested_trailing_exit);
bool historical_cascade_reach(const PendingOrder& order);

} // namespace pineforge::compat::pine

namespace pineforge {
using PineHistoricalBirthReach = compat::pine::HistoricalBirthReach;
}
2 changes: 1 addition & 1 deletion include/pineforge/compat/pine/order_priority.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <string>
#include <vector>

namespace pineforge { struct PendingOrder; }
namespace pineforge { inline namespace engine_script_run_v5 { struct PendingOrder; } }
namespace pineforge::compat::pine {

struct OrderPriorityContext {
Expand Down
Loading
Loading