Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions backend/agents.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Per-run CrewAI agent construction."""

from crewai import Agent
from crewai import LLM, Agent


def build_agents(model_name: str = "gpt-4o-mini") -> dict[str, Agent]:
Expand All @@ -22,7 +22,7 @@ def build_agents(model_name: str = "gpt-4o-mini") -> dict[str, Agent]:
allow_delegation=False,
cache=False,
memory=False,
llm=model_name,
llm=LLM(model=model_name, temperature=0),
)
athena = Agent(
name="Athena",
Expand All @@ -40,7 +40,7 @@ def build_agents(model_name: str = "gpt-4o-mini") -> dict[str, Agent]:
allow_delegation=False,
cache=False,
memory=False,
llm=model_name,
llm=LLM(model=model_name, temperature=0),
)
hephaestus = Agent(
name="Hephaestus",
Expand All @@ -58,7 +58,7 @@ def build_agents(model_name: str = "gpt-4o-mini") -> dict[str, Agent]:
allow_delegation=False,
cache=False,
memory=False,
llm=model_name,
llm=LLM(model=model_name, temperature=0),
)
argus = Agent(
name="Argus",
Expand All @@ -76,7 +76,7 @@ def build_agents(model_name: str = "gpt-4o-mini") -> dict[str, Agent]:
allow_delegation=False,
cache=False,
memory=False,
llm=model_name,
llm=LLM(model=model_name, temperature=0),
)
return {
"liaison": janus,
Expand Down
37 changes: 37 additions & 0 deletions backend/artifact_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
from pathlib import Path

_EXPLICIT_FUNCTION_PATTERN = re.compile(r"`([A-Za-z_][A-Za-z0-9_]*)\s*\(")
_FROM_IMPORT_PATTERN = re.compile(
r"(?P<prefix>\bfrom\s+)(?P<module>[A-Za-z_][A-Za-z0-9_.]*)(?P<suffix>\s+import\b)"
)


def explicit_function_names(user_request: str) -> tuple[str, ...]:
Expand Down Expand Up @@ -36,6 +39,40 @@ def validate_application_artifact(user_request: str, code: str) -> str | None:
return None


def normalize_test_imports(
application_file: str, user_request: str, test_code: str
) -> str:
"""Point explicit function imports at the planned application module."""
try:
tree = ast.parse(test_code)
except SyntaxError:
return test_code

required = set(explicit_function_names(user_request))
if not required:
return test_code

application_module = Path(application_file).stem
lines = test_code.splitlines(keepends=True)
for node in tree.body:
if not isinstance(node, ast.ImportFrom) or node.module == application_module:
continue
if not any(alias.name in required for alias in node.names):
continue

line_index = node.lineno - 1
line = lines[line_index]
match = _FROM_IMPORT_PATTERN.search(line, node.col_offset)
if match is None:
continue
lines[line_index] = (
line[: match.start("module")]
+ application_module
+ line[match.end("module") :]
)
return "".join(lines)


def validate_test_artifact(
application_file: str, user_request: str, test_code: str
) -> str | None:
Expand Down
10 changes: 1 addition & 9 deletions backend/models.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
"""Typed API and workflow models."""

import json
from datetime import datetime, timezone
from enum import Enum
from uuid import UUID, uuid4

from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from pydantic import BaseModel, ConfigDict, Field, model_validator

from rag.models import RetrievalEvent

Expand Down Expand Up @@ -97,13 +96,6 @@ class DevelopmentPlan(BaseModel):
developer_task: str = Field(min_length=1)
tester_task: str = Field(min_length=1)

@field_validator("developer_task", "tester_task", mode="before")
@classmethod
def normalize_structured_instructions(cls, value: object) -> object:
if isinstance(value, (dict, list)):
return json.dumps(value, indent=2)
return value

@model_validator(mode="after")
def validate_matching_file_names(self) -> "DevelopmentPlan":
if self.test_file_name != f"test_{self.file_name}":
Expand Down
30 changes: 28 additions & 2 deletions backend/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
from uuid import UUID

from crewai import Agent, Crew
from pydantic import BaseModel

from rag.index import get_retriever

from .agents import build_agents
from .artifact_validation import (
normalize_test_imports,
validate_application_artifact,
validate_test_artifact,
)
Expand Down Expand Up @@ -41,6 +43,14 @@


def _parse_json(raw_output: object) -> dict[str, object]:
structured_output = getattr(raw_output, "pydantic", None)
if isinstance(structured_output, BaseModel):
return structured_output.model_dump()

json_output = getattr(raw_output, "json_dict", None)
if isinstance(json_output, dict):
return json_output

cleaned = str(raw_output).strip().replace("```json", "").replace("```", "")
parsed = json.loads(cleaned.strip())
if not isinstance(parsed, dict):
Expand Down Expand Up @@ -260,7 +270,9 @@ def _develop_and_test(self, plan: DevelopmentPlan) -> str:
file_to_fix = plan.test_file_name
next_task = (
"Repair only the current test suite using this sanitized failure "
f"evidence:\n{test_results}"
"evidence. Re-audit every existing assertion against the original user "
"request before saving; fix unsupported expectations even when they are "
f"not named by this failure:\n{test_results}"
)
elif (
failure_kind in {FailureKind.timeout, FailureKind.resource}
Expand Down Expand Up @@ -293,7 +305,15 @@ def _develop_and_test(self, plan: DevelopmentPlan) -> str:
)
self._checkpoint()
if file_to_fix == plan.test_file_name:
tester_task = next_task
self.state.workspace.write(
plan.test_file_name,
"# Previous generated tests were discarded after a test-owned failure.\n",
)
tester_task = (
"Write a fresh test suite from the original user request and original "
"testing plan. Do not preserve assertions or expected values from the "
f"discarded suite. Root-cause guidance:\n{next_task}"
)
self._run_test_author(plan, tester_task)
elif file_to_fix == plan.file_name:
developer_task = next_task
Expand Down Expand Up @@ -393,6 +413,12 @@ def _run_tests(self, plan: DevelopmentPlan) -> str:

test_code = self.state.workspace.read(plan.test_file_name)
if test_code is not None:
normalized_test_code = normalize_test_imports(
plan.file_name, self.state.request, test_code
)
if normalized_test_code != test_code:
self.state.workspace.write(plan.test_file_name, normalized_test_code)
test_code = normalized_test_code
test_error = validate_test_artifact(
plan.file_name, self.state.request, test_code
)
Expand Down
48 changes: 33 additions & 15 deletions backend/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from crewai import Agent, Task
from crewai.tools import BaseTool

from .models import DevelopmentPlan
from .sandbox_dependencies import SANDBOX_CAPABILITY_SUMMARY


Expand Down Expand Up @@ -48,16 +49,21 @@ def build_tasks(
"{technical_brief}\n'''\n\nReturn one valid JSON object with four keys: "
"'file_name' for a PEP 8 Python filename, 'test_file_name' for its pytest "
"suite, 'developer_task' as one JSON string with precise functions, inputs, "
"outputs, and logic, and 'tester_task' as one JSON string with the test "
"strategy and specific cases. The developer_task and tester_task must use the "
"same exact public class and function names, file names, return keys, and "
"edge-case behavior "
"from the brief. Do not rename a requested function or invent a different "
"outputs, and logic, and 'tester_task' as one JSON string describing exactly "
"one representative happy-path case. The developer_task and tester_task must use the "
"same exact public class and function names, file names, return keys, and main "
"happy-path behavior from the brief. Do not rename a requested function or invent a different "
"output schema. Do not add case-insensitive behavior or exact exception-message "
"requirements unless the brief explicitly requires them. Do not return nested "
"objects or arrays for developer_task or tester_task. When wording such as "
"'normalize' is ambiguous, choose the narrowest behavior directly supported by "
"the brief and state it identically in both tasks. The offline sandbox provides "
"objects or arrays for developer_task or tester_task. Both tasks must be prose "
"instructions, not example input and output data. developer_task must state the "
"ordered implementation logic. tester_task must use ordinary valid inputs and "
"verify only the main requested operation and expected output. Do not include "
"malformed, missing, invalid, duplicate, boundary, ordering, mutation, exception, "
"or type-subtlety cases in tester_task. "
"When wording such as 'normalize' is ambiguous, choose the narrowest behavior "
"directly supported by the brief and state it identically in both tasks. The "
"offline sandbox provides "
f"these pinned packages: {SANDBOX_CAPABILITY_SUMMARY}. Do not introduce an "
"unrequested package. When the brief "
"depends on a third-party API, use search_official_documentation before "
Expand All @@ -69,6 +75,7 @@ def build_tasks(
),
agent=agents["lead"],
tools=list(retrieval_tools),
output_pydantic=DevelopmentPlan,
)
develop = Task(
description=(
Expand All @@ -94,23 +101,31 @@ def build_tasks(
)
test_suite = Task(
description=(
"Implement the current testing instruction while preserving the original test "
"plan. Assertions must check exact expected outcomes. If current tests are "
"present, repair only those tests and preserve unaffected coverage. The original "
"Generate exactly one pytest test function covering one representative happy "
"path with ordinary valid inputs. The test must verify only the main requested "
"operation and its expected output. Do not generate malformed, missing, invalid, "
"duplicate, boundary, ordering, mutation, exception, or type-subtlety cases. "
"If current tests are present, replace them as needed so the suite still contains "
"exactly one happy-path test. The original "
"user request is the immutable source of truth.\n\nOriginal User Request:\n'''\n"
"{user_request}\n'''\n\nOriginal "
"Testing Plan:\n'''\n{original_tester_task}\n'''\n\nCurrent Testing "
"Instruction:\n'''\n{tester_task}\n'''\n\nCurrent Tests:\n'''\n"
"{current_tests}\n'''\n\nUse the exact application file name, public class and function names, return keys, and "
"edge-case behavior from the original testing plan. Import the requested "
"main happy-path behavior from the original testing plan. Import the requested "
"symbol from the requested application module; never substitute a similar "
"function name or invent a different output schema. Treat strings and identifiers "
"as case-sensitive unless the original plan explicitly requires case-insensitive "
"behavior. Do not assert an exact exception message unless its text is explicitly "
"required. Do not invent normalization, response bodies, or validation rules "
"that are absent from the original plan. During repair, remove or correct assertions that encode unstated "
"requirements instead of preserving them. Before saving, verify that the test "
"file is complete, contains no Markdown fences, and is syntactically valid Python. "
"requirements instead of preserving them. Before every save, audit every expected "
"value and assertion against the original user request. Remove or correct any "
"assertion that cannot be tied to an explicit requirement, even when the current "
"repair instruction mentions a different defect. If the current tests say they "
"were discarded, rebuild the suite from the original request instead of restoring "
"prior assertions. Before saving, verify that the test file is complete, contains "
"no Markdown fences, and is syntactically valid Python. "
"The offline sandbox provides these pinned packages: "
f"{SANDBOX_CAPABILITY_SUMMARY}. Do not import an unrequested dependency. Use "
"save_file to save it to {test_file_name}."
Expand Down Expand Up @@ -145,7 +160,10 @@ def build_tasks(
"a broken test import. If the application does not parse, repair the application "
"first. If the application matches the original contract but the test imports "
"a different symbol, asserts a different schema, assumes unstated case-insensitive "
"behavior, or requires an unspecified exception message, repair the tests. Use "
"behavior, or requires an unspecified exception message, repair the tests. For "
"assertion failures, compare the actual candidate output and the test's expected "
"output independently against the original request before routing. The generated "
"testing plan is never allowed to override the original request. Use "
"search_official_documentation when the root cause depends on third-party API "
"behavior."
),
Expand Down
40 changes: 33 additions & 7 deletions docs/STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ accepted decisions. Day 7 deployment work has not started.
- Removed the Streamlit entry point and its direct runtime dependencies. Regenerated the
Python lockfile while constraining unrelated transitive versions to the prior lock.
- Live browser integration exposed that Athena can return structured JSON objects for
`developer_task` and `tester_task` even though the workflow model stores strings. Added
an explicit prompt constraint and deterministic object/list normalization so that valid
structured plans no longer terminate a run.
`developer_task` and `tester_task` even though the workflow contract requires prose.
Athena now uses typed output and nested plan instructions are rejected instead of being
normalized into misleading example data.
- Clarified failed-run accounting after live browser testing: repeated sandbox
infrastructure failures now end with an infrastructure-specific status message, and the
frontend separates consumed candidate attempts from raw test execution records.
Expand Down Expand Up @@ -100,9 +100,31 @@ accepted decisions. Day 7 deployment work has not started.
rather than embedding a replacement implementation.
- Routed deterministic request-contract failures directly to Hephaestus and test-artifact
failures directly to Argus, avoiding an unnecessary Athena diagnosis call.
- Tightened plan and test reliability after a live feature-flag regression. Athena now emits
the typed `DevelopmentPlan` schema with prose implementation logic instead of nested example
data, all agents use temperature zero, and repaired test suites must re-audit every assertion
against the original request before execution.
- Corrected the typed-plan integration after localhost verification exposed that CrewAI renders
`CrewOutput.__str__()` as a Pydantic representation rather than JSON. The pipeline now reads
typed `pydantic` and `json_dict` output directly before falling back to JSON text parsing.
- Added deterministic test-import normalization after Argus repeatedly preserved a placeholder
module during repair. Imports of explicitly requested functions now target the planned
application module before artifact validation, without changing test assertions.
- Changed test-owned semantic repair to discard the invalid generated suite before asking Argus
for a fresh suite. This prevents incorrect expected values from anchoring subsequent repairs
while preserving the original request and typed testing plan as the source of truth.

## Verification performed

- Paid localhost verification on 2026-07-22 confirmed one valid repaired pass and one false
positive. Feature-flag run `a1f3db16` corrected an invalid generated expectation and passed
on attempt two. Normalization run `4a93f7cd` reported success on attempt three, but its final
code violated the original display-name fallback and active-string normalization rules, so it
must not be counted as a successful run. Further paid prompts were stopped.
- After the feature-flag reliability fix, `.venv/bin/pytest -q` passed with 86 tests
and five environment-dependent tests skipped. Ruff checks and formatting, mypy,
frontend lint and type-check, the production frontend build, and a local browser
smoke test also passed without submitting another paid model request.
- `.venv/bin/pytest -q` passed with 86 tests and five environment-dependent tests skipped
after the benchmark-driven orchestration fixes.
- `ruff check backend benchmark rag tests`, `ruff format --check backend benchmark rag tests`,
Expand Down Expand Up @@ -210,6 +232,10 @@ accepted decisions. Day 7 deployment work has not started.
- Agent-generated code can still fail after repair despite stronger contracts because live
model output is nondeterministic. Such runs remain correctly marked failed and should be
retained as quality evidence rather than counted as successful executions.
- Generated tests can still create a false positive by asserting behavior that contradicts the
original request and then driving application repair toward those assertions. A terminal
`ALL TESTS PASSED` result is not trustworthy until an independent final contract audit compares
the resulting application directly with the immutable user request.
- FastAPI, CrewAI, Starlette, and OpenTelemetry continue to emit upstream deprecation
warnings during the Python test suite.

Expand All @@ -222,7 +248,7 @@ by displaying only precomputed, measured artifacts and never triggering or inven

## Exact next task

Finish the benchmark safety controls before more paid evaluation: checkpoint each task, add
resume support and per-call usage/cost telemetry, enforce model spending limits, and then run
a three-task pilot. Do not run another full Digital Forge benchmark or update resume and
LinkedIn comparison claims until that pilot is reviewed.
Add an independent final contract audit that cannot treat generated tests as the source of truth.
It must compare the final application directly with the immutable request and block a successful
status when repaired code drops or contradicts a requirement. Then finish benchmark checkpointing,
usage telemetry, and spending limits before another paid pilot or any resume claim update.
4 changes: 2 additions & 2 deletions frontend/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ const MAX_REQUEST_LENGTH = 20_000;

const EXAMPLES = [
"Build a Python function that validates nested brackets and include a focused pytest suite.",
"Create a typed Python client for a weather API with clear error handling and unit tests.",
"Implement a stable deduplication function that preserves input order and test edge cases.",
"Build a Python function that groups orders by customer and summarizes completed totals, pending totals, and order counts.",
"Implement a stable deduplication function that preserves input order and include a focused pytest suite.",
];

const PIPELINE: Array<{
Expand Down
Loading
Loading