feat(meet-kevin): prompt v2 — forward-looking action + expected_move field
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was canceled
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was canceled
User reported that the old prompt could emit 'sell' on backward-looking
capitulation ('Kevin sold after a 20% drop') — exactly the false signal
to avoid. v2 reframes every per-ticker field as forward-looking and
adds an explicit expected_move enum for the trading bot to weight.
Changes:
- New ExpectedMove enum (up_strong/up_mild/sideways/down_mild/
down_strong/unknown) in shared/schemas + shared/models, with
matching kevin_expected_move Postgres enum + column on
kevin_stock_mentions (migration e5f6a7b8c9d0). NOT NULL with
server_default 'unknown' so existing rows backfill cleanly.
- SYSTEM_PROMPT rewritten: action semantics now require a FORWARD
view; reactive sells get downgraded to 'watch' or skipped; the
rationale_quote must contain forward reasoning. Quality
checklist updated.
- _ANALYSIS_TOOL JSON schema gains expected_move (required).
- prompt_version v1 → v2 in config + infra + ad-hoc CLI default.
- pipeline.py persists ticker.expected_move into the new column.
Migration safety: the column is NOT NULL DEFAULT 'unknown' so 96
existing mentions auto-fill with 'unknown' (no forward call known
for backward analyses) without breaking any reads.
Cost to backfill the 27 existing analyses with v2 prompt: ~$3 LLM
spend. A follow-up reanalyze script will replay them after this
ships.
This commit is contained in:
parent
658c4d3221
commit
41ab95ec4d
7 changed files with 164 additions and 18 deletions
|
|
@ -75,6 +75,21 @@ class KevinTimeHorizon(str, enum.Enum):
|
|||
UNSPECIFIED = "unspecified"
|
||||
|
||||
|
||||
class KevinExpectedMove(str, enum.Enum):
|
||||
"""Forward-looking directional view over the mention's time_horizon.
|
||||
|
||||
Added in prompt_version v2 (2026-05-28) — captures the LLM's prediction
|
||||
of where the stock is going, separate from Kevin's reactive action.
|
||||
"""
|
||||
|
||||
UP_STRONG = "up_strong"
|
||||
UP_MILD = "up_mild"
|
||||
SIDEWAYS = "sideways"
|
||||
DOWN_MILD = "down_mild"
|
||||
DOWN_STRONG = "down_strong"
|
||||
UNKNOWN = "unknown"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Models
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -232,6 +247,15 @@ class KevinStockMention(Base):
|
|||
video_timestamp_seconds: Mapped[int | None] = mapped_column(
|
||||
Integer, nullable=True
|
||||
)
|
||||
expected_move: Mapped[KevinExpectedMove] = mapped_column(
|
||||
SAEnum(
|
||||
KevinExpectedMove,
|
||||
name="kevin_expected_move",
|
||||
values_callable=lambda x: [e.value for e in x],
|
||||
),
|
||||
nullable=False,
|
||||
server_default=KevinExpectedMove.UNKNOWN.value,
|
||||
)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), nullable=False
|
||||
)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,23 @@ class MarketOutlook(str, Enum):
|
|||
MIXED = "mixed"
|
||||
|
||||
|
||||
class ExpectedMove(str, Enum):
|
||||
"""Forward-looking directional view on a ticker over its time_horizon.
|
||||
|
||||
Independent of `action` — action records what Kevin recommends doing,
|
||||
expected_move records where the LLM thinks the stock is going next.
|
||||
This is the field the bridge should weight when deciding whether to
|
||||
paper-trade.
|
||||
"""
|
||||
|
||||
UP_STRONG = "up_strong" # >= +5% over the horizon
|
||||
UP_MILD = "up_mild" # +1% to +5%
|
||||
SIDEWAYS = "sideways" # -1% to +1%
|
||||
DOWN_MILD = "down_mild" # -5% to -1%
|
||||
DOWN_STRONG = "down_strong" # <= -5%
|
||||
UNKNOWN = "unknown" # Kevin made no directional call
|
||||
|
||||
|
||||
class VideoStatus(str, Enum):
|
||||
"""Status of a video in the processing pipeline."""
|
||||
|
||||
|
|
@ -92,6 +109,10 @@ class MeetKevinTickerMention(BaseModel):
|
|||
video_timestamp_seconds: int | None = Field(
|
||||
default=None, description="Timestamp for deep-link target"
|
||||
)
|
||||
expected_move: ExpectedMove = Field(
|
||||
default=ExpectedMove.UNKNOWN,
|
||||
description="Forward-looking directional view over time_horizon",
|
||||
)
|
||||
|
||||
@field_validator("symbol")
|
||||
@classmethod
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue