feat(verification): Phase A + Phase B soft rollout — Marcus authors verifications, gate prefers them, falls back to agent (#636)#642
Conversation
…Outcome (#636) First of two PRs implementing Invariant #2 v2 (CLAUDE.md MULTIAGENCY_PROCLAMATION) — verification command authorship moves from the integration agent to Marcus's setup-time pipeline. This PR ships the CONTRACT side only. The runtime gate change ships in PR 2 (atomic with the integration-agent prompt rewrite). Until that lands, the contract field is present but unused at completion time — fully backwards-compatible. Why --- Project test58 (purple-dot-snake-game, 2026-05-23) shipped an unplayable snake game because the integration verifier iterated agent-authored verification commands through multiple retries until exit=0 happened, without actually testing keyboard input. The fix per Kaia /kaia --chat review (Simon decision b8599a52): Marcus's setup-time pipeline generates one verification command per in-scope UserOutcome; the agent runs them but does not author them. Contract-net protocol pattern from 1980s MAS literature. What changed ------------ - src/ai/advanced/prd/verification_command_generator.py (new): - ContractVerification dataclass — typed in Python, serializes to dict for source_context storage (Kaia M2) - generate_verification_command — one LLM call per outcome. Returns None when LLM declines rather than hallucinating - generate_verification_commands — fan-out via asyncio.gather (Kaia M4 — bounds Phase A latency by slowest single call) - Generation prompt requires commands to EXERCISE the user-facing behavior and use only the project's existing tech stack (Kaia M3 scaffold-constraint, prompt-engineered) - src/integrations/integration_verification.py: - create_integration_task accepts contract_verifications parameter; stamps source_context["contract_verifications"] - enhance_project_with_integration forwards the parameter - Field is unused at runtime until PR 2 — backwards-compatible - src/integrations/nlp_tools.py (create_project_from_description): - After stashed_outcomes is resolved, fans out the verification generator on in-scope outcomes - Wraps generator call in try/except so a failure NEVER blocks project creation; gate falls back to legacy path - tests/unit/ai/test_verification_command_generator.py (new): 21 tests covering ContractVerification dataclass round-trips, single-outcome generator contract (success / null / malformed / missing fields / whitespace), fan-out semantics (empty input, N->N generation, drop-on-null, error propagation). What is NOT in this PR ---------------------- - No smoke-gate change in report_task_progress yet. Ships atomically with the integration-agent prompt rewrite in PR 2. - Coverage check ("every in-scope outcome must have a contract verification") deferred to PR 2. Tests ----- - 21 new unit tests pass - Broader unit suite passes (exit code 0) - 711 in scope (tests/unit/ai/ + integration_verification) pass - mypy clean on all 3 changed source files Related ------- - Issue #636 umbrella - PR #639 Invariant #2 v2 doc - Simon decisions: b8599a52 (philosophy), 77ade35a (pre-PR review) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Claude finished @lwgray's task —— View job Code Review Complete ✅I've thoroughly reviewed PR #642 implementing Phase A verification command generation. Here's my detailed analysis: Overall AssessmentExcellent work! This PR demonstrates high-quality software engineering with thoughtful design, comprehensive testing, and careful attention to the Marcus architecture. The implementation successfully addresses the core problem described in issue #636 while maintaining clean separation of concerns. Code Quality & Best Practices ⭐⭐⭐⭐⭐Strong Points:
Code Quality Examples:# Well-designed dataclass with validation
@dataclass
class ContractVerification:
signal_id: str
command: str
description: str
readiness_probe: Optional[str] = None# Robust error handling with context
raise ValueError(
f"Verification-command generator: LLM returned malformed JSON "
f"for outcome {outcome.id!r}: {exc}"
) from excSecurity Analysis ✅No security concerns identified. The implementation follows secure practices:
Performance Analysis ✅Well-optimized for Phase A latency requirements:
Potential Issues & RecommendationsMinor Issues:
Integration Considerations:
Test Coverage Analysis ⭐⭐⭐⭐⭐Exceptional test coverage! 378 LOC of tests for 334 LOC of implementation shows strong commitment to quality. Coverage Highlights:
Test Quality Examples:def test_rejects_malformed_llm_json(self):
"""Garbage from the LLM raises ValueError with outcome id in message."""
llm = _stub_llm("not json at all")
with pytest.raises(ValueError, match="outcome_play"):
await generate_verification_command(
_outcome(), project_description="x", llm_client=llm
)Architecture Alignment ✅Perfect adherence to Marcus patterns:
Marcus Architecture PatternsExcellent Pattern Usage:
Final Recommendations
SummaryThis is high-quality production code that successfully implements a critical architectural change while maintaining system stability. The comprehensive testing, thoughtful error handling, and clean integration demonstrate excellent software engineering practices. The Phase A/Phase B separation strategy is particularly well-executed, allowing safe rollout of this significant change. Recommendation: ✅ APPROVE - This PR meets all quality standards and successfully implements the required functionality. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 302a580984
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if contract_verifications: | ||
| source_context["contract_verifications"] = [ | ||
| cv.to_dict() for cv in contract_verifications | ||
| ] |
There was a problem hiding this comment.
Preserve empty contract verification lists
Store contract_verifications whenever generation ran, even when it produced an empty list. With the current truthy check, [] is dropped and source_context["contract_verifications"] is omitted, which makes the task indistinguishable from “generation never happened” and prevents downstream coverage/gap logic from detecting that in-scope outcomes had no contract-authored commands.
Useful? React with 👍 / 👎.
…fications list The truthy check ``if contract_verifications:`` dropped empty lists from ``source_context``, conflating two semantically distinct states: - ``None``: generation never happened (caller had no outcomes, no LLM engine, or wrapped the call in try/except that caught a failure). Phase B should fall back to the legacy agent-authored path here. - ``[]``: generation ran, the LLM declined to author a command for every in-scope outcome (typically because the tech stack does not include verification tooling for these outcomes). Phase B should surface this as a gap, not silently fall back. Fix: use ``is not None`` so the empty list round-trips intact. Pattern mirrors the existing ``in_scope_outcome_ids`` stamping just above, which uses ``if outcomes is not None``. Tests ----- Four new cases in ``TestIntegrationTaskOutcomesWiring``: - ``test_contract_verifications_absent_when_parameter_not_passed`` - ``test_contract_verifications_absent_when_parameter_is_none`` - ``test_contract_verifications_empty_list_is_stamped`` (Codex P2) - ``test_contract_verifications_populated_list_is_stamped`` All 66 tests in the file pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codex P2 fixed in
|
| Value | Meaning | Phase B behavior |
|---|---|---|
None (field absent) |
Generation never happened — caller had no outcomes, no LLM engine, or wrapped in try/except that caught a failure | Fall back to legacy agent-authored path |
[] (field present, empty) |
Generation ran; LLM declined to author commands for every in-scope outcome (tech stack lacks verification tooling) | Surface as a gap, don't silently fall back |
[...] (field present, populated) |
Normal case | Run the contract commands |
Added 4 unit tests covering all three states + the parameter-not-passed default. All 66 tests in test_integration_verification.py pass.
|
Claude finished @lwgray's task —— View job PR Review Complete ✅I've thoroughly reviewed PR #642 implementing Phase A verification command generation. Here's my detailed analysis: Overall AssessmentExcellent work! This PR demonstrates high-quality software engineering with thoughtful design, comprehensive testing, and careful attention to the Marcus architecture. The implementation successfully addresses the core problem described in issue #636 while maintaining clean separation of concerns. Code Quality & Best Practices ⭐⭐⭐⭐⭐Strong Points:
Code Quality Examples:# Well-designed dataclass with validation
@dataclass
class ContractVerification:
signal_id: str
command: str
description: str
readiness_probe: Optional[str] = None# Robust error handling with context
raise ValueError(
f"Verification-command generator: LLM returned malformed JSON "
f"for outcome {outcome.id!r}: {exc}"
) from excSecurity Analysis ✅No security concerns identified. The implementation follows secure practices:
Performance Analysis ✅Well-optimized for Phase A latency requirements:
Potential Issues & RecommendationsMinor Issues:
Integration Considerations:
Test Coverage Analysis ⭐⭐⭐⭐⭐Exceptional test coverage! 378 LOC of tests for 334 LOC of implementation shows strong commitment to quality. Coverage Highlights:
Test Quality Examples:def test_rejects_malformed_llm_json(self):
"""Garbage from the LLM raises ValueError with outcome id in message."""
llm = _stub_llm("not json at all")
with pytest.raises(ValueError, match="outcome_play"):
await generate_verification_command(
_outcome(), project_description="x", llm_client=llm
)Architecture Alignment ✅Perfect adherence to Marcus patterns:
Marcus Architecture PatternsExcellent Pattern Usage:
Final Recommendations
SummaryThis is high-quality production code that successfully implements a critical architectural change while maintaining system stability. The comprehensive testing, thoughtful error handling, and clean integration demonstrate excellent software engineering practices. The Phase A/Phase B separation strategy is particularly well-executed, allowing safe rollout of this significant change. Recommendation: ✅ APPROVE - This PR meets all quality standards and successfully implements the required functionality. |
…ilures, warn on empty result P2-2: asyncio.gather no longer poisons the well ------------------------------------------------ ``generate_verification_commands`` used the gather default ``return_exceptions=False``. A single bad LLM response (malformed JSON surviving retries, validation error, network blip) would raise out of the whole gather. The caller in nlp_tools.py catches it and falls back to ``contract_verifications_list=None`` — losing ALL N verifications because of ONE bad call. At ~2% per-call failure rate over 6 outcomes, that's a ~11% chance of losing the whole batch per project. Not acceptable. Fix: switch to ``return_exceptions=True`` and iterate. Per-outcome failures log a warning naming the outcome id and drop just that outcome; the rest of the batch ships. P3: empty-list log bumped to WARNING ------------------------------------ When the generator returns an empty list (all N outcomes failed or LLM declined for all of them), the corresponding log in nlp_tools.py was INFO. "Generated 0 contract verification(s) for N in-scope outcome(s)" is the operator-visible event the Codex P2 fix made representable. Bump to WARNING when count is 0. Tests ----- - test_partial_llm_failure_propagates_via_gather flipped to test_partial_llm_failure_is_isolated_per_outcome - All 21 generator tests + 66 integration tests pass - mypy clean Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Kaia P2-2 + P3 fixes landed in
|
|
Claude finished @lwgray's task —— View job PR Review Complete ✅I've thoroughly reviewed PR #642 implementing Phase A verification command generation. Here's my detailed analysis: Overall AssessmentExcellent work! This PR demonstrates high-quality software engineering with thoughtful design, comprehensive testing, and careful attention to the Marcus architecture. The implementation successfully addresses the core problem described in issue #636 while maintaining clean separation of concerns. Code Quality & Best Practices ⭐⭐⭐⭐⭐Strong Points:
Code Quality Examples:# Well-designed dataclass with validation
@dataclass
class ContractVerification:
signal_id: str
command: str
description: str
readiness_probe: Optional[str] = None# Robust error handling with context
raise ValueError(
f"Verification-command generator: LLM returned malformed JSON "
f"for outcome {outcome.id!r}: {exc}"
) from excSecurity Analysis ✅No security concerns identified. The implementation follows secure practices:
Performance Analysis ✅Well-optimized for Phase A latency requirements:
Potential Issues & RecommendationsMinor Issues:
Integration Considerations:
Test Coverage Analysis ⭐⭐⭐⭐⭐Exceptional test coverage! 390 LOC of tests for 363 LOC of implementation shows strong commitment to quality. Coverage Highlights:
Test Quality Examples:def test_rejects_malformed_llm_json(self):
"""Garbage from the LLM raises ValueError with outcome id in message."""
llm = _stub_llm("not json at all")
with pytest.raises(ValueError, match="outcome_play"):
await generate_verification_command(
_outcome(), project_description="x", llm_client=llm
)Architecture Alignment ✅Perfect adherence to Marcus patterns:
Marcus Architecture PatternsExcellent Pattern Usage:
Final Recommendations
SummaryThis is high-quality production code that successfully implements a critical architectural change while maintaining system stability. The comprehensive testing, thoughtful error handling, and clean integration demonstrate excellent software engineering practices. The Phase A/Phase B separation strategy is particularly well-executed, allowing safe rollout of this significant change. Recommendation: ✅ APPROVE - This PR meets all quality standards and successfully implements the required functionality. |
…ns, falls back to agent (#636) Second half of the #636 bundle. Phase A (earlier commits on this PR) generates contract verification commands at setup time and stamps them onto the integration task's source_context. Phase B (this commit) wires the runtime smoke gate to read those commands and prefer them over agent-authored ones. Soft rollout — contract is TRIED first, agent-supplied is the FALLBACK. Fallback fires on any of: - Contract field absent (Phase A never ran for this project) - Contract empty list (Phase A ran but LLM declined every outcome) - Contract incomplete coverage (in_scope_outcome_id without contract) - Contract command fails at runtime Each fallback case fires a WARNING log so operators can iterate on the generator prompt over time (#643 follow-up). Once the contract path is empirically reliable, a future PR can promote this to a hard cutover and drop the agent-supplied path. Why soft rollout, not hard cutover ----------------------------------- Hard cutover would have been: contract present -> trust absolutely; agent-supplied is dead code. Larry's pre-commit review: "what if Marcus's command is wrong? We'll be wrong a lot." Right. Without #643's scaffold-stack enforcement, Phase A's LLM-generated commands will reference unavailable tools, wrong paths, vacuous checks. Hard cutover means a buggy contract blocks ALL completions; soft rollout means a buggy contract loses to the agent-supplied fallback with a WARNING that lets us iterate. Phase B does NOT eliminate the gameability that motivated #636. It makes the gameability the FALLBACK instead of the default. As contract reliability grows, fallback fires less. Eventually we remove it. What changed ------------ - src/marcus_mcp/tools/task.py::_run_product_smoke_gate (~line 566): added the contract-first try-then-fall-through block BEFORE the existing Slice B escape-hatch + agent-supplied flow. The new block reads source_context["contract_verifications"], builds VerificationSpec records, runs the coverage check, runs the verifier, and falls through on any failure mode with a WARNING. - tests/unit/marcus_mcp/test_integration_smoke_gate.py: new TestPhaseBSoftRollout class with 6 tests: - contract accept (skip agent path) - contract failure -> fall back to agent (passes) - contract incomplete coverage -> fall back to agent - contract empty list -> fall back to agent (Codex P2 distinction) - contract absent -> legacy agent path unchanged - contract fail + no agent supplied -> existing escape-hatch rejection still fires No change to the integration-agent prompt. The agent continues to author verifications as before; Marcus quietly prefers its contract when available; agent's are the safety net. Tests ----- - 33 smoke-gate tests pass (was 27, +6 new) - 253 tests in the full scope (marcus_mcp + verification generator + integration_verification) all pass - mypy clean on all 4 changed source files Related ------- - Issue #636 umbrella - PR #639 Invariant #2 v2 doc - This PR's earlier commits: Phase A (302a580), Codex P2 (87d7fed), Kaia P2-2 + P3 (7c44b18) - #643 — scaffold-stack constraint follow-up - #644 — Cato cost-tracking verification group - #645 — Epictetus multi-agent transcript refactor - Simon decision b8599a52, thought a4219ac9 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Claude finished @lwgray's task —— View job PR Review Complete ✅I've thoroughly reviewed PR #642 implementing Phase A verification command generation. Here's my detailed analysis: Overall AssessmentExcellent work! This PR demonstrates high-quality software engineering with thoughtful design, comprehensive testing, and careful attention to the Marcus architecture. The implementation successfully addresses the core problem described in issue #636 while maintaining clean separation of concerns. Code Quality & Best Practices ⭐⭐⭐⭐⭐Strong Points:
Code Quality Examples:# Well-designed dataclass with validation
@dataclass
class ContractVerification:
signal_id: str
command: str
description: str
readiness_probe: Optional[str] = None# Robust error handling with context
raise ValueError(
f"Verification-command generator: LLM returned malformed JSON "
f"for outcome {outcome.id!r}: {exc}"
) from excSecurity Analysis ✅No security concerns identified. The implementation follows secure practices:
Performance Analysis ✅Well-optimized for Phase A latency requirements:
Potential Issues & RecommendationsMinor Issues:
Integration Considerations:
Test Coverage Analysis ⭐⭐⭐⭐⭐Exceptional test coverage! 390 LOC of tests for 362 LOC of implementation shows strong commitment to quality. Coverage Highlights:
Test Quality Examples:def test_rejects_malformed_llm_json(self):
"""Garbage from the LLM raises ValueError with outcome id in message."""
llm = _stub_llm("not json at all")
with pytest.raises(ValueError, match="outcome_play"):
await generate_verification_command(
_outcome(), project_description="x", llm_client=llm
)Architecture Alignment ✅Perfect adherence to Marcus patterns:
Marcus Architecture PatternsExcellent Pattern Usage:
Final Recommendations
SummaryThis is high-quality production code that successfully implements a critical architectural change while maintaining system stability. The comprehensive testing, thoughtful error handling, and clean integration demonstrate excellent software engineering practices. The Phase A/Phase B separation strategy is particularly well-executed, allowing safe rollout of this significant change. Recommendation: ✅ APPROVE - This PR meets all quality standards and successfully implements the required functionality. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ba1fde9584
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| try: | ||
| contract_verifications_list = ( | ||
| await generate_verification_commands( | ||
| in_scope_for_verification, |
There was a problem hiding this comment.
Skip contract verification generation when integration is disabled
generate_verification_commands(...) runs before enhance_project_with_integration(...), but that helper internally calls should_add_integration_task and can early-return for demo/POC/test-style projects. In those cases we still pay for one LLM call per in-scope outcome even though no integration task is created and the generated commands are discarded, which adds avoidable latency/cost and noisy warning logs on project creation. Gate this generation behind the same integration-task eligibility check (or move it into the integration enhancer after eligibility is confirmed).
Useful? React with 👍 / 👎.
…_add_integration_task
``enhance_project_with_integration`` internally calls
``IntegrationTaskGenerator.should_add_integration_task`` and
early-returns for demo / POC / prototype-shaped projects. Pre-fix,
``create_project_from_description`` ran the verification-command
generator BEFORE that eligibility check — spending N LLM calls per
in-scope outcome on projects where the integration task is never
created, and the generated commands are silently discarded.
Failure mode in numbers:
- ~$0.005 per LLM call × N outcomes per project = ~$0.03/project of
wasted spend on every demo/POC/prototype
- ~5s of wasted Phase A latency on each (the generator is
parallelized via asyncio.gather, but it's still wall-clock cost
that adds to project creation time)
- noisy WARNING log lines about generation results that are about
to be thrown away
Fix: gate the generator behind the same
``should_add_integration_task(description)`` predicate the
downstream enhancer uses. When eligibility is False, skip the
generator entirely and log INFO ("skipping — project doesn't
qualify for integration verification"). When True, fall through
to the existing generator block unchanged.
Pattern: mirror the predicate at the gate, not delegate to a deeper
function. Could have moved the generator INTO
``enhance_project_with_integration`` after the eligibility check,
but that helper is sync; making it async to host an async call
would force a wider API change for every other caller.
Tests
-----
- 131 in-scope tests pass (nlp_tools + integration_verification +
verification_command_generator + smoke gate)
- mypy clean for nlp_tools.py
A direct unit test for this gate inside
``create_project_from_description`` would require mocking the whole
project-creation pipeline; the gate is a wrapper around a function
that has its own coverage. Deferred to a future refactor that
extracts the eligibility-gated block into a testable helper.
Related
-------
- PR #642 — the PR this fix lives on
- Codex P2 on commit ba1fde9 — the finding
- ``IntegrationTaskGenerator.should_add_integration_task`` at
``src/integrations/integration_verification.py:230`` — the
predicate this gate mirrors
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codex P2 fixed in
|
|
Claude finished @lwgray's task —— View job Comprehensive PR Review Complete ✅I've thoroughly reviewed PR #642 implementing Phase A verification command generation. Here's my detailed analysis: Review Checklist
Overall AssessmentExcellent work! This PR demonstrates high-quality software engineering with thoughtful design, comprehensive testing, and careful attention to the Marcus architecture. The implementation successfully addresses the core problem described in issue #636 while maintaining clean separation of concerns. Code Quality & Best Practices ⭐⭐⭐⭐⭐Strong Points:
Code Quality Examples:# Well-designed dataclass with validation
@dataclass
class ContractVerification:
signal_id: str
command: str
description: str
readiness_probe: Optional[str] = None# Robust error handling with context
raise ValueError(
f"Verification-command generator: LLM returned malformed JSON "
f"for outcome {outcome.id!r}: {exc}"
) from excSecurity Analysis ✅No security concerns identified. The implementation follows secure practices:
Performance Analysis ✅Well-optimized for Phase A latency requirements:
Test Coverage Analysis ⭐⭐⭐⭐⭐Exceptional test coverage! 390 LOC of tests for 362 LOC of implementation shows strong commitment to quality. Coverage Highlights:
Test Quality Examples:def test_partial_llm_failure_is_isolated_per_outcome(self, caplog):
"""One bad LLM call drops that outcome but keeps the rest (P2-2)."""
# Tests that return_exceptions=True prevents poison-the-well behaviorArchitecture Alignment ✅Perfect adherence to Marcus patterns:
Marcus Architecture PatternsExcellent Pattern Usage:
Minor Issues & Recommendations1. Broad Exception Handling (line 1714 in nlp_tools.py):except Exception as gen_err: # noqa: BLE001Recommendation: Consider catching more specific exceptions (e.g., 2. Optional Enhancement:Consider adding basic shell command syntax validation to catch obviously malformed commands before they reach subprocess execution. 3. Marcus Error Framework:While current error handling is appropriate, consider integrating with Marcus Error Framework for consistency across the codebase. Architectural ContributionsThis PR successfully implements a critical architectural change:
Final Recommendations
SummaryThis is high-quality production code that successfully implements a critical architectural change while maintaining system stability. The comprehensive testing, thoughtful error handling, and clean integration demonstrate excellent software engineering practices. The Phase A/Phase B separation strategy is particularly well-executed, allowing safe rollout of this significant change. The soft rollout approach is especially commendable - it provides a safety net while allowing the system to learn and improve contract generation quality over time. Recommendation: ✅ APPROVE - This PR meets all quality standards and successfully implements the required functionality. |
…erification-commands
|
Claude finished @lwgray's task —— View job PR Review: Phase A + Phase B Verification Commands ✅I've thoroughly reviewed PR #642 implementing Phase A verification command generation. Here's my detailed analysis: Review Checklist
Overall AssessmentExcellent work! This PR demonstrates high-quality software engineering with thoughtful design, comprehensive testing, and careful attention to the Marcus architecture. The implementation successfully addresses the core problem described in issue #636 while maintaining clean separation of concerns. Code Quality & Best Practices ⭐⭐⭐⭐⭐Strong Points:
Code Quality Examples:# Well-designed dataclass with validation
@dataclass
class ContractVerification:
signal_id: str
command: str
description: str
readiness_probe: Optional[str] = None# Robust error handling with context
raise ValueError(
f"Verification-command generator: LLM returned malformed JSON "
f"for outcome {outcome.id!r}: {exc}"
) from excSecurity Analysis ✅No security concerns identified. The implementation follows secure practices:
Performance Analysis ✅Well-optimized for Phase A latency requirements:
Test Coverage Analysis ⭐⭐⭐⭐⭐Exceptional test coverage! 390 LOC of tests for 362 LOC of implementation shows strong commitment to quality. Coverage Highlights:
Test Quality Examples:def test_partial_llm_failure_is_isolated_per_outcome(self, caplog):
"""One bad LLM call drops that outcome but keeps the rest (P2-2)."""
# Tests that return_exceptions=True prevents poison-the-well behaviorArchitecture Alignment ✅Perfect adherence to Marcus patterns:
Marcus Architecture PatternsExcellent Pattern Usage:
Minor Issues & Recommendations1. Broad Exception Handling (line 1714 in nlp_tools.py):except Exception as gen_err: # noqa: BLE001Recommendation: Consider catching more specific exceptions (e.g., 2. Optional Enhancement:Consider adding basic shell command syntax validation to catch obviously malformed commands before they reach subprocess execution. 3. Marcus Error Framework:While current error handling is appropriate, consider integrating with Marcus Error Framework for consistency across the codebase. Architectural ContributionsThis PR successfully implements a critical architectural change:
Final Recommendations
SummaryThis is high-quality production code that successfully implements a critical architectural change while maintaining system stability. The comprehensive testing, thoughtful error handling, and clean integration demonstrate excellent software engineering practices. The Phase A/Phase B separation strategy is particularly well-executed, allowing safe rollout of this significant change. The soft rollout approach is especially commendable - it provides a safety net while allowing the system to learn and improve contract generation quality over time. Recommendation: ✅ APPROVE - This PR meets all quality standards and successfully implements the required functionality. |
|
Closing: this builds Marcus-authored verification commands (Phase A/B), the direction we've moved away from. We pivoted to agent self-verification (the agent owns verification; Marcus authors no verification command) and removed the Marcus-run build floor entirely (it was tech-specific and gridlock-prone). The premise here is superseded. Reopen if the verification-command-generation infra is needed standalone. |
Bundle of Phase A + Phase B for issue #636. Implements
Invariant #2 v2 (CLAUDE.md MULTIAGENCY_PROCLAMATION, PR #639):
verification command authorship moves from the integration agent
to Marcus's setup-time pipeline; the runtime smoke gate prefers
contract-authored commands and falls back to agent-supplied on
absence, empty, incomplete coverage, or runtime failure.
What this PR does, in plain English
Marcus today builds software by spawning AI agents in parallel.
After they all finish, an integration-verifier agent confirms the
system works. Until now the agent chose what verification commands
to run — and because the agent has retry pressure to keep weakening
commands until exit 0, they ended up shipping commands that
technically passed without actually testing the user-facing
behavior. Project test58 (purple-dot-snake-game) shipped unplayable
because the agent's verification for the "keyboard input" outcome
never simulated a keypress.
This PR moves verification authorship to Marcus. At project setup
(Phase A), Marcus generates one shell command per in-scope user
outcome via an LLM call. At completion (Phase B), Marcus's smoke
gate prefers those contract-authored commands over the agent's.
Soft rollout: if Marcus's command is wrong (absent, broken,
incomplete coverage), the gate falls back to the agent's verifications.
Each fallback fires a WARNING log so operators can iterate on the
generator prompt over time. Once the contract path is empirically
reliable, a future PR will promote to a hard cutover.
Why soft rollout, not hard cutover
The hard-cutover plan was "contract present -> trust absolutely."
Pre-merge Kaia review pushed back: without #643's scaffold-stack
enforcement, Phase A's LLM-generated commands will reference
unavailable tools, wrong paths, vacuous checks. A buggy contract
under hard cutover blocks ALL completions; under soft rollout it
loses to the agent-supplied fallback with a WARNING that lets us
iterate.
Honest trade-off: Phase B does NOT eliminate the gameability that
motivated #636. It makes the gameability the FALLBACK instead of
the default. As contract reliability grows (via #643), the fallback
fires less.
What changed
src/ai/advanced/prd/verification_command_generator.py(new)ContractVerificationtyped dataclass + per-outcome LLM generator + parallelized fan-out viaasyncio.gather(return_exceptions=True)for per-outcome isolationsrc/integrations/integration_verification.pycreate_integration_task+enhance_project_with_integrationacceptcontract_verificationsparameter; stampssource_context["contract_verifications"](preserves empty list per Codex P2)src/integrations/nlp_tools.py(create_project_from_description)src/marcus_mcp/tools/task.py::_run_product_smoke_gatetests/unit/ai/test_verification_command_generator.py(new)tests/unit/integrations/test_integration_verification.pycontract_verificationsparameter (absent / None / empty list / populated)tests/unit/marcus_mcp/test_integration_smoke_gate.pyTestPhaseBSoftRolloutclass with 6 tests covering all fallback modesCommit chain
302a580987d7fed1[](distinct fromNone) onsource_context7c44b187asyncio.gather(return_exceptions=True)isolation + WARNING-level log on empty resultba1fde95How the contract flows (worked example)
Project
test58style — 6 in-scope outcomes:Phase A runs at project creation:
N LLM calls, ~5s wall-clock total. Maybe 4 succeed, 1 LLM returns
null (tech stack can't verify that outcome), 1 raises. Result: 4
ContractVerification objects.
Integration task carries
source_context["contract_verifications"]with those 4 dicts (Codex P2 preservation: even if the list were
empty, it round-trips intact).
Phase B at agent completion:
source_context["contract_verifications"]— 4 entries2 in-scope outcome(s)"
In the happy-path case (all 6 LLM calls succeed AND all 6 commands
pass at runtime), the agent's path is never consulted — completion
is accepted via contract.
Glossary
generate_verification_commandLLM call per in-scopeUserOutcome.UserOutcomeid,action,success_signal,scope). Extracted byoutcome_extractor.py.ContractVerificationsignal_id(UserOutcome.id) with the shellcommandMarcus runs.How to verify it works
Unit tests
Expected: all pass. Currently 21 + 4 + 33 = 58 tests in scope, all passing.
Production smoke
task's
source_context["contract_verifications"]outcome the LLM didn't decline
PRODUCT SMOKE GATE:followed by "All N contract verification(s) passed for task X"
"contract has incomplete coverage" WARNING, followed by the
existing Slice B agent-supplied flow
generator is — fallback frequency tells us how much bug: verification-command generator infers tech stack from prose, not the scaffold's actual dependency manifest #643's
scaffold-stack work is needed.
Test plan
on the integration task's source_context
"fall back to agent-supplied" with WARNING — never a silent
regression
Related
b8599a52(philosophy), thoughts77ade35a+a4219ac9(Kaia reviews)🤖 Generated with Claude Code