Skip to content

DEM-PRODUCER-PLAN (reactor): the planned R:R becomes a verified provider fact - #89

Merged
Gio2050 merged 2 commits into
mainfrom
dem/plan-reactor
Aug 26, 2026
Merged

Gio2050 merged 2 commits into
mainfrom
dem/plan-reactor

Conversation

@Gio2050

@Gio2050 Gio2050 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Wave 1 of 4 — DEM-PRODUCER-PLAN, step 3 of 3. Merge after afi-core #36 and afi-config #91. This PR's CI is expected red until both are on main (the reactor builds afi-core main and reads afi-config main through file: links) — re-run it after those merges.

How the gate is met, clause by clause

Gate clause How
"verified against observed market data by the producer that emits it, and refused when it cannot be verified, proven by test" src/enrichment/tradePlanVerification.ts — every submitted level must lie within one observed-range width of the fetched window ([L−W, H+W]), the stop and targets must sit on opposite sides of the entry, and R:R is computed at the conservative entry bound. Any violation throws TradePlanVerificationError (a NodeConfigurationError: no retry, pipeline abort) → 422 trade_plan_unverifiable, no record. 31 KATs.
"the value is a provider fact, never synthesized from an analyst input — the role split proven by test" The facts are a pure function of (submitted plan, fetched candles). tradePlanProducer.test.ts proves analyst-side inputs cannot move them and that the emitted facts equal the pure law applied to those two inputs alone.
"absence fails closed under D-DEM-5(2) unless declared optional within D-DEM-5(4)(b)" No plan → no technical.plan block; a plan with no stop or no target → no rrToFirstTarget (no R:R was claimed). Both are declared in the technical plugin's contract and enumerated in the mapping; the mapping's floor default fires as a recorded degradation.
"collinearity recorded as resolved or residual per D-DEM-5(5)" Recorded in INTENTIONAL_DIFFS.md: resolved on plan-bearing CPJ submissions; residual on plan-less ones (see below).
"movement itemized" A new INTENTIONAL_DIFFS.md section itemizes every moved JSON path per golden, with an explicit byte-EQUAL list. A committed differ (test/oracle/support/goldenDiff.mjs) makes the audit reproducible — the gap DEM-BIND-PLAN recorded and nobody closed.

Scored-value movement (authorized in class by D-DEM-7(2))

golden rrMultiplePlanned risk uwrScore
cpj-blofin-perp-long.* 2 → 1.4286 (the provider's verified R:R) 0.9 → 0.5 0.59167 → 0.49167
the other ten 2 → 1 (the declared floor, recorded) 0.9 → 0.2 itemized per golden

The risk axis is no longer a single constant — it now spans {0.5, 0.2} across the corpus and is driven by the provider's plan where one exists.

One thing that needed a decision, and what I did

The two plan-bearing CPJ fixtures carried levels (BTC 42500/41800/43500) thousands of dollars outside any window the deterministic test feed can print — under the law this slot lands they would have been refused, and the golden corpus could not have been regenerated at all. I re-authored those two fixtures inside the feed's envelope (BTC 50000/49300/51000 → R:R 1.4286; ETH 3001.5, entry-only, keeping the non-integer decimal-string case) and added a test that the envelope contains every committed fixture plan, so the harness can never drift into silent refusal again. The consequential ingestHash/inputHash movement is itemized.

Verification

764/764 green; tsc --noEmit (strict, includes test/**) green; all four compiled-build proofs green against a real single-node replica set — honest-503 unavailable, 10 persistence checks, 7 oracle-equivalence checks, SIGTERM shutdown. Pre-open adversarial review (7 lenses, findings independently verified) found five real defects in the verification law; all five are fixed in the second commit.

🤖 Generated with Claude Code

Gio2050 and others added 2 commits August 25, 2026 17:48
…act; goldens regenerated once, itemized

DEM-GOV §9 DEM-PRODUCER-PLAN (owner-authorized 2026-08-25; afi-governance
#55; §9 determinations D-2/D-4/D-5 in #56). Merge AFTER afi-core dem/plan-core
and afi-config dem/plan-config.

Source:
- uss/cpjMapper.ts: the submitted plan survives as uss.plan (afi.trade-plan.v1,
  decimal strings, validated against the governed contract) or is refused at
  ingest (typed error → 422 trade_plan_invalid). TV/MarkitTick untouched.
- enrichment/tradePlanVerification.ts (NEW): the D-DEM-5(6) law — every
  submitted level within [L − W, H + W] of the fetched window; plan geometry
  from prices only (D-DIR-3 by construction); R:R to the nearest target,
  4 dp; refusal = TradePlanVerificationError (NodeConfigurationError).
- providers/adapters/technicalLocalAdapter.ts: the producer — verifies the
  plan against ITS fetched candles and emits technical.plan (declared
  absences: no plan → no block; no stop/target → no R:R).
- pipeline/nodes/laneView.ts: viewTechnical projects plan verbatim.
- server.ts: 422 trade_plan_unverifiable (unwrapping NodeExecutionError.cause),
  422 trade_plan_invalid; both persisted:false.
- types/TradePlan.ts (NEW), types/UssLenses.ts, uss/ussValidator.ts: types.

Registries/pins: the three fixture trees mirror afi-config (mapping 1.1.0,
config, three implementationVersion moves, registration hash 5cb9b7a4…);
registryLoader/officialArtifactPins pins rotated (pluginSetHash 36f911f4…).

Goldens: the two plan-bearing CPJ fixtures re-authored inside the demo
envelope (old levels were unverifiable by the law this slot lands); 12
goldens regenerated ONCE; every moved path itemized in INTENTIONAL_DIFFS.md
(risk 0.9 → {0.5 via the provider's rr 1.4286 | 0.2 via the declared floor};
executionSummaryHash flips executed → degraded on the two goldens where the
floor is the first fired default; identity-hash class on all 12).
test/oracle/support/goldenDiff.mjs (NEW): the committed per-path differ.

Tests: verification KATs (band, geometry, absences, error class), carrier
(decimal strings, refusals), producer (role split, D-DIR-3 negative test,
refusal, kernel floor, envelope-covers-fixtures), error-table rows for both
422s (no record), seam suites re-oracled to the composition reference with
the mapping resolved by mappingRef from the fixture registry, golden
scorerInput captured at the rubric call. 756/756; typecheck; compiled-build
proofs (unavailable 503; Mongo persistence 10/10; oracle equivalence 7/7;
SIGTERM) green locally.

No scoring-law value moves. Sealed records untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n law

An adversarial review of the branch (7 lenses, findings independently
verified) found five real defects in the D-DEM-5(6) law. All five fixed here;
no golden byte moves (every fix is refusal-side or message-side).

- MAJOR: an entry RANGE was verified only at its conservative bound, so a
  range containing (or on the wrong side of) its own stop was ACCEPTED and an
  R:R emitted from one end. The stop must now clear the FAR bound as well:
  long -> stop < entryLow, short -> stop > entryHigh. Three refusal KATs (long
  straddle, short straddle, far bound EQUALS the stop) + the accept-side edge.
- MINOR: the inclusive band edge was false on non-integer windows (binary
  float: 1.1 - 0.2 = 0.9000000000000001 refused an entry of exactly "0.9").
  Relative tolerance (1e-12) at both edges + bounded-precision numbers in the
  refusal message; a non-integer-window KAT pins both edges.
- MINOR: a non-array takeProfits (or a non-object levels) threw a bare
  TypeError, escaping the 422 unwrap. Both refuse properly now, with KATs.
- MINOR: "half-up to 4 decimals" was not what Math.round(v*1e4)/1e4 does at
  binary ties. The law is documented as what it is (deterministic binary
  quantisation) and the unfavourable tie (0.00015 -> 0.0001) is pinned.
- MINOR: missing edge KATs added: empty takeProfits array (no-target case),
  degenerate entry range (min === max), exotic numeric strings, an
  overflow-to-Infinity decimal string, malformed candles; the hedged
  short-geometry regex is tightened to its exact message.

756 -> 764 tests, all green; typecheck green; goldens byte-unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kilo-code-bot

kilo-code-bot Bot commented Aug 26, 2026

Copy link
Copy Markdown

Kilo Code Review could not run — your account is out of credits.

Add credits or switch to a free model to enable reviews on this change.

@Gio2050

Gio2050 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

afi-core #36 and afi-config #91 are on main; re-running CI against them.

@Gio2050
Gio2050 merged commit b0e0051 into main Aug 26, 2026
3 of 5 checks passed
@Gio2050
Gio2050 deleted the dem/plan-reactor branch August 26, 2026 04:03
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