Initial commit
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
"""Work-item metadata sync: verify context_assembler reads employee prompt /
|
||||
delta / progress_log via ``WorkItemContextView`` with proper fallback.
|
||||
|
||||
Covers:
|
||||
* ``_build_self_section`` reads ``employee_prompt_context`` /
|
||||
``employee_delta_context`` from work_item side when mirrored (company mode)
|
||||
* Falls back to task.metadata when view is None / task-mode
|
||||
* ``_build_working_summary`` reads ``progress_log`` with same precedence
|
||||
* Precedence (wi wins) when both sides populated
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from opc.core.models import Task
|
||||
from opc.layer1_perception.context_assembler import ContextAssembler
|
||||
from opc.layer2_organization.work_item_context_view import WorkItemContextView
|
||||
|
||||
|
||||
def _assembler() -> ContextAssembler:
|
||||
"""Build an assembler sufficient for the context helpers under test.
|
||||
|
||||
The helpers we target (_build_self_section, _build_working_summary)
|
||||
don't touch memory / store directly, so mocks are enough.
|
||||
"""
|
||||
return ContextAssembler(memory=MagicMock(), store=None)
|
||||
|
||||
|
||||
def _wi(metadata: dict | None = None) -> SimpleNamespace:
|
||||
return SimpleNamespace(metadata=metadata or {})
|
||||
|
||||
|
||||
def _task(metadata: dict | None = None, context_snapshot: dict | None = None) -> Task:
|
||||
return Task(
|
||||
id="t-1",
|
||||
title="t",
|
||||
metadata=metadata or {},
|
||||
context_snapshot=context_snapshot or {},
|
||||
)
|
||||
|
||||
|
||||
class BuildSelfSectionViewTests(unittest.TestCase):
|
||||
def test_prompt_context_from_work_item_when_mirrored(self) -> None:
|
||||
assembler = _assembler()
|
||||
task = _task({"employee_assignment": {"name": "Alice"}})
|
||||
view = WorkItemContextView(
|
||||
_wi({"employee_prompt_context": "WI persona content"}),
|
||||
task,
|
||||
)
|
||||
out = assembler._build_self_section(task, view)
|
||||
self.assertIn("### Employee Persona", out)
|
||||
self.assertIn("WI persona content", out)
|
||||
|
||||
def test_prompt_context_falls_back_to_task_metadata(self) -> None:
|
||||
assembler = _assembler()
|
||||
task = _task({"employee_prompt_context": "Task persona content"})
|
||||
view = WorkItemContextView(_wi({}), task)
|
||||
out = assembler._build_self_section(task, view)
|
||||
self.assertIn("Task persona content", out)
|
||||
|
||||
def test_no_view_passed_degrades_to_task_only(self) -> None:
|
||||
"""Backwards-compat: callers that don't pass view still get the
|
||||
task-side fallback (view=None constructs task-only internally)."""
|
||||
assembler = _assembler()
|
||||
task = _task({"employee_prompt_context": "fallback"})
|
||||
out = assembler._build_self_section(task)
|
||||
self.assertIn("fallback", out)
|
||||
|
||||
def test_wi_wins_over_task_when_both_populated(self) -> None:
|
||||
assembler = _assembler()
|
||||
task = _task({"employee_prompt_context": "task-loses"})
|
||||
view = WorkItemContextView(
|
||||
_wi({"employee_prompt_context": "wi-wins"}),
|
||||
task,
|
||||
)
|
||||
out = assembler._build_self_section(task, view)
|
||||
self.assertIn("wi-wins", out)
|
||||
self.assertNotIn("task-loses", out)
|
||||
|
||||
def test_delta_context_from_work_item(self) -> None:
|
||||
assembler = _assembler()
|
||||
task = _task({})
|
||||
view = WorkItemContextView(
|
||||
_wi({"employee_delta_context": "wi-delta"}),
|
||||
task,
|
||||
)
|
||||
out = assembler._build_self_section(task, view)
|
||||
self.assertIn("### Learned Working Profile", out)
|
||||
self.assertIn("wi-delta", out)
|
||||
|
||||
def test_empty_everything_returns_empty(self) -> None:
|
||||
assembler = _assembler()
|
||||
task = _task({})
|
||||
view = WorkItemContextView(_wi({}), task)
|
||||
self.assertEqual(assembler._build_self_section(task, view), "")
|
||||
|
||||
|
||||
class BuildWorkingSummaryViewTests(unittest.TestCase):
|
||||
def test_progress_log_from_work_item(self) -> None:
|
||||
assembler = _assembler()
|
||||
task = _task({})
|
||||
view = WorkItemContextView(
|
||||
_wi({"progress_log": ["wi step 1", "wi step 2"]}),
|
||||
task,
|
||||
)
|
||||
out = assembler._build_working_summary(task, view)
|
||||
self.assertIn("Recent progress:", out)
|
||||
self.assertIn("wi step 1", out)
|
||||
self.assertIn("wi step 2", out)
|
||||
|
||||
def test_progress_log_fallback_from_task_metadata(self) -> None:
|
||||
assembler = _assembler()
|
||||
task = _task({"progress_log": ["task fallback step"]})
|
||||
view = WorkItemContextView(_wi({}), task)
|
||||
out = assembler._build_working_summary(task, view)
|
||||
self.assertIn("task fallback step", out)
|
||||
|
||||
def test_no_view_passed_still_reads_task_metadata(self) -> None:
|
||||
assembler = _assembler()
|
||||
task = _task({"progress_log": ["legacy step"]})
|
||||
out = assembler._build_working_summary(task)
|
||||
self.assertIn("legacy step", out)
|
||||
|
||||
def test_progress_log_limited_to_last_4(self) -> None:
|
||||
"""Prompt budget guard: summary renders only last 4 items."""
|
||||
assembler = _assembler()
|
||||
task = _task({})
|
||||
view = WorkItemContextView(
|
||||
_wi({"progress_log": ["s1", "s2", "s3", "s4", "s5", "s6"]}),
|
||||
task,
|
||||
)
|
||||
out = assembler._build_working_summary(task, view)
|
||||
self.assertIn("s3", out)
|
||||
self.assertIn("s4", out)
|
||||
self.assertIn("s5", out)
|
||||
self.assertIn("s6", out)
|
||||
self.assertNotIn("s1", out)
|
||||
self.assertNotIn("s2", out)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user