feat: ritual + judgment + favor + cross-over (Workstream B)
Implements Workstream B of the character-depth-ghost-log spec: ritual_start/ritual_step/judgment WS handlers, the pure judgment.py logic module, and the User.favor / Entity.at_peace columns + migration. - app/judgment.py: pure ritual success roll (base 65%, floored at 30%, driven by an entity's power+deceptiveness difficulty), the "stuck spirit" cross_over rule (alignment >= 0.5 and volatility > 0.6, ~20% of entities), judgment correctness/favor-delta/essence-delta/ consequence resolution for all four verdicts, favor clamping, the favor-to-trait-roll bias applied at mint time, and tell-line generation (opaque behavioral flavor text, never a raw stat). - app/ws.py: wires ritual_start/ritual_step/judgment frames, emits ritual_complete/tell/judgment_result/item_drop per the spec's Contract; traits are added to serialize_entity for internal server-side use but stripped from the outbound `entity` frame via a new _public_entity helper so hidden ground truth never reaches the client outside ritual_complete; _summon excludes at-peace entities from signature re-contact and mints a fresh (salted-signature) entity instead; new entities' traits are nudged by the discovering user's favor before being persisted. - models/user.py, models/entity.py, main.py: User.favor and Entity.at_peace columns plus their idempotent ADD COLUMN IF NOT EXISTS migration lines in lifespan, alongside the existing ones. - tests/test_judgment.py, tests/test_ws_ritual_judgment.py: 56 new tests covering the ritual/judgment correctness matrix, favor clamping/bias, essence crediting, at_peace persistence + re-contact, and the entity-frame trait leak guard. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import DateTime, Integer, String
|
||||
from sqlalchemy import DateTime, Float, Integer, String
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.db import Base
|
||||
@@ -14,13 +14,12 @@ class User(Base):
|
||||
username: Mapped[str] = mapped_column(String(32), unique=True, index=True)
|
||||
password_hash: Mapped[str] = mapped_column(String(255))
|
||||
email: Mapped[str | None] = mapped_column(String(255), nullable=True)
|
||||
# NOTE: owned by Workstream B in the character-depth-ghost-log spec
|
||||
# (docs/superpowers/specs/2026-07-23-character-depth-ghost-log-design.md).
|
||||
# Added here so Workstream C (unlocks/items/sigils/drops) can build and
|
||||
# test against it in isolation; the merge controller reconciles this
|
||||
# against Workstream B's own edit to this file (which will also add
|
||||
# `favor: float` per the spec's Contract section).
|
||||
essence: Mapped[int] = mapped_column(Integer, default=0)
|
||||
# Workstream B (character-depth-ghost-log spec): hidden per-user score,
|
||||
# nudged by judgment correctness, clamped to [-1.0, 1.0] everywhere it's
|
||||
# written (see app.judgment.clamp_favor). Read back as a small bias on
|
||||
# new entities' trait rolls at mint time (app.judgment.apply_favor_bias).
|
||||
favor: Mapped[float] = mapped_column(Float, default=0.0)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user