ARCH: сделать catalog drilldown отдельным user-facing metadata шагом

This commit is contained in:
dctouch 2026-04-23 10:53:50 +03:00
parent 8fc90ae65f
commit 0d3b33578e
4 changed files with 120 additions and 0 deletions

View File

@ -0,0 +1,63 @@
{
"schema_version": "domain_truth_harness_spec_v1",
"scenario_id": "address_truth_harness_phase42_catalog_metadata_drilldown",
"domain": "address_phase42_catalog_metadata_drilldown",
"title": "Phase 42 catalog metadata drilldown replay",
"description": "Targeted AGENT replay for the new Big Block E seam where a catalog-oriented metadata surface should continue on a neutral follow-up into a deeper catalog metadata probe instead of collapsing back into generic metadata or asking for an unrelated lane choice.",
"bindings": {},
"steps": [
{
"step_id": "step_01_catalog_metadata_surface",
"title": "Catalog-oriented metadata surface is surfaced honestly for counterparties",
"question": "какие справочники 1С есть по контрагентам?",
"allowed_reply_types": [
"partial_coverage",
"factual_with_explanation"
],
"required_answer_patterns_all": [
"(?i)metadata|метадан",
"(?i)справоч|catalog|directory",
"(?i)контрагент"
],
"forbidden_answer_patterns": [
"(?i)получили",
"(?i)заплатили",
"(?i)нетто",
"(?i)документные строки найдены",
"(?i)строки денежных движений найдены"
],
"criticality": "critical",
"semantic_tags": [
"catalog_metadata_surface",
"counterparty_catalog_scope"
]
},
{
"step_id": "step_02_neutral_followup_catalog_drilldown",
"title": "Neutral follow-up continues into deeper catalog metadata instead of asking for a documents-vs-movements lane choice",
"question": "давай дальше",
"allowed_reply_types": [
"partial_coverage",
"factual_with_explanation"
],
"required_answer_patterns_all": [
"(?i)metadata|метадан|схем",
"(?i)справоч|catalog|directory",
"(?i)контрагент|counterpart"
],
"forbidden_answer_patterns": [
"(?i)документ",
"(?i)движени|регистр",
"(?i)уточн.*контур",
"(?i)получили",
"(?i)заплатили",
"(?i)нетто"
],
"criticality": "critical",
"semantic_tags": [
"catalog_drilldown",
"neutral_followup"
]
}
]
}

View File

@ -84,6 +84,12 @@ function isMovementPilot(pilot) {
function isMetadataPilot(pilot) {
return pilot.pilot_scope === "metadata_inspection_v1";
}
function isCatalogDrilldownPilot(pilot) {
return (isMetadataPilot(pilot) &&
(pilot.reason_codes.includes("planner_selected_catalog_drilldown_from_confirmed_metadata_surface_ref") ||
pilot.dry_run.reason_codes.includes("planner_selected_catalog_drilldown_from_confirmed_metadata_surface_ref") ||
pilot.reason_codes.includes("pilot_catalog_drilldown_metadata_scope_seeded_from_surface_ref")));
}
function isEntityResolutionPilot(pilot) {
return pilot.pilot_scope === "entity_resolution_search_v1";
}
@ -267,6 +273,9 @@ function headlineFor(mode, pilot) {
if (isMovementPilot(pilot) && mode === "confirmed_with_bounded_inference") {
return `По движениям${documentOrMovementScopeRu(pilot)} в 1С найдены подтвержденные строки; ответ ограничен проверенным окном и найденными строками.`;
}
if (isCatalogDrilldownPilot(pilot) && mode === "confirmed_with_bounded_inference") {
return "По метаданным 1С удалось углубиться в контур справочников и связанных объектов; это уже не общий обзор схемы, а следующий безопасный catalog drilldown.";
}
if (pilot.derived_metadata_surface && mode === "confirmed_with_bounded_inference") {
if (pilot.derived_metadata_surface.ambiguity_detected) {
return "По метаданным 1С найдены конкурирующие schema-поверхности; перед следующим шагом нужно удержать неоднозначность явно.";

View File

@ -123,6 +123,15 @@ function isMetadataPilot(pilot: AssistantMcpDiscoveryPilotExecutionContract): bo
return pilot.pilot_scope === "metadata_inspection_v1";
}
function isCatalogDrilldownPilot(pilot: AssistantMcpDiscoveryPilotExecutionContract): boolean {
return (
isMetadataPilot(pilot) &&
(pilot.reason_codes.includes("planner_selected_catalog_drilldown_from_confirmed_metadata_surface_ref") ||
pilot.dry_run.reason_codes.includes("planner_selected_catalog_drilldown_from_confirmed_metadata_surface_ref") ||
pilot.reason_codes.includes("pilot_catalog_drilldown_metadata_scope_seeded_from_surface_ref"))
);
}
function isEntityResolutionPilot(pilot: AssistantMcpDiscoveryPilotExecutionContract): boolean {
return pilot.pilot_scope === "entity_resolution_search_v1";
}
@ -353,6 +362,9 @@ function headlineFor(mode: AssistantMcpDiscoveryAnswerMode, pilot: AssistantMcpD
if (isMovementPilot(pilot) && mode === "confirmed_with_bounded_inference") {
return `По движениям${documentOrMovementScopeRu(pilot)} в 1С найдены подтвержденные строки; ответ ограничен проверенным окном и найденными строками.`;
}
if (isCatalogDrilldownPilot(pilot) && mode === "confirmed_with_bounded_inference") {
return "По метаданным 1С удалось углубиться в контур справочников и связанных объектов; это уже не общий обзор схемы, а следующий безопасный catalog drilldown.";
}
if (pilot.derived_metadata_surface && mode === "confirmed_with_bounded_inference") {
if (pilot.derived_metadata_surface.ambiguity_detected) {
return "По метаданным 1С найдены конкурирующие schema-поверхности; перед следующим шагом нужно удержать неоднозначность явно.";

View File

@ -486,6 +486,42 @@ describe("assistant MCP discovery answer adapter", () => {
expect(draft.must_not_claim).toContain("Do not present the inferred next checked lane as already executed data retrieval.");
});
it("uses a distinct human headline for catalog drilldown instead of repeating a generic metadata overview", async () => {
const planner = planAssistantMcpDiscovery({
metadataSurface: {
selected_entity_set: "Catalog",
selected_surface_objects: ["Catalog.Counterparties"],
downstream_route_family: "catalog_drilldown",
route_family_selection_basis: "selected_entity_set",
recommended_next_primitive: "drilldown_related_objects",
ambiguity_detected: false,
ambiguity_entity_sets: []
},
turnMeaning: {
asked_domain_family: "metadata",
asked_action_family: "inspect_catalog",
unsupported_but_understood_family: "schema_surface"
}
});
const pilot = await executeAssistantMcpDiscoveryPilot(
planner,
buildMetadataDeps([
{
FullName: "Catalog.Counterparties",
MetaType: "Catalog",
attributes: [{ Name: "Description" }]
}
])
);
const draft = buildAssistantMcpDiscoveryAnswerDraft(pilot);
expect(draft.answer_mode).toBe("confirmed_with_bounded_inference");
expect(draft.headline).toContain("углубиться");
expect(draft.headline).toContain("справочников");
expect(draft.headline).toContain("catalog drilldown");
});
it("keeps metadata answer honest when schema surface stays ambiguous", async () => {
const planner = planAssistantMcpDiscovery({
turnMeaning: {