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
44
alembic/versions/e5f6a7b8c9d0_kevin_expected_move.py
Normal file
44
alembic/versions/e5f6a7b8c9d0_kevin_expected_move.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
"""Add expected_move column to kevin_stock_mentions (prompt v2).
|
||||
|
||||
Adds the KevinExpectedMove enum and a NOT NULL column with default
|
||||
'unknown' so existing rows keep loading. New analyses produced by the
|
||||
v2 prompt will populate it with a real directional view.
|
||||
|
||||
Revision ID: e5f6a7b8c9d0
|
||||
Revises: d4e5f6a7b8c9
|
||||
Create Date: 2026-05-28
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
revision = "e5f6a7b8c9d0"
|
||||
down_revision = "d4e5f6a7b8c9"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
_ENUM_NAME = "kevin_expected_move"
|
||||
_VALUES = ("up_strong", "up_mild", "sideways", "down_mild", "down_strong", "unknown")
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
enum_type = postgresql.ENUM(*_VALUES, name=_ENUM_NAME, create_type=False)
|
||||
enum_type.create(op.get_bind(), checkfirst=True)
|
||||
|
||||
op.add_column(
|
||||
"kevin_stock_mentions",
|
||||
sa.Column(
|
||||
"expected_move",
|
||||
enum_type,
|
||||
nullable=False,
|
||||
server_default="unknown",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_column("kevin_stock_mentions", "expected_move")
|
||||
op.execute(f"DROP TYPE IF EXISTS {_ENUM_NAME}")
|
||||
Loading…
Add table
Add a link
Reference in a new issue