Date: 2026-07-07
State management is a central Hum design axis.
Most systems bugs are state bugs: hidden mutation, aliasing mistakes, data races, leaked resources, double frees, forgotten rollbacks, stale caches, untracked external authority, and state that changes outside the reader's mental model.
Hum's answer is not "never mutate." Systems programming needs mutation. Hum's answer is:
state is visible, permissioned, profile-aware, and evidence-producing
hum state-model and hum state-model --format json expose the V0 state model
contract.
The catalog schema is hum.state_model.v0; permission entries use
hum.state_permission.v0.
V0 mode is contract_only_partial_declared_mutation_check. This means the model
documents the intended state rules and names the small current checker behavior:
set name = ... must target a local change name: ... or a matching
changes: entry.
The hum state-model V0 contract document does not itself implement borrowing,
lifetime inference, move checking, concurrency, memory-order semantics, garbage
collection, executable semantics, optimizer behavior, or allocation placement.
hum ownership-check now implements narrow ordinary move checks, the first
Transaction-shaped linear-resource path check, and Session V's exact local
direct-field writable-alias/overlap slice; it is not a complete ownership,
borrow, alias, or memory-safety checker.
The schema document is HUM_STATE_MODEL_SCHEMA.md.
Hum should make the common path safe and boring:
- immutable values by default
- explicit local mutation with
change - explicit writes with
set - explicit external mutation with
changes: - explicit reads and authority with
uses: - explicit named state with
store - explicit resource policy with profiles
- explicit future ownership, borrowing, and linear-resource facts
The syntax should feel simple, but the compiler facts should be strict enough for a borrow checker, effect checker, debugger, verifier, optimizer, and agent to agree on what can change.
Ordinary data should be immutable unless the source asks for mutation.
let count: UInt = 0
Immutable values can be freely read, passed, printed, tested, and reasoned about. They are the paved road.
Task-local mutation must be declared:
change count: UInt = 0
set count = count + 1
This keeps mutation scannable and gives the future checker a clear permission
edge. A set without a matching change or changes: entry is already a
Milestone 0 diagnostic.
A place is a readable or writable location:
local
record.field
checked index
future store entry
Core Hum owns the exact place model. Backends must preserve place identity, source spans, aliasing facts, and mutation permission or report loss.
The first writable alias is deliberately bounded: let alias = change owner.field names one direct field in one straight-line task body. It writes
through, ends after its last syntactic use, accepts definitely distinct direct
fields, and rejects live overlap with H0808. H0809 keeps escape, storage,
permission wrapping, alias rebinding, live-owner rebinding, nested/element
aliases, already-visible-name shadowing, and control-flow use outside this
slice.
A store is named state with purpose and policy, not a casual global variable.
store sessions: map SessionId -> Session {
why:
remember active sessions
}
Future store declarations should carry ownership, durability, privacy, concurrency, target, and profile policy.
Handles, sockets, locks, transactions, raw buffers, foreign resources, and capabilities should eventually be linear resources: they must be consumed, closed, committed, rolled back, or transferred exactly once.
This is where Hum should learn from linear types without making every ordinary value painfully linear.
Shared mutable state is forbidden until Hum has a checked sharing form.
Future allowed forms may include actors, locks, atomics, regions, arenas, tasks, or runtime-owned queues, but each must expose ownership, synchronization, failure, replay, and profile facts.
Files, processes, network endpoints, clocks, randomness, devices, environment variables, host APIs, and platform authority are state too.
Hum must treat them as effects and capabilities, not implementation details.
Hum should teach state in source terms:
read: observe without mutation or ownership transferown: hold responsibility for a value or resourceborrow: temporarily read without owningchange: exclusively mutate a placeconsume: use a linear resource exactly onceshare: access through a checked shared-state form
These are human-facing names. The compiler may lower them to stricter internal facts, but diagnostics should explain state errors in these terms first.
- Immutable values are the default paved road.
- Mutation requires source-visible permission.
- A store is named state with policy, not a casual global variable.
- Shared mutable state is forbidden until a checked sharing form exists.
- Linear resources require exactly-once close, commit, rollback, consume, or transfer.
- Borrowing is permission to observe or change for a bounded region, not hidden copying.
- External state is an effect and a capability, not an implementation detail.
- Profiles may make the state model stricter, never looser without evidence.
State design affects every hard feature:
- type checking
- ownership and borrowing
- resource management
- async and concurrency
- unsafe boundaries
- foreign calls
- stdlib containers
- debugging
- profiling
- verification
- package and runtime profiles
- agent repair workflows
If state is not central, every later subsystem invents its own half-model.
- Keep
hum state-model --format jsonin preflight. - Keep
hum resolve --format jsonin preflight as the first checked source-place link report. - Add graph links for local mutable declarations and
settargets once the resolver shape is stable. - Add an effect report that compares declared
uses:/changes:with inferred reads and writes. - Keep widening ordinary move and no-use-after-move fixtures only when the executable core can demonstrate them.
- Broaden linear-resource fixtures from Transaction-shaped locals to handles, locks, and capabilities after the v0 path checker earns it.
- Delay concurrency syntax until the state model can explain ownership and memory-order facts.
No new Hum feature is allowed to hide state.
If it reads, writes, owns, borrows, consumes, shares, allocates, persists, caches, opens, closes, commits, rolls back, sends, receives, waits, or observes external authority, the state model must have a place for it.