Context
_summarize_apply_outcome and _derive_status_label (dict-typed) currently live in katana_mcp/tools/foundation/bom_table.py (introduced by #857). Both are cross-entity-generic — they bucket any modify response's action outcomes regardless of entity kind (BOM, PO, etc.). Today they have only two direct callers:
katana_mcp.tools.foundation.bom (apply path)
katana_mcp.tools.prefab_ui.build_po_modify_ui
_derive_status_label is also imported back into prefab_ui._action_to_row.
Why deferred
#857 housed them in bom_table.py to break the foundation/bom → prefab_ui underscore-import coupling without spinning up a second new module. With only two real callers, a dedicated shared-modify-helpers module would be premature abstraction.
When to revisit
When a third caller appears (likely candidates: SO modify card, MO modify card, generic modify-result renderer), hoist these two helpers into a sibling module, e.g.:
katana_mcp/tools/foundation/modify_outcome.py — holds _summarize_apply_outcome + dict-typed _derive_status_label
bom_table.py re-imports them or callers swap directly to the new home.
Symbol inventory to move at that point:
_summarize_apply_outcome(actions: list[dict[str, Any]]) -> tuple[str, str]
_derive_status_label(action: dict[str, Any]) -> str (dict variant; the ActionResult-typed variant in _modification.py is unrelated and stays)
- Possibly
_BOM_ROW_STATUS_VARIANTS — though it's BOM-row-specific (Badge variant bucketing per status). Decide based on whether the third caller needs the same status→variant mapping.
Tracked by inline comment
bom_table.py carries a # TODO(#<this-issue>) reference at the _summarize_apply_outcome definition so the deferred work isn't only in #857's PR description.
Context
_summarize_apply_outcomeand_derive_status_label(dict-typed) currently live inkatana_mcp/tools/foundation/bom_table.py(introduced by #857). Both are cross-entity-generic — they bucket any modify response's action outcomes regardless of entity kind (BOM, PO, etc.). Today they have only two direct callers:katana_mcp.tools.foundation.bom(apply path)katana_mcp.tools.prefab_ui.build_po_modify_ui_derive_status_labelis also imported back intoprefab_ui._action_to_row.Why deferred
#857 housed them in
bom_table.pyto break thefoundation/bom → prefab_uiunderscore-import coupling without spinning up a second new module. With only two real callers, a dedicated shared-modify-helpers module would be premature abstraction.When to revisit
When a third caller appears (likely candidates: SO modify card, MO modify card, generic modify-result renderer), hoist these two helpers into a sibling module, e.g.:
katana_mcp/tools/foundation/modify_outcome.py— holds_summarize_apply_outcome+ dict-typed_derive_status_labelbom_table.pyre-imports them or callers swap directly to the new home.Symbol inventory to move at that point:
_summarize_apply_outcome(actions: list[dict[str, Any]]) -> tuple[str, str]_derive_status_label(action: dict[str, Any]) -> str(dict variant; theActionResult-typed variant in_modification.pyis unrelated and stays)_BOM_ROW_STATUS_VARIANTS— though it's BOM-row-specific (Badge variant bucketing per status). Decide based on whether the third caller needs the same status→variant mapping.Tracked by inline comment
bom_table.pycarries a# TODO(#<this-issue>)reference at the_summarize_apply_outcomedefinition so the deferred work isn't only in #857's PR description.