Skip to content

Add typed history states - #14

Merged
SandroMaglione merged 2 commits into
mainfrom
agent/history-states
Aug 2, 2026
Merged

Add typed history states#14
SandroMaglione merged 2 commits into
mainfrom
agent/history-states

Conversation

@SandroMaglione

Copy link
Copy Markdown
Member

Summary

  • add shallow and deep history pseudo-states to schema-first machine definitions
  • add zero-argument, path-safe target.history builders and typed defaults for first use
  • preserve validated state values for deep restoration and require fresh typed initializers only where shallow restoration descends
  • persist and validate history records across snapshot encoding and decoding
  • document history semantics and add a minor changeset

Semantics

History nodes are routing pseudo-states: they have no schema, never become active, and are excluded from ordinary state identifiers, snapshots, initial builders, and local/branch/full targets.

Each history node owns one overwriteable register:

  • shallow history retains the parent and direct active-child values, then runs typed initializers below the remembered boundary
  • deep history restores the complete remembered descendant configuration and values
  • restoration does not consume the register; the next parent exit overwrites it
  • defaults return a typed parent snapshot when no configuration has been captured
  • entry actions and invokes run again; prior effects, actors, and timers are not rewound

Machine readiness tracks missing defaults and shallow initializers through the existing staged .handle(...) model. Remembered values are schema-validated at persistence boundaries, including nested and parallel configurations.

Verification

  • pnpm check
  • 216/216 runtime tests
  • 101/101 type tests, 417 assertions
  • consumer package validation
  • package verification

Dedicated coverage includes defaults, exact deep restoration, shallow fresh initialization, overwrite/not-stack behavior, multiple history registers, parallel and nested-parallel restoration, same-microstep parent exit/reentry, lifecycle ordering, effectful initializers, and corrupt persisted paths/values.

The adversarial suite exposed a nested-parallel ancestor-value bug during development; the final scoped-history target preserves active ancestors and unaffected parallel sibling regions.

Type performance

Measured with TypeScript 6.0.3 and skipLibCheck=true:

Scenario Before After Total change Marginal change
Machine.defineStates 2,883 2,894 +11 (+0.4%) +11
Machine.make 7,838 8,334 +496 (+6.3%) +485 (+9.8%)
machine.handle 17,314 19,389 +2,075 (+12.0%) +1,579 (+16.7%)

A bounded optimization pass kept active/history filtering and readiness analysis intact. Further reduction would require weakening the filtered API or materially restructuring handler-topology analysis.

@SandroMaglione
SandroMaglione marked this pull request as ready for review August 2, 2026 09:56
@SandroMaglione
SandroMaglione merged commit 0c5755f into main Aug 2, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant