Skip to content

symfonic.diagnostics.inspection.config_checks

config_checks

Configuration inspectors: legacy spellings, conflicts, and unchosen values.

Four questions, one adapter pass:

  • What did you write in the legacy dialect? Every supplied key that the T2.2.3 registry knows, mapped to the native target it feeds. Nothing was removed, so these are informational -- but they are the list a migration works through, and nobody could previously get it without reading 139 rows of a table by hand.
  • What contradicts what? The cross-capability rules already refuse a contradictory configuration at construction time. Reported here instead of raised, so an adopter sees all of them at once, before deploying.
  • What did you never choose? Provenance distinguishes a value that was set from one that arrived by default. Most defaults are fine; a curated few decide whether state survives a restart, whether a skill runs unapproved, and what a turn costs. Those are worth naming, and only those -- a report that listed all 117 defaults would be read by nobody.

capability_conflicts

capability_conflicts(probe: ConfigProbe) -> list[InspectionFinding]

Cross-capability rules this configuration breaks, reported not raised.

Source code in src/symfonic/diagnostics/inspection/config_checks.py
def capability_conflicts(probe: ConfigProbe) -> list[InspectionFinding]:
    """Cross-capability rules this configuration breaks, reported not raised."""
    if probe.rejected is not None:
        return [
            InspectionFinding(
                code="CONFIG-REJECTED",
                category="capability-conflict",
                severity=Severity.ERROR,
                subject="configuration",
                detail=f"the configuration could not be read: {probe.rejected}",
                migration_action=(
                    "Fix the value the error names; no other check could run "
                    "against this configuration."
                ),
            )
        ]
    return [
        InspectionFinding(
            code=rule,
            category="capability-conflict",
            severity=Severity.ERROR,
            subject=rule,
            detail=message,
            migration_action=_RULE_GUIDANCE.get(rule, _DEFAULT_GUIDANCE),
        )
        for rule, message in probe.errors
        if rule not in _EXTRA_RULES and rule not in _LIFECYCLE_RULES
    ]

implicit_defaults

implicit_defaults(probe: ConfigProbe) -> list[InspectionFinding]

Consequential values that arrived by default rather than by decision.

Source code in src/symfonic/diagnostics/inspection/config_checks.py
def implicit_defaults(probe: ConfigProbe) -> list[InspectionFinding]:
    """Consequential values that arrived by default rather than by decision."""
    if probe.normalized is None:
        return []
    entries = probe.normalized.provenance.entries
    findings: list[InspectionFinding] = []
    for target, (severity, consequence) in sorted(CONSEQUENTIAL_DEFAULTS.items()):
        entry = entries.get(target)
        if entry is None or entry.origin != "default":
            continue
        findings.append(
            InspectionFinding(
                code="UNSET",
                category="implicit-default",
                severity=severity,
                subject=target,
                detail=(
                    f"never set; the effective value is "
                    f"{entry.resolved_value!r} -- {consequence}"
                ),
                migration_action=(
                    f"Decide {target} explicitly, or record that the default is "
                    "the decision."
                ),
            )
        )
    return findings

legacy_configuration

legacy_configuration(probe: ConfigProbe) -> list[InspectionFinding]

Legacy keys in use, plus every compatibility diagnostic the adapter raised.

Source code in src/symfonic/diagnostics/inspection/config_checks.py
def legacy_configuration(probe: ConfigProbe) -> list[InspectionFinding]:
    """Legacy keys in use, plus every compatibility diagnostic the adapter raised."""
    findings = [
        InspectionFinding(
            code="LEGACY-KEY",
            category="legacy-configuration",
            severity=Severity.INFO,
            subject=key,
            detail=f"legacy spelling of the native target {target}",
            migration_action=(
                f"Still supported. When you move to native configuration, this "
                f"value becomes {target}."
            ),
        )
        for key, target in probe.legacy_keys
    ]
    findings.extend(
        InspectionFinding(
            code=diagnostic.rule_id,
            category="legacy-configuration",
            severity=Severity.WARN,
            subject=diagnostic.legacy_field,
            detail=(
                f"resolved to {diagnostic.native_target} = "
                f"{diagnostic.chosen_value!r} by rule {diagnostic.rule_id}"
            ),
            migration_action=diagnostic.migration_action,
        )
        for diagnostic in probe.diagnostics
    )
    return findings

legacy_pin

legacy_pin(config: Mapping[str, Any], *, package_version: str | None) -> list[InspectionFinding]

Expose a countable legacy-generation-pin verdict from raw data.

Source code in src/symfonic/diagnostics/inspection/config_checks.py
def legacy_pin(
    config: Mapping[str, Any], *, package_version: str | None
) -> list[InspectionFinding]:
    """Expose a countable legacy-generation-pin verdict from raw data."""
    declared = config.get(LEGACY_OVERRIDE_CONFIG_KEY)
    if not isinstance(declared, Mapping) or not declared:
        release = f"release {package_version}" if package_version else "release unspecified"
        return _pin_finding(
            "LP-0", Severity.INFO,
            f"{release}: inspected key {LEGACY_OVERRIDE_CONFIG_KEY!r} is absent or empty",
            "Keep generation overrides absent.",
        )
    bundles = ", ".join(sorted(str(bundle) for bundle in declared))
    if package_version is None:
        return _unknown_release_finding("not supplied", bundles)
    try:
        version, last_supported, first_rejecting = _policy_versions(package_version)
    except ConfigurationError:
        return _unknown_release_finding(repr(package_version), bundles)
    if version >= first_rejecting:
        return _pin_finding(
            "LP-2", Severity.ERROR,
            f"release {package_version} rejects the legacy pin declared for bundle(s): {bundles}",
            f"Pin symfonic-core=={LAST_SUPPORTED_LEGACY_OVERRIDE_VERSION}, migrate "
            "durable state to the current generation, then remove the override and upgrade.",
        )
    if version > last_supported:
        return _pin_finding(
            "LP-4", Severity.ERROR,
            f"release {package_version} has an undefined policy for the legacy pin "
            f"declared for bundle(s): {bundles}",
            "Use a release covered by the named legacy-override policy; do not deploy "
            "this pin on a gap release.",
        )
    return _pin_finding(
        "LP-1", Severity.WARN,
        f"release {package_version} honors the legacy pin declared for bundle(s): {bundles}",
        "Migrate durable state to the current generation and remove the override before "
        f"upgrading to {FIRST_REJECTING_RETIREMENT_VERSION}.",
    )