Добавить dogfood-манифест stage-loop

This commit is contained in:
dctouch 2026-05-09 13:34:56 +03:00
parent de1aa3d17c
commit 913745380f
5 changed files with 193 additions and 1 deletions

View File

@ -0,0 +1,100 @@
{
"schema_version": "domain_scenario_pack_v1",
"pack_id": "agentic_semantic_development_loop_stage_pack",
"domain": "agentic_semantic_development_loop_control",
"title": "Agentic semantic development loop control pack",
"description": "Compact stage pack for dogfooding the agentic development loop against business-overview, VAT, stale-scope, and legacy-canary questions.",
"analysis_context": {
"as_of_date": "2026-05-09",
"source": "agentic_semantic_development_loop_stage_pack"
},
"bindings": {
"main_organization": "ООО Альтернатива Плюс",
"control_year": "2020",
"svk_counterparty": "Группа СВК"
},
"scenarios": [
{
"scenario_id": "agentic_loop_business_overview_control",
"title": "Business overview and stale-scope control",
"description": "Checks direct business-answer shape, period carryover, all-time reset, VAT boundary, and organization scope hygiene.",
"steps": [
{
"step_id": "step_01_business_overview",
"title": "Business overview for explicit period",
"question": "Дай взрослый бизнес-обзор {{bindings.main_organization}} за {{bindings.control_year}} год по данным 1С: обороты, входящие и исходящие деньги, нетто, НДС, долги, склад, клиенты, поставщики и что пока нельзя утверждать.",
"expected_intents": ["business_overview"],
"required_answer_shape": "direct_answer_first",
"forbidden_answer_patterns": [
"(?i)capability_id",
"(?i)selected_chain_id",
"(?i)runtime_",
"(?i)business_overview_route_template_v1"
]
},
{
"step_id": "step_02_money_followup",
"title": "Money follow-up",
"question": "Раскрой деньги подробнее: сколько получили, сколько заплатили, какой чистый денежный поток, кто главный клиент и главный поставщик в {{bindings.control_year}}.",
"depends_on": ["step_01_business_overview"],
"required_answer_shape": "direct_answer_first"
},
{
"step_id": "step_03_best_year_all_time",
"title": "All-time best operating-flow year",
"question": "А если смотреть за все доступное время, какой самый доходный год по подтвержденным оборотам и почему? Не называй это бухгалтерской прибылью, если чистой прибыли нет.",
"depends_on": ["step_02_money_followup"],
"required_answer_shape": "direct_answer_first"
},
{
"step_id": "step_04_vat_explicit_period",
"title": "VAT explicit period",
"question": "Что с НДС за {{bindings.control_year}} год по {{bindings.main_organization}}: какая позиция видна, на чем она основана и чего не хватает для налогового вывода?",
"depends_on": ["step_03_best_year_all_time"],
"required_answer_shape": "direct_answer_first"
},
{
"step_id": "step_05_all_time_no_vat_carryover",
"title": "All-time reset without stale VAT carryover",
"question": "Теперь за все доступное время дай обзор компании в целом, но не тащи НДС за {{bindings.control_year}} как подтвержденную общую налоговую позицию.",
"depends_on": ["step_04_vat_explicit_period"],
"required_answer_shape": "direct_answer_first"
}
]
},
{
"scenario_id": "agentic_loop_counterparty_pivot_control",
"title": "Counterparty pivot and legacy canaries",
"description": "Checks explicit counterparty arbitration after organization context and keeps technical/debug details out of the final answer.",
"steps": [
{
"step_id": "step_01_svk_money",
"title": "Explicit counterparty money flow",
"question": "Теперь отдельно по контрагенту {{bindings.svk_counterparty}}: сколько денег прошло, что входящее, что исходящее и есть ли документы или движения, на которых это основано?",
"expected_intents": ["value_flow"],
"required_answer_shape": "direct_answer_first",
"forbidden_answer_patterns": [
"(?i)capability_id",
"(?i)selected_chain_id",
"(?i)runtime_",
"(?i)mcp_discovery"
]
},
{
"step_id": "step_02_svk_documents",
"title": "Counterparty documents follow-up",
"question": "Покажи документы по этой цепочке и не смешивай {{bindings.svk_counterparty}} с организацией {{bindings.main_organization}}.",
"depends_on": ["step_01_svk_money"],
"required_answer_shape": "direct_answer_first"
},
{
"step_id": "step_03_final_summary",
"title": "Final executive summary",
"question": "Собери короткий итог: что мы подтвердили по компании, что отдельно по {{bindings.svk_counterparty}}, какие выводы можно делать и какие нельзя.",
"depends_on": ["step_01_svk_money", "step_02_svk_documents"],
"required_answer_shape": "direct_answer_first"
}
]
}
]
}

View File

@ -145,7 +145,7 @@ It stores the GUI review under `artifacts/domain_runs/stage_agent_loops/<stage_i
Use `python scripts/stage_agent_loop.py status --manifest docs/orchestration/<stage_loop>.json` as the cheap read-only checkpoint before continuing a stage. It prints the current next action, closing gate, latest GUI run, latest repair coder status, and latest repair validation status without modifying artifacts. Use `python scripts/stage_agent_loop.py status --manifest docs/orchestration/<stage_loop>.json` as the cheap read-only checkpoint before continuing a stage. It prints the current next action, closing gate, latest GUI run, latest repair coder status, and latest repair validation status without modifying artifacts.
Use `python scripts/stage_agent_loop.py continue --manifest docs/orchestration/<stage_loop>.json` as the safe one-command continuation layer. It can prepare a repair iteration and materialize `run-repair --dry-run` automatically; it will not run the real coder pass unless `--execute-repair` is passed, and it waits for a `--run-id assistant-stage1-<id>` when the next required step is post-repair rerun/ingest validation. Use `python scripts/stage_agent_loop.py continue --manifest docs/orchestration/<stage_loop>.json` as the safe one-command continuation layer. From a cold start it materializes `domain_pack_loop.command.txt` without launching the long live loop; after a GUI review it can prepare a repair iteration and materialize `run-repair --dry-run` automatically; it will not run the real coder pass unless `--execute-repair` is passed, and it waits for a `--run-id assistant-stage1-<id>` when the next required step is post-repair rerun/ingest validation.
It also writes `stage_repair_handoff.md/json` next to the stage summary. That handoff is the preferred input for the next coder pass: it lists primary repair targets and sample user-facing failures without forcing the coder to reread the entire GUI conversation first. It also writes `stage_repair_handoff.md/json` next to the stage summary. That handoff is the preferred input for the next coder pass: it lists primary repair targets and sample user-facing failures without forcing the coder to reread the entire GUI conversation first.

View File

@ -0,0 +1,27 @@
{
"schema_version": "stage_agent_loop_manifest_v1",
"stage_id": "agentic_semantic_development_loop",
"module_name": "Agentic Semantic Development Loop",
"title": "Agentic semantic development loop dogfood gate",
"architecture_phase": "turnaround_11_agentic_semantic_development_loop",
"agent_focus": "Automate stage implementation, semantic replay review, repair handoff, coder pass, rerun validation, and final human confirmation.",
"current_stage_status": "active_dogfood",
"global_plan_refs": [
"docs/orchestration/domain_scenario_loop_repo_adapter.md",
"docs/ARCH/11 - architecture_turnaround/README.md",
"AGENTS.md codex_domain_loop and agent_semantic_runs"
],
"pack_manifest": "docs/orchestration/agentic_semantic_development_loop_stage_pack.json",
"loop_id": "agentic_semantic_development_loop",
"target_score": 88,
"max_iterations": 6,
"acceptance_invariants": [
"status command exposes next_action, repair state, validation state, and closing gate",
"continue command never runs the real coder pass without --execute-repair",
"patched repair cannot close the stage without successful rerun/ingest validation",
"business answers remain direct, context-aware, and free of internal route/debug ids",
"manual GUI confirmation remains required after accepted semantic replay"
],
"save_autorun_on_accept": true,
"manual_confirmation_required_after_accept": true
}

View File

@ -1265,6 +1265,32 @@ def handle_continue(args: argparse.Namespace) -> int:
), ),
} }
) )
elif next_action == "run_stage_loop_or_ingest_gui_run":
if getattr(args, "run_id", None):
ingest_summary = ingest_gui_run_review(args)
payload.update(
{
"performed_action": "ingest_gui_run_from_cold_start",
"ingest_summary": ingest_summary,
"next_action": ingest_summary.get("next_action"),
}
)
else:
write_json(stage_dir / "stage_manifest.json", stage_manifest)
write_text(stage_dir / "stage_manifest_source.txt", repo_relative(stage_manifest_path) + "\n")
command = build_domain_pack_loop_command(args, stage_manifest, stage_dir)
write_text(stage_dir / "domain_pack_loop.command.txt", " ".join(command) + "\n")
payload.update(
{
"performed_action": "materialize_stage_run_dry_run",
"domain_pack_loop_command": command,
"next_action": next_action,
"suggested_command": (
"python scripts/stage_agent_loop.py run "
"--manifest <stage_manifest.json>"
),
}
)
else: else:
payload.update( payload.update(
{ {

View File

@ -778,6 +778,45 @@ class StageAgentLoopTests(unittest.TestCase):
self.assertEqual(result["performed_action"], "wait_for_rerun_ingest") self.assertEqual(result["performed_action"], "wait_for_rerun_ingest")
self.assertEqual(result["next_action"], "rerun_same_stage_or_gui_and_ingest_result") self.assertEqual(result["next_action"], "rerun_same_stage_or_gui_and_ingest_result")
def test_handle_continue_materializes_stage_run_from_cold_start(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
manifest_path = root / "stage.json"
output_root = root / "stage_runs"
stage_dir = output_root / "agent_loop"
write_json(
manifest_path,
{
"stage_id": "agent_loop",
"module_name": "Agent Loop",
"title": "Agent Loop",
"pack_manifest": "docs/orchestration/demo_pack.json",
},
)
exit_code = stage_loop.handle_continue(
stage_args(
manifest=str(manifest_path),
output_root=str(output_root),
handoff=None,
iteration_id=None,
plan=None,
coder_schema=str(root / "coder.schema.json"),
execute_repair=False,
run_id=None,
session_file=None,
sessions_dir=str(root / "sessions"),
reports_dir=str(root / "reports"),
review_output_dir=None,
)
)
result = json.loads((stage_dir / "stage_continue_result.json").read_text(encoding="utf-8"))
command_text = (stage_dir / "domain_pack_loop.command.txt").read_text(encoding="utf-8")
self.assertEqual(exit_code, 0)
self.assertEqual(result["performed_action"], "materialize_stage_run_dry_run")
self.assertIn("run-pack-loop", command_text)
def test_resolve_stage_repair_iteration_auto_prepares_from_handoff(self) -> None: def test_resolve_stage_repair_iteration_auto_prepares_from_handoff(self) -> None:
with tempfile.TemporaryDirectory() as tmp: with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp) root = Path(tmp)