degrade: The Degradation Engine (capability-driven lowering, annotate + report)#

lower_with_enclaves immutably rewrites every non-native node through the declarative REGISTRY until the target writer sees only native semantic nodes. Exact target rules override target-neutral fallbacks; instance preflights refine nominally-native capability entries; every approximation, replacement, drop, and verified enclosure produces a path/span-addressed ConversionReport entry. A ConversionArtifact binds each enclosed report row to one exact source-occurrence carrier and a writer-recovered final typed marker link; legacy lower raises rather than discard a real carrier. Provenance comments are target-native and remain beside the affected flow construct when structurally legal.

Extensions receive the same process-wide REGISTRY: use REGISTRY.register, REGISTRY.register_preflight, and REGISTRY.register_comment to extend policy without changing the traversal mechanism.

The Degradation Engine (capability-driven lowering, annotate + report).

lower_with_enclaves immutably rewrites every non-native node through the declarative REGISTRY until the target writer sees only native semantic nodes. Exact target rules override target-neutral fallbacks; instance preflights refine nominally-native capability entries; every approximation, replacement, drop, and verified enclosure produces a path/span-addressed ConversionReport entry. A ConversionArtifact binds each enclosed report row to one exact source-occurrence carrier and a writer-recovered final typed marker link; legacy lower raises rather than discard a real carrier. Provenance comments are target-native and remain beside the affected flow construct when structurally legal.

Extensions receive the same process-wide REGISTRY: use REGISTRY.register, REGISTRY.register_preflight, and REGISTRY.register_comment to extend policy without changing the traversal mechanism.

class myform.degrade.Action(*values)#

The externally meaningful result of a non-native capability decision.

classmethod from_capability(capability: Capability) → Action#

Map a non-native writer capability to its report action.

exception myform.degrade.ArtifactRequiredError(enclaves: tuple[EnclaveRecord, ...], *, operation: str)#

A legacy return shape would discard one or more enclave carriers.

class myform.degrade.ConversionArtifact(*, text: str, report: ConversionReport, enclaves: tuple[EnclaveRecord, ...] = (), marker_links: tuple[Link, ...] = (), marker_text_hash: str | None = None, marker_format: str | None = None, marker_options: dict[str, JsonValue] | None = None)#

Target text, its complete report, and every addressed enclave carrier.

classmethod from_parts(*, text: str, report: ConversionReport, enclaves: tuple[EnclaveRecord, ...] = (), marker_links: tuple[Link, ...] = (), marker_options: Mapping[str, JsonValue] | None = None) → Self#

Recover target-native marker evidence from the exact rendered target text.

Caller-supplied links are accepted only when they exactly match the target writer’s recovery result; they cannot stand in for parsing the final target syntax.

class myform.degrade.ConversionReport(*, target: str, entries: tuple[ReportEntry, ...] = ())#

The complete ordered record of a single lowering pass.

property lossy: bool#

Whether at least one node was replaced or dropped rather than approximated.

ENCLOSED is deliberately not lossy, and the exclusion is the point of the capability rather than an oversight: an enclave relocates its node’s content into a carrier that ships with the output instead of degrading it, so nothing was lost. A conversion whose only non-native acts were enclosures is complete, not lossy – which is precisely what makes ENCLAVE worth reaching for over CARRY or DROP.

summary() → str#

Render one deterministic CLI-ready summary line.

class myform.degrade.EnclaveRecord(*, id: str, content_hash: str, source_format: str, source_path: tuple[int, ...] = (), node_kind: str, carrier_path: str, payload: AnyNode, source_text: str | None = None)#

One deterministic, reversible carrier for a source node.

id addresses the canonical carrier envelope, while content_hash retains the node’s position-independent semantic identity. The JSON carrier path is always relative and derived from the full SHA-256 id.

classmethod from_node(node: Node, *, source_format: str, source_path: tuple[int, ...] = ()) → Self#

Build a carrier from one typed source node.

Parameters:
  • node – Original typed node before lowering.

  • source_format – Registered format that produced node.

  • source_path – Structural occurrence path in the source document.

Returns:

A validated carrier with a canonical full-SHA address.

Raises:

ValueError – If source_format is empty or node is not a concrete typed node.

restore() → Node#

Revalidate and return an independent copy of the original typed node.

exception myform.degrade.DegradationError#

Base class for structured degradation failures.

class myform.degrade.LoweringContext(target: str, source: str, path: Path, capability: Capability, config: DegradeConfig, options: Mapping[str, object], document: Doc, _enclave_subject: Node | None = None, _enclave_source: Node | None = None)#

Read-only context handed to a lowering transform.

enclave(node: Node) → EnclaveRecord#

Build the canonical carrier from the engine-owned pre-transform source snapshot.

exception myform.degrade.LoweringCycleError(target: str, node_kind: str, path: tuple[int, ...])#

A lowering rule recreated a node already active in its replacement lineage.

exception myform.degrade.LoweringDepthError(target: str, node_kind: str, path: tuple[int, ...], depth: int)#

A lowering lineage exceeded the configured replacement-depth guard.

class myform.degrade.LoweringRegistry#

Mutable extension registry consulted read-only during each lowering pass.

property rules: Mapping[tuple[str, str], LoweringRule]#

A read-only live view of the registered lowering table.

property comments: Mapping[str, CommentFactory]#

A read-only live view of target-specific provenance comment factories.

property preflights: Mapping[tuple[str, str], PreflightRule]#

A read-only live view of content-sensitive native checks.

register(target: str, node_kind: str, *, name: str | None = None, note: str = '', purpose: PurposeTag | None = None, fallback: str = '', improve: Improve | None = None, replace: bool = False) → Callable[[Transform], Transform]#

Decorate and register a transform under (target, node_kind).

Parameters:
  • target – Target format name, or '*' for a target-neutral fallback.

  • node_kind – The model node type discriminator.

  • name – Stable report rule name. Defaults to the function name.

  • note – Static report note, joined with any dynamic RuleResult.note.

  • purpose – Assist purpose tag; None means the assist is never called.

  • fallback – Human-readable deterministic-fallback description for assist requests.

  • improve – Optional interpreter for an AssistResult; the generic text interpreter is used when absent.

  • replace – Permit deliberate replacement of an existing key.

Returns:

A decorator that returns the transform unchanged.

register_preflight(target: str, node_kind: str, *, name: str | None = None, replace: bool = False) → Callable[[Preflight], Preflight]#

Decorate a content-sensitive refinement for a nominally native node kind.

A check returns None/NATIVE when the instance is writable and a non-native capability when it needs ordinary registered lowering. Checks refine only NATIVE table entries; an explicit table policy is never upgraded or bypassed.

register_comment(target: str, *, replace: bool = False) → Callable[[CommentFactory], CommentFactory]#

Decorate a target-specific provenance-comment node factory.

resolve(target: str, node_kind: str) → LoweringRule | None#

Resolve an exact target rule, falling back to the target-neutral table.

preflight_for(target: str, node_kind: str) → PreflightRule | None#

Resolve an exact content-sensitive check, then a target-neutral one.

comment_for(target: str, entry: ReportEntry, context: LoweringContext) → Node | None#

Build a target-native provenance comment, when that target registered one.

class myform.degrade.LoweringRule(target: str, node_kind: str, transform: Transform, name: str, note: str = '', purpose: PurposeTag | None = None, fallback: str = '', improve: Improve | None = None)#

One registered lowering transform and its assist/report metadata.

exception myform.degrade.MissingLoweringRuleError(target: str, node_kind: str, capability: Capability)#

A capability table requested lowering but no target/neutral rule exists.

class myform.degrade.PreflightRule(target: str, node_kind: str, check: Preflight, name: str)#

One content-sensitive refinement of a nominally native kind.

class myform.degrade.ReportEntry(*, span: Span | None = None, path: tuple[int, ...] = (), node_kind: str, action: Action, rule: str, note: str = '', carrier_id: str | None = None, carrier_path: str | None = None)#

One reported non-native act at a source-tree address.

class myform.degrade.RuleResult(nodes: Replacement, note: str = '', terminal: bool = False, enclave: EnclaveRecord | None = None)#

A normalized-friendly rule result with optional out-of-band carrier.

exception myform.degrade.StrictDegradationError(entry: ReportEntry)#

Strict mode encountered a replacement or drop.

myform.degrade.lower(doc: ~myform.model.nodes.Doc, capabilities: ~collections.abc.Mapping[str, ~myform.writers.base.Capability], config: ~myform.config.options.DegradeConfig | ~collections.abc.Mapping[str, ~typing.Any] | None = None, assist: ~myform.assist.base.Assist | None = None, *, target: str, default_capability: ~myform.writers.base.Capability = Capability.NATIVE, options: ~collections.abc.Mapping[str, ~typing.Any] | None = None, registry: ~myform.degrade.registry.LoweringRegistry = <myform.degrade.registry.LoweringRegistry object>, max_depth: int = 64) → tuple[Doc, ConversionReport]#

Lower a document only when the legacy return shape would discard no carriers.

Use lower_with_enclaves when a capability table may request Capability.ENCLAVE. Marker-only rules remain compatible here because they produce no carrier and are reported as ordinary, lossy replacements.

Raises:

ArtifactRequiredError – A lowering returned a real carrier; call lower_with_enclaves.

myform.degrade.lower_with_enclaves(doc: ~myform.model.nodes.Doc, capabilities: ~collections.abc.Mapping[str, ~myform.writers.base.Capability], config: ~myform.config.options.DegradeConfig | ~collections.abc.Mapping[str, ~typing.Any] | None = None, assist: ~myform.assist.base.Assist | None = None, *, target: str, default_capability: ~myform.writers.base.Capability = Capability.NATIVE, options: ~collections.abc.Mapping[str, ~typing.Any] | None = None, registry: ~myform.degrade.registry.LoweringRegistry = <myform.degrade.registry.LoweringRegistry object>, max_depth: int = 64) → tuple[Doc, ConversionReport, tuple[EnclaveRecord, ...]]#

Lower doc until every remaining semantic node is native to target.

The original document is never mutated. A wholly native document is returned by identity; a changed document is revalidated from owned data before return. The supplied assist object is captured once for the whole call and invoked only by rules explicitly carrying a purpose tag, after their deterministic fallback has already succeeded.

Parameters:
  • doc – The source typed document.

  • capabilities – Writer node-kind capability table.

  • config – DegradeConfig, a raw degrade-section mapping, or defaults.

  • assist – One optional assist instance for the whole pass.

  • target – Target writer format name (the first registry-key component).

  • default_capability – Capability for kinds absent from capabilities.

  • options – Full conversion/target options exposed immutably to lowering rules. This is separate from the compatible config=DegradeConfig policy path.

  • registry – Lowering registry, overridable for isolated extensions/tests.

  • max_depth – Maximum non-native replacement-chain depth.

Returns:

The writer-native document, its complete non-native-action report, and every addressed enclave carrier in stable encounter order.

Raises: