Files
FabledScribe/alembic/versions/0119_rule_moment_misfires.py
T
bvandeusenandClaude Opus 5.5 4e1320120d
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m19s
CI & Build / Python tests (push) Successful in 2m3s
CI & Build / Build & push image (push) Successful in 18s
feat(moments): a mount that keeps arriving where it does not apply proposes its own removal (milestone 458 step 7b, #4955)
The open-after-moment signal proposes a mount; nothing proposed taking one
off, so a wrong mount was noise at every occurrence until someone happened
to notice. rule_misfired(rule_id, moment, why, reached_by) records a report
against a MOUNTED pair, counted per distinct day (the MCP door carries no
session id) on a new rule_moment_judgments.misfire column (migration 0119,
backup v24). At three days the response carries a line asking the agent to
offer the operator the fix - reject takes the rule off, unmap_action stops
the action reaching the moment, confirm keeps the mount and stops the
asking - and Settings > Moments lists it as an unmount proposal with the
reasons and the actions that reached it. A re-mount clears the count.

Taught in moments.md, missed-retrieval.md and the reply hold's wording.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 18:19:59 -04:00

37 lines
1.2 KiB
Python

"""rule_moment_judgments.misfire — a mount reported as arriving where it does
not apply (milestone 458 step 7b, #4955)
Revision ID: 0119
Revises: 0118
Create Date: 2026-10-05
The open-after-moment signal proposes a mount; nothing proposed taking one
off. This column is the evidence for that direction: each time a session says
a mounted rule arrived at a moment where it did not apply, the report is
counted here per distinct day, with its reason and the action that reached
the moment. At the bar it becomes an unmount proposal for the operator.
A column on the judgment row rather than a table of its own: a misfire is
always about a (rule, moment) pair that is mounted, and that pair already has
its row. Nullable and no backfill — nobody has reported a misfire yet.
"""
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
from alembic import op
revision = "0119"
down_revision = "0118"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.add_column(
"rule_moment_judgments",
sa.Column("misfire", postgresql.JSONB(), nullable=True),
)
def downgrade() -> None:
op.drop_column("rule_moment_judgments", "misfire")