АРЧ АП11 - Commit title: Добавить контрактный слой переходов и capability-деклараций ассистента

This commit is contained in:
2026-04-15 22:53:57 +03:00
parent 8056bdfaf2
commit 93ad18daa3
30 changed files with 4175 additions and 13 deletions
@@ -0,0 +1,256 @@
# 01 - Project Architecture Baseline Map
## Purpose
This note is the compact execution-oriented map of the current project.
It is not a market review and not a historical report. It answers:
- what the main subsystems are;
- where the assistant runtime really starts and ends;
- what already acts as architecture, not as incidental code;
- where the main structural debt sits.
## System Map
### 1. 1C Acquisition And Probe Layer
Main areas:
- `odata_probe/`
- `scripts/*` probe and verification scripts
Role:
- verify read-only access viability;
- inspect published 1C entity sets and links;
- produce source-level readiness for higher layers.
This is a prerequisite layer, not the assistant runtime itself.
### 2. Canonical And Analytical Data Layer
Main areas:
- `canonical_layer/`
- `data/`
- `logs/`
Current runtime entry:
- [canonical_layer/app.py](/x:/1C/NDC_1C/canonical_layer/app.py:1)
Role:
- expose normalized read-only data services;
- refresh and maintain the canonical store;
- run feature engine;
- run risk engine.
This layer is the project's data foundation.
### 3. LLM Backend And Assistant Runtime
Main area:
- `llm_normalizer/backend/`
Current server entry:
- [server.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/server.ts:1)
Role:
- provider gateway;
- normalizer runtime;
- assistant runtime;
- eval runtime;
- autorun runtime;
- session persistence.
This is the architectural center of the interactive product.
### 4. Domain Orchestration And Acceptance Loop
Main areas:
- `.codex/`
- `docs/orchestration/active_domain_contract.json`
- `artifacts/domain_runs/`
Role:
- define the current active domain pack;
- execute scenario-based hardening;
- store machine-readable before/after artifacts;
- turn user runs into acceptance and repair targets.
This is a first-class quality contour, not auxiliary documentation.
### 5. Experimental Routing / Benchmark Contour
Main area:
- `router/`
Role:
- route-selection experiments;
- store-sufficiency heuristics;
- benchmark and validation support via Python scripts.
Important:
- this contour is not the current source of truth for the production assistant runtime;
- current production routing lives in the TypeScript assistant stack.
## Assistant Runtime Map
The assistant runtime currently has these working layers:
1. `provider/model gateway`
2. `living router`
3. `address orchestration runtime`
4. `exact execution lane`
5. `coverage / evidence / grounding`
6. `answer policy / packaging / debug`
7. `session memory / navigation state`
### Provider / Model Gateway
Current main entry:
- [openaiResponsesClient.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/openaiResponsesClient.ts:1)
Current shape:
- pragmatic two-mode provider layer: `openai` and `local`
This layer is functional, but future-fragile if hybrid execution semantics grow.
### Living Router
Current main entry:
- [assistantService.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantService.ts:4248)
Current top-level modes:
- `address_data`
- `assistant_data_scope`
- `chat`
This is where the system decides which runtime contour gets control.
### Address Orchestration Runtime
Current main entry:
- [assistantAddressOrchestrationRuntimeAdapter.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantAddressOrchestrationRuntimeAdapter.ts:1)
Current responsibilities:
- predecompose;
- effective message normalization;
- carryover resolution;
- rewrite protection;
- continuation contract assembly;
- address runtime metadata.
### Exact Execution Lane
Current main areas:
- [addressQueryService.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/addressQueryService.ts:1)
- [addressIntentResolver.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/addressIntentResolver.ts:1)
- [addressFilterExtractor.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/addressFilterExtractor.ts:1)
- [addressRecipeCatalog.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/addressRecipeCatalog.ts:1)
- [decomposeStage.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/address_runtime/decomposeStage.ts:1325)
- [composeStage.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/address_runtime/composeStage.ts:1)
This lane already acts as a real exact-data runtime, not as generic chat assistance.
### Coverage / Evidence / Grounding
Current main areas:
- [assistantCoverageGrounding.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantCoverageGrounding.ts:1)
- [assistantClaimBoundEvidence.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantClaimBoundEvidence.ts:1)
- [assistantDataLayer.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantDataLayer.ts:1)
This layer already exists in code, even if it has not yet been named strongly enough in architecture docs.
### Answer Policy / Packaging / Debug
Current main areas:
- [answerComposer.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/answerComposer.ts:1)
- [assistantAnswerPackageBuilder.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantAnswerPackageBuilder.ts:1)
- [assistantDebugPayloadAssembler.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantDebugPayloadAssembler.ts:1)
This layer should own answer shape, not truth determination.
### Session Memory / Navigation State
Current main areas:
- [assistantSessionStore.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantSessionStore.ts:1)
- [addressNavigationState.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/addressNavigationState.ts:329)
- [investigationState.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/investigationState.ts:1)
This layer is one of the strongest parts of the architecture today.
## First-Class Runtime Artifacts Already Present
The following should be treated as first-class architectural artifacts, not helper byproducts:
- `dialogContinuationContractV2`
- `result_set`
- `focus_object`
- `date_scope`
- `organization_scope`
- `coverage report`
- `grounding check`
- `evidence bundle`
- `scenario manifest`
- `scenario state`
- `baseline_turn / rerun_turn artifacts`
## Structural Debt
The main structural debt is concentrated in oversized modules with mixed responsibilities:
- `assistantService.ts`
- `composeStage.ts`
- `answerComposer.ts`
- `addressQueryService.ts`
- `assistantDataLayer.ts`
This indicates the following problem:
- the system already has the right layers;
- but too many of those layers are still implemented as tightly coupled code inside a few large files.
## Baseline Constraints
Any architectural turnaround must preserve:
- `AddressQueryService` as exact lane;
- structured navigation state;
- continuation contract semantics;
- selected-object continuity;
- limited-mode truthfulness;
- scenario-based acceptance.
## Baseline Diagnosis
The project is not missing architecture.
The project already has architecture, but it is still expressed too much through:
- god services;
- implicit workflow;
- heuristic branching;
- mixed policy/state/answer concerns.
That is the baseline condition that the rest of this package is designed to address.
@@ -0,0 +1,393 @@
# 02 - State And Transition Contracts
## Purpose
This document defines the objects that must become explicit in project design:
1. `state objects`
2. `transition classes`
The goal is to stop treating the assistant as a prompt-driven flow with ad hoc carryover and start treating it as a stateful runtime with explicit transitions.
## State Model
### 1. Assistant Session Aggregate
Top-level first-class runtime state:
`assistant_session_state`
It must aggregate:
- `living_mode_state`
- `address_navigation_state`
- `investigation_state`
- `clarification_state`
- `answer_context_state`
- `coverage_gate_state`
This aggregate is the architectural owner of cross-turn continuity.
### 2. Living Mode State
Purpose:
- remember which major runtime contour is active.
Fields:
- `living_mode`
- `mode_reason`
- `mode_source`
- `mode_entry_turn_id`
Allowed values:
- `address_data`
- `assistant_data_scope`
- `chat`
- `meta_followup`
- `clarification`
### 3. Root Frame State
Purpose:
- represent the currently active root business slice.
Fields:
- `domain_id`
- `root_route_id`
- `organization_scope`
- `date_scope`
- `root_result_set_id`
- `root_answer_object_ref`
- `frame_status`
This state survives more transitions than object state.
### 4. Selected Object Frame State
Purpose:
- represent the currently active drilldown object.
Fields:
- `focus_object_ref`
- `focus_object_kind`
- `source_result_set_id`
- `compatible_route_family`
- `provenance_bundle_ref`
- `temporal_ceiling`
- `frame_status`
This state may only survive compatible object-level transitions.
### 5. Meta Frame State
Purpose:
- support questions about the already returned answer without replaying exact execution blindly.
Fields:
- `source_answer_object_ref`
- `meta_question_kind`
- `source_gate_status`
- `meta_truth_mode`
Allowed meta classes:
- `evaluation`
- `comparison`
- `memory_recap`
- `boundary_explanation`
- `answer_interpretation`
### 6. Clarification State
Purpose:
- represent unfinished business queries that are waiting for missing anchors or disambiguation.
Fields:
- `clarification_kind`
- `missing_anchors`
- `candidate_scopes`
- `resume_target_route`
- `resume_target_frame`
### 7. Coverage Gate State
Purpose:
- capture whether the exact execution result is admissible for full, partial, or blocked downstream behavior.
Fields:
- `coverage_status`
- `evidence_grade`
- `grounding_status`
- `truth_mode`
- `carryover_eligibility`
- `reason_codes`
Allowed values:
- `coverage_status`: `full`, `partial`, `blocked`
- `truth_mode`: `confirmed`, `limited`, `clarification_required`, `unsupported`
- `carryover_eligibility`: `full`, `root_only`, `object_only`, `meta_only`, `none`
## Transition Model
The architecture must distinguish transition classes explicitly.
### T1. Root Query Entry
Trigger:
- new root business question
Inputs:
- raw user query
- living mode state
Outputs:
- new `root_frame_state`
- new `coverage_gate_state`
Must not:
- inherit stale `focus_object`
### T2. Root Follow-Up With Date Or Scope Change
Trigger:
- `а на март 2020`
- `на тот же период`
- `еще раз по этой дате`
Inputs:
- existing `root_frame_state`
- compatible temporal or organization shift
Outputs:
- updated `root_frame_state`
- new exact route execution
Must preserve:
- root domain
- organization scope if not explicitly changed
Must not:
- downgrade into `unknown` if supported root route exists
### T3. Explicit Selected Object Drilldown
Trigger:
- item selected from current result set
- UI selected-object wording
- full explicit object mention
Inputs:
- active `root_frame_state`
- selected object reference
Outputs:
- `selected_object_frame_state`
Must preserve:
- source result set
- compatible temporal ceiling
### T4. Short Action Follow-Up On Selected Object
Trigger:
- `кто поставщик`
- `где купили`
- `кому продали`
- `какие документы`
Inputs:
- active `selected_object_frame_state`
- compatible action request
Outputs:
- exact item-level capability route
Must not:
- fall into generic chat
- fall into data-scope selection
- lose selected object because the wording is short
### T5. Pronoun Or Compressed Object Follow-Up
Trigger:
- `по ней`
- `по этой позиции`
- `а эта кому ушла`
Inputs:
- active `selected_object_frame_state`
- prior compatible object route
Outputs:
- continued object drilldown
Must not:
- degrade full object anchor into vague semantic noise
### T6. Domain Pivot With Root-Only Carryover
Trigger:
- user leaves the current object drilldown but remains in compatible higher business scope
Inputs:
- `root_frame_state`
- incompatible `selected_object_frame_state`
Outputs:
- preserved root context
- dropped object context
Must preserve:
- organization/date root scope
Must not:
- replay object route into another domain
### T7. Clarification Continuation
Trigger:
- user resolves missing anchor or ambiguity
Inputs:
- active `clarification_state`
Outputs:
- resumed target route
- cleared or updated clarification state
Must not:
- forget the suspended target route
### T8. Meta Follow-Up Over Answer Object
Trigger:
- `это много или мало`
- `это мы должны или нам`
- `что из этого важнее`
Inputs:
- `answer_context_state`
- `coverage_gate_state`
Outputs:
- meta answer
Must not:
- blindly replay exact route
### T9. Memory Recap
Trigger:
- `мы это обсуждали?`
- `помнишь, о чем говорили`
Inputs:
- prior grounded answer context
Outputs:
- truthful recap
Must not:
- invent conversation memory
### T10. Unsupported Or Blocked Boundary
Trigger:
- unsupported route
- blocked evidence gate
- execution failure
Inputs:
- exact runtime outcome
- `coverage_gate_state`
Outputs:
- bounded truthful answer or clarification
Must not:
- masquerade blocked execution as confirmed factual answer
## Transition Invariants
Every transition must declare:
- `entry condition`
- `required prior state`
- `allowed carryover depth`
- `state mutations`
- `forbidden carryover`
- `expected answer mode`
## Required Artifacts
Any future implementation of these contracts should produce:
- transition table or registry;
- state schema definitions;
- transition tests;
- scenario acceptance coverage by transition class.
## Done Criteria
This document is only considered implemented in architecture when:
- every major follow-up case maps to a named transition class;
- every transition class has a declared state owner;
- every transition class has a scenario-based regression family;
- no critical follow-up behavior depends only on unnamed heuristic carryover.
@@ -0,0 +1,253 @@
# 03 - Capability Contract Specification
## Purpose
This document defines what every runtime capability must declare in order to participate safely in the assistant architecture.
The system should stop treating capabilities as partially implicit products of:
- intent detection;
- filter extraction;
- recipe selection;
- wording heuristics.
Instead, each capability must be a first-class contract object.
## Capability Contract Object
Each capability must declare the following fields.
### 1. Identity
- `capability_id`
- `domain_id`
- `runtime_lane`
- `intent_ids`
Purpose:
- stable identification;
- relation between capability, domain and route family.
### 2. Entry Semantics
- `entry_modes`
- `supported_transition_classes`
- `frame_compatibility`
Minimum allowed values:
- `root_entry`
- `root_followup`
- `selected_object_drilldown`
- `meta_reuse`
- `clarification_resume`
Purpose:
- define where the capability may legally be entered from.
### 3. Anchor Contract
- `required_anchors`
- `optional_anchors`
- `anchor_source_priority`
- `anchor_admissibility_rules`
Purpose:
- make anchor requirements explicit;
- prevent garbage anchor extraction from being treated as business input.
### 4. Scope Contract
- `organization_scope_behavior`
- `date_scope_behavior`
- `temporal_ceiling_policy`
- `root_context_compatibility`
Purpose:
- define whether the capability reuses, narrows, widens, or rejects prior scope.
### 5. Selected-Object Contract
- `requires_focus_object`
- `accepted_focus_object_kinds`
- `focus_object_override_policy`
- `bundle_reuse_policy`
Purpose:
- define whether the capability depends on an existing selected object;
- define how object continuity is preserved.
### 6. Execution Contract
- `resolver_owner`
- `recipe_owner`
- `execution_adapter`
- `result_shape`
- `answer_object_shape`
Purpose:
- clearly identify the exact runtime owner of execution and output form.
### 7. Truth Gate Contract
- `minimum_evidence_policy`
- `coverage_gate_behavior`
- `truth_mode_fallbacks`
- `blocked_reason_codes`
Purpose:
- declare what counts as sufficient evidence for this capability;
- prevent answer policy from inventing truth semantics later.
### 8. Clarification Contract
- `clarification_triggers`
- `clarification_questions`
- `resume_policy`
Purpose:
- define when the capability must ask, not guess.
### 9. Failure Contract
- `empty_match_behavior`
- `route_expectation_failure_behavior`
- `execution_error_behavior`
Purpose:
- keep failures truthful and stable.
### 10. Acceptance Contract
- `required_unit_tests`
- `required_transition_tests`
- `required_scenario_families`
Purpose:
- make capability completion measurable.
## Minimal Contract Template
Each capability should be designable in the following shape:
```yaml
capability_id: inventory_purchase_provenance_for_item
domain_id: inventory_stock
runtime_lane: address_exact
intent_ids:
- inventory_purchase_provenance_for_item
entry_modes:
- selected_object_drilldown
- clarification_resume
supported_transition_classes:
- T3
- T4
- T5
frame_compatibility:
root_frame: required
selected_object_frame: required
required_anchors:
- item
optional_anchors:
- organization
- date_scope
anchor_admissibility_rules:
- no_low_quality_item_rewrite
- no_conversational_noise_as_entity
organization_scope_behavior: reuse_or_clarify
date_scope_behavior: respect_root_temporal_ceiling
temporal_ceiling_policy: must_not_expand_beyond_root_without_reason_code
requires_focus_object: true
accepted_focus_object_kinds:
- inventory_item
bundle_reuse_policy: provenance_bundle_preferred
minimum_evidence_policy: route_specific_threshold
coverage_gate_behavior: partial_or_blocked_if_evidence_insufficient
empty_match_behavior: truthful_empty_match
required_scenario_families:
- canonical
- colloquial
- ui_selected_object
- short_action_followup
- pronoun_followup
```
## Contract Rules
### Rule 1. Capability Must Declare Entry Legality
No capability may be entered only because a heuristic guessed it.
It must declare:
- which transition classes are legal;
- which frames are required;
- which frames are incompatible.
### Rule 2. Capability Must Declare Admissible Anchors
No capability may silently accept low-quality business anchors.
It must declare:
- what entity values are required;
- what counts as an admissible extracted value;
- when clarification is mandatory.
### Rule 3. Capability Must Declare Truth Gate Behavior
No capability may leave truth semantics to answer wording.
It must declare:
- what evidence threshold it needs;
- how it behaves under partial evidence;
- when it becomes blocked.
### Rule 4. Capability Must Declare Selected-Object Compatibility
All selected-object actions must explicitly declare:
- whether they require focus object;
- whether they reuse a bundle from prior steps;
- whether they tolerate short follow-up wording.
### Rule 5. Capability Must Declare Scenario Coverage
A capability is not accepted just because canonical wording works.
At minimum it must declare which of the following wording families are required:
- `canonical`
- `colloquial`
- `ui_selected_object`
- `ui_selected_object_colloquial`
- `short_action_followup`
- `pronoun_followup`
- `followup_date_carryover`
## What This Specification Replaces
This specification is designed to reduce architectural pressure on:
- `assistantService`
- hidden carryover logic
- implicit capability semantics in answer shaping
## Done Criteria
This specification is considered operational only when:
- critical capabilities are represented as explicit contract objects;
- contract fields are sufficient to predict allowed entry, required anchors, truth behavior, and scenario acceptance;
- new capability enablement can be reviewed primarily through contract review and tests, not only by reading large service files.
@@ -0,0 +1,196 @@
# 04 - Coverage Evidence Truth Gate
## Purpose
This document defines the missing architectural layer between:
- `exact execution lane`
and
- `answer policy / packaging`
This layer must exist as a first-class object because the system already needs to answer questions such as:
- do we have enough evidence;
- is the result full, partial, or blocked;
- may this result power follow-up carryover;
- is limited mode required;
- can the assistant speak as confirmed truth or only as bounded evidence.
## Architectural Position
The target runtime stack should be read as:
1. route and transition policy
2. exact execution lane
3. `coverage / evidence / truth gate`
4. answer policy
5. packaging and debug
Answer policy must not own the truth gate.
## Current Code Owners
The gate already exists in code in fragmented form:
- [assistantCoverageGrounding.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantCoverageGrounding.ts:1)
- [assistantClaimBoundEvidence.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantClaimBoundEvidence.ts:1)
- [assistantDataLayer.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantDataLayer.ts:622)
- [addressQueryService.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/addressQueryService.ts:2806)
- [answerComposer.ts](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/answerComposer.ts:22)
The architectural problem is not absence, but insufficient naming and isolation.
## Gate Inputs
The gate should consume:
- exact runtime result
- normalized retrieval result
- evidence items
- candidate evidence items
- coverage report
- route expectation outcome
- current frame state
- requested truth mode
## Gate Outputs
The gate should produce:
- `coverage_status`
- `grounding_status`
- `truth_mode`
- `carryover_eligibility`
- `reason_codes`
- `evidence_grade`
- `blocked_or_limited_explanation`
These outputs must be machine-readable.
## Status Classes
### 1. `full_confirmed`
Meaning:
- coverage is sufficient;
- evidence is admissible;
- route expectation passed;
- answer may speak in confirmed mode.
### 2. `partial_supported`
Meaning:
- some evidence exists;
- some requirements remain uncovered or weakly covered;
- answer must remain bounded and explicit about limitations.
### 3. `blocked_missing_anchor`
Meaning:
- exact execution cannot safely complete because required anchors are unresolved.
### 4. `blocked_route_expectation_failure`
Meaning:
- route was attempted, but the route contract itself did not pass baseline expectations.
### 5. `blocked_execution_error`
Meaning:
- system failure or execution failure prevents reliable business answer.
### 6. `limited_temporal_or_contextual`
Meaning:
- the system can say something useful, but only within a narrow and explicit evidence window.
## Carryover Eligibility Contract
The gate must also determine follow-up eligibility.
Allowed values:
- `full`
- `root_only`
- `object_only`
- `meta_only`
- `none`
Examples:
- `full_confirmed` result from root stock snapshot may often allow `full` or `root_only`
- selected-object provenance with weak buyer evidence may allow `object_only` or `meta_only`
- blocked route expectation should usually allow `none`
## Truth Rules
### Rule 1. Answer Policy May Downgrade, But Not Upgrade
Answer policy may choose a clearer wording.
Answer policy may not:
- turn blocked into confirmed;
- turn partial into full;
- suppress critical truth reason codes.
### Rule 2. Limited Mode Must Remain Truthful
If evidence is insufficient, limited mode must be explicit about:
- what is confirmed;
- what is not confirmed;
- why the system is limited.
### Rule 3. Carryover Must Respect The Gate
Follow-up policy may not assume that every previous answer is equally reusable.
Carryover must obey:
- gate-produced eligibility;
- evidence window;
- blocked or limited reason codes.
### Rule 4. Route Expectation Failure Is A Truth Event
If route expectation fails, this is not just a technical footnote.
It is a first-class truth gate outcome.
## Required Gate Artifacts
Every gated answer should be traceable through these artifacts:
- `evidence_bundle`
- `coverage_contract`
- `grounding_check`
- `truth_mode`
- `carryover_eligibility`
- `reason_codes`
## Non-Goals
This gate is not responsible for:
- model wording style;
- cosmetic answer formatting;
- provider selection;
- UI packaging details.
## Done Criteria
This layer is considered architecturally established only when:
- it is documented as separate from answer policy;
- its outputs are explicit inputs to answer shaping;
- carryover policy depends on gate output rather than hidden heuristics;
- scenario acceptance can fail specifically on gate behavior, not only on final wording.
@@ -0,0 +1,213 @@
# 05 - AssistantService Extraction Map
## Purpose
This document maps the current architectural overload of `assistantService.ts` and identifies what should stop living there over time.
The goal is not to empty the file arbitrarily.
The goal is to turn it from a god-service into a thinner coordinator.
## Current Situation
`assistantService.ts` is currently the largest and most overloaded module in the assistant runtime.
Approximate size:
- `6243` lines
It currently mixes concerns from:
- living route selection;
- follow-up carryover;
- continuation contracts;
- mode boundaries;
- meta-followup logic;
- memory recap detection;
- provider-aware predecompose orchestration;
- chat/data-scope/address boundary policy.
## Extraction Principle
`assistantService` should remain the top-level coordinator.
It should stop being the main owner of:
- policy logic;
- transition semantics;
- boundary semantics;
- meta semantics.
## Extraction Targets
### 1. Living Route Policy
Current owner:
- `resolveAssistantOrchestrationDecision()`
Current location:
- [assistantService.ts:4248](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantService.ts:4248)
Target owner:
- `assistantRoutePolicyRuntimeAdapter`
Expected artifact:
- explicit living-route decision contract
Done when:
- route policy can be reviewed without reading the full coordinator;
- top-level mode decisions are data-driven or contract-driven enough to be testable as a separate unit.
### 2. Carryover And Transition Policy
Current owner:
- `resolveAddressFollowupCarryoverContext()`
- `buildAddressDialogContinuationContractV2()`
Current location:
- [assistantService.ts:2828](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantService.ts:2828)
- [assistantService.ts:3111](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantService.ts:3111)
Target owner:
- `assistantTransitionRuntimeAdapter`
- `assistantContinuationContractBuilder`
Expected artifact:
- explicit transition classes with state inputs and carryover depth
Done when:
- follow-up continuation is understood in terms of transitions, not just heuristic carryover.
### 3. Meta Follow-Up Policy
Current owner:
- meta and evaluative follow-up detection inside route decision logic
Target owner:
- `assistantMetaFollowupPolicy`
Expected artifact:
- meta question class registry
- legal source answer object types
Done when:
- meta questions no longer depend on implicit branches buried inside living route logic.
### 4. Data-Scope And Boundary Policy
Current owner:
- `assistant_data_scope_query_detected` branches
Current references:
- [assistantService.ts:3974](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantService.ts:3974)
- [assistantService.ts:4412](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantService.ts:4412)
- [assistantService.ts:6052](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantService.ts:6052)
Target owner:
- `assistantBoundaryPolicy`
Expected artifact:
- explicit boundary mode contract:
- `data_scope`
- `operational_boundary`
- `capability_contract`
- `non_domain_chat`
Done when:
- emotional or colloquial user messages cannot accidentally trigger data-scope selection through hidden shared logic.
### 5. Memory Recap Policy
Current owner:
- route decision + living chat cooperation
Related consumer:
- [assistantLivingChatRuntimeAdapter.ts:255](/x:/1C/NDC_1C/llm_normalizer/backend/src/services/assistantLivingChatRuntimeAdapter.ts:255)
Target owner:
- `assistantMemoryRecapPolicy`
Expected artifact:
- truthful recap contract over grounded prior answer objects
Done when:
- memory recap logic becomes a named subsystem with its own truth rules.
### 6. Provider-Aware Orchestration Glue
Current owner:
- coordinator-level logic that adapts to `openai` vs `local`
Target owner:
- `assistantProviderExecutionPolicy`
Expected artifact:
- provider/runtime compatibility layer for orchestration expectations
Done when:
- provider quirks no longer leak into business routing logic.
## What Should Stay In AssistantService
After extraction, `assistantService` should still own:
- high-level request coordination;
- dependency wiring;
- stage invocation order;
- final turn assembly and persistence orchestration.
It should not be removed as an architectural object.
It should become thinner.
## Proposed Extraction Order
1. extract route decision contract
2. extract transition/carryover policy
3. extract boundary/data-scope policy
4. extract meta and memory recap policy
5. isolate provider-aware orchestration glue
This order is chosen because route and transition pressure are currently the main source of runtime fragility.
## Non-Goals
- do not split the file mechanically just to reduce line count;
- do not create many tiny helpers with no architectural ownership;
- do not move exact execution logic out of its proper lane.
## Done Criteria
This extraction plan is complete only when:
- the remaining `assistantService` can be described as a coordinator;
- major policy categories have explicit owners outside `assistantService`;
- scenario regressions can point to policy subsystems instead of a single god-service.
@@ -0,0 +1,238 @@
# 06 - Phase Acceptance Matrix
## Purpose
This document turns the high-level turnaround direction into a phase-by-phase execution matrix.
Each phase must specify:
- `goal`
- `output artifacts`
- `done criteria`
- `non-goals`
- `acceptance signals`
## Phase 0. Shared Baseline
Goal:
- align the team on one architecture vocabulary and one baseline map.
Output artifacts:
- baseline note in `docs/ARCH/11 - unified_project_architecture_and_reference_update_plan_2026-04-15.md`
- this package under `docs/ARCH/11 - architecture_turnaround/`
Done when:
- project discussions use the same names for layers, state, transitions, truth gate, and capabilities;
- no major planning discussion treats the system as "just a chat with LLM".
Non-goals:
- code changes;
- capability rewrites.
Acceptance signals:
- planning references point to the package rather than ad hoc prose;
- new refactor proposals can be mapped to a package artifact.
## Phase 1. Formal Layer Separation
Goal:
- explicitly separate project subsystems and their sources of truth.
Output artifacts:
- updated architecture notes if needed;
- clear internal naming for:
- data foundation
- assistant runtime
- domain loop
- experimental router contour
Done when:
- production assistant routing is no longer confused with Python router experiments;
- `canonical_layer` and `llm_normalizer/backend` are treated as different subsystems in planning.
Non-goals:
- merging runtimes;
- changing domain behavior.
Acceptance signals:
- no architecture review uses the wrong contour as the current runtime source of truth.
## Phase 2. State And Transition Contracts
Goal:
- make state and transition classes explicit.
Output artifacts:
- state schema note
- transition class registry note
- transition-oriented tests or planning matrix
Done when:
- every critical follow-up path is described as a named transition class;
- root frame, selected object frame, meta frame, clarification state, and coverage gate state are explicit objects.
Non-goals:
- answer wording cleanup;
- adding new business capabilities.
Acceptance signals:
- critical scenario failures can be described as transition failures, not only as "assistant got confused";
- at least one major follow-up-heavy domain can be read through transition contracts alone.
## Phase 3. Capability Contracts
Goal:
- make capabilities explicit contract objects instead of half-implicit route behavior.
Output artifacts:
- capability contract schema
- pilot contract set for critical inventory capabilities
Done when:
- critical capabilities declare entry modes, anchors, scope policy, truth behavior, and scenario families;
- new capability review can happen via contract inspection.
Non-goals:
- low-code workflow migration;
- removing recipe catalog.
Acceptance signals:
- at least one selected-object capability and one root capability are represented as full contract specs.
## Phase 4. Coverage / Evidence / Truth Gate Isolation
Goal:
- separate truth determination from answer policy.
Output artifacts:
- gate contract
- reason-code taxonomy
- carryover-eligibility contract
Done when:
- answer layer no longer decides whether a result is full, partial, or blocked;
- truth mode and carryover eligibility are explicit gate outputs.
Non-goals:
- UI redesign;
- full answer package rewrite.
Acceptance signals:
- scenario regressions can fail specifically on gate semantics;
- limited mode honesty is measurable independently from wording quality.
## Phase 5. AssistantService Extraction
Goal:
- reduce `assistantService` from god-service to coordinator.
Output artifacts:
- extraction map
- named policy owners
- reduced coordinator responsibility map
Done when:
- route policy, transition policy, boundary policy, and meta policy have explicit owners outside the coordinator;
- `assistantService` retains orchestration ownership but not most raw policy logic.
Non-goals:
- file splitting for its own sake;
- replacing the coordinator with a monolithic new router.
Acceptance signals:
- scenario regressions can point to extracted policy owners;
- code review no longer requires reading most of `assistantService.ts` to understand one policy area.
## Phase 6. Provider / Runtime Axis Hardening
Goal:
- make provider/runtime behavior an explicit architectural concern.
Output artifacts:
- provider execution contract
- structured-output compatibility matrix
- local/openai execution semantics note
Done when:
- provider quirks no longer bleed into business routing policy;
- structured output, tool calling expectations, and fallback behavior are documented per provider mode.
Non-goals:
- adding many providers immediately;
- model benchmarking as primary objective.
Acceptance signals:
- changing provider mode does not silently change core business semantics without explicit compatibility review.
## Phase 7. Scenario Acceptance As Primary Gate
Goal:
- enforce scenario-tree acceptance as the refactoring completion standard.
Output artifacts:
- phase-specific acceptance matrix
- updated scenario packs and required wording families
Done when:
- no phase is considered complete based only on unit tests or prettier answers;
- critical paths, critical edges, and selected-object continuity remain mandatory acceptance criteria.
Non-goals:
- shrinking evaluation to smoke tests;
- accepting root-only success as domain completion.
Acceptance signals:
- `pack_state.final_status`
- scenario acceptance matrix
- no unresolved `P0`
- direct answer, temporal honesty, selected-object continuity, and truth gate invariants all pass.
## Cross-Phase Rule
A phase is not done when the code "looks cleaner".
A phase is done only when:
- the declared artifact exists;
- the responsible layer is explicit;
- acceptance signals are green.
@@ -0,0 +1,135 @@
# 07 - External Reference Appendix
## Purpose
This appendix keeps external references available without overloading the core planning documents.
It records:
- which pattern is borrowed;
- why it is relevant;
- what should not be copied literally.
## Dify
Sources:
- <https://github.com/langgenius/dify>
- <https://docs.dify.ai/versions/3-0-x/en/user-guide/workflow/key-concepts>
- <https://docs.dify.ai/en/use-dify/nodes/agent>
- <https://docs.dify.ai/en/use-dify/nodes/variable-assigner>
Borrow:
- explicit distinction between workflow and chatflow;
- named nodes for classifier, agent, answer, variable management;
- persistent conversation variables.
Do not borrow literally:
- low-code canvas as a direct replacement for exact 1C runtime logic.
## Open WebUI
Sources:
- <https://github.com/open-webui/open-webui>
- <https://docs.openwebui.com/features/extensibility/>
- <https://docs.openwebui.com/features/chat-conversations/rag/>
Borrow:
- layered extensibility model;
- clear distinction between in-process tools, external APIs, and separate heavy pipelines;
- input/output filter mindset.
Do not borrow literally:
- generic plugin-first shell as the main architecture for exact-data routing.
## Onyx
Sources:
- <https://github.com/onyx-dot-app/onyx>
- <https://docs.onyx.app/admins/actions/overview>
Borrow:
- platform view of chat, agents, actions, connectors;
- separation between indexed knowledge, actions, and chat experience.
Do not borrow literally:
- enterprise search architecture as a substitute for 1C exact route discipline.
## LibreChat
Sources:
- <https://github.com/danny-avila/LibreChat>
- <https://www.librechat.ai/docs/features/agents>
Borrow:
- explicit agent capability surface;
- tool exposure discipline;
- deferred tools concept.
Do not borrow literally:
- treat MCP/tool abundance as a substitute for domain-specific capability contracts.
## Vanna
Source:
- <https://github.com/vanna-ai/vanna>
Borrow:
- exact-data assistant framing;
- tool registry plus structured outputs;
- user-aware execution semantics.
Do not borrow literally:
- SQL assistant assumptions as the whole model for our multi-layer accounting runtime.
## DB-GPT
Source:
- <https://github.com/eosphoros-ai/DB-GPT>
Borrow:
- AI data assistant as platform-plus-domain-skill composition;
- workflows and skills as explicit architectural objects.
Do not borrow literally:
- broad platform scope at the expense of current bounded hardening goals.
## LangGraph
Source:
- <https://docs.langchain.com/oss/javascript/langgraph/durable-execution>
Borrow:
- durable execution mindset;
- checkpointing and deterministic replay;
- explicit state graph thinking.
Do not borrow literally:
- framework migration as an end in itself.
## Summary
The external references collectively support one conclusion:
- the project should move toward more explicit state, transition, and capability contracts;
- it should not dissolve its exact-data rails into a generic agent shell.
@@ -0,0 +1,70 @@
# 11 - Architecture Turnaround Package
## Purpose
This folder is the execution-oriented continuation of the baseline note:
- [11 - unified_project_architecture_and_reference_update_plan_2026-04-15.md](</x:/1C/NDC_1C/docs/ARCH/11 - unified_project_architecture_and_reference_update_plan_2026-04-15.md:1>)
That baseline note answers:
- what the project is today;
- where the main architectural fragility sits;
- what direction is safe.
This package answers the next question:
- how the team should design the architectural turnaround without breaking the current exact-data baseline.
## Package Contents
1. [01 - project_architecture_baseline_map.md](./01%20-%20project_architecture_baseline_map.md)
2. [02 - state_and_transition_contracts.md](./02%20-%20state_and_transition_contracts.md)
3. [03 - capability_contract_spec.md](./03%20-%20capability_contract_spec.md)
4. [04 - coverage_evidence_truth_gate.md](./04%20-%20coverage_evidence_truth_gate.md)
5. [05 - assistantService_extraction_map.md](./05%20-%20assistantService_extraction_map.md)
6. [06 - phase_acceptance_matrix.md](./06%20-%20phase_acceptance_matrix.md)
7. [07 - external_reference_appendix.md](./07%20-%20external_reference_appendix.md)
## Architectural Objects Of Planning
This package makes five objects explicit:
1. `state model`
2. `transition model`
3. `capability contract model`
4. `coverage / evidence / truth gate`
5. `assistantService extraction plan`
These are the objects that should now drive refactoring discussions.
## How To Use The Package
Read in this order:
1. baseline note in `docs/ARCH/11 - unified_project_architecture_and_reference_update_plan_2026-04-15.md`
2. `01 - project_architecture_baseline_map.md`
3. `02 - state_and_transition_contracts.md`
4. `03 - capability_contract_spec.md`
5. `04 - coverage_evidence_truth_gate.md`
6. `05 - assistantService_extraction_map.md`
7. `06 - phase_acceptance_matrix.md`
8. `07 - external_reference_appendix.md`
## Planning Rules
- Do not treat this package as a rewrite plan.
- Do not dissolve `AddressQueryService` into generic chat logic.
- Do not move state back into transcript-only memory.
- Do not let answer wording substitute for policy/runtime fixes.
- Use scenario-based acceptance as the primary gate for all phases.
## Expected Outcome
When this package is fully operational, the project should stop being described as:
- "a big custom assistant service with many heuristics"
and start being described as:
- "a stateful exact-data assistant with explicit transition contracts and isolated truth gating."
@@ -0,0 +1,992 @@
# 11 - Unified Project Architecture And Reference Update Plan 2026-04-15
## 1. Назначение документа
Этот документ фиксирует единый архитектурный срез проекта `NDC_1C` на `2026-04-15` и связывает:
- текущее фактическое устройство репозитория;
- текущее устройство assistant runtime;
- уже существующие архитектурные ограничения и сильные стороны;
- внешний reference landscape из open-source LLM-проектов;
- безопасный план обновления подхода без разрушения рабочего baseline.
Связанный execution-oriented пакет planning artifacts:
- [11 - architecture_turnaround](</x:/1C/NDC_1C/docs/ARCH/11 - architecture_turnaround/README.md:1>)
Документ нужен не для исторического обзора, а как единая опорная карта:
- что в проекте уже является устойчивым фундаментом;
- что является техническим и архитектурным долгом;
- где проект типовой по классу систем;
- где проект уже имеет осмысленную кастомную специализацию;
- как переходить от heuristic-heavy hardening к более устойчивой архитектурной форме.
Этот документ дополняет, а не заменяет:
- `docs/ARCH/10 - current_assistant_architecture_2026-04-15.md`
- `docs/ARCH/10A - current_assistant_hardening_plan_2026-04-15.md`
- `graphify-out/GRAPH_REPORT.md`
## 2. Executive Summary
На текущем этапе `NDC_1C` уже не является "просто чат-приложением с LLM".
Фактически проект состоит из нескольких самостоятельных архитектурных контуров:
1. `1C/OData acquisition + canonical layer`
2. `feature/risk engines over canonical store`
3. `LLM normalizer + assistant runtime`
4. `domain orchestration / scenario loop / eval artifacts`
5. `research and benchmark contour` вокруг Python `router/`
Главный вывод по результатам локального анализа и сравнения с open-source references:
- по классу продукта проект действительно типовой: это `LLM + tools/data + state + UI/API`;
- по реализации текущий runtime у нас уже существенно более специализирован, чем обычный generic chat shell;
- основная проблема проекта не в отсутствии "правильной идеи", а в том, что слишком много системной политики собрано вручную внутри нескольких очень больших модулей;
- мы уже имеем сильные архитектурные элементы, которые нельзя терять;
- правильный следующий шаг это не rewrite в сторону "универсального суперагента", а переход к более явной workflow/state-oriented форме поверх уже существующих exact-capability rails.
Короткая формула:
`проект типовой по классу`
но
`архитектурно перегружен ручной orchestration-логикой`
и потому
`нуждается не в изобретении новых возможностей, а в упорядочивании существующих слоев`.
## 3. Источники для этого среза
### 3.1 Локальные источники
- `graphify-out/GRAPH_REPORT.md`
- `README.md`
- `canonical_layer/app.py`
- `llm_normalizer/backend/src/server.ts`
- `llm_normalizer/backend/src/services/*`
- `docs/orchestration/active_domain_contract.json`
- `.codex/` и `artifacts/domain_runs/*`
### 3.2 Внешние reference sources
- Dify: <https://github.com/langgenius/dify>
- Dify docs, key concepts: <https://docs.dify.ai/versions/3-0-x/en/user-guide/workflow/key-concepts>
- Dify docs, agent node: <https://docs.dify.ai/en/use-dify/nodes/agent>
- Dify docs, variable assigner: <https://docs.dify.ai/en/use-dify/nodes/variable-assigner>
- Open WebUI: <https://github.com/open-webui/open-webui>
- Open WebUI docs, extensibility: <https://docs.openwebui.com/features/extensibility/>
- Open WebUI docs, RAG: <https://docs.openwebui.com/features/chat-conversations/rag/>
- Onyx: <https://github.com/onyx-dot-app/onyx>
- Onyx docs, actions overview: <https://docs.onyx.app/admins/actions/overview>
- LibreChat: <https://github.com/danny-avila/LibreChat>
- LibreChat docs, agents: <https://www.librechat.ai/docs/features/agents>
- Vanna: <https://github.com/vanna-ai/vanna>
- DB-GPT: <https://github.com/eosphoros-ai/DB-GPT>
- LangGraph docs, durable execution: <https://docs.langchain.com/oss/javascript/langgraph/durable-execution>
## 4. Текущая карта проекта целиком
### 4.1 Верхнеуровневые контуры репозитория
Текущий репозиторий содержит не один сервис, а несколько связанных слоев:
- `odata_probe/`
- слой исследования и проверки read-only доступа к 1C OData;
- `canonical_layer/`
- Python/FastAPI слой над канонической моделью и хранилищем;
- `llm_normalizer/backend/`
- TypeScript/Express runtime для LLM normalizer, assistant, eval и autoruns;
- `router/`
- Python policy/benchmark контур для route selection и sufficiency checks;
- `orchestration/`
- служебный orchestration runtime для batch/use-case loops;
- `docs/orchestration/active_domain_contract.json`
- single mutable source для текущего активного domain/scenario pack;
- `.codex/`
- project-scoped loop/orchestration навыки и роли;
- `artifacts/domain_runs/`
- машинно-читаемые артефакты сценарных прогонов и hardening loop;
- `graphify-out/`
- knowledge graph и архитектурный срез кодовой базы.
### 4.2 Ключевой смысл этой композиции
Проект уже организован как многоступенчатая AI/data система:
1. сначала добываются и нормализуются read-only данные 1C;
2. затем они кладутся в канонический слой и feature/risk engines;
3. затем поверх них строится exact-data assistant runtime;
4. затем этот runtime проверяется domain scenarios, evaluation и artifacts;
5. отдельно существует research/policy contour, который не является главным runtime.
Это важно: обсуждая архитектуру, нельзя сводить проект только к `llm_normalizer/backend`.
## 5. Слой 1: 1C acquisition и canonical layer
### 5.1 Что это такое
Базовый контур проекта по-прежнему rooted в read-only интеграции с 1C.
Это видно уже из top-level README:
- `odata_probe/` собирает и проверяет доступность entity sets и link semantics;
- `canonical_layer/` строит каноническую модель поверх 1C данных;
- проект принципиально read-only по policy.
### 5.2 Текущая реализация
`canonical_layer/app.py` поднимает FastAPI-приложение:
- `CanonicalService`
- `RefreshService`
- `FeatureService`
- `RiskService`
Доступные API-поверхности включают:
- `GET /documents`
- `GET /postings`
- `GET /graph/document/{document_id}`
- `POST /refresh/run`
- `POST /features/run`
- `POST /risk/run`
То есть canonical layer уже не ограничивается "просто прокси к 1C", а включает:
- data access API;
- refresh pipeline;
- feature engine;
- risk engine.
### 5.3 Архитектурная роль
Этот слой это не accessory для ассистента, а нижний data foundation проекта.
Именно он отвечает за:
- устойчивый read-only доступ;
- канонизацию сущностей;
- промежуточное локальное store-представление;
- data services, которые могут использоваться не только LLM-слоем.
По классу архитектуры это типичный `data platform substrate` для AI assistant products.
## 6. Слой 2: LLM normalizer backend
### 6.1 Входная точка
`llm_normalizer/backend/src/server.ts` поднимает Express-приложение и регистрирует:
- `/api/health`
- `testConnection`
- `sharedLlmConfig`
- `normalize`
- `eval`
- `assistant`
- `autoRuns`
- `history`
- `presets`
- `accountingAgent`
Текущая сборка сервисов:
- `OpenAIResponsesClient`
- `NormalizerService`
- `EvalService`
- `AssistantSessionStore`
- `AssistantService`
- `InMemoryRuntimeAdapter`
### 6.2 Что это значит
Backend уже совмещает несколько ролей:
- LLM gateway;
- normalizer runtime;
- assistant runtime;
- eval runtime;
- batch/autorun runtime;
- session persistence for assistant mode.
Именно здесь архитектура становится наиболее плотной и наиболее хрупкой.
## 7. Слой 3: Текущая архитектура assistant runtime
### 7.1 Зафиксированная форма
Согласно `ARCH 10` и текущему коду, assistant runtime уже устроен как пятислойная система:
1. `living router`
2. `address orchestration runtime`
3. `address exact execution lane`
4. `session memory + navigation state`
5. `answer/debug contract layer`
### 7.2 Living router
Главная точка выбора режима сейчас это:
- `resolveAssistantOrchestrationDecision()` в `assistantService.ts`
Текущие верхние living modes:
- `address_data`
- `assistant_data_scope`
- `chat`
На этом слое решается:
- идти ли в exact data contour;
- уйти ли в data-scope/meta contract;
- оставить ли запрос в обычном chat mode;
- перехватить ли follow-up/meta/memory case.
### 7.3 Address orchestration runtime
Вынесен в:
- `assistantAddressOrchestrationRuntimeAdapter.ts`
Он уже отвечает за:
- LLM predecompose и fallback predecompose;
- нормализацию effective message;
- resolution carryover context;
- защиту от плохой canonical rewrite;
- сборку `dialogContinuationContract`;
- формирование `addressRuntimeMeta`.
Это уже похоже не на "просто helper", а на отдельный orchestration stage.
### 7.4 Exact execution lane
Текущий exact lane строится вокруг:
- `AddressQueryService`
- `addressRecipeCatalog`
- `addressCapabilityPolicy`
- `addressIntentResolver`
- `addressFilterExtractor`
- `address_runtime/decomposeStage.ts`
- `address_runtime/composeStage.ts`
Именно этот слой исполняет конкретные capabilities, routes и recipes.
### 7.5 Session/navigation state
Критический текущий актив:
- `addressNavigationState.ts`
State уже хранит:
- `active_result_set_id`
- `active_focus_object`
- `last_confirmed_route`
- `date_scope`
- `organization_scope`
- `result_sets`
- `navigation_history`
То есть система уже не полагается только на transcript memory.
### 7.6 Answer/debug contract layer
Ответ формируется не напрямую из LLM output, а через отдельный packaging/debug contour:
- `answerComposer.ts`
- `assistantAnswerPackageBuilder.ts`
- `assistantDebugPayloadAssembler.ts`
- `assistantStage4AnswerContractAudit.ts`
Это означает, что проект уже имеет машинно-читаемые answer/debug rails, а не просто "text in/text out".
## 8. Что graphify говорит о текущей кодовой базе
На `2026-04-15` по `graphify-out/GRAPH_REPORT.md`:
- корпус: `473 files`
- граф: `4865 nodes`
- `10622 edges`
- `132 communities`
Ключевые god nodes:
- `resolveAddressIntent()`
- `composeFactualReply()`
- `resolveAssistantOrchestrationDecision()`
Наиболее важные сообщества для assistant runtime:
- orchestration around `AssistantService`
- exact execution around `AddressQueryService`
- navigation state / focus object / result sets
- address orchestration runtime adapters
Это подтверждает центральный архитектурный факт:
`главная форма системы уже не prompt-centric, а runtime-centric`
но при этом
`runtime слишком сильно сосредоточен вокруг нескольких god modules`.
## 9. Что в проекте уже сделано сильно
### 9.1 Structured state вместо transcript-only memory
Во многих LLM-продуктах контекст держится только историей сообщений.
У нас уже есть явные сущности:
- `result_set`
- `focus_object`
- `date_scope`
- `organization_scope`
- `last_confirmed_route`
Это зрелее, чем у большинства generic agent shells.
### 9.2 Exact-data lane как отдельный контур
`AddressQueryService` у нас уже отделен от chat/mode выбора.
Это означает:
- есть шанс держать business truthfulness;
- есть шанс тестировать exact capabilities отдельно;
- можно hardening делать не только через wording, но и через route policy.
### 9.3 Limited mode и truthfulness rails
В кодовой базе уже присутствуют:
- route expectation contracts;
- limited mode;
- missing anchor handling;
- honesty around empty/incomplete results.
Это правильное направление для exact assistant над бухгалтерскими данными.
### 9.4 Scenario-oriented hardening loop
Через `artifacts/domain_runs/*` и `.codex/skills/domain-case-loop` проект уже имеет не только тесты, но и domain acceptance artifacts:
- `baseline_turn.json`
- `rerun_turn.json`
- `scenario_manifest.json`
- `scenario_state.json`
- acceptance matrices
Это очень сильная инженерная практика, которой нет у многих open-source chat products.
## 10. Где сейчас архитектурная хрупкость
### 10.1 God services
По размеру и плотности ответственности особенно выделяются:
- `assistantService.ts` - 6243 lines
- `address_runtime/composeStage.ts` - 4817 lines
- `answerComposer.ts` - 4681 lines
- `addressQueryService.ts` - 4415 lines
- `assistantDataLayer.ts` - 4272 lines
Это главный симптом того, что:
- routing;
- state evolution;
- policy;
- answer shaping;
- partial chat/meta behavior;
- exact capability glue
слишком часто живут в одних и тех же модулях.
### 10.2 Implicit workflow вместо explicit workflow
Система уже ведет себя как state machine, но выражена в основном через:
- `if/else`
- guard trees
- carryover heuristics
- rewrite protection
- mode decisions
а не через явный graph/workflow model.
Из-за этого:
- локальный фикс легко меняет глобальное поведение;
- сложно визуально понимать допустимые переходы;
- acceptance часто приходится собирать эмпирически по прогонам.
### 10.3 Policy смешана с orchestration и answer layer
В текущей форме слишком много policy decisions живет внутри orchestration ядра:
- domain pivot
- meta-followup
- memory recap
- data-scope boundary
- short follow-up behavior
- raw vs canonical message preference
Это делает систему чувствительной к incremental patching.
### 10.4 Provider/runtime abstraction узкая
`OpenAIResponsesClient` сейчас фактически является главным LLM gateway с режимом:
- `openai`
- `local`
То есть провайдерная архитектура пока прагматичная, но не полноформатная.
Для текущего этапа этого достаточно, но это означает:
- модельный слой пока не является сильной самостоятельной осью архитектуры;
- orchestration и provider logic не так чисто разведены, как в крупных product shells.
### 10.5 Python router не является главным runtime
`router/` полезен как bench/policy contour:
- `query_classifier.py`
- `route_selector.py`
- `store_sufficiency.py`
Но он не является source of truth для текущего assistant runtime.
Это значит, что:
- нельзя проектировать основную архитектуру, думая, что Python router и есть текущий production routing;
- любые будущие сближения этих контуров надо делать явно и документированно.
## 11. Что показывают внешние references
### 11.1 Dify
Полезный architectural pattern:
- явное разделение `Workflow` и `Chatflow`;
- node-based orchestration;
- встроенные classifier, agent, tool, variable, answer nodes;
- отдельные conversation variables, переживающие многоходовый чат.
Что полезно для нас:
- идея сделать часть нашей текущей implicit orchestration более явной;
- отделить workflow state от answer wording;
- использовать более явную модель conversation variables/state transitions.
Что не нужно делать буквально:
- переписывать текущий exact runtime в low-code canvas;
- пытаться заменить существующие domain rails на generic visual flow.
### 11.2 Open WebUI
Полезный architectural pattern:
- product shell + extensibility layers;
- разделение на in-process tools, external OpenAPI/MCP, separate pipelines;
- input/output filters;
- четкое понимание, где живут heavy operations.
Что полезно для нас:
- явнее развести `tool/action layer`, `message filters`, `heavy execution lanes`;
- отделить extensibility concerns от core orchestration;
- думать о boundary/filter layer как о самостоятельном слое.
### 11.3 Onyx
Полезный architectural pattern:
- AI platform как слой поверх connectors/search/chat/agents/actions;
- MCP/OpenAPI actions;
- enterprise-friendly separation между agents, actions и indexed knowledge.
Что полезно для нас:
- видеть assistant не как monolith, а как application layer;
- усиливать distinction между exact domain actions и general conversational shell.
### 11.4 LibreChat
Полезный architectural pattern:
- agent/tool shell;
- MCP integration;
- deferred tools, чтобы не перегружать контекст;
- тонкая настройка agent capabilities.
Что полезно для нас:
- capability exposure должен быть более декларативным;
- tool universe не должен быть размазан по orchestration heuristics;
- selection of available actions может быть более explicit.
### 11.5 Vanna
Полезный architectural pattern:
- exact-data assistant через agent + tool registry;
- user-aware execution;
- structured UI outputs;
- observability и lifecycle hooks.
Что полезно для нас:
- точные data routes надо трактовать как first-class actions;
- identity/scope/date constraints должны протекать через tool execution и answer shape явно;
- structured outputs должны быть устойчивым контрактом.
### 11.6 DB-GPT
Полезный architectural pattern:
- AI data assistant как отдельный класс продукта;
- skills, workflows, SQL/code execution, sandboxing;
- separation between platform and domain skills.
Что полезно для нас:
- наш проект не обязательно "уникален";
- data assistant products уже давно строятся как composable platform + domain logic;
- это аргумент в пользу архитектурной декомпозиции, а не против нее.
### 11.7 LangGraph
Полезный conceptual pattern:
- durable execution;
- persistence/checkpointing;
- deterministic replay;
- explicit state graph;
- idempotent tasks.
Что полезно для нас:
- follow-up heavy assistant с carryover почти неизбежно выигрывает от explicit state graph mindset;
- наш current navigation state уже является хорошей базой для более graph-like architecture;
- особенно важно для multi-turn domain scenarios и bounded recovery после ошибок.
## 12. Где мы типовые, а где уже нет
### 12.1 Типовые части проекта
Мы полностью типовые в следующем:
- есть LLM gateway;
- есть tool/data execution;
- есть retrieval/data grounding;
- есть session state;
- есть answer packaging;
- есть eval/autorun контур;
- есть multi-layer backend over business data.
В этом смысле проект действительно не изобретает новый класс систем.
### 12.2 Нетиповые, но сильные части
Мы уже сильнее generic OSS chat shells в следующем:
- exact capability discipline;
- structured navigation state;
- selected-object continuity;
- scenario-tree acceptance;
- limited-mode truthfulness;
- explicit answer/debug contracts;
- domain hardening through machine-readable artifacts.
Это нельзя терять в погоне за "более красивой" типовой архитектурой.
### 12.3 Нетиповые и хрупкие части
Мы хрупки там, где типовые проекты обычно используют более явный framework layer:
- implicit orchestration inside god services;
- policy encoded in large custom functions;
- state transitions expressed through heuristic branches instead of explicit graph/node semantics;
- boundary/meta handling слишком тесно связано с main assistant coordinator.
## 13. Что нельзя ломать при архитектурном обновлении
При любом дальнейшем update plan нельзя разрушать следующие baseline элементы:
- `AddressQueryService` как отдельный exact lane;
- `addressNavigationState` с `result_set/focus_object/date_scope/organization_scope`;
- `dialogContinuationContractV2`;
- selected-object continuity;
- route expectation audit;
- limited mode truthfulness;
- domain artifacts и scenario acceptance loop;
- `docs/orchestration/active_domain_contract.json` как mutable active domain source.
Принцип:
`generic best practices не должны размывать exact-data baseline`.
## 14. Unified diagnosis
На `2026-04-15` архитектурная проблема проекта формулируется так:
### 14.1 Не проблема
Проблема не в том, что:
- проект слишком специфичен;
- проект делает что-то принципиально уникальное;
- для проекта не существует внешних референсов;
- нужен новый "умный супер-роутер", который заменит все существующие слои.
### 14.2 Реальная проблема
Реальная проблема в том, что:
- правильные слои уже есть;
- правильные state entities уже есть;
- правильный exact runtime уже есть;
но
- orchestration и policy слишком централизованы;
- implicit workflow слишком велик;
- код слишком легко деградирует от incremental heuristics;
- system behavior недостаточно выражен как явные runtime contracts и state transitions.
Коротко:
`архитектура не отсутствует`
а
`архитектура уже есть, но собрана слишком вручную и слишком плотно`.
## 15. Целевой update direction
Правильное направление обновления:
`не rewrite`
и
`не новый универсальный агент`
а
`explicit workflow/state shell поверх существующих exact rails`.
Это значит:
- меньше hidden orchestration;
- больше explicit route/state contracts;
- тоньше coordinator modules;
- более явные boundaries между:
- route policy;
- state transition policy;
- capability registry/execution;
- answer policy;
- meta/chat boundary.
## 16. План обновления по найденным references
### Phase 0. Зафиксировать единый baseline
Цель:
- прекратить обсуждать проект как "просто LLM чат";
- закрепить единый словарь слоев и boundaries.
Что сделать:
- использовать этот документ как общий architecture map;
- сохранить `ARCH 10` и `ARCH 10A` как assistant-runtime specific docs;
- считать текущий baseline immutable without explicit note.
Ожидаемый результат:
- любые дальнейшие изменения обсуждаются относительно явной карты проекта, а не по ощущениям.
### Phase 1. Развести проектные слои формально
Borrowed pattern:
- product shell layering из Open WebUI / Onyx
Цель:
- явно отделить:
- data foundation;
- assistant runtime;
- orchestration/eval loop;
- experimental router contour.
Что обновить концептуально:
- `canonical_layer` и `llm_normalizer/backend` должны описываться как разные subsystems;
- Python `router/` должен быть явно помечен как benchmark/research contour;
- `.codex` и `artifacts/domain_runs` должны считаться отдельным quality/hardening contour.
Ожидаемый результат:
- меньше путаницы, где именно находится source of truth для runtime behavior.
### Phase 2. Вынести orchestration grammar в явные contracts
Borrowed pattern:
- Workflow/Chatflow + conversation variables из Dify
- state graph mindset из LangGraph
Цель:
- превратить главный orchestration policy из "большого дерева if-ов" в более явный contract system.
Что обновить концептуально:
- формализовать переходы между:
- `address_data`
- `assistant_data_scope`
- `chat`
- `meta-followup`
- `memory-recap`
- `organization-clarification`
- для каждого класса перехода иметь:
- входной trigger class;
- допустимый carryover depth;
- allowed state reuse;
- forbidden cross-domain leakage;
- expected answer mode.
Ожидаемый результат:
- routing перестает быть набором локальных heuristic patches и становится описуемой state policy.
### Phase 3. Разделить root policy и object policy
Borrowed pattern:
- explicit conversation variables из Dify
- durable state semantics из LangGraph
Цель:
- окончательно закрепить различие между:
- `root frame`
- `selected object frame`
- `meta frame`
Что обновить концептуально:
- root state живет дольше и используется шире;
- object state переносится только в совместимых сценариях;
- meta state работает поверх answer object/result object, а не replay-ит exact route вслепую.
Ожидаемый результат:
- меньше ложных carryover;
- меньше cross-domain contamination;
- меньше случайных уходов в generic chat.
### Phase 4. Сделать capability exposure более декларативным
Borrowed pattern:
- tool/action registry from LibreChat / Open WebUI / Vanna / Onyx
Цель:
- capabilities должны быть first-class registry, а не только следствием разбросанной policy.
Что обновить концептуально:
- описывать capability не только через intent/resolver;
- дополнительно иметь явные поля:
- supported wording families;
- allowed anchor types;
- selected-object compatibility;
- root-context compatibility;
- meta-followup compatibility;
- answer mode;
- clarification policy.
Ожидаемый результат:
- меньше логики в giant service functions;
- больше declarative routing discipline.
### Phase 5. Выделить answer policy как самостоятельный слой
Borrowed pattern:
- answer nodes / structured outputs из Dify и Vanna
- filters/boundary layers из Open WebUI
Цель:
- отделить:
- exact answer shape;
- limited answer shape;
- clarification shape;
- meta/explanatory shape;
- operational boundary shape.
Что обновить концептуально:
- не позволять routing fix-ам решаться только wording patch-ами;
- answer layer должен знать свой response class и формировать shape по контракту;
- `direct_answer_first` должен быть частью policy, а не удачной случайностью конкретного compose path.
Ожидаемый результат:
- ответы становятся устойчивее и предсказуемее даже при edge-cases.
### Phase 6. Зафиксировать runtime checkpoints и replay-safe state
Borrowed pattern:
- durable execution / replay / idempotent tasks из LangGraph
Цель:
- сблизить session/navigation state с моделью checkpointed execution.
Что обновить концептуально:
- каждый важный state transition должен иметь machine-readable checkpoint semantics;
- follow-up interpretation должна опираться на сохраненные transition objects, а не только на текст прошлых сообщений;
- сценарные прогоны должны проверять не только answer text, но и корректность state transitions.
Ожидаемый результат:
- меньше регрессий, где exact route есть, но follow-up interpretation ломает доступ к нему.
### Phase 7. Упорядочить provider and execution interfaces
Borrowed pattern:
- product shell abstraction из LibreChat / Open WebUI / Dify
Цель:
- постепенно превратить LLM gateway в более явный provider runtime layer.
Что обновить концептуально:
- развести:
- orchestration logic;
- provider execution;
- model-specific JSON / response normalization;
- local/openai compatibility concerns.
Ожидаемый результат:
- меньше provider-driven логики внутри business orchestration.
### Phase 8. Сценарная приемка как главный architectural gate
Borrowed pattern:
- LLMOps/observability from Dify
- enterprise auditability from Onyx/Vanna
Цель:
- закрепить, что acceptance идет по scenario-tree, а не по отдельным красивым ответам.
Что обновить концептуально:
- любой architectural update считается успешным только если:
- сохраняется root path;
- сохраняются critical edges;
- сохраняется selected-object continuity;
- не деградирует limited truthfulness;
- не ломаются neighboring domains.
Ожидаемый результат:
- меньше "качелей", где один кейс улучшается ценой трех соседних.
## 17. Что не нужно делать
В рамках update plan не нужно:
1. Переписывать runtime под Dify/Open WebUI/LibreChat как платформенную миграцию.
2. Вводить "универсальный суперклассификатор", который обходит текущие rails.
3. Возвращать state обратно в transcript-only memory.
4. Маскировать state/policy проблемы только answer wording правками.
5. Смешивать Python `router/` и текущий TS assistant runtime без явного redesign note.
6. Жертвовать exact-data discipline ради более "естественного" чата.
## 18. Целевая формула обновленного проекта
Если выражать желаемое состояние кратко, то проект должен двигаться к следующей форме:
### 18.1 Слой проекта
`1C/OData -> canonical store -> feature/risk data services -> assistant orchestration shell -> exact capabilities -> answer/debug contracts -> scenario acceptance loop`
### 18.2 Архитектурная форма assistant runtime
`thin router + explicit state transitions + declarative capability contracts + isolated answer policy + exact execution lane`
### 18.3 Главный принцип
`не делать систему "умнее любой ценой"`
а
`делать систему более явной, более контрактной и менее хрупкой`.
## 19. Итог
На `2026-04-15` проект `NDC_1C` уже нельзя честно описывать как "обычный чат с LLM и другой базой".
Правильнее описывать его так:
- это read-only AI/data system поверх 1C;
- у нее есть canonical/data foundation;
- есть feature/risk layer;
- есть specialized exact-data assistant runtime;
- есть scenario-based hardening loop;
- и есть существенный orchestration debt, возникший из-за ручной эволюции.
Поэтому правильный next move:
`не ломать то, что уже собрано`
и
`не пытаться заменить систему generic framework-ом`
а
`собрать более явную architecture grammar поверх уже существующих рабочих слоев`.
Это и есть safest update path по итогам локального анализа и внешних references.