symfonic.capabilities.memory.positional_rows¶
positional_rows ¶
Classify stored positional v0 rows for an explicit kind-aware migration.
Owner decision (CORE-171, 2026-10-13): a v0 row moves to native v1 identity only when its owner is recoverable without guessing. A row whose kinds were lost is quarantined for explicit deletion. Nothing here dual-reads positional keys as v1; classification is pure and never touches a backend.
A v0 row is one of two shapes:
- Explicit kinds -- a legacy
TenantScopepath whose stored kinds are not the positional stamp. The row names its whole owner, so it migrates as stored, at any depth. - Positional stamp --
tenant[/sub_tenant[/session]]written by the v0 capability, or a pre-v8 row with no path (tenant-global). Those kinds are what the v0 codec wrote, not what the owner was. The adopter must declare which native kinds the store ever wrote at that depth; exactly one candidate migrates, none or several quarantine. A depth-three row also quarantines when deeper scopes were ever composed against the store, because the pre-guard converter truncated them onto depth three.
PositionalOwnerDeclaration
dataclass
¶
PositionalOwnerDeclaration(kinds_by_depth: Mapping[int, tuple[tuple[str, ...], ...]], max_written_depth: int)
The adopter's attestation of the kinds a store ever wrote positionally.
kinds_by_depth maps a positional depth (1-3) to every native kind path
composed at that depth against this store. max_written_depth is the
deepest typed scope ever composed against it, including scopes the old
converter truncated. An undeclared depth is never inferred.
RowDisposition ¶
Bases: StrEnum
What a planned migration does with one stored row.
RowVerdict
dataclass
¶
A row's disposition; target is a storage key, never row content.
claim_verdict ¶
claim_verdict(record: str | None, stored: object, verdict: RowVerdict, owners: Mapping[str, str | None]) -> RowVerdict
A claim follows its record node's resolved owner, never its own path alone.
It migrates only when that node migrates to, or already holds, exactly the claim's own target; a missing, quarantined or different owner quarantines it.
Source code in src/symfonic/capabilities/memory/positional_rows.py
classify_stored_path ¶
classify_stored_path(stored: str | None, tenant_id: str, declaration: PositionalOwnerDeclaration) -> RowVerdict
Decide one row from its stored owner path alone.
Source code in src/symfonic/capabilities/memory/positional_rows.py
covering_keys ¶
target's own key and each ancestor key: every key whose forget erased it.
edge_verdict ¶
edge_verdict(source: str | None, target: str | None, stored: object, verdict: RowVerdict, owners: Mapping[str, str | None]) -> RowVerdict
An edge migrates only with both endpoints visible at its new owner.
owners maps a node id to the native owner it resolves to after the
migration; a node that is missing, quarantined or unmoved maps to None.
Source code in src/symfonic/capabilities/memory/positional_rows.py
erased_verdict ¶
A row whose new owner a recorded native forget erased never moves there.
Moving it would put back content the forget of that owner, or of any ancestor of it, was asked to erase (CORE-171 owner decision, 2026-10-14).
Source code in src/symfonic/capabilities/memory/positional_rows.py
origin_ids ¶
The ids a v0 owner names, root first; None when they cannot be read.
Every native owner a declaration could give the row carries exactly these ids, whatever kinds it declares.
Source code in src/symfonic/capabilities/memory/positional_rows.py
quarantine_key ¶
A key no positional or native read can match, carrying its origin.
Source code in src/symfonic/capabilities/memory/positional_rows.py
quarantined_origin ¶
The stored path a quarantine key replaced; None for a pre-v8 row.