fix: stop misreading per-work-item spec as run-level company plan

Every completed company session's follow-up was answered with the canned
"Legacy company runtime run ... read-only" text (project 000, 2026-07-07).
Root cause: snapshot loaders read task.metadata work_item_runtime_plan as a
serialized run-level CompanyWorkItemRuntimePlan, but work-item tasks persist a
per-item assignment spec (projection_id/turn_type/summary/deliverables/...)
under that key. from_dict on the wrong shape silently yields an empty plan
(no projections, empty metadata), _runtime_uses_multi_team_org returns False,
and the resume path falls through to the legacy read-only branch.

Add is_serialized_company_work_item_runtime_plan (a run-level plan always
serializes with projections + runtime_model; a spec always carries
projection_id) and route all full-plan metadata reads through
serialized_company_plan_from_metadata, which skips wrong-shaped candidates so
the loaders fall back to the sample-metadata-constructed plan instead of an
empty one. Fixes existing DBs read-side; no data migration.

Verified: old path on the 000 shape classifies multi_team_org=False, new path
True; regression tests cover shape discrimination, snapshot classification,
and the follow-up never reporting legacy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
LZH-YS1998
2026-07-07 22:33:39 +08:00
parent c901800062
commit b4d28aefeb
3 changed files with 241 additions and 13 deletions
+34 -6
View File
@@ -317,6 +317,35 @@ def deserialize_company_work_item_runtime_plan(data: dict[str, Any] | None) -> C
return deserialize_company_work_item_plan(data)
_SERIALIZED_PLAN_MARKER_KEYS = ("projections", "seeds", "root_projection_id", "runtime_model")
def is_serialized_company_work_item_runtime_plan(data: Any) -> bool:
"""Whether ``data`` is a run-level serialized CompanyWorkItemRuntimePlan.
Work-item tasks overload plan-adjacent metadata keys: ``work_item_runtime_plan``
holds a per-item assignment spec (``projection_id``/``turn_type``/``summary``/...),
not the run-level plan. Feeding that shape to ``from_dict`` silently yields an
empty plan, which downstream misreads as a legacy (non multi-team-org) run and
refuses to resume the session.
"""
if not isinstance(data, dict) or not data:
return False
if "projection_id" in data:
return False
return any(key in data for key in _SERIALIZED_PLAN_MARKER_KEYS)
def serialized_company_plan_from_metadata(metadata: dict[str, Any] | None) -> dict[str, Any] | None:
"""Return the first metadata value that is a real serialized run-level plan."""
source = dict(metadata or {})
for key in ("company_work_item_plan", "work_item_runtime_plan"):
candidate = source.get(key)
if is_serialized_company_work_item_runtime_plan(candidate):
return candidate
return None
def _coerce_company_work_item_runtime_plan(plan: Any) -> CompanyWorkItemRuntimePlan | None:
"""Accept projection-plan-like test doubles without consuming obsolete plan fields."""
if plan is None or isinstance(plan, CompanyWorkItemRuntimePlan):
@@ -1475,7 +1504,7 @@ class CompanyWorkItemExecutor:
return plan, tasks
plan_data = None
for task in sorted(latest_by_projection_id.values(), key=lambda item: (item.created_at, item.id), reverse=True):
candidate = task.metadata.get("company_work_item_plan") or task.metadata.get("work_item_runtime_plan")
candidate = serialized_company_plan_from_metadata(task.metadata)
if candidate:
plan_data = candidate
break
@@ -1601,8 +1630,8 @@ class CompanyWorkItemExecutor:
def _plan_view_for_task(self, task: Task) -> CompanyWorkItemRuntimePlan | None:
if self._active_plan is not None:
return self._active_plan
plan_data = task.metadata.get("company_work_item_plan") or task.metadata.get("work_item_runtime_plan")
if isinstance(plan_data, dict) and plan_data:
plan_data = serialized_company_plan_from_metadata(task.metadata)
if plan_data:
return deserialize_company_work_item_runtime_plan(plan_data)
return None
@@ -8983,9 +9012,8 @@ class CompanyWorkItemExecutor:
"requires_user_feedback": True,
}
plan_data = (
intake_meta.get("company_work_item_plan")
or intake_meta.get("work_item_runtime_plan")
or dict(intake_meta.get("delegation_playbook", {}) or {}).get("company_work_item_plan")
serialized_company_plan_from_metadata(intake_meta)
or serialized_company_plan_from_metadata(dict(intake_meta.get("delegation_playbook", {}) or {}))
)
if isinstance(plan_data, dict) and plan_data:
try: