Архитектура: стабилизировать organization authority после late company switch и закрыть phase16 multi-company replay

This commit is contained in:
2026-04-19 15:31:50 +03:00
parent 6e6f94b08c
commit af15e21bf6
25 changed files with 1063 additions and 36 deletions
@@ -499,6 +499,13 @@ Still open after the accepted phase12 replay:
- keeping that contract in one helper reduces another major chance that future domain expansion introduces contradictory exact-route vs deep-fallback precedence in nearby branches;
- targeted route/continuity/transition suites remain green after the move, including direct regression coverage that an exact VAT route must stay in the address lane even when only a semantic deep hint is present;
- a fresh live rerun of `address_truth_harness_phase12_wider_saved_session_pool` on `2026-04-19` remains accepted `20/20`, which is the proof that the flagship mixed contour still survives after extracting the route-protection seam.
- the next replay-breadth and continuity-authority pass now closes a non-flagship late-switch seam that was still dangerous before multi-domain expansion:
- `assistantOrganizationScopeRuntimeAdapter` now prefers continuity-backed selected/active organization over stale address navigation scope after a late chat-side company switch, so a fresh company fixation in living-chat can no longer be silently overwritten by the previous address snapshot on the very next exact-data turn;
- `mergeFollowupContextWithOrganizationScopeRuntime(...)` now treats active session organization as the stronger authority over stale `previous_filters.organization` / `root_filters.organization`, which closes the last hot-path drift where follow-up carryover could rehydrate the old company even after the user had already switched contours;
- this matters because the system previously looked “almost fixed” on flagship chains while still failing a real multi-company late-pivot path: `Alternative Plus -> switch to RAYM in chat -> referential inventory/receivables follow-up -> switch back`;
- targeted `assistantOrganizationScopeRuntimeAdapter`, `assistantContinuityPolicy`, `assistantRoutePolicy`, and referential-organization regressions are green after the owner-precedence fix, and backend build stays green;
- the phase16 live replay `address_truth_harness_phase16_multicompany_late_pivot` is now accepted on `2026-04-19`, which is the first explicit proof that a non-flagship multi-company late switch keeps truthful company authority across both inventory and receivables exact routes in the same saved session;
- the same phase16 pass also hardened replay-gate honesty: its receivables step now accepts semantically equivalent honest empty-match phrasing (`31.03.2020` or `31 марта 2020`, `долг` / `долж`) instead of overfitting to one single first-line wording, so this pack is now a trustworthy breadth gate rather than a fragile phrasing oracle.
## Next Execution Slice (2026-04-18)
@@ -0,0 +1,246 @@
{
"schema_version": "domain_truth_harness_spec_v1",
"scenario_id": "address_truth_harness_phase16_multicompany_late_pivot",
"domain": "address_phase16_multicompany_late_pivot",
"title": "Phase 16 multi-company late-pivot replay for breadth beyond the flagship path",
"description": "Alternative AGENT replay focused on a non-flagship saved-session contour: proactive scope offer, explicit company selection, late company switch, human capability-meta interrupt, return to exact business questions, same-date carryover inside the second company, and a final switch back to the first company. The scenario validates that organization authority survives real session pivots instead of being proven only on one flagship trajectory.",
"bindings": {},
"steps": [
{
"step_id": "step_01_smalltalk_scope_offer",
"title": "Smalltalk entry proactively offers organization scope",
"question": "приветик, как дела?",
"required_answer_patterns_all": [
"(?i)привет|норм|дела",
"(?i)организац|компан|альтернатива плюс|лайсвуд|райм"
],
"forbidden_answer_patterns": [
"(?i)mcp",
"(?i)tool_gate_reason",
"(?i)living_reason",
"(?i)snapshot_items"
],
"criticality": "critical",
"semantic_tags": [
"smalltalk_entry",
"scope_offer"
]
},
{
"step_id": "step_02_choose_alternative_plus",
"title": "Explicitly select Alternative Plus as the first active organization",
"question": "Альтернатива Плюс",
"required_answer_patterns_all": [
"(?i)зафиксир|рабочую организац|работаем по",
"(?i)альтернатива плюс"
],
"criticality": "critical",
"semantic_tags": [
"organization_authority",
"company_selected"
]
},
{
"step_id": "step_03_inventory_today_alt",
"title": "Inventory root uses the first selected organization",
"question": "что у нас сейчас на складе по остаткам?",
"allowed_reply_types": [
"factual",
"partial_coverage"
],
"expected_intents": [
"inventory_on_hand_as_of_date"
],
"required_filters": {
"as_of_date": "{{runtime.today_iso}}",
"organization": "ООО Альтернатива Плюс"
},
"required_direct_answer_patterns_any": [
"(?i)остат|на складе",
"{{runtime.today_dot_regex}}"
],
"criticality": "critical",
"semantic_tags": [
"inventory_root",
"company_authority"
]
},
{
"step_id": "step_04_switch_to_raym",
"title": "Late company switch changes the active organization instead of asking again from scratch",
"question": "теперь давай по РАЙМ",
"required_answer_patterns_all": [
"(?i)зафиксир|переключ|работаем по|активн",
"(?i)райм"
],
"forbidden_answer_patterns": [
"(?i)mcp",
"(?i)read_only",
"(?i)не могу определить"
],
"criticality": "critical",
"semantic_tags": [
"late_company_switch",
"organization_authority"
]
},
{
"step_id": "step_05_inventory_today_raym",
"title": "Inventory root after the late switch uses RAYM instead of the old company",
"question": "а по этой компании что сейчас на складе?",
"allowed_reply_types": [
"factual",
"partial_coverage"
],
"expected_intents": [
"inventory_on_hand_as_of_date"
],
"required_filters": {
"as_of_date": "{{runtime.today_iso}}",
"organization": "РАЙМ"
},
"required_direct_answer_patterns_any": [
"(?i)остат|на складе",
"{{runtime.today_dot_regex}}"
],
"forbidden_direct_answer_patterns": [
"(?i)уточните организацию",
"(?i)по какой компании"
],
"criticality": "critical",
"semantic_tags": [
"inventory_root",
"late_company_switch"
]
},
{
"step_id": "step_06_capability_meta_after_switch",
"title": "Capability-meta interrupt stays human and does not tear down the second company context",
"question": "а что ты вообще умеешь?",
"allowed_reply_types": [
"factual",
"factual_with_explanation"
],
"required_answer_patterns_any": [
"(?i)могу|умею",
"(?i)ндс|документ|контрагент|склад|остат|долг"
],
"forbidden_answer_patterns": [
"(?i)mcp",
"(?i)read_only",
"(?i)snapshot",
"(?i)assistant_state",
"(?i)tool_gate_reason"
],
"criticality": "important",
"semantic_tags": [
"capability_meta",
"meta_interrupt"
]
},
{
"step_id": "step_07_receivables_march_2020_raym",
"title": "Return to business contour after the meta interrupt keeps RAYM as the active company",
"question": "а по этой компании кто нам должен на март 2020?",
"allowed_reply_types": [
"factual",
"partial_coverage"
],
"expected_intents": [
"receivables_confirmed_as_of_date"
],
"required_filters": {
"as_of_date": "2020-03-31",
"period_from": "2020-03-01",
"period_to": "2020-03-31",
"organization": "РАЙМ"
},
"required_direct_answer_patterns_any": [
"(?i)долг|долж",
"(?:31\\.03\\.2020|31\\s+марта\\s+2020)"
],
"forbidden_direct_answer_patterns": [
"(?i)уточните организацию",
"(?i)по какой компании"
],
"criticality": "critical",
"semantic_tags": [
"receivables_root",
"meta_return_to_business"
]
},
{
"step_id": "step_08_same_date_inventory_raym",
"title": "Same-date inventory follow-up keeps the second company and the restored date",
"question": "а по этой же дате остатки на складе?",
"allowed_reply_types": [
"factual",
"partial_coverage"
],
"expected_intents": [
"inventory_on_hand_as_of_date"
],
"required_filters": {
"as_of_date": "2020-03-31",
"period_from": "2020-03-01",
"period_to": "2020-03-31",
"organization": "РАЙМ"
},
"required_direct_answer_patterns_any": [
"(?i)остат|на складе",
"31\\.03\\.2020"
],
"forbidden_direct_answer_patterns": [
"(?i)уточните организацию",
"(?i)по какой компании"
],
"criticality": "critical",
"semantic_tags": [
"same_date_pivot",
"inventory_root",
"second_company_continuity"
]
},
{
"step_id": "step_09_switch_back_to_alt",
"title": "Switch back to Alternative Plus late in the same session",
"question": "ок, верни обратно Альтернативу Плюс",
"required_answer_patterns_all": [
"(?i)зафиксир|переключ|работаем по|активн",
"(?i)альтернатива плюс"
],
"criticality": "important",
"semantic_tags": [
"late_company_switch_back",
"organization_authority"
]
},
{
"step_id": "step_10_activity_age_after_switch_back",
"title": "Activity-age analytics still work after two company pivots in one session",
"question": "а по Альтернативе Плюс сколько лет активности в базе 1С?",
"allowed_reply_types": [
"factual",
"factual_with_explanation",
"partial_coverage"
],
"expected_intents": [
"counterparty_activity_lifecycle"
],
"required_direct_answer_patterns_any": [
"(?i)активност",
"(?i)первая подтвержденная|последняя подтвержденная|лет"
],
"forbidden_direct_answer_patterns": [
"(?i)не найден контрагент",
"(?i)уточните организацию",
"(?i)по какой компании"
],
"criticality": "critical",
"semantic_tags": [
"activity_age",
"switch_back_integrity"
]
}
]
}