Skip to content

symfonic.agent.cutover.force_lever

force_lever

The C1-H replacement: one lever, two spellings, and only one of them on 11.0.

The contract half of TA8.39's single REPLACE row. The fourteen surfaces themselves live in :mod:~symfonic.agent.cutover.tools_surfaces and :mod:~symfonic.agent.cutover.tool_result_surfaces, and the rule that reads the row below lives in :mod:~symfonic.agent.cutover.config_retirement -- the same contract / data / rule split pause_policy, pause_surfaces and settings_contract already make, and made for the same two reasons: the published surface reads end to end without the enforcement in the way, and each piece stays inside the repository's module budget.

Why this is a REPLACE and not a migration. TA8.25 recommended MIGRATE for all six C1-H rows as one recommendation. It cannot be right for this one: procedural_force_first_action_tool is the deprecated half of a lever whose replacement already ships in the same model. config.py declares it "DEPRECATED v7.20.0", FrameworkConfig._warn_procedural_force_bool_deprecation emits a DeprecationWarning on every True, and FrameworkConfig.resolve_force_tool_choice already collapses both spellings into one mode with the Literal winning. Migrating the bool would carry a second spelling of one lever onto this line and preserve exactly the precedence tangle the deprecation exists to end.

What this replacement does NOT claim. The surviving spelling, procedural_force_tool_choice, is itself still refused to legacy -- it has its own row, with its own argument, in tools_surfaces. So this changes which field an adopter writes, not which body serves it. Saying that plainly is the point: reading a REPLACE as though the capability had reached the kernel is the mirror image of the error that collapses REPLACE into MIGRATE, and it would be just as wrong.

replaced_force_setting

replaced_force_setting(stock: Any, inactive: str, was: str) -> RetiredSetting

Build the row from the constants above, so nothing can drift.

Derived rather than written out for the reason pause_surfaces._replaced gives: the refusal an adopter reads and the contract published here are then the same sentence by construction.

Source code in src/symfonic/agent/cutover/force_lever.py
def replaced_force_setting(stock: Any, inactive: str, was: str) -> RetiredSetting:
    """Build the row from the constants above, so nothing can drift.

    Derived rather than written out for the reason ``pause_surfaces._replaced``
    gives: the refusal an adopter reads and the contract published here are then
    the same sentence by construction.
    """
    return RetiredSetting(
        group=FORCE_LEVER_GROUP,
        stock=stock,
        inactive=inactive,
        instead=(
            f"{was} On this line the lever continues under "
            f"{FORCE_REPLACEMENT}. What changes for you: {FORCE_BREAK}."
        ),
    )