Holons Shared Objects Layer Design Spec (v0.1)¶
Status¶
Proposed
Purpose¶
The Holons Shared Objects Layer defines the runtime object model that is shared across MAP host, guest, command, dance, query, loader, and SDK-facing execution surfaces. It is the home for in-memory holon lifecycle semantics, transaction staging semantics, relationship mutation intent, and commit-facing runtime contracts.
For the broader architectural frame that relates this layer to integrity-layer
persistence, the reference layer, and typed core structs, see
holon-layered-representation-design-spec.md.
This spec is intentionally scoped to the shared runtime objects that determine how holons move through transient, staged, saved, abandoned, and committed states. It does not define persistence storage formats, descriptor schema structure, command routing, or user-facing SDK ergonomics except where those surfaces depend on shared object semantics.
Layer Boundary¶
The Holons Shared Objects Layer owns:
- runtime holon variants such as
TransientHolon,StagedHolon, andSavedHolon - references to those runtime objects
HolonState,StagedState,SavedState, andValidationStateHolonCollectionand relationship map phase semantics- nursery-held staged object state
- lifecycle accounting for governed mutations and assembled relationship changes
- controlled replacement of staged validation state and identity-only findings
- the commit-facing meaning of staged actions and relationship anchors
It does not own:
- Holochain entry or link storage mechanics
- descriptor schema definitions
- descriptor-owned semantic metadata such as
IsDefinitional - command, dance, query, or SDK-specific public API shape
- issue-specific implementation sequencing
Descriptors remain the semantic source of truth for relationship metadata. The shared objects layer consumes descriptor metadata to classify runtime mutation intent.
Core Concepts¶
HolonState¶
HolonState is an access-control state for a runtime holon object.
Mutablemeans the object may accept write operations permitted by its phase.Immutablemeans the object may be read, cloned, committed where applicable, or abandoned where applicable, but may not accept ordinary writes.
HolonState is orthogonal to StagedState. A staged holon can be mutable while
it is being edited and immutable after it is committed or abandoned.
ValidationState¶
ValidationState records the most recent descriptor-aware validation observation for the runtime
holon. It does not determine whether Commit validates the holon, creates a new holon node, updates
an existing holon node, or performs graph-only relationship persistence.
The canonical states are NoDescriptor, ValidationRequired, Validated, and
Invalid. ValidationState and CommitValidationViolation findings are runtime state of
StagedHolon; they are not persisted authored Holon content. Validation findings are stored
separately from operational HolonErrors because a semantic rejection is an assessed outcome,
not a failure to assess. A mutation to properties,
relationships, descriptor selection, or an applicable descriptor/binding may mark a prior result
stale and return the affected staged holon to ValidationRequired.
Validated is not a validation cache and never allows Commit to skip a staged holon. Every Commit
validates the complete current Nursery and refreshes validation findings. Commit also
performs its aggregate Commit-local relationship pass before persistence, and that pass may mark
a holon Invalid even if a prior pass reported it Validated.
holons_core exposes one controlled operation that replaces a staged holon's validation state and
validation findings together after an assessment pass. Consumers must not update one without the
other or append new findings indefinitely. Operational errors are preserved independently.
Validation Crate Boundary¶
Descriptor-aware validation is implemented in a separate WASM-safe holons_validation crate. The
dependency direction is:
- dependency-safe
CommitValidationViolationidentity and subject-path primitives live incore_types, belowholons_core, so staged state can store findings without depending upward on the validator. They must not be placed inintegrity_core_types, which remains descriptor-independent for PVL even though it ownsHolonError; holons_coreowns references, descriptor semantics, effective products, and controlled staged-outcome replacement;holons_validationowns validation contexts, registries, handlers, collectors, andCommitValidationReport;holons_boundaryowns the wire projection.StagedHolonWirecarries a serializable identity-only findings collection alongside its existingvalidation_state, kept separate from its operationalerrors. Bound runtime references must not appear in findings and therefore never cross this boundary; and- guest Commit owns prospective relationship views, prepared persistence plans, execution of those plans, and response projection.
The required holons_core validation facade is intentionally narrow: effective targets with
provenance, effective constraint and binding accessors, subtype compatibility, property snapshots,
native value-kind checking, and controlled validation-outcome replacement. Validation must not
introduce a parallel reference, descriptor, mutation, or persistence surface.
StagedHolon¶
A StagedHolon is a transaction-scoped runtime object held by the Nursery. It
can represent:
- a new holon that has never been persisted
- an existing holon cloned for possible update
- an existing holon used only as a graph mutation context
- a version-producing update to an existing holon
- a completed or abandoned staged object
Staging an existing holon is not itself a persistence obligation. It is a statement of intent and a place to collect possible mutation intent. Commit work is created only when an accepted mutation changes the staged action.
StagedState Contract¶
StagedState is the action state machine for staged holons. It is not merely a
flag that a holon is in the Nursery. It tells commit what kind of action, if
any, is required.
Canonical staged action states:
| State | Meaning |
|---|---|
ForCreate |
A new holon will create a new persisted holon node during commit. |
ForUpdate |
An existing holon has been staged for possible update, but no commit-relevant mutation has occurred. |
ForUpdateGraphOnly |
An existing holon has only non-definitional relationship mutations. Commit performs graph writes without creating a new holon node version. |
ForUpdateNewVersion |
An existing holon has a version-producing mutation. Commit creates a new persisted holon node version. |
Committed(LocalId) |
Commit has completed for this staged holon and resolved the local relationship anchor. |
Abandoned |
The staged holon has been intentionally abandoned and will not be committed. |
If an implementation currently exposes a legacy ForUpdateChanged name, that
name denotes the same semantic role as ForUpdateNewVersion: an existing holon
has been changed in a way that requires a new persisted version. Runtime
contracts should converge on the semantic state names above.
Mutation Triggers¶
State transitions should be labeled and implemented by trigger, not by effect. The target state expresses the effect.
Property Mutation¶
A property mutation means any accepted operation that adds, changes, or removes a property value on an existing staged holon.
Property mutations are always version-producing for existing holons.
Relationship Mutation¶
A relationship mutation means any accepted operation that adds or removes a relationship occurrence on an existing staged holon.
Relationship mutations must be classified by the relationship descriptor's
schema-backed IsDefinitional value:
IsDefinitional == truemeans the relationship mutation is version-producing.IsDefinitional == falsemeans the relationship mutation is graph-only.
Governed mutation APIs must resolve the relevant relationship descriptor before accepting
a relationship mutation that affects staged action. If the descriptor cannot be
resolved, or if IsDefinitional cannot be read, the mutation must fail loudly.
Governed APIs must not silently default either to graph-only or to version-producing behavior.
Ungoverned graph assembly skips targets already present and preserves lifecycle while writing.
After relationship assembly, producers account for net additions against the assembled contract.
Undeclared names preserve lifecycle and are rejected by Commit; other classification failures
are diagnosed and conservatively produce a new version to preserve version-bound state.
This assembly exception does not authorize relationships or bypass Commit validation.
Reattaching the same descriptor preserves the edge; changing DescribedBy is definitional.
For ForCreate, IsDefinitional does not decide whether a node is created. A
new holon creates a new node by construction. Descriptor metadata may still
matter for validation and relationship legality.
StagedHolon State Machine¶
stateDiagram-v2
state "Committed(LocalId)" as Committed
[*] --> ForCreate: new_for_create / new_from_clone_model / stage_new_holon
[*] --> ForUpdate: stage_new_version / stage_for_update
ForCreate --> Abandoned: abandon_staged_changes
ForCreate --> Committed: commit
ForUpdate --> Abandoned: abandon_staged_changes
ForUpdate --> ForUpdate: commit with no mutation
ForUpdate --> ForUpdateNewVersion: property mutation
ForUpdate --> ForUpdateNewVersion: relationship mutation, IsDefinitional == true
ForUpdate --> ForUpdateGraphOnly: relationship mutation, IsDefinitional == false
ForUpdateGraphOnly --> Abandoned: abandon_staged_changes
ForUpdateGraphOnly --> Committed: commit
ForUpdateGraphOnly --> ForUpdateGraphOnly: relationship mutation, IsDefinitional == false
ForUpdateGraphOnly --> ForUpdateNewVersion: property mutation
ForUpdateGraphOnly --> ForUpdateNewVersion: relationship mutation, IsDefinitional == true
ForUpdateNewVersion --> Abandoned: abandon_staged_changes
ForUpdateNewVersion --> Committed: commit
ForUpdateNewVersion --> ForUpdateNewVersion: property mutation
ForUpdateNewVersion --> ForUpdateNewVersion: relationship mutation
Committed --> Committed: commit
Transition Semantics¶
ForCreate¶
ForCreate is entered when a new staged holon is created from a transient holon
or clone model whose result is intended to be a new holon rather than an update
to an existing persisted holon.
Commit creates a new holon node and resolves Committed(LocalId) to the new
node's local id.
ForUpdate¶
ForUpdate is entered when a caller stages an existing holon for possible
update. This usually requires cloning the previous version into a transaction
editing context.
ForUpdate is only a statement of intent. If the caller does not make a
property mutation or relationship mutation, there is nothing to persist. Commit
must perform no node write and no graph write for that staged holon.
ForUpdateGraphOnly¶
ForUpdateGraphOnly is entered when an existing staged holon receives at least
one relationship mutation whose descriptor has IsDefinitional == false, and no
version-producing mutation has occurred.
Commit must not create a new holon node version for this state. It must persist
only the relevant graph relationship changes and resolve Committed(LocalId) to
the existing source holon's local id.
ForUpdateNewVersion¶
ForUpdateNewVersion is entered when an existing staged holon receives either:
- a property mutation
- a relationship mutation whose descriptor has
IsDefinitional == true - an assembly addition whose post-assembly classification fails for a reason other than an undeclared name, using the conservative fallback above
Commit creates a new persisted holon node version and resolves
Committed(LocalId) to the new version's local id.
Once an existing staged holon reaches ForUpdateNewVersion, later
non-definitional relationship mutations must not downgrade it to
ForUpdateGraphOnly. Definitional mutations dominate graph-only mutations.
Committed(LocalId)¶
Committed(LocalId) records that commit has completed the staged action and
resolved the source local id to use for relationship persistence.
An unchanged ForUpdate candidate returns NoAction and remains ForUpdate; it never
transitions to Committed or appears in SavedHolons for that outcome.
The LocalId means:
| Source state before commit | Committed(LocalId) value |
|---|---|
ForCreate |
the new holon node id |
ForUpdateGraphOnly |
the existing/original holon node id |
ForUpdateNewVersion |
the new holon node version id |
Because Committed(LocalId) is the relationship anchor result, all relationship
persistence paths must consume a single resolved anchor rather than duplicating
source-selection logic.
Abandoned¶
Abandoned is terminal for ordinary mutation. Commit skips abandoned staged
holons. Abandoning a staged holon makes it immutable.
Relationship Mutation and Baseline Content¶
A staged clone may contain baseline properties and baseline relationship content copied from a previous version so the caller can inspect and edit the holon inside the transaction.
Baseline content is not itself write intent.
For update states, relationship persistence must be based on accepted staged relationship mutations, not merely on every relationship collection present in the editing snapshot. Otherwise a no-op update or graph-only update could accidentally duplicate existing relationship writes or create a new version without an accepted version-producing trigger.
Relationship Anchoring¶
Commit must expose exactly one resolved source LocalId for relationship
persistence for each staged holon that has relationship work to perform.
The source anchoring rule is:
| Staged action | Node persistence | Relationship anchor |
|---|---|---|
ForCreate |
create new node | new node LocalId |
ForUpdate |
none | none |
ForUpdateGraphOnly |
none | existing/original LocalId |
ForUpdateNewVersion |
create new version | new version LocalId |
Abandoned |
none | none |
Committed(LocalId) |
already resolved | contained LocalId |
Forward and inverse SmartLink persistence must use the same resolved
relationship anchor. Inverse persistence must not independently infer a source
from stale staged state.
Target identity is resolved separately for every Commit invocation:
- A staged target with
Committed(LocalId)resolves to that committed identity. - A staged target accepted as
NoActionin the same invocation resolves to its versioned source id. The invocation records that accepted anchor without changing the target's lifecycle or weakening ordinaryholon_id()semantics. - An uncommitted create or an abandoned target remains an error; staging alone supplies no persisted target identity.
Invariants¶
ForUpdaterepresents intent to update, not a persistence obligation.- Property mutations on existing holons are always version-producing.
- Relationship mutations on existing holons are classified by descriptor-backed
IsDefinitional. IsDefinitional == truerelationship mutations are version-producing.IsDefinitional == falserelationship mutations are graph-only unless the staged holon has already become version-producing.- Version-producing mutations dominate graph-only mutations.
- A staged holon must never downgrade from
ForUpdateNewVersiontoForUpdateGraphOnly. - Governed relationship classification failures are errors. Assembly accounts for net additions after relationship assembly; undeclared names preserve lifecycle, while other failures use a logged, conservative new-version fallback (§Relationship Mutation).
- Reattaching the same descriptor preserves the
DescribedByedge. Attaching a different descriptor is a definitional mutation and produces a new version of an existing staged holon. - Commit source anchoring must be centralized and shared by all relationship persistence paths.
- Baseline relationships copied into a staged update context are not themselves relationship write intent.
NoActionretainsForUpdateand supplies only an accepted saved target anchor for that invocation, not a newSavedHolonsresult (§Relationship Anchoring).- Validation state and identity-only findings are replaced atomically and remain separate from operational errors.