Skip to content

symfonic.kernel.contracts.diagnostics

diagnostics

G10 โ€” the compile record (IPL-11).

The rule this module serves is narrow and testable: "why did this invocation not use my capability?" must be answerable from the diagnostics alone, without re-running. Everything published here is pure data โ€” no exception objects, live bindings, secrets, or tenant payloads. The internal manifest builder reduces live contributions to that same safe shape.

DiagnosticRecord dataclass

DiagnosticRecord(category: str, subject: str, detail: str)

One fact about how this plan was compiled.

PlanDiagnostics dataclass

PlanDiagnostics(records: tuple[DiagnosticRecord, ...] = ())

The whole compile record, ordered as the compiler produced it.

explain

explain() -> str

Render the record as safe-to-log text (ERR-5).

Source code in src/symfonic/kernel/contracts/diagnostics.py
def explain(self) -> str:
    """Render the record as safe-to-log text (ERR-5)."""
    return "\n".join(record.render() for record in self.records)

composition_manifest

composition_manifest(stages: Sequence[Any], tools: Sequence[tuple[str, Any]], names: Sequence[str], preconditions: Sequence[Any]) -> Mapping[str, Any]

Return an immutable, payload-free attestation of a contribution fold.

Source code in src/symfonic/kernel/contracts/diagnostics.py
def composition_manifest(
    stages: Sequence[Any],
    tools: Sequence[tuple[str, Any]],
    names: Sequence[str],
    preconditions: Sequence[Any],
) -> Mapping[str, Any]:
    """Return an immutable, payload-free attestation of a contribution fold."""
    stage_rows = tuple(_stage_row(stage) for stage in stages)
    tool_rows = tuple(
        (str(owner), str(getattr(tool, "name", "") or "")) for owner, tool in tools
    )
    material = {
        "capabilities": tuple(str(name) for name in names),
        "stages": stage_rows,
        "tools": tool_rows,
        "tool_signatures": tuple(_tool_signature(*row) for row in tools),
        "preconditions": tuple(_precondition_row(check) for check in preconditions),
    }
    encoded = json.dumps(material, sort_keys=True, separators=(",", ":"))
    return MappingProxyType(
        {
            **material,
            "digest": f"sha256:{hashlib.sha256(encoded.encode()).hexdigest()}",
        }
    )