Skip to content

feat: pre-trade hard gate — block no-stop BUYs, show blocked as non-actionable - #9

Merged
trogers1052 merged 2 commits into
mainfrom
feat/pre-trade-hard-gate
Jul 27, 2026
Merged

feat: pre-trade hard gate — block no-stop BUYs, show blocked as non-actionable#9
trogers1052 merged 2 commits into
mainfrom
feat/pre-trade-hard-gate

Conversation

@trogers1052

Copy link
Copy Markdown
Owner

What

Completes the pre-trade hard gate (Phase 1 remaining item). It was not display-only as the CLAUDE.md TODO claimed — BLOCKED already suppressed on earnings/size/regime. The gaps this closes:

  1. No-stop BUYs weren't blocked. A BUY whose plan lacked a valid stop only became REVIEW and still published as actionable. Now it's a hard block (the MOH lesson).
  2. Blocked signals were invisible. They were suppressed before publishing, so the trader never learned what the gate filtered. Now a blocked BUY is published marked BLOCKED (with block_reasons) so alert-service renders it as 🚫 NON-ACTIONABLE — real-time observability of exactly what the gate catches.

Changes

  • checklist.py — no-valid-stop → hard block (scoped to when a plan exists; the plan-engine-disabled path stays REVIEW). Adds block_reasons to the result + to_dict.
  • service.py — emit path publishes BLOCKED BUYs (debounced) instead of suppressing, and skips the actionable gates for them. HARD_GATE_ENABLED=false reverts to suppression.
  • config.pyhard_gate_enabled flag (default true).

Safety

Verified only alert-service consumes trading.decisions (trading-journal uses positions, stock-service uses trades/positions, reporting reads the DB) — so publishing blocked signals has no downstream side effects.

+9 tests (no-stop block, block_reasons, emit publish-vs-suppress, debounce). Full suite green.

Based on main. Uses datetime.utcnow() to match main (the in-flight feat/clock-adoption clock-seam refactor will convert it along with the rest).

🤖 Generated with Claude Code

trogers1052 and others added 2 commits July 27, 2026 06:57
…ctionable

The checklist already hard-BLOCKED on earnings/size/regime, but everything
else that failed a check (including a BUY with no stop plan) only became
REVIEW and was still published as an actionable signal. And BLOCKED signals
were suppressed entirely — the trader never saw what the gate filtered.

- checklist: a plan with no valid stop is now a hard block (the MOH lesson);
  every block records human-readable block_reasons for the alert.
- emit path: instead of suppressing BLOCKED BUYs, publish them MARKED BLOCKED
  (debounced) so alert-service can show them as NON-ACTIONABLE, and skip the
  actionable gates. HARD_GATE_ENABLED=false reverts to silent suppression.
- config: hard_gate_enabled flag (default true).

Only alert-service consumes trading.decisions, so publishing blocked signals
has no downstream side effects. +9 tests; suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
risk-engine's pip install pulls trading-py-commons from a git URL, which
needs git in the builder image. Latent since risk-engine adopted the git
dependency; surfaced now because main hasn't rebuilt since April. Without
this the image build fails and the Pi can't pull a new decision-engine.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@trogers1052
trogers1052 merged commit aa131d2 into main Jul 27, 2026
1 check passed
@trogers1052
trogers1052 deleted the feat/pre-trade-hard-gate branch July 27, 2026 13:09
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