The contract an item logic must satisfy to carry the improvement flag and the Skill Development Roll (SDR) — the shared progression seam behind the ☆ star, the Improvement Flag checkbox, and the Improve with SDR action.

Implemented by sohl.document.item.logic.SkillLogic and sohl.document.item.logic.MysticalAbilityLogic. Both drive the exact same executors (setImproveFlag, unsetImproveFlag, toggleImproveFlag, improveWithSDR) and the exact same action definitions (defineImproveSdrActions), so the two can never drift.

interface SdrImprovable {
    actions: SohlMap<string, sohl.entity.action.SohlAction>;
    canImprove: boolean;
    masteryLevel: sohl.entity.modifier.MasteryLevelModifier;
    sdrIncr: number;
    sdrSkillBase: number;
    get actor(): null | SohlActor;
    get actorLogic(): null | SohlActorLogic<any>;
    get data(): TData;
    get document(): TData["parent"];
    get id(): DocumentId;
    get item(): SohlItem;
    get kind(): string;
    get label(): string;
    get name(): string;
    get parent(): TData;
    get speaker(): sohl.core.logic.SohlSpeaker;
    get typeLabel(): string;
    get uuid(): string;
    deleteDocument(
        _context: sohl.entity.action.SohlActionContext,
    ): Promise<void>;
    editDocument(_context: sohl.entity.action.SohlActionContext): Promise<void>;
    evaluate(): void;
    executeAction(
        shortcode: string,
        context?: sohl.entity.action.SohlActionContext,
    ): Promise<unknown>;
    finalize(): void;
    getContextOptions(): ContextMenuEntry[];
    initialize(): void;
    postFinalize(context: sohl.entity.action.SohlActionContext): void;
    toJSON(): PlainObject;
    [key: symbol]: true;
}

Hierarchy (View Summary)

Indexable

  • [key: symbol]: true

Properties

actions: SohlMap<string, sohl.entity.action.SohlAction>

Executable actions for this document, keyed by shortcode — context-menu entries, chat-card buttons, and lifecycle hooks. A script action shadows (wholly overrides) the intrinsic action of the same shortcode (see the constructor).

canImprove: boolean

Whether this item may be improved right now — the gate every improve executor checks before writing anything. Typically "the current user is a GM or owns the item, and the mastery level is live".

The mastery level the SDR is rolled against and, on success, raises.

sdrIncr: number

The amount by which a successful improveWithSDR raises the base mastery level.

sdrSkillBase: number

The Skill Base added to the SDR's 1d100. A Skill contributes its own computed Skill Base, so natural aptitude speeds improvement; an item with no Skill Base of its own (a Mystical Ability using its internal mastery level) contributes 0 and improves on the raw 1d100.

Accessors

  • get actor(): null | SohlActor
  • The owning SohlActor — the document itself when it is an actor, otherwise its owning actor (for an item, combatant, or effect), or null.

    Returns null | SohlActor

  • get actorLogic(): null | SohlActorLogic<any>
  • The logic of the owning actor — the Foundry-free way to reach the actor layer from any logic. For an actor's own logic this is itself; for an item's logic it is the owning actor's logic; otherwise null.

    Returns null | SohlActorLogic<any>

    Resolved through the SohlLogicData port, so logic code can navigate to the actor (and iterate items via allLogics / logicTypes / getItemLogic) without touching the Foundry document.

  • get data(): TData
  • This logic's typed data — its *Data interface (e.g. SkillData), the same persisted object as document.system. Prefer document.logic.data when reading a document's fields from a macro, Script Action, or module: it is the typed, API-documented surface (autocomplete and reference links resolve), whereas document.system is typed as the internal DataModel.

    Returns TData

    Convenience accessor for parent.

  • get item(): SohlItem
  • The owning SohlItem.

    Returns SohlItem

    If this logic is not embedded in an item.

  • get kind(): string
  • The owning document's kind (its actor or item type id).

    Returns string

  • get typeLabel(): string
  • Localized type (and sub-type, when present) label for the owning document.

    Returns string

  • get uuid(): string
  • The owning document's UUID — the opaque identity token from the data port.

    Returns string

Methods

  • Compute derived values that depend on sibling items being initialized.

    Returns void

    Called on every item after ALL items have completed initialize.

    Safe to access: sibling items' initialized state (e.g., reading trait attribute values for a skill base formula).

    Not safe to access: sibling items' evaluated state — another item's evaluate() may not have run yet. Dependencies on evaluated state belong in finalize.

    Example: a Skill reads trait attribute values to compute its skill base; a gear item resolves its containerId to find its parent container.

  • Resolve cross-item dependencies that require all items to have been evaluated.

    Returns void

    Called on every item after ALL items have completed evaluate.

    Safe to access: all sibling items' initialized and evaluated state.

    Example: fate mastery level (which depends on an already-evaluated Aura trait); encumbrance totals summed across all evaluated gear.

  • The context-menu options — the actions currently available — for this logic's document.

    Returns ContextMenuEntry[]

    The available context-menu entries.

    One entry per action whose visible predicate currently passes (an action's trigger / domain preconditions can hide it); SCRIPT actions are additionally permission-gated when executed. Use this to discover which actions can be performed on the document.

  • Set up base state from persisted data: create ValueModifiers, set base values.

    Returns void

    Called on every item before any item's evaluate runs.

    Safe to access: own persisted data fields (this.data.*).

    Not safe to access: sibling items on the same actor — they may not have initialized yet. Cross-item reads belong in evaluate.

    Example: a Skill creates its MasteryLevelModifier from persisted fields; it does not yet read trait attribute values.

  • Serialize this logic to a plain reference.

    Returns PlainObject

    A uuid-keyed reference to this logic.

    A logic is a behavior wrapper over a live Foundry document; it is never revived from its own JSON (its constructor needs that document). Wherever a logic is persisted — a chat card, an action sohl.entity.action.SohlActionContext.scope — it is re-resolved from its uuid (e.g. via fvttLogicFromUuidSync), not rebuilt from a payload. So it serializes as a compact, resolvable reference (name/kind are carried for display and debugging); the owning document holds the actual persisted state.