CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 19s
CI & Build / integration (push) Failing after 43s
CI & Build / Python tests (push) Failing after 46s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / Build & push image (push) Skipped
A rule written before moments existed is mounted on nothing. Step 7 records, per (rule, moment), whether it belongs there and who said so: - rule_moment_judgments (migration 0118, backup v23): suggested / confirmed / rejected, from a pass, the signal, or an edit. Moment "" is "no moment fits". - The pass: rules_to_mount lists unjudged rules; propose_rule_moments records suggestions that mount nothing; rule_moment_proposals and judge_rule_moments put them to the operator. A confirm mounts, a reject is kept so the pair is never proposed again. Same service behind REST and a "Waiting on you" panel in Settings > Moments. - Edits are judgments: set_rule_moments, the one mount write path, confirms what was added and rejects what was removed in the same transaction. - The signal: scribe_moment.sh keeps a per-session acts ledger; when a rule is opened, scribe_record_opened.sh sends the last three minutes of it to /api/plugin/rule-opened. The acts resolve through the install's mappings; work.run and work.change are not evidence. Counted per distinct session with lesson_rules' evidence model, and once due the open returns one line asking the reader to offer the mount. - scribe_session_end.sh removes the session's scribe-moment files. Plugin 2026.10.05.2003. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
61 lines
2.3 KiB
Python
61 lines
2.3 KiB
Python
"""Moment proposals and judgments — what a mock can see (milestone 458 step 7).
|
|
|
|
The behaviour against real tables is tests/test_integration_rule_moment_judgments.py.
|
|
These pin the pieces that need no database: that the migration's CHECKs and
|
|
the model agree (rule 36), which moments count as evidence, and that the line
|
|
the signal hands a session names the tool that answers it.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
|
|
from scribe.models.rule_moment_judgment import JUDGMENT_STATES, NO_MOMENT, SOURCES
|
|
from scribe.services import moments as moments_svc
|
|
from scribe.services import rule_moment_judgments as svc
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def _migration():
|
|
path = ROOT / "alembic" / "versions" / "0118_rule_moment_judgments.py"
|
|
spec = importlib.util.spec_from_file_location("m0118", path)
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
def test_the_migration_checks_and_the_model_agree():
|
|
m = _migration()
|
|
assert tuple(m._STATES) == tuple(JUDGMENT_STATES)
|
|
assert tuple(m._SOURCES) == tuple(SOURCES)
|
|
|
|
|
|
def test_verdicts_name_real_states():
|
|
assert set(svc.VERDICTS.values()) <= set(JUDGMENT_STATES)
|
|
|
|
|
|
def test_no_moment_is_not_a_mountable_name():
|
|
""""" is the "none fits" answer; if it ever became mountable, a pass's
|
|
"no moment" would read as a mount on nothing."""
|
|
assert not moments_svc.is_moment(NO_MOMENT)
|
|
|
|
|
|
def test_the_ubiquitous_moments_are_not_evidence():
|
|
assert svc.signal_moments(["work.run", "work.verify", "work.change", "work.verify",
|
|
"not.a.moment", "skill.brainstorming"]) == [
|
|
"work.verify", "skill.brainstorming",
|
|
]
|
|
# Every skipped name is a real moment — a typo here would skip nothing.
|
|
assert all(moments_svc.is_moment(m) for m in svc.SIGNAL_SKIP)
|
|
|
|
|
|
def test_the_proposal_line_names_the_tool_that_answers_it():
|
|
rule = SimpleNamespace(id=11, title="Definition of done", kind="rule")
|
|
line = svc._proposal_line(rule, "work.verify", {"situations": ["a", "b", "c"]})
|
|
assert line.startswith("> Rule #11")
|
|
assert "`work.verify`" in line and "3 distinct sessions" in line
|
|
assert '"rule_id": 11' in line and '"moment": "work.verify"' in line
|
|
assert "judge_rule_moments" in line and '"reject"' in line
|