Document name-first write plan selectors
This commit is contained in:
@@ -770,7 +770,7 @@ METHODS = [
|
|||||||
{"name": "metadata.form.command_button.write", "transport": "POST /rpc", "description": "Plan/apply a form command workflow: optional BSL handler routine upsert plus form command and visible command button append. Recognizes CommonForm/top-level common forms and object-owned forms; prepares saved-state when needed. XML is analysis/learning input only, not the live adapter write transport."},
|
{"name": "metadata.form.command_button.write", "transport": "POST /rpc", "description": "Plan/apply a form command workflow: optional BSL handler routine upsert plus form command and visible command button append. Recognizes CommonForm/top-level common forms and object-owned forms; prepares saved-state when needed. XML is analysis/learning input only, not the live adapter write transport."},
|
||||||
{"name": "metadata.form.command_button.verify", "transport": "POST /rpc", "description": "Read-only verification for a saved-state form command workflow: command, visible button, embedded handler routine, command-handler link, and button-command link. Accepts the same public form selectors as metadata.form.command_button.write."},
|
{"name": "metadata.form.command_button.verify", "transport": "POST /rpc", "description": "Read-only verification for a saved-state form command workflow: command, visible button, embedded handler routine, command-handler link, and button-command link. Accepts the same public form selectors as metadata.form.command_button.write."},
|
||||||
{"name": "metadata.module.write_apply", "transport": "POST /rpc", "description": "Orchestrate saved-state BSL module stream writes from module_ref/table/file_name: plan, apply, or apply_and_rollback. Requires explicit saved-state write/apply gates."},
|
{"name": "metadata.module.write_apply", "transport": "POST /rpc", "description": "Orchestrate saved-state BSL module stream writes from module_ref/table/file_name: plan, apply, or apply_and_rollback. Requires explicit saved-state write/apply gates."},
|
||||||
{"name": "metadata.write.plan", "transport": "POST /rpc", "description": "Read-only metadata write planner. Resolves full 1C paths or concrete saved-state references, reports layer/provenance requirements, and never applies changes."},
|
{"name": "metadata.write.plan", "transport": "POST /rpc", "description": "Read-only name-first metadata write planner. For forms pass target.kind=form with extension/ref/form and element, command, or attribute plus edits; for modules reuse the public write_plan_target from metadata.saved_state.modules.search. The adapter resolves saved-state SQL handles internally, reports layer/provenance requirements, and never applies changes."},
|
||||||
{"name": "metadata.write.preflight", "transport": "POST /rpc", "description": "Read-only preflight for high-level writes. Combines metadata.write.plan with live saved-state verification and reports ready, needs_prepare, needs_resolution, or blocked before any write."},
|
{"name": "metadata.write.preflight", "transport": "POST /rpc", "description": "Read-only preflight for high-level writes. Combines metadata.write.plan with live saved-state verification and reports ready, needs_prepare, needs_resolution, or blocked before any write."},
|
||||||
{"name": "metadata.write.capabilities", "transport": "POST /rpc", "description": "Agent-facing matrix of what the adapter can read, plan, and write to the saved-state layer. SQL/storage details are hidden unless include_storage=true."},
|
{"name": "metadata.write.capabilities", "transport": "POST /rpc", "description": "Agent-facing matrix of what the adapter can read, plan, and write to the saved-state layer. SQL/storage details are hidden unless include_storage=true."},
|
||||||
{"name": "metadata.write", "transport": "POST /rpc", "description": "High-level metadata write orchestrator. Routes saved-state form, module, and scheduled-job schedule targets by public 1C names, builds reviewable proposals, and can apply with explicit saved-state SQL gates. Module writes support text, old/new, and routine_name/routine_text edits with expected_sha1/expected_text_sha1 guards."},
|
{"name": "metadata.write", "transport": "POST /rpc", "description": "High-level metadata write orchestrator. Routes saved-state form, module, and scheduled-job schedule targets by public 1C names, builds reviewable proposals, and can apply with explicit saved-state SQL gates. Module writes support text, old/new, and routine_name/routine_text edits with expected_sha1/expected_text_sha1 guards."},
|
||||||
@@ -1033,6 +1033,14 @@ METHOD_INPUT_SCHEMAS["metadata.write"] = {
|
|||||||
"area": {"type": "string", "enum": ["object", "form", "module", "schedule"]},
|
"area": {"type": "string", "enum": ["object", "form", "module", "schedule"]},
|
||||||
"ref": {"type": "string", "description": "Public 1C object/member ref."},
|
"ref": {"type": "string", "description": "Public 1C object/member ref."},
|
||||||
"canonical_path": {"type": "string", "description": "Public 1C code or metadata path."},
|
"canonical_path": {"type": "string", "description": "Public 1C code or metadata path."},
|
||||||
|
"extension": {"type": "string", "description": "Public extension name for an extension-owned form or module."},
|
||||||
|
"form": {"type": "string", "description": "Exact 1C form name."},
|
||||||
|
"element": {"type": "string", "description": "Exact 1C form element name."},
|
||||||
|
"command": {"type": "string", "description": "Exact 1C form command name."},
|
||||||
|
"attribute": {"type": "string", "description": "Exact 1C form attribute name."},
|
||||||
|
"module": {"type": "string", "description": "Public module role/name returned by saved-state module search."},
|
||||||
|
"qualified_name": {"type": "string", "description": "Public qualified form or module name returned by search."},
|
||||||
|
"stream_ordinal": {"type": "integer", "minimum": 1, "description": "Public 1-based stream ordinal returned by saved-state module search."},
|
||||||
"property": {"type": "string"},
|
"property": {"type": "string"},
|
||||||
"operation": {
|
"operation": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -1051,6 +1059,17 @@ METHOD_INPUT_SCHEMAS["metadata.write"] = {
|
|||||||
"extension": {"type": "string"},
|
"extension": {"type": "string"},
|
||||||
"property": {"type": "string"},
|
"property": {"type": "string"},
|
||||||
"value": {},
|
"value": {},
|
||||||
|
"edits": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["property", "value"],
|
||||||
|
"properties": {
|
||||||
|
"property": {"type": "string"},
|
||||||
|
"value": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"schedule": {"type": "object", "additionalProperties": True},
|
"schedule": {"type": "object", "additionalProperties": True},
|
||||||
"template_member_ref": {"type": "string"},
|
"template_member_ref": {"type": "string"},
|
||||||
"new_member_name": {"type": "string"},
|
"new_member_name": {"type": "string"},
|
||||||
@@ -1090,6 +1109,18 @@ METHOD_INPUT_SCHEMAS["metadata.write"] = {
|
|||||||
},
|
},
|
||||||
"mode": "plan",
|
"mode": "plan",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"base_id": "upo_test",
|
||||||
|
"target": {
|
||||||
|
"kind": "form",
|
||||||
|
"extension": "test2",
|
||||||
|
"ref": "Catalog.test2",
|
||||||
|
"form": "t_Форма",
|
||||||
|
"command": "ЗаменаДомена",
|
||||||
|
},
|
||||||
|
"edits": [{"property": "Заголовок", "value": "Замена домена"}],
|
||||||
|
"mode": "plan",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"base_id": "upo_test",
|
"base_id": "upo_test",
|
||||||
"target": {
|
"target": {
|
||||||
@@ -1101,6 +1132,78 @@ METHOD_INPUT_SCHEMAS["metadata.write"] = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
METHOD_INPUT_SCHEMAS["metadata.write.plan"] = {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["base_id", "target"],
|
||||||
|
"additionalProperties": True,
|
||||||
|
"properties": {
|
||||||
|
"base_id": {"type": "string", "description": "Adapter base identifier."},
|
||||||
|
"target": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["kind"],
|
||||||
|
"additionalProperties": True,
|
||||||
|
"description": "Prefer a public name-first selector; storage handles are optional follow-up values resolved internally from names.",
|
||||||
|
"properties": {
|
||||||
|
"kind": {"type": "string", "enum": ["form", "module", "metadata"]},
|
||||||
|
"ref": {"type": "string", "description": "Preferred public owner ref, for example Catalog.Номенклатура."},
|
||||||
|
"extension": {"type": "string", "description": "Public extension name."},
|
||||||
|
"form": {"type": "string", "description": "Exact 1C form name."},
|
||||||
|
"element": {"type": "string", "description": "Exact form element name."},
|
||||||
|
"command": {"type": "string", "description": "Exact form command name."},
|
||||||
|
"attribute": {"type": "string", "description": "Exact form attribute name."},
|
||||||
|
"module": {"type": "string", "description": "Public module role/name returned by metadata.saved_state.modules.search."},
|
||||||
|
"qualified_name": {"type": "string", "description": "Public qualified name returned by saved-state search."},
|
||||||
|
"stream_ordinal": {"type": "integer", "minimum": 1},
|
||||||
|
"canonical_path": {"type": "string", "description": "Full public 1C metadata/code path when one is already known."},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"edits": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Form property edits. Planning resolves the target but does not apply them.",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["property", "value"],
|
||||||
|
"properties": {
|
||||||
|
"property": {"type": "string", "description": "Public property presentation or canonical property name."},
|
||||||
|
"value": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"intent": {"type": "object", "additionalProperties": True, "description": "Module or metadata operation intent."},
|
||||||
|
"resolve_origin": {"type": "boolean", "description": "Resolve a canonical path origin when no saved-state selector is available."},
|
||||||
|
"timeout_seconds": {"type": "integer", "minimum": 1, "maximum": 300},
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
{
|
||||||
|
"base_id": "upo_test",
|
||||||
|
"target": {
|
||||||
|
"kind": "form",
|
||||||
|
"extension": "test2",
|
||||||
|
"ref": "Catalog.test2",
|
||||||
|
"form": "t_Форма",
|
||||||
|
"command": "ЗаменаДомена",
|
||||||
|
},
|
||||||
|
"edits": [{"property": "Заголовок", "value": "Замена домена"}],
|
||||||
|
"resolve_origin": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"base_id": "upo_test",
|
||||||
|
"target": {
|
||||||
|
"kind": "module",
|
||||||
|
"ref": "Catalog.Номенклатура",
|
||||||
|
"module": "Модуль менеджера",
|
||||||
|
"stream_ordinal": 1,
|
||||||
|
},
|
||||||
|
"intent": {
|
||||||
|
"operation": "replace_with_control",
|
||||||
|
"control_fragment": "Процедура Обновить()",
|
||||||
|
"new": "Процедура Обновить()\nКонецПроцедуры",
|
||||||
|
},
|
||||||
|
"resolve_origin": False,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
METHOD_INPUT_SCHEMAS["metadata.write.preflight"] = copy.deepcopy(METHOD_INPUT_SCHEMAS["metadata.write.plan"])
|
||||||
METHOD_INPUT_SCHEMAS["metadata.code_index.build"] = {
|
METHOD_INPUT_SCHEMAS["metadata.code_index.build"] = {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["base_id"],
|
"required": ["base_id"],
|
||||||
|
|||||||
@@ -21787,6 +21787,27 @@ def test_metadata_write_plan_reports_unresolved_public_form_selector(monkeypatch
|
|||||||
assert any(problem["code"] == "public_form_target_not_resolved" for problem in result["problems"])
|
assert any(problem["code"] == "public_form_target_not_resolved" for problem in result["problems"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_metadata_write_plan_help_describes_name_first_form_and_module_targets() -> None:
|
||||||
|
methods = {
|
||||||
|
row["name"]: row
|
||||||
|
for row in adapter_server.call_method("help.methods", {})["methods"]
|
||||||
|
}
|
||||||
|
|
||||||
|
for method_name in ("metadata.write.plan", "metadata.write.preflight"):
|
||||||
|
method = methods[method_name]
|
||||||
|
target_properties = method["input_schema"]["properties"]["target"]["properties"]
|
||||||
|
assert method["input_schema"]["required"] == ["base_id", "target"]
|
||||||
|
assert {"ref", "extension", "form", "element", "command", "attribute", "module", "qualified_name", "stream_ordinal"} <= set(target_properties)
|
||||||
|
assert method["input_schema"]["properties"]["edits"]["items"]["required"] == ["property", "value"]
|
||||||
|
examples = method["input_schema"]["examples"]
|
||||||
|
assert any((example.get("target") or {}).get("kind") == "form" and (example.get("target") or {}).get("ref") for example in examples)
|
||||||
|
assert any((example.get("target") or {}).get("kind") == "module" and (example.get("target") or {}).get("module") for example in examples)
|
||||||
|
|
||||||
|
description = methods["metadata.write.plan"]["description"]
|
||||||
|
assert "name-first" in description
|
||||||
|
assert "metadata.saved_state.modules.search" in description
|
||||||
|
|
||||||
|
|
||||||
def test_metadata_write_preflight_verifies_concrete_saved_state(monkeypatch: pytest.MonkeyPatch) -> None:
|
def test_metadata_write_preflight_verifies_concrete_saved_state(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
def fake_diff(payload: dict[str, Any]) -> dict[str, Any]:
|
def fake_diff(payload: dict[str, Any]) -> dict[str, Any]:
|
||||||
assert payload["module_ref"] == "ConfigCASSave:object-guid__module-guid.0#stream:4"
|
assert payload["module_ref"] == "ConfigCASSave:object-guid__module-guid.0#stream:4"
|
||||||
|
|||||||
Reference in New Issue
Block a user