Compose name-first form write plans

This commit is contained in:
2026-07-26 17:30:04 +03:00
parent c1d5d06f6d
commit 39c8c4ab18
6 changed files with 603 additions and 10 deletions
+236
View File
@@ -3129,6 +3129,67 @@ def test_saved_state_forms_search_default_is_name_first(monkeypatch: pytest.Monk
assert storage_marker not in str(result)
def test_saved_state_forms_search_infers_public_extension_name_without_filter(monkeypatch: pytest.MonkeyPatch) -> None:
extension_guid = "fb26cf42-7609-11f1-828f-005056b0d483"
file_name = f"{extension_guid}__form-guid.0"
monkeypatch.setattr(
adapter_server,
"extension_map_by_guid",
lambda base_id: {extension_guid: {"guid": extension_guid, "name": "test2"}},
)
monkeypatch.setattr(
adapter_server,
"storage_files_list",
lambda payload: {"status": "ok", "files": [{"FileName": file_name}]},
)
monkeypatch.setattr(
adapter_server,
"saved_state_form_search_row",
lambda **kwargs: {
"table": "ConfigCASSave",
"file_name": file_name,
"name": "t_Форма",
"owner": {"status": "resolved", "kind": "Catalog", "name": "test2"},
"form": {"name": "t_Форма"},
"source": {"table": "ConfigCASSave", "file_name": file_name},
"matches": [
{
"name": "ЗаменаДомена",
"section": "commands",
"writable_properties": [
{
"property": "title",
"presentation": "Заголовок",
"value": "Замена домена",
"value_type": "string",
}
],
}
],
},
)
result = adapter_server.metadata_saved_state_forms_search(
{
"base_id": "upo_test",
"tables": ["ConfigCASSave"],
"limit": 1,
}
)
form = result["forms"][0]
assert form["selector"]["extension"] == "test2"
assert form["matches"][0]["selector"] == {
"extension": "test2",
"ref": "Catalog.test2",
"form": "t_Форма",
"qualified_name": "test2.t_Форма",
"command": "ЗаменаДомена",
}
assert extension_guid not in str(result)
assert "ConfigCASSave" not in str(result["forms"])
def test_saved_state_form_search_resolves_owner_for_internal_name_first_write(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(
adapter_server,
@@ -14015,6 +14076,87 @@ def test_mcp_selector_chain_smoke_uses_generic_placeholders() -> None:
assert concrete_value not in examples_json
def test_mcp_selector_chain_selects_name_first_form_write_plan_candidate() -> None:
candidate = mcp_selector_chain_smoke.first_public_form_write_plan_candidate(
{
"forms": [
{
"selector": {
"extension": "test2",
"ref": "Catalog.test2",
"form": "t_Форма",
},
"matches": [
{
"selector": {
"extension": "test2",
"ref": "Catalog.test2",
"form": "t_Форма",
"command": "ЗаменаДомена",
},
"writable_properties": [
{
"property": "name",
"presentation": "Имя",
"value": "ЗаменаДомена",
"value_type": "string",
},
{
"property": "title",
"presentation": "Заголовок",
"value": "Замена домена",
"value_type": "string",
},
],
}
],
}
]
}
)
assert candidate == {
"target": {
"kind": "form",
"extension": "test2",
"ref": "Catalog.test2",
"form": "t_Форма",
"command": "ЗаменаДомена",
},
"edit": {
"property": "Заголовок",
"value": "Замена домена [NAME-FIRST PLAN]",
},
}
assert not any(key in candidate["target"] for key in ("table", "file_name", "guid", "form_guid"))
def test_mcp_selector_chain_form_composition_strict_check() -> None:
missing = mcp_selector_chain_smoke.live_form_write_plan_composition_required_issue(
{
"form_write_plan_composition": {
"attempted": True,
"status": "skipped_no_public_form_target",
"composed": False,
"name_first": False,
}
}
)
ready = mcp_selector_chain_smoke.live_form_write_plan_composition_required_issue(
{
"form_write_plan_composition": {
"attempted": True,
"status": "planned",
"composed": True,
"name_first": True,
}
}
)
assert missing["code"] == "live_form_write_plan_composition_required"
assert ready is None
def test_mcp_selector_chain_smoke_rejects_concrete_selector_values() -> None:
issues = mcp_selector_chain_smoke.validate_chain(
{
@@ -21551,6 +21693,100 @@ def test_metadata_write_plan_resolves_public_module_selector_internally(monkeypa
assert hint["payload"]["expected_sha1"] == "saved-payload-sha1"
def test_metadata_write_plan_resolves_public_form_selector_internally(monkeypatch: pytest.MonkeyPatch) -> None:
seen: dict[str, Any] = {}
def fake_resolve(payload: dict[str, Any]) -> dict[str, Any]:
seen.update(payload)
return {
"schema": "onec_form_write_target_resolution.v1",
"status": "ok",
"source": {
"kind": "live_sql",
"table": "ConfigCASSave",
"file_name": "extension-guid__form-guid.0",
},
"counts": {"matches": 1},
}
monkeypatch.setattr(adapter_server, "metadata_form_write_target_resolve", fake_resolve)
result = adapter_server.metadata_write_plan(
{
"base_id": "upo_test",
"target": {
"kind": "form",
"extension": "test2",
"ref": "Catalog.test2",
"form": "t_Форма",
"command": "ЗаменаДомена",
},
"edits": [{"property": "Заголовок", "value": "Новое имя"}],
"resolve_origin": False,
}
)
assert seen["table"] == "ConfigCASSave"
assert seen["ref"] == "Catalog.test2"
assert seen["form"] == "t_Форма"
assert seen["command"] == "ЗаменаДомена"
assert seen["property"] == "Заголовок"
assert seen["value"] == "Новое имя"
assert seen["include_storage"] is True
assert result["allowed"] is True
assert result["status"] == "planned"
assert result["route"]["name_resolution"] == {
"status": "resolved",
"method": "metadata.form.write_target.resolve",
"selector": {
"extension": "test2",
"ref": "Catalog.test2",
"form": "t_Форма",
"command": "ЗаменаДомена",
},
"counts": {"matches": 1},
}
hint = result["route"]["apply_payload_hint"]
assert hint["ready_for_apply_method"] is True
assert hint["payload"]["table"] == "ConfigCASSave"
assert hint["payload"]["file_name"] == "extension-guid__form-guid.0"
assert hint["payload"]["ref"] == "Catalog.test2"
assert hint["payload"]["form"] == "t_Форма"
assert hint["payload"]["command"] == "ЗаменаДомена"
assert hint["payload"]["edits"] == [{"property": "Заголовок", "value": "Новое имя"}]
def test_metadata_write_plan_reports_unresolved_public_form_selector(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(
adapter_server,
"metadata_form_write_target_resolve",
lambda payload: {
"schema": "onec_form_write_target_resolution.v1",
"status": "not_found",
"counts": {"matches": 0},
},
)
result = adapter_server.metadata_write_plan(
{
"base_id": "upo_test",
"target": {
"kind": "form",
"ref": "Catalog.Контрагенты",
"form": "ФормаЭлемента",
"element": "КнопкаЗаписать",
},
"edits": [{"property": "Заголовок", "value": "Записать"}],
"resolve_origin": False,
}
)
assert result["allowed"] is False
assert result["status"] == "needs_origin"
assert result["route"]["name_resolution"]["status"] == "not_found"
assert any(problem["code"] == "public_form_target_not_resolved" for problem in result["problems"])
def test_metadata_write_preflight_verifies_concrete_saved_state(monkeypatch: pytest.MonkeyPatch) -> None:
def fake_diff(payload: dict[str, Any]) -> dict[str, Any]:
assert payload["module_ref"] == "ConfigCASSave:object-guid__module-guid.0#stream:4"