Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
- Before designing an experiment, read [`experiments/README.md`](experiments/README.md): open checks plus every decided result and learning.
- When starting or closing one, edit its file, then run `python scripts/experiments.py index` and commit the README (CI fails if it is stale).
- `python scripts/experiments.py due` lists checks that are due; `readout <id>` prints the read-only SQL command for `$ANALYST_DATABASE_URL`.
- Metrics: use the `v_*` views and [`docs/analyst/north_star.sql`](docs/analyst/north_star.sql) (sessions, actives, shares, funnel); never redefine them ad hoc.
- Always exclude `segment = 'excluded'` (automated accounts, `v_metric_user`) from metrics and readouts.

## Operational notes
- Manual upload review happens entirely inside the designated Telegram upload review chat. Keep communications and escalations there for traceability.
Expand Down
2 changes: 2 additions & 0 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ User presses /start → meme with Like/Dislike → reaction triggers next meme.
**Session north star**: session length (memes per session), not like rate alone.
**Growth north star**: organic users via share deep links — see
[docs/growth/virality-loop.md](docs/growth/virality-loop.md).
**Measured by**: [docs/analyst/north_star.sql](docs/analyst/north_star.sql) on the
shared `v_*` metric views (definitions: [docs/analyst/README.md](docs/analyst/README.md)).

**Supply**: ETL of TG channels + VK publics → quality filters → recommendation pool.

Expand Down
10 changes: 2 additions & 8 deletions alembic/versions/2026-03-18_stats_perf_indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ def upgrade() -> None:
# for an index. All queries that filter on reaction_id either:
# - Filter within a per-user subset (uses PK)
# - Filter globally (WHERE reaction_id = 1 matches 50%, seq scan is faster)
op.execute(
"DROP INDEX CONCURRENTLY IF EXISTS "
"user_meme_reaction_reaction_id_idx"
)
op.execute("DROP INDEX CONCURRENTLY IF EXISTS user_meme_reaction_reaction_id_idx")

# Tune autovacuum for user_meme_reaction (22M rows).
# Default scale_factor=0.2 means vacuum triggers at 4.4M dead tuples.
Expand Down Expand Up @@ -66,7 +63,4 @@ def downgrade() -> None:
"ON user_meme_reaction (reaction_id)"
)

op.execute(
"DROP INDEX CONCURRENTLY IF EXISTS "
"ix_user_meme_reaction_reacted_at"
)
op.execute("DROP INDEX CONCURRENTLY IF EXISTS ix_user_meme_reaction_reacted_at")
16 changes: 4 additions & 12 deletions alembic/versions/2026-03-22_chat_agent_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,17 @@ def upgrade() -> None:
server_default=sa.func.now(),
nullable=False,
),
sa.UniqueConstraint(
"chat_id", "meme_id", "user_id", name="uq_chat_meme_reaction"
),
sa.UniqueConstraint("chat_id", "meme_id", "user_id", name="uq_chat_meme_reaction"),
)

op.create_table(
"chat_agent_usage",
sa.Column("id", sa.Integer(), sa.Identity(), primary_key=True),
sa.Column("chat_id", sa.BigInteger(), nullable=False),
sa.Column("user_id", sa.BigInteger(), nullable=False),
sa.Column(
"prompt_tokens", sa.Integer(), nullable=False, server_default="0"
),
sa.Column(
"completion_tokens", sa.Integer(), nullable=False, server_default="0"
),
sa.Column(
"tool_calls", sa.Integer(), nullable=False, server_default="0"
),
sa.Column("prompt_tokens", sa.Integer(), nullable=False, server_default="0"),
sa.Column("completion_tokens", sa.Integer(), nullable=False, server_default="0"),
sa.Column("tool_calls", sa.Integer(), nullable=False, server_default="0"),
sa.Column("response_time_ms", sa.Integer()),
sa.Column("trigger_type", sa.String()),
sa.Column(
Expand Down
12 changes: 3 additions & 9 deletions alembic/versions/2026-03-23_telegram_chat_and_wrapped.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,8 @@ def upgrade() -> None:
sa.Column("bot_status", sa.String(20)),
sa.Column("bot_joined_at", sa.DateTime()),
sa.Column("bot_left_at", sa.DateTime()),
sa.Column(
"created_at", sa.DateTime(), server_default=sa.func.now()
),
sa.Column(
"updated_at", sa.DateTime(), server_default=sa.func.now()
),
sa.Column("created_at", sa.DateTime(), server_default=sa.func.now()),
sa.Column("updated_at", sa.DateTime(), server_default=sa.func.now()),
)

op.add_column(
Expand All @@ -52,9 +48,7 @@ def upgrade() -> None:
),
sa.Column("data", JSONB, nullable=False),
sa.Column("card_telegram_file_id", sa.String()),
sa.Column(
"created_at", sa.DateTime(), server_default=sa.func.now()
),
sa.Column("created_at", sa.DateTime(), server_default=sa.func.now()),
)


Expand Down
4 changes: 1 addition & 3 deletions alembic/versions/2026-04-01_deep_link_log_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,4 @@ def upgrade() -> None:
def downgrade() -> None:
op.execute("COMMIT")

op.execute(
"DROP INDEX CONCURRENTLY IF EXISTS ix_user_deep_link_log_deep_link"
)
op.execute("DROP INDEX CONCURRENTLY IF EXISTS ix_user_deep_link_log_deep_link")
8 changes: 2 additions & 6 deletions alembic/versions/2026-04-01_meme_source_id_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,11 @@ def upgrade() -> None:
# Without an index the planner does a full sequential sort on every 15-min stats run,
# causing the 300s timeout. CONCURRENTLY avoids table lock on the large meme table.
op.execute(
"CREATE INDEX CONCURRENTLY IF NOT EXISTS "
"ix_meme_meme_source_id "
"ON meme (meme_source_id)"
"CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_meme_meme_source_id ON meme (meme_source_id)"
)


def downgrade() -> None:
op.execute("COMMIT")

op.execute(
"DROP INDEX CONCURRENTLY IF EXISTS ix_meme_meme_source_id"
)
op.execute("DROP INDEX CONCURRENTLY IF EXISTS ix_meme_meme_source_id")
8 changes: 2 additions & 6 deletions alembic/versions/2026-04-13_channel_growth_measurement.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ def upgrade() -> None:
sa.Column("comments", sa.Integer()),
sa.Column("reactions_detail", JSONB),
sa.Column("message_text", sa.String()),
sa.Column(
"snapshot_at", sa.DateTime(), server_default=sa.func.now(), nullable=False
),
sa.Column("snapshot_at", sa.DateTime(), server_default=sa.func.now(), nullable=False),
)
op.create_index(
"ix_crossposting_snapshots_channel_msg",
Expand All @@ -73,9 +71,7 @@ def upgrade() -> None:
sa.Column("posts_count", sa.Integer()),
sa.Column("total_forwards", sa.Integer()),
sa.Column("total_views", sa.Integer()),
sa.Column(
"created_at", sa.DateTime(), server_default=sa.func.now(), nullable=False
),
sa.Column("created_at", sa.DateTime(), server_default=sa.func.now(), nullable=False),
sa.UniqueConstraint("channel", "date"),
)

Expand Down
Loading
Loading