STATE-WP-0092: persist flavor from files, treat depends_on as the C-20 canonical edge, exclude flavor=residual from summary/next_steps/deps unless include_residuals is set. Live primary still needs the alembic revision applied. Assistant: grok Assistant-Session: 01a09dc1-b21e-77e1-919e-fcad2f82b267
48 lines
1.1 KiB
Python
48 lines
1.1 KiB
Python
"""Work-record flavor (STATE-WP-0092).
|
|
|
|
Flavor is a closed bucket on workplans and tasks, orthogonal to kind and
|
|
status. Unset flavor is not residual.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
WORK_RECORD_FLAVORS: tuple[str, ...] = (
|
|
"planning",
|
|
"implementation",
|
|
"refactoring",
|
|
"extension",
|
|
"residual",
|
|
)
|
|
RESIDUAL_FLAVOR = "residual"
|
|
FLAVOR_PROMOTION_REASONS: tuple[str, ...] = ("demand", "risk")
|
|
|
|
_EMPTY = {"", "~", "null", "none", "nil"}
|
|
|
|
|
|
def normalize_flavor(value: Any) -> str | None:
|
|
if value is None:
|
|
return None
|
|
text = str(value).strip().lower()
|
|
if text in _EMPTY:
|
|
return None
|
|
return text
|
|
|
|
|
|
def is_known_flavor(value: Any) -> bool:
|
|
flavor = normalize_flavor(value)
|
|
return flavor is None or flavor in WORK_RECORD_FLAVORS
|
|
|
|
|
|
def is_residual_flavor(value: Any) -> bool:
|
|
return normalize_flavor(value) == RESIDUAL_FLAVOR
|
|
|
|
|
|
def normalize_promotion_reason(value: Any) -> str | None:
|
|
if value is None:
|
|
return None
|
|
text = str(value).strip().lower()
|
|
if text in _EMPTY:
|
|
return None
|
|
return text
|