| <?xml version="1.0" encoding="UTF-8"?> |
| <prompt> |
|
|
| <meta> |
| <title>Self-Healing Code Agent — Post-Implementation Verification Suite</title> |
| <description> |
| Run every verification step sequentially. For each step, execute the command or script, |
| capture the output, and report PASS or FAIL with details. If a step fails, log the |
| error clearly but continue to the next step — do NOT stop on first failure. |
| At the end, produce a summary table of all steps with their status. |
| </description> |
| <repo_root>The current project directory (Self-Healing-Code-Agent)</repo_root> |
| </meta> |
|
|
| <global_rules> |
| <rule>Run every step in order. Do not skip any step.</rule> |
| <rule>If a step fails, log the full error output, mark it FAIL, and continue to the next step.</rule> |
| <rule>Do not attempt to fix anything during verification — only observe and report.</rule> |
| <rule>At the end, produce a SUMMARY TABLE with columns: Step Number, Step Name, Status (PASS/FAIL), Notes.</rule> |
| <rule>Use LLM_PROVIDER=mock for all test commands unless the step explicitly says otherwise.</rule> |
| <rule>For steps that require running Python scripts, use the project root as the working directory.</rule> |
| <rule>Capture and display both stdout and stderr for every command.</rule> |
| </global_rules> |
|
|
| |
| |
| |
| <step id="1" name="Verify Python Version"> |
| <command>python3 --version</command> |
| <expected>Python 3.11 or higher</expected> |
| </step> |
|
|
| <step id="2" name="Install Dependencies"> |
| <command>pip install -r requirements.txt 2>&1 | tail -20</command> |
| <expected>All packages install without errors. Note any version conflicts or failures.</expected> |
| <note>If chromadb fails to install, note it but continue — tests are designed to skip when chromadb is absent.</note> |
| </step> |
|
|
| |
| |
| |
| <step id="3" name="Run Full Test Suite"> |
| <command>LLM_PROVIDER=mock pytest -v --tb=short 2>&1</command> |
| <expected> |
| All tests pass. The report from Claude Code said 44 passed, 3 skipped. |
| Verify the exact count. Skipped tests should only be chromadb-related. |
| No test should have status "ERROR" (as opposed to "FAIL" or "SKIP"). |
| </expected> |
| <checks> |
| <check>Total passed count matches or exceeds 44</check> |
| <check>Skipped tests are only in test_memory_store.py</check> |
| <check>Zero failures</check> |
| <check>Zero errors</check> |
| <check>"running" does NOT appear as an accepted terminal status in test_graph_mock.py output</check> |
| </checks> |
| </step> |
|
|
| |
| |
| |
| <step id="4" name="Verify All YAML Prompt Files Load Correctly"> |
| <command><![CDATA[ |
| python3 -c " |
| from llm.prompt_loader import list_available_roles, get_system_prompt, get_schema, get_raw_template |
|
|
| roles = list_available_roles() |
| print(f'Available roles: {sorted(roles)}') |
| assert 'generator' in roles, 'Missing generator role' |
| assert 'qa_adversarial' in roles, 'Missing qa_adversarial role' |
| assert 'debugger' in roles, 'Missing debugger role' |
| assert 'memory_summarizer' in roles, 'Missing memory_summarizer role' |
| assert 'critic' in roles, 'Missing critic role (Fix 15)' |
|
|
| for r in roles: |
| prompt = get_system_prompt(r) |
| schema = get_schema(r) |
| assert len(prompt) > 10, f'{r}: system prompt too short ({len(prompt)} chars)' |
| print(f' {r}: prompt={len(prompt)} chars, schema_keys={list(schema.get(\"properties\", {}).keys())}') |
|
|
| # Verify new templates exist |
| templates_to_check = [ |
| ('generator', 'initial'), |
| ('generator', 'repair'), |
| ('qa_adversarial', 'generate'), |
| ('qa_adversarial', 'generate_from_spec'), |
| ('debugger', 'diagnose'), |
| ('debugger', 'react_diagnose'), |
| ('memory_summarizer', 'summarize'), |
| ('critic', 'review'), |
| ] |
| for role, template_key in templates_to_check: |
| raw = get_raw_template(role, template_key) |
| assert len(raw) > 20, f'{role}/{template_key}: template too short' |
| print(f' {role}/{template_key}: {len(raw)} chars OK') |
|
|
| print('ALL YAML CHECKS PASSED') |
| " |
| ]]></command> |
| <expected>All 5 roles found. All templates load. No KeyError or FileNotFoundError.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="5" name="Verify Graph Builds with Each Config Preset"> |
| <command><![CDATA[ |
| LLM_PROVIDER=mock python3 -c " |
| from agent.config import AgentConfig |
| from agent.graph import build_graph |
| from llm.router import LLMRouter |
| from llm.providers.mock_provider import MockProvider |
|
|
| router = LLMRouter(provider=MockProvider()) |
|
|
| for preset_name in ['development', 'staging', 'production']: |
| config = getattr(AgentConfig, preset_name)() |
| print(f'--- {preset_name} ---') |
| print(f' autonomy_level={config.autonomy_level}') |
| print(f' enable_critic={config.enable_critic}') |
| print(f' enable_spec_tests={config.enable_spec_tests}') |
| print(f' parallel_strategies={config.parallel_strategies}') |
| print(f' enable_checkpointing={config.enable_checkpointing}') |
|
|
| try: |
| app = build_graph(config=config, router=router) |
| # Try to get the mermaid diagram as a topology check |
| mermaid = app.get_graph().draw_mermaid() |
| edge_count = mermaid.count('-->') |
| print(f' Graph built OK: {edge_count} edges') |
| except Exception as e: |
| print(f' GRAPH BUILD FAILED: {e}') |
| import traceback |
| traceback.print_exc() |
|
|
| print('GRAPH BUILD CHECKS COMPLETE') |
| " |
| ]]></command> |
| <expected> |
| All three presets build without errors. |
| Development should have the fewest edges. |
| Production should have the most edges. |
| </expected> |
| </step> |
|
|
| |
| |
| |
| <step id="6" name="Run Single Task End-to-End with Mock Provider"> |
| <command><![CDATA[ |
| LLM_PROVIDER=mock python3 -c " |
| import asyncio |
| from agent.graph import run_agent |
| from agent.config import AgentConfig |
| from llm.router import LLMRouter |
| from llm.providers.mock_provider import MockProvider |
|
|
| async def test(): |
| config = AgentConfig.development() |
| router = LLMRouter(provider=MockProvider()) |
| state = await run_agent( |
| 'Write a function add(a, b) that returns a + b.', |
| max_iterations=2, |
| router=router, |
| config=config, |
| ) |
| print(f'Status: {state[\"status\"]}') |
| print(f'Iterations: {state[\"iteration\"]}') |
| print(f'Code length: {len(state.get(\"current_code\", \"\"))} chars') |
| print(f'Events count: {len(state.get(\"events\", []))}') |
| print(f'Degraded nodes: {state.get(\"degraded_nodes\", [])}') |
| print(f'Spec test code length: {len(state.get(\"spec_test_code\", \"\"))} chars') |
|
|
| assert state['status'] in ('success', 'max_iterations_reached'), f'Bad status: {state[\"status\"]}' |
| assert len(state.get('current_code', '')) > 0, 'No code generated' |
| assert len(state.get('events', [])) > 0, 'No events emitted' |
| print('SINGLE TASK TEST PASSED') |
|
|
| asyncio.run(test()) |
| " |
| ]]></command> |
| <expected>Status is "success" or "max_iterations_reached". Code is non-empty. Events are emitted.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="7" name="Verify Stream Agent Yields Events"> |
| <command><![CDATA[ |
| LLM_PROVIDER=mock python3 -c " |
| import asyncio |
| from agent.graph import stream_agent |
| from agent.config import AgentConfig |
| from llm.router import LLMRouter |
| from llm.providers.mock_provider import MockProvider |
|
|
| async def test(): |
| config = AgentConfig.development() |
| router = LLMRouter(provider=MockProvider()) |
| events = [] |
| async for event in stream_agent( |
| 'Write a trivial function.', |
| max_iterations=1, |
| router=router, |
| config=config, |
| ): |
| events.append(event) |
|
|
| print(f'Total events streamed: {len(events)}') |
| event_types = set(e.get('type', '') for e in events) |
| print(f'Event types seen: {sorted(event_types)}') |
|
|
| assert len(events) > 0, 'No events streamed' |
| for e in events: |
| assert 'type' in e, f'Event missing type field: {e}' |
| assert 'message' in e, f'Event missing message field: {e}' |
| print('STREAM AGENT TEST PASSED') |
|
|
| asyncio.run(test()) |
| " |
| ]]></command> |
| <expected>Multiple events streamed. Each event has "type" and "message" fields.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="8" name="Verify Context Builder Truncation Actually Works"> |
| <command><![CDATA[ |
| python3 -c " |
| from llm.context_builder import build_context |
|
|
| # Test 1: Large input gets truncated |
| huge_var = 'x' * 50000 |
| template = 'Code: {code}' |
| rendered = template.format(code=huge_var) |
| result = build_context(rendered, {'code': huge_var}, template_str=template, max_context_tokens=100) |
| assert len(result) < len(rendered), f'Truncation did not reduce size: {len(result)} >= {len(rendered)}' |
| assert 'TRUNCATED' in result, 'Missing TRUNCATED marker' |
| print(f'Test 1 PASSED: {len(rendered)} chars -> {len(result)} chars') |
|
|
| # Test 2: Small input passes through unchanged |
| small_var = 'def f(): pass' |
| rendered_small = template.format(code=small_var) |
| result_small = build_context(rendered_small, {'code': small_var}, template_str=template, max_context_tokens=5000) |
| assert result_small == rendered_small, 'Small input was incorrectly modified' |
| print(f'Test 2 PASSED: small input unchanged') |
|
|
| # Test 3: Fallback without template_str |
| result_fallback = build_context(rendered, {'code': huge_var}, max_context_tokens=100) |
| assert len(result_fallback) < len(rendered), 'Fallback truncation failed' |
| print(f'Test 3 PASSED: fallback truncation works') |
|
|
| print('CONTEXT BUILDER TESTS ALL PASSED') |
| " |
| ]]></command> |
| <expected>All three tests pass. This confirms Fix 1 (the original bug) is actually fixed.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="9" name="Verify Router call_with_fallback Behavior"> |
| <command><![CDATA[ |
| LLM_PROVIDER=mock python3 -c " |
| import asyncio |
| from llm.router import LLMRouter |
| from llm.base import BaseLLMProvider, InferenceRequest, InferenceResponse |
|
|
| class AlwaysBadProvider(BaseLLMProvider): |
| @property |
| def provider_name(self): return 'test' |
| @property |
| def model_name(self): return 'test' |
| async def infer(self, request): |
| return InferenceResponse(text='not valid json at all', provider='test', model='test') |
|
|
| async def test(): |
| router = LLMRouter(provider=AlwaysBadProvider()) |
|
|
| # call_with_fallback should NOT raise — should return fallback |
| result, used_fallback = await router.call_with_fallback( |
| role='debugger', |
| template_key='diagnose', |
| variables={ |
| 'task_description': 'test', |
| 'code': 'def f(): pass', |
| 'test_results': 'assert False', |
| 'iteration_history': 'none', |
| }, |
| ) |
| assert used_fallback, 'Expected fallback to be used' |
| assert 'root_cause' in result, f'Fallback missing root_cause: {result}' |
| assert result.get('confidence', 1.0) <= 0.2, f'Fallback confidence too high: {result}' |
| print(f'Fallback result: {result}') |
| print('ROUTER FALLBACK TEST PASSED') |
|
|
| asyncio.run(test()) |
| " |
| ]]></command> |
| <expected>Fallback is used. Result contains role-specific safe defaults with low confidence.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="10" name="Verify Debugger Tools Work in Isolation"> |
| <command><![CDATA[ |
| LLM_PROVIDER=mock python3 -c " |
| import asyncio |
| from agent.tools import run_snippet, inspect_function, diff_iterations, call_tool |
|
|
| async def test(): |
| # Test run_snippet |
| result = await run_snippet('print(1 + 1)') |
| assert '2' in result, f'run_snippet failed: {result}' |
| print(f'run_snippet: {result.strip()[:100]}') |
|
|
| # Test inspect_function |
| code = ''' |
| def merge_intervals(intervals: list[list[int]]) -> list[list[int]]: |
| \"\"\"Merge overlapping intervals.\"\"\" |
| if not intervals: |
| return [] |
| return sorted(intervals) |
| ''' |
| result = inspect_function(code, 'merge_intervals') |
| assert 'merge_intervals' in result, f'inspect_function failed: {result}' |
| assert 'intervals' in result, f'inspect_function missing args: {result}' |
| print(f'inspect_function: {result.strip()[:200]}') |
|
|
| # Test diff_iterations |
| v1 = 'def f(x):\n return x\n' |
| v2 = 'def f(x):\n return x + 1\n' |
| result = diff_iterations(v1, v2) |
| assert 'return x + 1' in result or '+' in result, f'diff failed: {result}' |
| print(f'diff_iterations: {result.strip()[:200]}') |
|
|
| # Test call_tool dispatch |
| result = await call_tool('run_snippet', {'code': 'print(42)'}) |
| assert '42' in result, f'call_tool dispatch failed: {result}' |
| print(f'call_tool dispatch: OK') |
|
|
| # Test unknown tool |
| result = await call_tool('nonexistent_tool', {}) |
| assert 'Unknown' in result, f'Unknown tool should return error: {result}' |
| print(f'Unknown tool handling: OK') |
|
|
| print('ALL TOOL TESTS PASSED') |
|
|
| asyncio.run(test()) |
| " |
| ]]></command> |
| <expected>All three tools produce correct output. call_tool dispatches correctly. Unknown tools return error message.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="11" name="Verify Schema Validator Edge Cases"> |
| <command><![CDATA[ |
| python3 -c " |
| from llm.schema_validator import parse_and_validate, StructuredOutputError |
|
|
| SCHEMA = { |
| 'type': 'object', |
| 'required': ['code'], |
| 'properties': { |
| 'code': {'type': 'string'}, |
| 'explanation': {'type': 'string'}, |
| }, |
| } |
|
|
| # Truncated JSON salvage |
| raw = '{\"code\": \"def add(a,b):\\\\n return a+b\\\\n\", \"explanation\": \"adds tw' |
| try: |
| result = parse_and_validate(raw, SCHEMA) |
| assert 'def add' in result['code'], f'Salvage failed: {result}' |
| print('Truncated JSON salvage: PASS') |
| except Exception as e: |
| print(f'Truncated JSON salvage: FAIL ({e})') |
|
|
| # Markdown fenced |
| raw2 = 'Here is my solution:\n\`\`\`json\n{\"code\": \"def f(): pass\"}\n\`\`\`\nDone!' |
| result2 = parse_and_validate(raw2, SCHEMA) |
| assert result2['code'] == 'def f(): pass' |
| print('Markdown fence extraction: PASS') |
|
|
| # Nested dict coercion |
| raw3 = '{\"code\": {\"functions\": [{\"name\": \"add\"}]}, \"explanation\": \"oops\"}' |
| result3 = parse_and_validate(raw3, SCHEMA) |
| assert isinstance(result3['code'], str) |
| print('Nested dict coercion: PASS') |
|
|
| # Invalid JSON raises |
| try: |
| parse_and_validate('this is not json', SCHEMA) |
| print('Invalid JSON rejection: FAIL (should have raised)') |
| except StructuredOutputError: |
| print('Invalid JSON rejection: PASS') |
|
|
| print('ALL SCHEMA VALIDATOR CHECKS PASSED') |
| " |
| ]]></command> |
| <expected>All four edge cases handled correctly.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="12" name="Verify Sandbox Namespace Isolation and Resource Limits"> |
| <command><![CDATA[ |
| LLM_PROVIDER=mock python3 -c " |
| import asyncio |
| from sandbox.python_executor import execute |
|
|
| async def test(): |
| # Basic pass |
| r = await execute('def add(a,b): return a+b', 'assert add(1,2) == 3') |
| assert r.passed, f'Basic test failed: {r.stderr}' |
| print('Basic execution: PASS') |
|
|
| # Timeout enforcement |
| r = await execute('x = 1', 'while True: pass', timeout=2.0) |
| assert not r.passed, 'Infinite loop should fail' |
| print(f'Timeout enforcement: PASS (type={r.exception_type})') |
|
|
| # Syntax error captured |
| r = await execute('def add(a, b return a', 'assert True') |
| assert not r.passed, 'Syntax error should fail' |
| print(f'Syntax error capture: PASS') |
|
|
| # Import error captured |
| r = await execute('import nonexistent_xyz', 'assert True') |
| assert not r.passed, 'Import error should fail' |
| print(f'Import error capture: PASS') |
|
|
| # Solution uses importlib isolation (public names only) |
| r = await execute( |
| 'def public_func(): return 42\n_private = 99', |
| 'assert public_func() == 42' |
| ) |
| assert r.passed, f'Public function access failed: {r.stderr}' |
| print('Public function access: PASS') |
|
|
| print('ALL SANDBOX CHECKS PASSED') |
|
|
| asyncio.run(test()) |
| " |
| ]]></command> |
| <expected>All sandbox isolation tests pass including timeout, syntax error, import error capture.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="13" name="Verify AgentConfig Presets and Field Defaults"> |
| <command><![CDATA[ |
| python3 -c " |
| from agent.config import AgentConfig |
|
|
| dev = AgentConfig.development() |
| stg = AgentConfig.staging() |
| prd = AgentConfig.production() |
|
|
| # Development should have everything disabled |
| assert dev.autonomy_level == 'full_auto' |
| assert dev.enable_critic == False |
| assert dev.enable_spec_tests == False |
| assert dev.parallel_strategies == False |
| assert dev.enable_cross_session_memory == False |
| assert dev.enable_checkpointing == False |
| print('Development preset: PASS') |
|
|
| # Staging should enable features with review_repairs |
| assert stg.autonomy_level == 'review_repairs' |
| assert stg.enable_critic == True |
| assert stg.enable_spec_tests == True |
| assert stg.parallel_strategies == True |
| assert stg.enable_cross_session_memory == True |
| assert stg.enable_checkpointing == True |
| assert stg.persist_checkpoints == False |
| print('Staging preset: PASS') |
|
|
| # Production should enable everything including persistent checkpoints |
| assert prd.autonomy_level == 'review_all' |
| assert prd.enable_critic == True |
| assert prd.enable_spec_tests == True |
| assert prd.parallel_strategies == True |
| assert prd.enable_cross_session_memory == True |
| assert prd.enable_checkpointing == True |
| assert prd.persist_checkpoints == True |
| print('Production preset: PASS') |
|
|
| # Default constructor should have sensible defaults |
| default = AgentConfig() |
| assert default.max_iterations == 4 |
| assert default.critic_confidence_threshold == 0.6 |
| print('Default constructor: PASS') |
|
|
| print('ALL CONFIG CHECKS PASSED') |
| " |
| ]]></command> |
| <expected>All three presets have correct field values. Default constructor works.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="14" name="Verify Metrics Module"> |
| <command><![CDATA[ |
| python3 -c " |
| from agent.metrics import NodeMetrics, RunMetrics |
|
|
| # NodeMetrics |
| nm = NodeMetrics(node_name='test', start_time=0.0, end_time=1.5, input_tokens=100, output_tokens=50) |
| assert nm.latency_seconds == 1.5 |
| assert nm.estimated_cost_usd >= 0 |
| print(f'NodeMetrics: latency={nm.latency_seconds}s cost=\${nm.estimated_cost_usd:.6f}') |
|
|
| # RunMetrics |
| rm = RunMetrics(task_id='test_task', node_metrics=[nm]) |
| d = rm.to_dict() |
| assert d['task_id'] == 'test_task' |
| assert 'nodes' in d |
| assert len(d['nodes']) == 1 |
| assert d['nodes'][0]['name'] == 'test' |
| print(f'RunMetrics.to_dict(): {list(d.keys())}') |
|
|
| print('METRICS MODULE CHECKS PASSED') |
| " |
| ]]></command> |
| <expected>NodeMetrics computes latency and cost. RunMetrics serializes correctly.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="15" name="Verify Memory Store (ChromaDB)"> |
| <command><![CDATA[ |
| python3 -c " |
| try: |
| import chromadb |
| print(f'ChromaDB version: {chromadb.__version__}') |
| except ImportError: |
| print('ChromaDB not installed — SKIPPED (expected on some environments)') |
| exit(0) |
|
|
| import tempfile |
| from agent.memory_store import LessonStore |
|
|
| with tempfile.TemporaryDirectory() as tmpdir: |
| store = LessonStore(persist_dir=tmpdir) |
|
|
| # Store lessons |
| store.store_lesson('Always handle empty inputs before indexing.', 'interval_merging', 'boundary', 'test001') |
| store.store_lesson('Touching intervals need >= not > in merge condition.', 'interval_merging', 'off_by_one', 'test002') |
| print(f'Stored 2 lessons. Total: {store.total_lessons}') |
|
|
| # Retrieve by semantic query |
| results = store.retrieve_relevant_lessons('empty list edge case') |
| assert len(results) > 0, 'No lessons retrieved' |
| print(f'Retrieved {len(results)} lessons for query \"empty list edge case\"') |
| print(f' Top result: {results[0][:80]}') |
|
|
| # Retrieve with category filter |
| results_filtered = store.retrieve_relevant_lessons('merge condition', task_category='interval_merging') |
| print(f'Retrieved {len(results_filtered)} lessons with category filter') |
|
|
| # Deduplication (store same lesson again) |
| store.store_lesson('Always handle empty inputs before indexing.', 'interval_merging', 'boundary', 'test001') |
| assert store.total_lessons == 2, f'Dedup failed: expected 2, got {store.total_lessons}' |
| print('Deduplication: PASS') |
|
|
| print('MEMORY STORE CHECKS PASSED') |
| " |
| ]]></command> |
| <expected>If chromadb is installed: store, retrieve, and dedup all work. If not installed: gracefully skipped.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="16" name="Verify All Event Types and Streaming Formatters"> |
| <command><![CDATA[ |
| python3 -c " |
| from agent.events import ( |
| STEP, CODE_GENERATED, FAILURE, LEARNING_UPDATE, SUCCESS, |
| TESTS_GENERATED, DIAGNOSIS, SPEC_TESTS_GENERATED, REPAIR_REVIEW, |
| TOOL_USE, CRITIC_REVIEW, PARALLEL_REPAIR, |
| step_event, code_generated_event, failure_event, success_event, |
| spec_tests_event, repair_review_event, tool_use_event, critic_event, |
| parallel_repair_event, diagnosis_event, |
| ) |
| from framework.streaming import PUBLIC_EVENT_TYPES, format_event_for_timeline |
|
|
| # Verify all new event types exist |
| new_types = [SPEC_TESTS_GENERATED, REPAIR_REVIEW, TOOL_USE, CRITIC_REVIEW, PARALLEL_REPAIR] |
| for t in new_types: |
| assert t in PUBLIC_EVENT_TYPES, f'{t} not in PUBLIC_EVENT_TYPES' |
| print(f'PUBLIC_EVENT_TYPES count: {len(PUBLIC_EVENT_TYPES)}') |
|
|
| # Verify each constructor produces a valid event dict |
| constructors = [ |
| ('step_event', step_event('test', iteration=1)), |
| ('code_generated_event', code_generated_event('def f(): pass', iteration=1)), |
| ('failure_event', failure_event('assert failed', iteration=1)), |
| ('success_event', success_event('def f(): pass', iteration=1)), |
| ('spec_tests_event', spec_tests_event(5, iteration=0)), |
| ('repair_review_event', repair_review_event('cause', 'logic', 'fix it', 0.8, iteration=1)), |
| ('tool_use_event', tool_use_event('run_snippet', {'code': 'x'}, 'output', iteration=1)), |
| ('critic_event', critic_event('approve', [], 0.9, iteration=1)), |
| ('parallel_repair_event', parallel_repair_event('minimal_fix', True, False, iteration=1)), |
| ('diagnosis_event', diagnosis_event('root cause', 'logic_error', 'fix', iteration=1)), |
| ] |
|
|
| for name, event_obj in constructors: |
| d = event_obj.to_dict() |
| assert 'type' in d, f'{name}: missing type' |
| assert 'message' in d, f'{name}: missing message' |
| # Verify formatter doesn't crash |
| formatted = format_event_for_timeline(d) |
| assert len(formatted) > 0, f'{name}: empty formatted output' |
| print(f' {name}: type={d[\"type\"]} formatted={formatted[:80]}') |
|
|
| print('ALL EVENT AND STREAMING CHECKS PASSED') |
| " |
| ]]></command> |
| <expected>All event constructors produce valid dicts. All formatters produce non-empty timeline strings.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="17" name="Verify Graph Mermaid Diagram Generation"> |
| <command><![CDATA[ |
| LLM_PROVIDER=mock python3 -c " |
| from agent.graph import get_graph_mermaid |
| from agent.config import AgentConfig |
|
|
| for preset in ['development', 'staging', 'production']: |
| config = getattr(AgentConfig, preset)() |
| mermaid = get_graph_mermaid(config=config) |
| assert len(mermaid) > 50, f'{preset}: mermaid too short ({len(mermaid)} chars)' |
| assert '-->' in mermaid, f'{preset}: no edges in mermaid' |
| edge_count = mermaid.count('-->') |
| print(f'{preset}: {edge_count} edges, {len(mermaid)} chars') |
|
|
| print('GRAPH VISUALIZATION CHECKS PASSED') |
| " |
| ]]></command> |
| <expected>All three presets generate valid Mermaid diagrams with edges. Production has more edges than development.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="18" name="Verify HumanEval Adapter Module Imports"> |
| <command><![CDATA[ |
| python3 -c " |
| from evaluation.humaneval_adapter import load_humaneval_tasks, humaneval_to_agent_task, extract_completion |
|
|
| # Test extract_completion |
| test_code = ''' |
| def has_close_elements(numbers, threshold): |
| for i in range(len(numbers)): |
| for j in range(i+1, len(numbers)): |
| if abs(numbers[i] - numbers[j]) < threshold: |
| return True |
| return False |
| ''' |
| completion = extract_completion(test_code, 'has_close_elements') |
| assert 'for i in range' in completion or 'return' in completion, f'extract_completion failed: {completion[:100]}' |
| print(f'extract_completion: {len(completion)} chars extracted') |
|
|
| # Test humaneval_to_agent_task |
| task = {'prompt': 'def add(a, b):\\n \"\"\"Add two numbers.\"\"\"\\n', 'entry_point': 'add'} |
| agent_task = humaneval_to_agent_task(task) |
| assert 'def add' in agent_task |
| assert 'Complete' in agent_task or 'complete' in agent_task or 'implement' in agent_task.lower() |
| print(f'humaneval_to_agent_task: {len(agent_task)} chars') |
|
|
| print('HUMANEVAL ADAPTER CHECKS PASSED') |
| " |
| ]]></command> |
| <expected>Both adapter functions work correctly without needing the actual HumanEval dataset file.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="19" name="Verify Benchmark Reference Tests Are Populated"> |
| <command><![CDATA[ |
| python3 -c " |
| from evaluation.benchmark_tasks import BENCHMARK_TASKS |
|
|
| total_ref_tests = 0 |
| for task in BENCHMARK_TASKS: |
| ref_code = getattr(task, 'reference_test_code', '') |
| has_ref = bool(ref_code and ref_code.strip()) |
| assert_count = ref_code.count('assert') if has_ref else 0 |
| total_ref_tests += assert_count |
| status = f'{assert_count} asserts' if has_ref else 'MISSING' |
| print(f' {task.task_id}: {status}') |
| assert has_ref, f'{task.task_id} is missing reference_test_code!' |
|
|
| print(f'Total reference test assertions across all tasks: {total_ref_tests}') |
| assert total_ref_tests >= 40, f'Expected at least 40 total assertions, got {total_ref_tests}' |
| print('BENCHMARK REFERENCE TESTS CHECK PASSED') |
| " |
| ]]></command> |
| <expected>All 8 tasks have reference_test_code with at least 5 assertions each. Total >= 40.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="20" name="Verify Multi-Model Routing"> |
| <command><![CDATA[ |
| LLM_PROVIDER=mock python3 -c " |
| from llm.router import LLMRouter |
| from llm.providers.mock_provider import MockProvider |
|
|
| # Create two mock providers with different model names |
| default_provider = MockProvider() |
| summarizer_provider = MockProvider() |
|
|
| router = LLMRouter( |
| provider=default_provider, |
| role_providers={'memory_summarizer': summarizer_provider} |
| ) |
|
|
| # _get_provider should return the override for memory_summarizer |
| p1 = router._get_provider('generator') |
| p2 = router._get_provider('memory_summarizer') |
| assert p1 is default_provider, 'Generator should use default provider' |
| assert p2 is summarizer_provider, 'memory_summarizer should use override' |
| print(f'generator provider: {p1.provider_name}') |
| print(f'memory_summarizer provider: {p2.provider_name}') |
| print('MULTI-MODEL ROUTING CHECK PASSED') |
| " |
| ]]></command> |
| <expected>Generator routes to default. memory_summarizer routes to override.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="21" name="Verify CI Workflow File Exists and Is Valid"> |
| <command><![CDATA[ |
| python3 -c " |
| import yaml |
| from pathlib import Path |
|
|
| ci_path = Path('.github/workflows/test.yml') |
| assert ci_path.exists(), 'CI workflow file missing!' |
|
|
| with open(ci_path) as f: |
| ci = yaml.safe_load(f) |
|
|
| assert 'on' in ci, 'Missing trigger config' |
| assert 'jobs' in ci, 'Missing jobs' |
| assert 'test' in ci['jobs'], 'Missing test job' |
|
|
| steps = ci['jobs']['test']['steps'] |
| step_names = [s.get('name', '') for s in steps if 'name' in s] |
| print(f'CI steps: {step_names}') |
|
|
| # Check it runs pytest |
| has_pytest = any('pytest' in str(s) for s in steps) |
| assert has_pytest, 'CI does not run pytest' |
|
|
| # Check it uses LLM_PROVIDER=mock |
| has_mock = any('LLM_PROVIDER' in str(s) and 'mock' in str(s) for s in steps) |
| assert has_mock, 'CI does not set LLM_PROVIDER=mock' |
|
|
| print('CI WORKFLOW CHECK PASSED') |
| " |
| ]]></command> |
| <expected>test.yml exists, is valid YAML, runs pytest with LLM_PROVIDER=mock.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="22" name="Verify README Contains Updated Architecture Description"> |
| <command><![CDATA[ |
| python3 -c " |
| readme = open('README.md').read() |
|
|
| checks = { |
| 'ReAct': 'ReAct' in readme or 'react' in readme.lower(), |
| 'Human-in-the-loop': 'human' in readme.lower() and 'loop' in readme.lower(), |
| 'Critic': 'critic' in readme.lower() or 'Critic' in readme, |
| 'Dual-oracle or spec tests': 'spec' in readme.lower() or 'dual' in readme.lower() or 'oracle' in readme.lower(), |
| 'Checkpoint or time-travel': 'checkpoint' in readme.lower() or 'time-travel' in readme.lower() or 'time travel' in readme.lower(), |
| 'Observability or LangSmith': 'observ' in readme.lower() or 'langsmith' in readme.lower(), |
| 'Reference-validated metrics': 'reference' in readme.lower() and 'valid' in readme.lower(), |
| 'ChromaDB or cross-session': 'chromadb' in readme.lower() or 'cross-session' in readme.lower() or 'cross session' in readme.lower(), |
| } |
|
|
| all_passed = True |
| for check_name, passed in checks.items(): |
| status = 'PASS' if passed else 'FAIL' |
| if not passed: |
| all_passed = False |
| print(f' {check_name}: {status}') |
|
|
| if all_passed: |
| print('README CONTENT CHECKS PASSED') |
| else: |
| print('README CONTENT CHECKS: SOME MISSING (see above)') |
| " |
| ]]></command> |
| <expected>README mentions all major new concepts. Any missing items should be noted but are not blockers.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="23" name="Verify No Circular Imports"> |
| <command><![CDATA[ |
| LLM_PROVIDER=mock python3 -c " |
| # Import every module in the project to catch circular imports |
| import_order = [ |
| 'agent.config', |
| 'agent.state', |
| 'agent.events', |
| 'agent.metrics', |
| 'agent.tools', |
| 'llm.base', |
| 'llm.schema_validator', |
| 'llm.prompt_loader', |
| 'llm.context_builder', |
| 'llm.router', |
| 'llm.providers.mock_provider', |
| 'sandbox.python_executor', |
| 'framework.event_bus', |
| 'framework.streaming', |
| 'agent.nodes.generate_solution', |
| 'agent.nodes.create_adversarial_tests', |
| 'agent.nodes.execute_solution', |
| 'agent.nodes.diagnose_failure', |
| 'agent.nodes.update_learning_log', |
| 'agent.nodes.generate_spec_tests', |
| 'agent.nodes.review_repair', |
| 'agent.nodes.critic_review', |
| 'agent.nodes.parallel_generate', |
| 'agent.graph', |
| 'evaluation.benchmark_tasks', |
| 'evaluation.metrics', |
| 'evaluation.humaneval_adapter', |
| ] |
|
|
| for module_name in import_order: |
| try: |
| __import__(module_name) |
| print(f' {module_name}: OK') |
| except Exception as e: |
| print(f' {module_name}: IMPORT FAILED — {e}') |
|
|
| print('IMPORT CHAIN VERIFICATION COMPLETE') |
| " |
| ]]></command> |
| <expected>All modules import without circular import errors or missing dependency errors.</expected> |
| </step> |
|
|
| |
| |
| |
| <step id="24" name="Run Linter"> |
| <command>pip install ruff 2>&1 | tail -3 && ruff check . --statistics 2>&1</command> |
| <expected> |
| Zero errors is ideal. Minor warnings (unused imports, line length) are acceptable. |
| Report the total count and categories of any issues found. |
| </expected> |
| </step> |
|
|
| |
| |
| |
| <step id="25" name="Verify All Expected Files Exist"> |
| <command><![CDATA[ |
| python3 -c " |
| from pathlib import Path |
|
|
| expected_new_files = [ |
| 'agent/config.py', |
| 'agent/metrics.py', |
| 'agent/memory_store.py', |
| 'agent/tools.py', |
| 'agent/nodes/generate_spec_tests.py', |
| 'agent/nodes/review_repair.py', |
| 'agent/nodes/critic_review.py', |
| 'agent/nodes/parallel_generate.py', |
| 'prompts/critic.yaml', |
| 'evaluation/humaneval_adapter.py', |
| 'evaluation/run_humaneval.py', |
| 'tests/test_context_builder.py', |
| 'tests/test_router.py', |
| 'tests/test_memory_store.py', |
| '.github/workflows/test.yml', |
| ] |
|
|
| all_exist = True |
| for f in expected_new_files: |
| exists = Path(f).exists() |
| status = 'EXISTS' if exists else 'MISSING' |
| if not exists: |
| all_exist = False |
| print(f' {f}: {status}') |
|
|
| # Count total Python files |
| py_count = len(list(Path('.').rglob('*.py'))) |
| yaml_count = len(list(Path('prompts').rglob('*.yaml'))) |
| test_count = len(list(Path('tests').rglob('test_*.py'))) |
|
|
| print(f'') |
| print(f'Total .py files: {py_count}') |
| print(f'Total prompt YAML files: {yaml_count}') |
| print(f'Total test files: {test_count}') |
|
|
| if all_exist: |
| print('ALL EXPECTED FILES EXIST') |
| else: |
| print('SOME FILES MISSING (see above)') |
| " |
| ]]></command> |
| <expected>All 15 new files exist. Total test files should be 8+. Total prompt YAML files should be 5.</expected> |
| </step> |
|
|
| |
| |
| |
| <final_instructions> |
| After running all 25 steps, produce a summary table in this exact format: |
|
|
| | Step | Name | Status | Notes | |
| |------|------|--------|-------| |
| | 1 | Verify Python Version | PASS/FAIL | ... | |
| | 2 | Install Dependencies | PASS/FAIL | ... | |
| | ... | ... | ... | ... | |
| | 25 | Verify All Expected Files Exist | PASS/FAIL | ... | |
|
|
| Then add a final line: |
| **Overall: X/25 PASSED, Y/25 FAILED, Z/25 SKIPPED** |
|
|
| If any steps failed, list them with a brief explanation of what went wrong. |
| </final_instructions> |
|
|
| </prompt> |
|
|