tangl.core artifacts¶
Immutable and semi-structured artifacts used for recording and template-based construction.
Related design docs
Related notes
Artifacts¶
Immutable ordered records and append-only ordered registries.
This module defines Record as a frozen, content-addressed artifact and
OrderedRegistry as an append-only Registry
specialization with range slicing over a comparable sort-key space.
See also
tangl.core.basesRecord composition traits (
HasContent,HasOrder).tangl.core.registryBase registry behavior, selector filtering, and mapping semantics.
- class Record(_ctx=None, *, uid=<factory>, label=None, tags=<factory>, templ_hash=None, seq=None, origin_id=None, **kwargs)[source]¶
Frozen ordered artifact with content identity and optional origin reference.
Why¶
Records capture immutable runtime facts that should compare by content and remain orderable for stream-like processing.
Key Features¶
Three identity layers: stable
uidfromEntity, content equality fromHasContent, and sequence ordering fromHasOrder.Frozen + flexible schema:
frozen=Truewithextra='allow'supports arbitrary payload fields in derived record families.External origin dereference:
origin_idstores a producer reference, andorigin()resolves it through an explicitly supplied registry.
Notes
origin_idis not a registry-aware pointer. Dereference requires passing the correct lookup registry at call time.Example
>>> r = Record(content="foo") >>> r.get_hashable_content() 'foo' >>> try: ... r.content = "bar" ... except ValidationError as e: ... print(e) 1 validation error ...
- class OrderedRegistry(_ctx=None, *, uid=<factory>, label=None, tags=<factory>, templ_hash=None, members=<factory>, markers=<factory>)[source]¶
Append-only ordered registry with sort-key range slicing.
Why¶
Ordered registries provide deterministic range queries over members with
sort_key()support while keeping the core primitive independent from higher-level stream marker/bookmark policies.Key Features¶
append-only mutation model via
append()/extend();generic key accessors
min_key()/max_key();half-open range queries through
get_slice()with optional selector composition.
Notes
Named bookmarks/sections are intentionally out of scope for this core type and should be layered above it (for example in VM/story stream services). Core keeps append/slice only; bookmark channels and destructive undo truncation are runtime-policy concerns.
- class Snapshot(registry=None, graph=None, *, uid=<factory>, label=None, tags=<factory>, templ_hash=None, seq=None, origin_id=None, payload, admission_scope=None, **kwargs)[source]¶
Persistence convenience: a template that recreates an entity exactly.
A Snapshot is not part of the authoring loop. It is a persistence helper that reuses the template/materialization machinery to recreate a live entity with the same identifier and state.
materialize() preserves uid and rejects updates.
decompile() is not typically meaningful for snapshots.
Example
>>> e = Entity(label='abc') >>> s = Snapshot.from_entity(e) >>> ee = s.materialize() >>> e is not ee and e == ee # preserves uid True
- class BaseFragment(_ctx=None, *, uid=<factory>, label=None, tags=<factory>, templ_hash=None, seq=None, origin_id=None, fragment_type='content', content=None, **kwargs)[source]¶
Record-based fragment envelope for journal/content payloads.
- class EntityTemplate(payload: Entity)[source]¶
Template wrapper around an entity payload.
Why¶
EntityTemplateseparates authoring-time prototypes from runtime entities. A template can be compiled, searched, stored, and materialized repeatedly without becoming part of the live graph itself.Key Features¶
Supports authoring-loop transforms through
compileanddecompile.Supports runtime instantiation through
materialize().Distinguishes template-kind matching from payload-kind matching so callers can query wrapper shape and produced entity kind independently.
Can participate in template registries and hierarchical groups used by provisioning and materialization.
API¶
has_template_kind()checks the wrapper record type.has_payload_kind()checks the materialized entity kind.has_kind()matches either axis as a convenience.materialize()creates a live entity from the stored payload.
Example
>>> class PseudoEntity(Entity): ... >>> data = {'label': 'abc'} >>> templ = EntityTemplate.from_data(data, default_kind=PseudoEntity) >>> templ.has_template_kind(EntityTemplate) and templ.has_payload_kind(PseudoEntity) True >>> templ.materialize() <PseudoEntity:abc> >>> class PseudoEntity2(PseudoEntity): ... >>> templ.materialize(kind=PseudoEntity2, label="def") <PseudoEntity2:def> >>> templ.materialize().uid != templ.payload.uid # fresh id by default True
- class TemplateRegistry(_ctx=None, *, uid=<factory>, label=None, tags=<factory>, templ_hash=None, members=<factory>)[source]¶
Registry of templates with convenience materialization and authoring helpers.
TemplateRegistry is the primary container for authoring-loop operations:
compile(script) builds a flat registry from a list of script dicts.
decompile_all() emits a list of script dicts from top-level template groups.
Materialization helpers (materialize_one, materialize_all) provide a simple bridge into runtime, but they are not required for linting/compile/decompile.
Example
>>> tr = TemplateRegistry() >>> tr.add(EntityTemplate.from_data({'label': 'abc'})) >>> tr.add(EntityTemplate.from_data({'label': 'def'})) >>> tr.materialize_one(Selector.from_identifier('abc')) <Entity:abc> >>> list(tr.materialize_all()) [<Entity:abc>, <Entity:def>]