Instruction file imported from detain/sugarcraft (
.cursor/rules/model-pattern.mdc). Copyright stays with the author.
SugarCraft TUI Model + value-object pattern
declare(strict_types=1);first line, PSR-4SugarCraft\<Sub>\(quirk:candy-core→SugarCraft\Core\).- Public classes
finalunless extension is part of contract. Publicreadonlyproperties for state. - Immutable + fluent: every
with*()returns a NEW instance via a privatemutate(...)helper. Canonicalcandy-sprinkles/src/Style.php; traitcandy-core/src/Concerns/Mutable.php. - Nullable fields need a paired
bool $XSet = falsesentinel. Canonicalsugar-bits/src/TextInput/TextInput.php. - Bare accessors (no
get). Factories mirror upstream —::new()default,Theme::ansi(),Spinner::line(),Spring::fps(60); never::create()/::make()/::default(). - TUI
Model(candy-core/src/Model.php):init(): ?\Closure·update(Msg): [Model, ?Cmd]·view(): string. Side effects →Cmds, neverview(). - Doc-comment cites
Mirrors charmbracelet/<repo>.<Method>. Comment WHY not WHAT. - i18n via
Lang::t($key,$params)(candy-pty/src/Lang.php).