feat(sl-hunting): v4g knowledge from the 13 Aug live session - #123
Merged
Conversation
Source: Intraday Hunter live session, 13 Aug 2026 (Vig9Kjab2T0, 10:36). A REDUCED win -- the trade reached most of its target, reversed into a loss, recovered, and was booked for about half. That arc produces the two structural ideas and the most complete discipline block in the series. Knowledge changes (all prose): - OPENING_DRIVE: A COMPLETED STOP-HUNT ENDS THAT DIRECTION. The sharpest idea here and it inverts the naive read of a bounce: a move that has just cleared one side's stops has SPENT its fuel and turns rather than continues. "Yesterday it took support EXACTLY at the 500 level and gave a retracement, so whoever was selling got chased out -- the chances of going DIRECTLY UP are LOW... if it has chased the sellers out, we follow THAT SAME DIRECTION", meaning the direction before the clearing bounce. The large-gap escape hatch is kept in the prose and asserted by a test, because unconditional it would harden into "always fade the bounce". - OPENING_DRIVE: THE ROUND NUMBER IS WHERE THE THESIS DIES, NOT JUST WHERE IT PAYS. v4d used round numbers for targets and v4c for recruitment; this adds the declared invalidation, named per index before entry. "Until the market crosses 24,500 we will not have much problem"; "when is there no danger to these buyers? If the market goes above 58,000." - RISK: FEAR IS NOT A SIGNAL -- NEVER CONVERT IT INTO AN EXIT; TIME SPENT IN THE TRADE SHRINKS THE ACHIEVABLE TARGET; NEVER EXIT AT ZERO AFTER A GOOD PROFIT HAS PRINTED. The fear rule sits directly on top of v4f's BOOK WHEN THE PROFIT STOPS GROWING and the pair is the most dangerous in the prompt: read carelessly v4g disables v4f, while v4f licenses exactly the fear-driven exit v4g forbids. The encoded distinction is MEASUREMENT versus EMOTION, and test_v4g_fear_rule_and_v4f_book_rule_do_not_cancel_each_other asserts both halves say so and that the fear rule still enumerates legitimate exit reasons rather than banning exits. Prompt 105,933 -> 111,283 chars. HEADROOM IS NOW 8,717 -- at ~5,000 per version that is roughly two more before the 120,000 cap, so the next pass should prune superseded prose rather than only append. The doc addendum also records the agent's day, which is the exact inverse of 12 Aug: SL Hunting was the BEST strategy on the board (+2,727.00 over 2 trades, cross-checked against its own Result summary) where yesterday it was the worst. Both trades were SHORT off the flat open -- the same side IH took -- and both exits keyed off the round number (profit_booking_round_number, profit_book_stall_near_round_number) rather than the premise-STALL churn that cost it yesterday. The read was short on both days; what changed is that the exits had a checkable reason, which is what v4g's fear rule demands. Two trades is a small sample and the basket was still deeply negative (-9,229.75 provisional, runner live at 14:13). Gates: SL Hunting pytest 179 passed, master 516 OK, ruff clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The durable/marks split's first live session exposed a second hole. On 2026-08-12 the supervisor stopped writing marks at 12:30 while workers traded on until 15:10 -- no exception, no partial file, no log line. It was found hours later by comparing file mtimes, and even then the cause could not be determined, because MainThread emits nothing during a healthy session so its silence carried no information. Worse, the marks left on disk described 11 open positions where 23 were genuinely open. With resume enabled that 2h40m-stale set would have been restored as a current book -- inventing exposure that had been closed and omitting exposure that had been opened. That is the exact failure ADR-0012 exists to prevent, arriving through the file it created. Two additions: - SUPERVISOR HEARTBEAT (SESSION_STATE_HEARTBEAT_SECONDS, default 300s, ~75 lines a session): workers alive, completed marks writes, marks age, open positions, trades recorded. Its presence proves the loop is turning; the gap between the last heartbeat and a crash localises where it stopped. SessionStateStore.health() supplies the counters and warn_if_marks_stalled() raises one ERROR per stall episode once the age exceeds MARKS_STALL_INTERVALS x the interval. The heartbeat swallows its own exceptions and still advances its stamp: a diagnostic that can take down the supervisor, or spin the log, is worse than none. - STALE-MARKS GUARD. load_session_state now records marks_age_seconds from the two documents' updated_at stamps, and resumable_open_positions refuses EVERY position when that lag exceeds MAX_RESUMABLE_MARKS_AGE_SECONDS (300s) or cannot be determined. Fail-closed on an unknown lag is deliberate: a book of unknown age is not a book. Realized P&L is explicitly unaffected by the refusal and the log line says so. What deliberately gets no guard: the durable half. Trade events are written by the trading threads themselves, so a frozen supervisor cannot touch realized P&L -- which is why the 12 Aug reconciliation was exact even though the marks were useless. Test fixtures had to be corrected as well, and the correction is the point: both the module and the runner suites built state by hand in the PRE-SPLIT single-file shape, so they carried no marks lag and the new guard refused them. They now write the real pair of files, which is what they should always have done -- a fixture that does not match the on-disk shape cannot exercise a guard that reads it. 8 new module tests (53 total) covering live/stalled health, the one-shot warning latch, the latch clearing on recovery, lag measurement, and the stale / just-inside-limit / unknown-lag resume cases; 4 new runner tests covering heartbeat throttling, stall detection, exception isolation, and a stale-marks resume refusal. Gates: master 520 OK, market-data-health 26 OK, pytest 1158 passed, ruff/mypy clean, session_state.py branch coverage 91.3% against its 90% budget. check-env reports zero undocumented keys. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CI caught a platform-dependent bug that passed cleanly on the local box. `time.monotonic()` has an ARBITRARY origin. On Windows it is machine uptime, so a seed of 0.0 reads as "long ago" and the first supervised tick emits a heartbeat. In a freshly booted Linux container the counter starts near zero, so the same 0.0 reads as "just now" and the first heartbeat is suppressed for a full interval -- five minutes during which the loop's liveness is exactly as unobservable as it was on 2026-08-12, which is the whole thing this heartbeat exists to fix. The seed is now `None`, meaning "never emitted", so the first call always logs regardless of the platform's monotonic origin. The docstring and the supervisor comment both said the first tick would emit; that claim is now actually true rather than true only on Windows. test_first_heartbeat_always_fires_regardless_of_the_monotonic_origin is the regression guard, and test_heartbeat_never_breaks_supervision now asserts against a captured baseline instead of the literal 0.0 that made it platform-dependent too. Gates: master 521 OK, ruff/mypy clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reverses a decision this ADR made two days ago. The durable/marks split rejected a writer thread because a 0.414s median stall did not seem to justify weakening durability. That reasoning was incomplete: the stalls do not merely add latency, THEY DROP THE MARKET FEED. On 2026-08-11, 86% of the websocket disconnects (25 of 29) landed within 20 seconds of a session-state write stall, and `keepalive ping timeout` is the dominant feed error across the whole log -- the signature of a blocked event loop. Pre-feature days show 1-18 reconnects with zero write stalls. The split already cut correlated errors from 25 to 3; what remains are the ~15 trade-event writes still on trading threads. Two things I previously mis-stated about the trade-off: - The data does NOT land later. The write takes the same time either way, so it reaches the platter at the same wall-clock moment. What changes is that the publishing thread is not frozen meanwhile -- and it was frozen for exactly that interval before, unable to act on anything. - A lost queued event still has its log line. publish_trade_event is called AFTER the EXIT log record is emitted, and that log is what _parse_eod_pnl_by_day reads for the Sheet, so the fallback is the same one the system used before this module existed. What genuinely changes: a hard kill can lose events queued in the last write cycle rather than only the one in flight. Coalescing bounds that -- the document is a full rewrite, so a burst becomes ONE write, which also reduces total fsyncs rather than merely relocating them. DEFAULT OFF (SESSION_STATE_ASYNC_WRITES). This is a real reduction of the guarantee ADR-0012 exists to provide, so it is the operator's call rather than a silent default change -- the same treatment SESSION_STATE_RESUME_ENABLED got. Recommended ON for this hardware, where the feed cost is measured and recurring. stop_durable_writer() drains before the clean-shutdown flag is written, so an orderly end of day is exactly as durable as the synchronous path, and a failed drain falls back to a synchronous write rather than leaving a recorded trade unwritten. A write that raises re-marks the state dirty so the next cycle retries it instead of losing the event. 7 new tests (60 total): the caller not blocking, the synchronous path staying unchanged when no writer runs, burst coalescing into fewer writes, shutdown draining everything, idempotent stop, no double writer, and a failing write being retried rather than swallowed. Gates: master 521 OK, market-data-health 26 OK, pytest 1165 passed, ruff/mypy clean, session_state.py branch coverage 90.9% against its 90% budget, check-env zero undocumented keys. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
…ideo Source: Intraday Hunter, "Prediction For 14 AUG 2026" (MhmlrlUEUGI, uploaded 2026-08-13, 2:14). Neither side is seated, and he says so outright for two of the three indices: BankNIFTY "buyers and sellers would be sitting at the SAME price level", Sensex "to say more sellers are seated, or more buyers are seated, would be WRONG". That is the empty-book condition v4f describes, stated more plainly than the series has had it -- and it is the exact condition v4e's expensive loss came from forecasting a crowd into. The note records the absence rather than smoothing it into a direction. His mechanism for trading a thin book is the line worth keeping: "where the crowd is THIN, that is where the market tries to make momentum." Thin is not dead -- the move goes where there is least resistance, which sits alongside v4f's AN EMPTY BOOK MEANS A TRAP IS COMING rather than against it. He also states a preference the series had only inferred: "better that it is NOT flat -- either a gap-up or a gap-down", because a flat open "keeps extracting a small momentum and going away". That is v4d's participation reading turned into an operational preference. Plan: SELL-side on flat-to-gap-down (on Sensex explicitly to target the buyers sitting on support since yesterday), BUY-side and follow on a gap-up where "the buyer becomes safe". On BankNIFTY there is little pressure on the sellers, so that branch is recorded as a FOLLOW of the drift rather than a seller hunt. Transcription caveat, and a repeat: NIFTY's second support arrived as the same unresolvable "2476" token as the 13 Aug video, so it is omitted again. Twice in two days makes it a consistent ASR failure on one number rather than noise; the test asserts NIFTY carries exactly one support so a tidy-up cannot invent it. Sensex's levels are unchanged from yesterday, consistent with a session that went nowhere. test_shipped_note_matches_august_14_intraday_hunter_plan replaces the 13 Aug equivalent and asserts both branch directions plus the thin-crowd mechanism and the gap-over-flat preference, which are what a summarising edit would drop first. Gates: SL Hunting pytest 179 passed, ruff clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The "2476" token that the auto-caption produced on both 13 and 14 Aug is 24,176. It was read directly off the chart rather than inferred. Method, which is now the standard step whenever a level does not parse: force the player to 1080p with setPlaybackQualityRange (it defaults to 854x480, where the axis labels are illegible), seek to the moment he reads the levels, draw the <video> element to a canvas, crop the right-hand price-axis band and upscale ~3x. TradingView prints each line's exact price in a tag on the axis, so every level is readable. Everything on the 14 Aug NIFTY chart matches what he speaks: resistance 24,540.85 "24540" resistance 24,443.85 "24440" spot 24,395.85 -- support 24,275.25 "24275" support 24,176.20 "2476" <- the garbled one So the 13 Aug note's omitted support was 24176 as well; the level simply had not moved, which is why the same token appeared twice. Omitting was defensible with only the caption to go on, but reading the frame is strictly better: the chart is authoritative and the auto-caption is not. The 13 Aug doc entry carries a correction block pointing here rather than leaving the wrong conclusion standing, and the test comment now records how the number was obtained so a future reader does not mistake it for a guess. Gates: SL Hunting pytest 179 passed, ruff clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Distils Intraday Hunter's 13 Aug 2026 live session (
Vig9Kjab2T0) into the SL Hunting agent's knowledge. A reduced win — the trade reached most of its target, reversed into a loss, recovered, and was booked for roughly half. That arc produces the two structural ideas below plus the most complete discipline block in the series.Structural
A COMPLETED STOP-HUNT ENDS THAT DIRECTION — the sharpest idea here, and it inverts the naive read of a bounce. A move that has just cleared one side's stops has spent its fuel:
— meaning the direction before the clearing bounce. The large-gap escape hatch is kept in the prose and asserted by a test, because unconditional this would harden into "always fade the bounce".
THE ROUND NUMBER IS WHERE THE THESIS DIES, NOT JUST WHERE IT PAYS — v4d used round numbers for targets, v4c for recruitment. This adds the declared invalidation, named per index before entry: "until the market crosses 24,500 we will not have much problem"; "when is there no danger to these buyers? If the market goes above 58,000."
Discipline
FEAR IS NOT A SIGNAL — NEVER CONVERT IT INTO AN EXIT, plus TIME SPENT SHRINKS THE ACHIEVABLE TARGET and NEVER EXIT AT ZERO AFTER A GOOD PROFIT HAS PRINTED.
The test that matters
The fear rule sits on top of v4f's BOOK WHEN THE PROFIT STOPS GROWING, and the pair is the most dangerous in the prompt: read carelessly, v4g reads as "hold through everything" and disables v4f, while v4f licenses exactly the fear-driven exit v4g forbids.
The encoded distinction is measurement versus emotion.
test_v4g_fear_rule_and_v4f_book_rule_do_not_cancel_each_otherasserts both halves say so, and that the fear rule still enumerates the legitimate exit reasons rather than banning exits.105,933 → 111,283 chars. Headroom is now 8,717. At the recent ~5,000 per version that is roughly two more versions before the 120,000 cap. The next pass should start pruning superseded prose rather than only appending.
Our agent on the same session
The exact inverse of 12 Aug. SL Hunting was the best strategy on the board — +2,727.00 over 2 trades (cross-checked against its own
Result summary), where yesterday it was the worst.Both trades were SHORT off the flat open — the same side IH took — and both exits keyed off the round number:
profit_booking_round_numberprofit_book_stall_near_round_numberContrast 12 Aug: four entries in 47 minutes, three released on premise-stall judgements. The read was short on both days — what changed is that the exits had a checkable reason, which is exactly what v4g demands.
Two trades is a small sample, and the basket was still deeply negative: −9,229.75 provisional (runner live at 14:13), with Renko −4,127.50 over six trades.
Gates
SL Hunting pytest 179 passed · master 516 OK · ruff clean.
🤖 Generated with Claude Code