InstrumentSpec: deploy-grade metadata (instrument_id, contract size, pip value, lots) #113

Closed
opened 2026-06-22 16:30:50 +02:00 by Brummel · 1 comment
Owner

Extend the InstrumentSpec shape (aura-ingest/src/lib.rs:346) with the deploy-grade fields a realistic broker needs to turn pips/volume into account currency:

  • instrument_id: i64 (stable — the position-event table's instrument_id column)
  • contract_size / point-value
  • pip_value_per_lot
  • min_lot, lot_step
  • quote_currency (label only this cycle — no FX conversion yet)

This is a PERMANENT authored layer, not a stand-in

A data source can never be guaranteed to ship instrument metadata, and when it does the values are often wrong or unrealistic (the canonical example: a broker feed records a constant 2-pip spread that has nothing to do with the real, higher, volatile historical spread). So the authored values must be authoritative-by-choice and overridable — they are not a placeholder the provider later replaces.

Resolution hierarchy (precedence high → low), into which this issue's authored table fits as the permanent fallback:

1. Explicit authored override  (project/run; Rust now, Aura.toml later) — always wins
2. Recorded dataset metadata   (provider-sourced at curate time, via the DataServer seam)   [forward issue]
3. Vetted authored fallback    (instrument_spec() table) — THIS issue; permanent floor
4. Refuse-don't-guess          (exit 2) — absolute floor

This issue delivers tiers 3 + 4 (and, until a recorded tier exists, the authored table also serves as the de-facto override). Keep the _ => None refuse arm. The broker (#116) and derivation (#115) must read the resolved spec injected at the ingestion edge — not call instrument_spec() directly — so a resolver can sit in front later without touching them.

Source the values from the same Rust-authored vetted table at the ingestion edge; research real values for the existing GER40/FRA40/EURUSD/GBPUSD/USDCAD set.

depends on: nothing
relates: the resolution-hierarchy / recorded-metadata-tier forward issue; #71 (DataServer/Source seam).

Extend the `InstrumentSpec` *shape* (aura-ingest/src/lib.rs:346) with the deploy-grade fields a realistic broker needs to turn pips/volume into account currency: - `instrument_id: i64` (stable — the position-event table's `instrument_id` column) - `contract_size` / point-value - `pip_value_per_lot` - `min_lot`, `lot_step` - `quote_currency` (label only this cycle — no FX conversion yet) ## This is a PERMANENT authored layer, not a stand-in A data source can **never be guaranteed** to ship instrument metadata, and when it does the values are often wrong or unrealistic (the canonical example: a broker feed records a constant 2-pip spread that has nothing to do with the real, higher, volatile historical spread). So the authored values must be **authoritative-by-choice and overridable** — they are not a placeholder the provider later replaces. **Resolution hierarchy** (precedence high → low), into which this issue's authored table fits as the permanent fallback: ``` 1. Explicit authored override (project/run; Rust now, Aura.toml later) — always wins 2. Recorded dataset metadata (provider-sourced at curate time, via the DataServer seam) [forward issue] 3. Vetted authored fallback (instrument_spec() table) — THIS issue; permanent floor 4. Refuse-don't-guess (exit 2) — absolute floor ``` This issue delivers tiers 3 + 4 (and, until a recorded tier exists, the authored table also serves as the de-facto override). Keep the `_ => None` refuse arm. The broker (#116) and derivation (#115) must read the **resolved** spec injected at the ingestion edge — not call `instrument_spec()` directly — so a resolver can sit in front later without touching them. Source the values from the same Rust-authored vetted table at the ingestion edge; research real values for the existing GER40/FRA40/EURUSD/GBPUSD/USDCAD set. depends on: nothing relates: the resolution-hierarchy / recorded-metadata-tier forward issue; #71 (DataServer/Source seam).
Brummel added this to the Realistic broker & position-event table (C10 A-side) milestone 2026-06-22 16:30:50 +02:00
Brummel added the feature label 2026-06-22 16:30:50 +02:00
Author
Owner

Design decisions (specify, cycle 0063 broker-foundation — derived)

Spec 0063-broker-foundation covers this issue (#113) bundled with #114.
Running under /boss; the decisions below were derived by the
orchestrator from the sources + ledger + existing code (not user decisions).
Recorded here so they can be audited and vetoed.

  • Fork: quote_currency field type&'static str.
    Basis (derived): keeps InstrumentSpec: Copy (the struct is Copy today
    and instrument_spec_or_refuse returns it by value); fits the static
    Rust-authored vetted table; a String would break Copy and allocate for
    no benefit this cycle (label only, no FX). The later Aura.toml override layer
    (deferred) owns any owned-string need then.

  • Fork: action representation → a type-safe enum PositionAction { Buy, Sell, Close } held in PositionEvent, serde-encoded as i64
    (ordinal Buy=0, Sell=1, Close=2) via From<PositionAction> for i64 +
    TryFrom<i64>.
    Basis (derived): the ledger C10 column spec is action: i64 (C7 scalar
    discipline for the columnar/persisted form), but the in-memory canonical
    type may be safer — the issue title is "action enum", and an enum makes an
    invalid action unrepresentable. Encoding as i64 keeps the persisted/columnar
    shape ledger-faithful and makes #122's columnar projection trivial. An
    out-of-range i64 fails TryFrom (the honesty lever mirroring
    instrument_spec's None). Ordinal 0/1/2 is the least-surprising closed-enum
    encoding; the ledger says "direction IS the action" (categorical), so no
    sign-carrying trick.

  • Fork: instrument_id assignment + vetted reference values → stable
    small ints assigned in table order (GER40=1, FRA40=2, EURUSD=3, GBPUSD=4,
    USDCAD=5; never renumber), with industry-standard contract metadata
    (FX standard lot = 100 000 units, pip value = contract_size·pip_size in quote
    currency; indices €1/point, contract_size 1).
    Basis (derived): #113 asks to "research real values"; these are vetted
    reference data per the resolution hierarchy's permanent authored floor, kept
    overridable (the milestone's authored-override-wins contract). Flagged as
    the spec's most-suspect bytes — factual reference data, not validated by an
    existing test — overridable by design so a later correction is cheap.

Scope: foundation only (#113 + #114) — no broker, no derivation, fully
testable. derive_position_events (#115) and the broker (#116) consume these
shapes later.

## Design decisions (specify, cycle 0063 broker-foundation — derived) Spec `0063-broker-foundation` covers this issue (#113) bundled with #114. Running under `/boss`; the decisions below were **derived** by the orchestrator from the sources + ledger + existing code (not user decisions). Recorded here so they can be audited and vetoed. - **Fork: `quote_currency` field type** → `&'static str`. Basis (derived): keeps `InstrumentSpec: Copy` (the struct is `Copy` today and `instrument_spec_or_refuse` returns it by value); fits the static Rust-authored vetted table; a `String` would break `Copy` and allocate for no benefit this cycle (label only, no FX). The later Aura.toml override layer (deferred) owns any owned-string need then. - **Fork: `action` representation** → a type-safe `enum PositionAction { Buy, Sell, Close }` held in `PositionEvent`, serde-encoded **as i64** (ordinal `Buy=0, Sell=1, Close=2`) via `From<PositionAction> for i64` + `TryFrom<i64>`. Basis (derived): the ledger C10 column spec is `action: i64` (C7 scalar discipline for the columnar/persisted form), but the in-memory canonical type may be safer — the issue title is "action enum", and an enum makes an invalid action unrepresentable. Encoding as i64 keeps the persisted/columnar shape ledger-faithful and makes #122's columnar projection trivial. An out-of-range i64 fails `TryFrom` (the honesty lever mirroring `instrument_spec`'s `None`). Ordinal 0/1/2 is the least-surprising closed-enum encoding; the ledger says "direction IS the action" (categorical), so no sign-carrying trick. - **Fork: `instrument_id` assignment + vetted reference values** → stable small ints assigned in table order (GER40=1, FRA40=2, EURUSD=3, GBPUSD=4, USDCAD=5; never renumber), with industry-standard contract metadata (FX standard lot = 100 000 units, pip value = contract_size·pip_size in quote currency; indices €1/point, contract_size 1). Basis (derived): #113 asks to "research real values"; these are vetted reference data per the resolution hierarchy's permanent authored floor, kept **overridable** (the milestone's authored-override-wins contract). Flagged as the spec's most-suspect bytes — factual reference data, not validated by an existing test — overridable by design so a later correction is cheap. Scope: foundation only (#113 + #114) — no broker, no derivation, fully testable. `derive_position_events` (#115) and the broker (#116) consume these shapes later.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Brummel/Aura#113