scope gate: the scope
gate trims what the brief over-added; this gate elicits what the request
under-specified. Both share the same x-feedback → interrupt() → resume
machinery, so the frontend renders it with the existing universal panel — no FE
change.
What’s changed
- New detector —
worker/worker/orchestration/requirements_detector.py:detect_underspecification(raw_prompt, providers)runs one free-model JSON call and returns aRequirementsClarification(vague, candidateFeatureOptions withrecommendedflags,question,confidence). Lenient parse, fail-open. - New runner —
ClarifyRequirementsLevelRunnerinworker/worker/graph/scenarios/runners.py(kind=clarify_requirements). Builds a multi-selectx-feedbackschema (or a free-text ask when there are no candidate options), interrupts, and foldsstate["clarify_decision"] = {selected, text, options}. Interrupt-unavailable fallback accepts the recommended features. - Downstream consumption —
_clarify_directive(state)inworker/worker/graph/scenarios/prompts.py, injected into the L1 brief, L2 plan, and L4 executor prompts as the authoritative feature scope. The scope gate folds the confirmed features into the request it audits so they aren’t re-flagged as inflation. - Scenario —
knowledge-hub/scenarios/code_build.yaml:clarify_gateis now the first level (clarify_gate → l1_brief → scope_gate → l2_plan → …). NewLevelKindliteralclarify_requirementsinschemas.py. - Config / env —
WorkerConfig.clarify_requirements(defaultalways), parsed fromCEREBRUM_CLARIFY_REQUIREMENTS=always|auto|never.main.pystampsis_first_promptinto job metadata so the in-graph runner only asks on the first build.
Impact scope
- Default
always→ every first build of a project pauses once for confirmation.autoasks only when the detector judges the request vague;neverships the gate dark. Follow-up prompts never re-ask, in any mode — flip the env var with no logic redeploy. - Backwards-compatible: existing scenarios without a
clarify_requirementslevel are unaffected. Replays and non-interactive orchestrator runs force the gate tonever(it cannot answer an interrupt deterministically). - Frontend: no change — the universal feedback panel already renders multi-select
- free-text
x-feedback.
- free-text
Tests
tests/test_requirements_detector.py— detector JSON judge (vague vs specific, prose-wrapped, fail-open, option filtering).tests/test_clarify_gate.py—never/auto/alwaysbehavior, the first-prompt-only rule, feature fold, free-text fallback, recommended-fallback, replay dedup, the_clarify_directiveinjection, and config parsing.tests/test_scope_gate.py— confirmed features fold into the scope detector’s request (de-conflict).- Updated structural/replay/event/cancel expectations for the new first level
(
tests/test_scenarios.py,test_scenario_phase6.py,test_scenario_compiler.py,test_scenario_events.py,test_stop_cancel.py).
worker/.venv/bin/python -m pytest tests/ — 995 passed, 6 skipped (baseline
green; the 6 skips are pre-existing).