- Added a new SceneRulebook system to manage data-driven validation rules for actions. - Introduced rule checks for actions like "take", "open", "move", "introduce", and "describe". - Created a rulebook engine to evaluate conditions and enforce rules during action validation. - Enhanced action handling with support for scene entry and character descriptions. - Updated the architecture documentation to reflect the new rule-based validation approach. - Added new endpoints and improved the persistence layer for rulebooks.
95 lines
3.6 KiB
TypeScript
95 lines
3.6 KiB
TypeScript
/**
|
|
* SceneRulebook — data-driven validation rules for the truth engine.
|
|
*
|
|
* Rules are stored per-scene in the database and evaluated by rulebookEngine.ts.
|
|
* The default set is seeded from defaultRulebook.ts and mirrors the original
|
|
* hardcoded logic in truthEngine.ts.
|
|
*/
|
|
|
|
/** Which entity in the action context a condition refers to. */
|
|
export type EntityRole = "actor" | "target" | "actorRoom" | "targetRoom";
|
|
|
|
/**
|
|
* A composable, JSON-serialisable condition expression.
|
|
*
|
|
* Combinators: and | or | not
|
|
* Predicates:
|
|
* entityExists — entity referenced by role is present in world state
|
|
* entityExistsOrWillBeCreated — entity exists OR will be created earlier in this turn
|
|
* entityType — entity.type === requiredType
|
|
* eq / neq — entity field comparison (id, name, type, or attributes[attribute])
|
|
* attributeExists — entity.attributes[attribute] is not undefined
|
|
* sameLocation — two entities share the same location attribute value
|
|
* actorIdIn — action.actorId is included in an allowed list
|
|
* actorNameIn — actor.name matches one of an allowed list (case-insensitive)
|
|
* attributeRef — entities[checkRole].attributes[prefix + entities[refRole].attributes[refAttribute]] === true
|
|
* metaValueNotInRoom — no entity of entityType in actor's room has name === action.metadata[metaKey]
|
|
*/
|
|
export type ConditionExpr =
|
|
| { op: "and"; conditions: ConditionExpr[] }
|
|
| { op: "or"; conditions: ConditionExpr[] }
|
|
| { op: "not"; condition: ConditionExpr }
|
|
| { op: "entityExists"; role: EntityRole }
|
|
| { op: "entityExistsOrWillBeCreated"; role: EntityRole }
|
|
| { op: "entityType"; role: EntityRole; requiredType: string }
|
|
| { op: "eq"; role: EntityRole; attribute: string; value: unknown }
|
|
| { op: "neq"; role: EntityRole; attribute: string; value: unknown }
|
|
| { op: "attributeExists"; role: EntityRole; attribute: string }
|
|
| { op: "sameLocation"; roleA: EntityRole; roleB: EntityRole }
|
|
| { op: "actorIdIn"; allowedIds: string[] }
|
|
| { op: "actorNameIn"; allowedNames: string[] }
|
|
| {
|
|
op: "attributeRef";
|
|
/** Entity whose attribute is being tested */
|
|
checkRole: EntityRole;
|
|
/** Optional string prepended to the resolved key (e.g. "has_") */
|
|
prefix?: string;
|
|
/** Entity that provides the dynamic attribute name */
|
|
refRole: EntityRole;
|
|
/** Attribute on refRole whose value supplies the key name */
|
|
refAttribute: string;
|
|
}
|
|
| {
|
|
op: "metaValueNotInRoom";
|
|
/** Key in action.metadata whose value to match against entity names */
|
|
metaKey: string;
|
|
/** Only match entities of this type */
|
|
entityType: string;
|
|
};
|
|
|
|
/** A single named check within an action rule set. */
|
|
export type RuleCheck = {
|
|
id: string;
|
|
/** Human-readable label shown in the rulebook editor. */
|
|
description: string;
|
|
condition: ConditionExpr;
|
|
failReason: string;
|
|
/**
|
|
* Failure message template.
|
|
* Supports: {actor.id}, {actor.name}, {target.id}, {target.name}
|
|
*/
|
|
failMessage: string;
|
|
};
|
|
|
|
/** All checks that apply to a specific action type. */
|
|
export type ActionRuleSet = {
|
|
actionType: string;
|
|
/**
|
|
* When false, all checks are skipped and the action always passes.
|
|
* Useful for quickly disabling enforcement without deleting the rules.
|
|
*/
|
|
enabled: boolean;
|
|
checks: RuleCheck[];
|
|
};
|
|
|
|
/** The full rulebook attached to a scene/world. */
|
|
export type SceneRulebook = {
|
|
id: string;
|
|
worldId: string;
|
|
name: string;
|
|
description?: string;
|
|
rules: ActionRuleSet[];
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
};
|