From 796a9a93f25de095ee6cf4ae452b2ef4303b45b3 Mon Sep 17 00:00:00 2001 From: dctouch Date: Fri, 24 Apr 2026 18:35:12 +0300 Subject: [PATCH] =?UTF-8?q?Post-F:=20=D0=B7=D0=B0=D0=BA=D1=80=D0=B5=D0=BF?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=81=D0=B5=D0=BC=D0=B0=D0=BD=D1=82=D0=B8?= =?UTF-8?q?=D1=87=D0=B5=D1=81=D0=BA=D1=83=D1=8E=20=D1=86=D0=B5=D0=BB=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20MCP-=D1=86=D0=B5?= =?UTF-8?q?=D0=BF=D0=BE=D1=87=D0=B5=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- artifacts/m23_latest.json | Bin 0 -> 282932 bytes ...semantic_integrity_hardening_2026-04-23.md | 8 +- .../11 - architecture_turnaround/README.md | 6 +- ...2_human_mixed_integrity_status_dialog.json | 249 ++++++++++++ ...t_f_cross_stage_canary_agent_20260424.json | 238 ++++++++++++ .../assistantMcpDiscoveryAnswerAdapter.js | 26 +- .../assistantMcpDiscoveryTurnInputAdapter.js | 165 +++++--- .../backend/dist/services/assistantService.js | 28 +- .../assistantMcpDiscoveryAnswerAdapter.ts | 15 +- .../assistantMcpDiscoveryTurnInputAdapter.ts | 127 +++++-- .../backend/src/services/assistantService.ts | 28 +- .../assistantAddressLlmPredecompose.test.ts | 98 ++++- ...assistantMcpDiscoveryAnswerAdapter.test.ts | 56 +++ ...istantMcpDiscoveryTurnInputAdapter.test.ts | 79 ++++ .../data/autorun_generators/history.json | 168 +++++++++ ..._20260423184425_gen-ag04231844-8e552a.json | 281 ++++++++++++++ ..._20260424140630_gen-ag04241406-abe4d8.json | 353 ++++++++++++++++++ ..._20260423184425_gen-ag04231844-8e552a.json | 82 ++++ ..._20260424140630_gen-ag04241406-abe4d8.json | 97 +++++ ..._saved_session_runtime_job-C4l-4Yfuqm.json | 78 ++++ ..._saved_session_runtime_job-FvKPQG152c.json | 123 ++++++ ..._saved_session_runtime_job-IYhHuIIG_n.json | 42 +++ ..._saved_session_runtime_job-LndQtjGZU3.json | 123 ++++++ ..._saved_session_runtime_job-X1z7AFW_Nq.json | 42 +++ 24 files changed, 2408 insertions(+), 104 deletions(-) create mode 100644 artifacts/m23_latest.json create mode 100644 docs/orchestration/address_truth_harness_phase82_human_mixed_integrity_status_dialog.json create mode 100644 docs/orchestration/address_truth_harness_post_f_cross_stage_canary_agent_20260424.json create mode 100644 llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260423184425_gen-ag04231844-8e552a.json create mode 100644 llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260424140630_gen-ag04241406-abe4d8.json create mode 100644 llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260423184425_gen-ag04231844-8e552a.json create mode 100644 llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260424140630_gen-ag04241406-abe4d8.json create mode 100644 llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-C4l-4Yfuqm.json create mode 100644 llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-FvKPQG152c.json create mode 100644 llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-IYhHuIIG_n.json create mode 100644 llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-LndQtjGZU3.json create mode 100644 llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-X1z7AFW_Nq.json diff --git a/artifacts/m23_latest.json b/artifacts/m23_latest.json new file mode 100644 index 0000000000000000000000000000000000000000..2718b41d7f0abfde7453d9d8bcf7fee0525a18b1 GIT binary patch literal 282932 zcmeI5Yj530a_0Xp_$oj?!*cwF894M%6semnUpF%WW^5$cNwC0TU`W)}mMDdk#?}P+ z>bqONE|&X#NdE7KZV;4sIXvv$8i$yr)sCJ)ZXjv3p($~ z+pX^S;%DB=-cDrAoGl*zPM(2t&nwFr=2>~=&gHAGv7%P0|PNzMeVb843Zug&V9oU~;`K>QxZ*S!pcIA0q$;bTWmkxW_nU8+K2djM5 zeJ78=Rq&vy?KF(U6$STg{x7+F!IiCn-4#d{qa~2J&7QWqbyNIpBx9&AQmuGtJ zKH_=o?DBemP`>tG-G9s5KVG2dreTBKKbODfQ~8&_DX4uV=i`ms)SU4gEn_31?+Qvd zz^6DC%W>!8W{WX!TQG5_A)#QEIGHE%n!lD;{EfWscxb!MYM%%u-U~8b&47fyE2tp> z-|x2IAw+?Gd?XlYHeuI!<5>Lg^?xLVZ7hSlXJ!|U9=xJzO`oS)+7xy`th z^`5`py+MR9<(f)pITE{ZTW*kJXFcuk@f|h^k40?~HY$AeesXcj3;C+~8;UQY zAmU5)e|Q!mY~`!wx$TzUK@E$F!yJpm=z4D|yP`anvM;~3_$s^~VNGDIh%AXEPaP`Z z1kRit!@GVfAHQ*|0L)(=XU&7T`BqxP)~ySB7F#(!yDRn&PN-q)a%{n#o`|PqX#1Vm zyr=S&@ZMZ6-sW0;9fQP!d87z7;UXIXFGrxiIk9r^gWSbLl5h%d1)JQ+9*@eIhAgDA zlha0&WqUWz+Uw}MCGo+n#LvS5!d@K89oz61;xF{(;QHUn8<|FMr(PWl79QL(7@K;1 zH5|ci!eKPD)X+js0-Pv1{Hb39QpR3e9VO(|N_QRklRNFU6T1=O2d|1-3U*vAjPVhw zQc$jx{2u<+2YFx8pPzTNb&TDW`>Yf%-jdsl_hzFuV+=b5>R=^cQum$b1Ok_`RXMW8 zUt=9l$ATI%yz$#D$B-SgJMU7PjiCeE6OL=}CTlGk|SQu3-nW2qrBUbID(^t*Ib1k**I`Yt}kQ<8MP&^&W z*ALnqDJZEU4+Ymd$v5sx?1v5eQ63#5Zw@vgM%6fL+Ju<+8h83tj=wb$`S+^CA-@V>+^yC*C?-)jgA z5tw_-e|7gBnpITom(j13Jv@FE7FTa*s}4y$zPzro zzlGe6oz;*_&Z*Sx0TutTSjgrjPVxHI?N5%(UBNTHsNUveT3L}QwNKo4c!b8*yWQ6k zNgqlS{pHTO5Ix_HYe-i_m$a03oqyY~9y2*GI9hv7eEd>;N_tmZW|MO+xP)l+b4yW| zR`aFynn!X6@Na)yhs^rAcUQtN>J4#|L6-@9lgl-+3q>e-`kTOJaLl_gz9g`~yD99q~qD#8cDSv|86ge9h{m zwO{5>fMR+`>~-G=#$oAiyL0eh=bN1`9P;mN3FgS3VgL5d z(ay2p|FfMxx>Mk>Z#RO^SFPFZ_df%3{RQf0fr>ixZ223}Ys+R_?=0X;pE+M1kN$G& zZ?C`F{ZHjIJd}IjH{EaKW>6lc%*M>+&0ps6tZlz_oF59#OE&*lynAZc8y^!!ahJdD zrqIhhnjF*kHrs;dW%gCWE!7mnpSiCBZtpkLMin@hp|;MI)#6j)QT%h%GxsD8-R+L# zD_HB#oUJBO<*OFImi_no?;W3ixe0%R(rGx9cvZDwc?V_cwHrqhdn(Vw`+#LE`602c z$MZ4xv9Dd#r2dr8m0Q-wt1!qJ!6u%`@1UD_uD%|k_6hHz_3WgEOFRfPi@BAiBB^;6 zs3)ii*>yS#GA$<#Gpad7?L(G@{@$m;hyP9f_g$D$|AG#`mtz{c>Z|3ZKr+8qWpy?D;E|%JP4PpI3*K9{kM6GI^!)%xM5$Vxph zG+`(gbheB4*ud#+E?c|jAHAk;-yXCmt-34Np zrJ=0l)$9@$E$-!tU3w)0hROaql8M03y2Ex?iuv?!QX5A%GGemGzjgl zXw^#CJ&(f^v6I}pC=aP>S%YPqa?Lfo!Ip3vq*k!q&dg=xKF;x$->lR`fg;0PSi9me zM~5?XuK0I~H*Rct`-eAje~&M{edkzb4Oi&(s83IEbs!N0neHW(P0Fv**#eecJ#Xvm zM5WU+S^2KKPV@^ipX_?m82kK&9A~_qtbpElYRi~osZ%21=;Af{ngD(~N>bmuD)khZ zzh#q1;YIsYf~IJjZ?!edac{zWq){vS3G{W#F~EKBu-%AbvJSB=_D$!Rcs6;=2xC0d zU1h~JMA;pUgdu@(`T)_-c<{`FsL?H@<{3x4qi z@>!4CFOc|8Z8g!9kIKmq62+s0z?!4rN#{PYM!u$u!IQ=B*)#(<#%h26Hof!bSZ4`ia0_GvO8F_KV>WIf z&wwd^W&Me7RLi%eveiOW4-FBvh#9-O9=E>eRi)*N$U*)7O4X%hgxWGW?W|xr-V`iNJ3cVskJ` zjYf;lbN@i|SwD$IEooAe;n#UH&z-e3dwLc7X})eA<)>am|JZ3w>#yUIZV36LHaLDT z+jKBFE-&+2(-@fv-*m^Y%$1M0tb*L8C#CtSILaTY!rEjhr(Sane?&*{lc`tA=U}ki z+}FRkPb9`S9hGMJJyV1&jide)gDDbre?jk*_=}N0#j0xv#LA(2PNR0v*YJ0J>ldTT z?pf|>>}FmA7vd|AlltGjms#m4)>*?C>OF4R)XMP{l=Tf~W8nTN2bv5;0q7dkrXWU(!v%n=XibuEXq)l#>wJN|vo;9!B;;+fO&*6eEbhFHs^9a-I0SfMYK_XEtcrBrGIs`7a z`WhnXzevy8+^0j`(Bjt1eLAe)Tfr3EQyEX1Q~Ocupw3#+Y8=BLQG~I2WZHNPu?0Bg zRKmD`X0)-sf}H!AnugH!PKVpI@3Dq%kPTCq+gq${V+qUX4mI3VbUk)h410B!5e-kc zFF2)}3q3oiAoJLU!z)!a_}}2s?-e@ZVtV~Mt05U(1H5*Q=R0-01J!*qIVL6TWuT z(fuqQnN~hO7p!2#Qs2#Dj~HLX9z6ev>tLmNt2gq~Q{il`wbt;)q)|Gjr8g%Xf~f&* zvBKrIXP&Fj+I&;vdDc%O;8I_-kar%>icPb!8kP_73Hl{hhU;S%r7$Ytqheqxq#3I;af`;C=)_Y7RzVIwq%v1T< zFrM&i-M%~`X6r%}6XWvipt!&7TKR_!R#AD2t7xrRUD5iDkkKjIPm%htOz$Dd_a zA32MKt@F3Ip%JU6)BpCxTU7j*z2rN3d*e0Y3Bb7RcJ{NDhc?vlcvIn%p+fq}>7>32kIULO_w+{FvFZJrLHhH#Z4s)v30@+u`Ex$)Q_-cH_b6{!tpRem@ zs*$i$)Zfake^)gOqs%F*t?9Lo9=1jEX*BPBy>Gj3x_=QYnFT!;i%ail^1#aU#2vwW z4-t!}{Lkj`75)SIYw~(vzdt^gU2zS2_@5dZr7SqMlUctFdnxu}e@+>ixc9SRkt!0{ z@wnp~nDQOU@iSiwQf;n{-uM=4DUx5v^Qh%Tqw~h`7YxfjcDYyTGCiTGPNC7;N;A9eJ^{L96Oc`rZr zs{78}kT5O})^J8qs>z;m&4Tf>nh>vSnx&k0CQc+EiTC^hNm@s<+yh=i?EG$ z%J>kAb9t>%aiIGq_6T=AwVk^DT1q&g`!y4-P&t;WN0;-j!oTIO3q|_Mvgde4HmV@% zo?%j6I(8e(!40A!GIjXUxEo{jC8W~PTIXEk@c>#LI$bxkUfmZ=&s5DHy3Eel>m7C= z@t6dmzPbtz4@Sm#82*m#eXKv`dP{i3V_-TwI?L3iq6$8e z=)8Fh!#sv}&i6#OLq<@mF;s(&j$QEz!a}R4XxxnDd3m6vcTqwwaTyrJuT8Bf%u`X+M6!638AkRTIDe#gDF;4Lm66Dx@)BvgEgebP2*LDS}x!Fjk~Ud zDOIGNx!9C`IX1bB`YMeZUb`4|D!fg(!aD9yuavsP!ediI-R#>i`$m*V9rYW*j!rX4 zZzFgQuT>3EXson#HK789I##+It5#L>dN1VJ&qn2==U#OkpUj}=o{itMV^gz=L#?9S zv}WtVT7Pg^iwi8Hf#n$EL$rO-h|r{4~ObzL&f)kJFU&~oi5J1?;ZNTcQ`F`eNUaPP3y0% zf;-I@((4T0mD6Mu+$dF1f2(e-zt6hXz0|QxH;WRt!xRL*-n@-r-o_@z8tZFH$uRfQ zAAdPN*#Gy}FoV{$d?9J+#TK{TU zm((}KrV+W&eT2;K<#-FxNsS)UNyof5$6C!MM4=~0@kC_JEehAue6L}?SBw!NX*36# zNz+=F{4VwJbt%Fa6Jb-Wu8z2JS1~wlCY~)>7q^XZYwl}@J`s^@sPYeAZDSFYahYG+ zI{i9p7}ShP$$vuuNJhBXykRyE4o~~e!dt&|DBSJ#x<82C^m9?4J{0BYZuiyBA9jxA zE5}ZK>Z1wHA-xz>ZIv=7Ii~5qK&?D{_t5zkamC;A`>0`C61H z@FFnMRI~ifaU?L`u|>^M>+NcaT(XDb*9gq9(i#etg-N|fK3DZ>v!p{K;XS9=-@Q=q z9~6}ObxrE#N|7fU+*|@!5xm%pMLStfb z4LhmfSUZE1x^?k2rWdz}XIR7&_wd9@>hsxjN9{s{K1XL@nNq^f;N6$+ol34md)CoW z4xCek>U$z8Uo<9a=U;anqvhUR%0-fKX&7Awqc$bbI7?O$&N^4CtDXQ8OEsGetGPzx zj=h^Yp5fJVg$}jSe0|yO$v1=R>}$Qs7@)H)njHLG#dJykvrVWTwxdnRriw3(y2y!x z?N;A6)GO|bYbvA9#KFX|GeYoAH9ho3>r z_ePktR0ptzIB%Ri)Um7GfpYAUhdpTO6R}In#C+aX?TgI>tv`xa3~Q0j6ZJgrxIG2> zTHPTluj3T1x759jiX&X}J2l_iAF;z$U&kx)RnG5XceM(nMPAEUS>k!PFs3$}MO8J|X8XHd z6pz27Iz@V%}Q)ZsU`fxk;e(IPeQY+OXkSj)k)_mWgo&<`V zQY{raMY6n174lsk;tq#?5;S>Z>ime#c(#`p3Wr*UVk+yW_9)i4vl`OzDyUS=V?6W_ z4dv@VIaAi~HbE}ErBMG;OFbonHV%rfxAGcFse7fjUW!t@VrH8*4`Y~zG0tlp)-vXu zj{Wc02HXzaOAX1YQpYn+-*ifP)32|?;$HprN4KX{Xwz$h{TWK9E?mcF8hdXwtP>T& zPo!3x4&h|(8XLDhtkVJ0cc1cj+cukh-F?(CtZ`tDVSJJn2M+J=;xRUsO{>55+ik0d z?yHV*I#j0q2%j^(xM?Y-#5mUWnM8Ic!q4&glF^GR0jw@5)T_a6z%avpP~CCnB11*D zDcP2?*z@nGhHJEzdCZ6mjEMoQ58W56(@SpZ>bv@Fw8Wlj$Yv@YGaPfT zq;;KxC0mEZPHlA9J%0O8J;rWocs_7=Mpcx)Y5(|^LtKNc-h=?(JIrh8*YAOhwWB(& zwGJfrt?6mjJnMDXX>t_!()iKoYy;m#*=Bn@l`d3qN83;rKW2r<7{18(d#hvpj$`$5 ztP@A#v9v7BR9Tv<`=-=WKNSU@_omAzvpo59lRnD77nRDqyV->25-&pi9=u5FDZU1u zgdRWi!@}!FSxRTXQ+b06q32Z@W!r)7@%L88I=w6N+G{d3Xs27I=DJu{Z$T9seqNk^ zMgJ-Yr79}-H$=AGwVO~S7 z#3B?-F~eTzw@ql6DG^^diZK%c(2Rw z#+cMeDLQ$AE+veWN*PHS1qy2PsM_(UOJvYA@L-&ooH{=tdd?e8T@*SWIc zL}Z^e2s{39i_dkxPr0@_*6s*jREmc1QIF)U-OqjR=ajdn2h=NP3$clH9L|ZkIo4Rm z9(tHk?*~-6a7&HD>~HC~#bGg(V~11c#)Xr_>V<4kSX;2P zC`jsS6=BGqixmWm^ltpCAavhlgvfEe5oPVO0&5gcPrjOk-0l8BZf|Oh%k{~>9Wc2f z^m*5}qfNLj^Y-M7jvDiHOIREhCNU5w3$6mA079!nGbzS?x2QS>b~fB zli%qmom!kT6tyYKqq%Urgj2cgpUUhr2xxX!{e|jObSo%6%V{REOih1L@X!wb^4}yufpUF(zTQVQ_)15!<{Ig8O zW$NSc&O>>>Egyfe^X1Mx_t{r&UT!Jgp+YOK)=F_RC1N#JTk9_C_@@tf&L!QGQvsjZ z@|r_!toCFEoqOGC8yY(QEM( zUWnCwF8^xYK<(!Bi^cg(%iu}mM09Lu-lYxHYuG1_ui_7PERg;gy;T?x~p z;#h7ScDMh^>o`3YoR*ME{sEq$acRT2G@ITFr&jLiT(_5Y124;yExCg_Ztn;>v8MSO zs=nqc47IPh!avL_aQAyIq1>CxeBC;}$F!>Rt+#~9TiqvuN2W=araj;bG&?%Xj&9Dm z+KdLOLDBxDz2e41+88UTV+eH!74+#FN`U4y4z+6GT^8#{Vt+4GDerYK{0}Af^`+ze zzjj=|=27)#-lRpD6Pat>T@CGco_7V+`5lhu+4T2A(H?WAbT;u5LF%{iI=s$h)?P!Z z#_Xw0Ms2`*o3bzzsiv7yjtQh{^@x2vjmOu4QCrA$ zzUuz$q8(IKbXmo3uqjKhMLM~06GCB3p9tg6W6@qQP0XHGdl-k$GnGQiext^5%j~3t z;M;;=^sKP_xrK$FYO&LGVy93uUsiI}kdXSoAhCq>5TW3nJQj~cQ}DCoZ6AsCrn;Xj zuBi*im1$H4cYyYQ?f}D7h}*f-(iu2(R=mb(5&1PsKGc%G76iT$T)q^9<}o~9$@$rG zH?-LMSWEP`-u;yj4`YT`eOT~Z(D0)2ZFc`Uc0bqgnw?MW`cKX((|yJFUkfLiVxO_n zdPCQCw}ePyK<)oi%j7m&dObvv+j{Dz&*=P^be?$p`o>Ih zibK5MU3s>&H+K4*>SShFkKM#)ZneHMQ;aP)$ab$PCqC z-Z4<)Hx%LY3dUyUIvBIEu=s3Z!UG z?X#V4q?+cloj1-~NS=+)sId7$K0lDG+dX;zlgqiOSDNF_yx1u_2(4%JCA1Pv z(N(R)pizt4x?NK1cOA6mkqBP_dqhK6zZdd9h{WnqSqrAWmQ3+(_fT+4edM9M|6VF0 zKb5cY`H}n&#;KE}UQF@K^Oky9&w=Xg+hqy;_XPbq@hkU#vD8gBaXsvZysF;C+A)TT z93nHOx|I9}AGLAX(s;}8PW1MpyyNA<8js^OEWPFuE{V&)-+>@7WeRluB3)vd7jZqi z9D0W~H2^fC=6?H2hECNE^n#1?cJxESTBn?tq7c8fW{=0gY3ze9yZ$<6sSeA13F;Q; zr`{KISaGvw5+7Msn9;dSk&hH21DC+yq~Q;~x; zZg#l89X2Hle|>xdkgUEkIRom$sN_~IZ5@_(?iH7CdF-M#)jFoQY%!bf_~!Xj)U-rg zSWx;7ek=YH*_cP&Z{5uu`UYwPdE|-w1X+Nv8|Q2JTq^T*aWtv8_p8c)o&{x~?xr+W$t^q&ujYM6VQ_z(@7Cd{ecl$8D z#I9?n<5129y_D0_!K9hSKU|-C3+;Fu!I623UwLxE;MMk*{H!*JRVzv5yjh z;VD2V=*|5Q*o&5F8xrwd{>r0;d?#;IQkpW?;~FhIUiEgNdG0;ckWKe{`bDO;8SPo? z#XQV5r>xudTIaRwq>f@ZMe}2SNU8X-R+C-fqL_` z<2I(qN6)+75+dQ6>G;T;oZLe|3B07Or51)7GM%%IrrXb;v8;qv^pf?WF5D~`uQaM! z^xar2v@aiZf4R6fs7!m+eJ775`v0hVAn#a0eg-QDmo@J1R=cSd)}}Y<%CWnO%V)9% zt(jA0B{`FK-9yK8T3zU_te8Ebs_@(eTA%0g#_FHT$Na^NZPps0^8wQ*`1>ut@)COC zfWfc!;!ha|K3~pH7#BawVmCf{oDSl5jnDR7t{JT{Dosu*CzCw1olJ6p&*VEN@<_Z1 zu$lMr^>su4DW?Fu5&Mx(?5}NK!@5hj1+}nYWrYM;400O{yP8`YV)OMLAln9NvApD= zsb4EAfcTEyA&PIcqNvpPs-NqVV$`EOM>bX&Z(Sz_rJelxqnq1m{X47SAMG%)Txzwc zKw7eX?k3so5Fwm^r(#*T%{SF`?p;h4`jbo+x_6A3+jZ@Y8 z%1?T(;D>O^)Ow%DX#)K}xm!WK60hXP^TNhy>_!hFycB#fI1{`udbj9fxC=C2qmS5* zoz<`pA6Me!sB&Jmp7~~>KlNMb2=rEPWEnpE=reg!r4lyU{C>O?JQ}STsoxbug~T3M zVj>9j^T~$W3|Q5YK6Q6adTR{9|90%HbOJ!RcG1GqN$o$Z^pY&d%{~F}A9(17^+)2< zs6SrPL+9R*`Shk=(wii#$kynqk!iy}Gf1c!CzK2W~NDq5b%*VJ=?89#OY6Elu|AFj6&(^99X{GvTN^mB+J z_}$tS0KaBfC$13bYur-}^S8v_GwC2@8nrs>R^u9-&k?g0*XKERolU2D7HsfrAe4TH z_|PzjuqsryfZ`C-X5CeH%}tnhBC@V?G1tSha7y?W9}0hn$xGqy3Qt6TyB}5_u6b{@ zGXS@PMk+l6`qd@#@i)u!na1kd3CWSiJ@KLYI6(Zz@;S4c;`;SrQSaJ!RYSe@@6xLA z(BsGdp(ovv{T3VUnf^$(a#U94zr;6#_jX`wh#*d!r6)e#m!Etlwm$ATx;?(mkR8?V z4u7v+O^9~=n5y2ERkbR!q3k|=!z^!#zXKw_cZmExK(pCxRj<4kD{Xnv@8##oWRYz} zY50AXN%q+Hr$haDd>ni#JRf5!`>~m8+eHc2Xa$a3ZmPuEpo?w1%{ZvWlD@l$81=^2 zj4Hl2nugHBu5*)N9;?58zsfOLu*g zY3>vjoNjjX2f-p!<)oekd?MV1x7cw6ItEJDx1So);XCks(@2p12)6|3EfyTdnud%) zj*ghepzCdpQS%<^wpRTL(5^Y2Gxt2HmNt(XLod5O`nPL`_4A<2cW(KqhHrY9aZUpm z^gcI;t)trWcs%B{*mHaePDse*d8?oD(jouh{h0nZU(4F-2!_wdyW(Nt@o1XwGKTNc z4+U0L1``ezuZrQA!Cnr<)2zRaWI8F7G%BhVZwjq(tg-jQLqBBSu@m^w{Ubham1FO~ z*b%&Y?Un9x`EVIl@8JEI{`Pu%cDLyqlxic;D8hv_9&hY(fL`#eL*~1Pj~@FZs1hB2 zCgcn`6~5+V4CJqGKQ*kwSyM@o#-n`R@-yS$JoS)k-i5c$X0_C41N zn;!26JNHGWORkysy$cm>UvAnIV?+z{uDFI(_z~XnSdkgW4XxXRRzoS3T*q60)$)4l zNX1vkSw1>WqI7K@#5Q8pZ0!0itD!YraUHL<+63(v(jvd5@JfDK>&Vb*D8szT8&CxX zzBIl1teO%AJif)#O87lDNdq6^_`-)EQ!y{n*Rj|789}j>*RG-H)>`_;^i9L`k!LZz z1##O+z+O{_12@flWGZ~nXn^_?`I>PZmZ#aj_=>4MLN-u!Aex!fxyoeYnK<*+&L8AV zeC_JqU{yYdewLFsMEjAmnd{!;rZa)&DfP&y=e#FxEptE4y)iysd@X<8MdRGnHlT~@ z&xI_z;yPZ*Ha0swhMmS@#T`OIp5tm6Ml5tXjZ?WetHs3Y!Ro@;VWSnTRON@(dzij@ zefuckmoEI&jva|@P1!nXY+6h?j;#$dCq4si%IDbkxZJ}iAsqghJkKNX?CDMM#3`oG zNAbHiot$yhecQFe(pf+=sHY&WrNkeBQ)*Uz94qhpji~1hUR6h}QDy3n+nKPLMd|mk z;=XF^a2?>e($qtShHNU&T&A z>SvGXxh%ET8b)Cqsd7oZ6Ra`0n`V*6u*m56K%~|R?72D4%)ve0`ATLu?{;6vM_)=8 zpU-!Wf(f{}29{ZlTDfcfNbb=qinUweCPjDuIB~tZsi7QS8$DExa&kV6^H7~#Y@7Pj zv&YXs7Fs7P(MdsBKl+T&!`QmE8IH>eRL=*7HraC>zKhRTk>$E}unEu9-sE`ZYbc(Y z-5$ek=V+kzChpQu_bm+D9=n(K;Cv@sHJKnPbF@n?Q+bUIpAO~g+gBa?)a&LGOYvCH zbT{OWf&ARBpzB}WcP;dv_d5KUuf?O;6U<)LkIr+} zhSfd&{rR=;sfKyf4q!X?f?yb1^g5ka@9p!h_$uVpiA$ARtb6h$1W)hT%(K=yMu|I1 z^CQupv|6)yFp4%CtGg@SweR%gYs82%4V|Uz&s26c#OC;GtYMM}@mA4p;#nWdTl1mE z@D=JlH2D$J`RzKb;F)NmuH!R@h_tSid)@yK2JwOD0q@E?emMQW`N}stp9#bGP`>s@ z`PyfJ7K<}LwJ_Z@KXjiDR1c7b}J{6Rj$hgCgP?4LXq1Z!RrA3Ww8F3-`2_uLS+Z~0Z1Fne1t ziynk&skxT{&)u>)Q*n17F=n23w8f%CTaI^8WTUJ`ZF~$6r?od8){x=CPC+ zKX#e%hP|nE0g8>W#aeI@Yjjr5r19IGt9S%^Sn!<^JGnVUu17 zqAVtlRbNZ8`ctf|hCeFaa{rDDKYf1a7~b$V4gSsqf9LY{(rG-xJN7Erqj#0DoYaNR z!+FlT<~nBSN>$Qxlewq9p<#9m%;JgV)ySXje7AE;@J2u4{`JUVpOTQj*IdDPQOsJ_ zzX{9S@~I7`Z#QpCcK!(&J|a?`ji{GQjnBVwO_dwq1#{id(CW?r7s#TPfS9CuKXPIe#ZT3aY0{lN-f=yK* zw}cv8dw42l`M$1L_sh?)3p`r=m*?W|WqGbQau3jrFy~Blc7yiL*P4mp{ZUfo?KbVW zeul^&+%23T;QiBNEhmUv)(?VQbP1rmHmlWYCN#QxCHTkh;U_GTQ~#V(0q;qk zO*P>}d)NkSfms!5J^5LzO6lB;lWW+Py_HVIp~Q}daweF*38&U>k*QANuDhw;30luC zEd9Bl5~hNRH!SJ9u}evj(a;7e3{p*%4?898OX8gED^P;Tj)u=mm#x+AAYyBn4ILQ~PvZk8!e zm7X3|#v97>?Q()lFY6MQsCG9waABcB~&f`R$zdx_Y z?S~~;+g?hjC*OBhkWbYq+|Y87^ihy!n*tHe2GVZ28gZz9g=X%|`BB^tWOqKu`(r`3V)B`M^hVB)KQrDl zW1XA>y<5^#!7Yck#_fjZ_FA4-Rizp&4%6X>=jNvWg-WMUs|wLy-*sMGo|9^x-Bfl0 zFD=9$`FJLv6OG_Y?aTWc`BzVqeHH8zr{uR0w~n4kye9hYy%gpkJcZiF3I8zV29~<1 zwrj_w6Qnh{$8v(0!H%9K)x0iQ$2b*s*K)^&EH8YRD!GY`@Ts_)wCYvw4~vdWcU3zl z-s9sD7UwAcpd2J@0`nl>OFU#Z91#>#Lh!_h);MR{|Mf?AVu$n{-o|~FPYYFKoEH2) zaw+j?X&#}myE?6DOjbO-Z{mA}>Vo)IAgae}gGtl)MXP%_2Wcea?;e{C9Qt=!SH#cR z4K!A)v-}=PC#DERTJ&Z*gT@C{Ib->r!mELTKP5XqKtInWwIbt9i_euo=xMo=0bYvtE9e+F}#|` zSg%L3j(wETj#qthHF+)d8g^1b zy!LVVM9>cQ^Lhn*`^MMI!`Gnb1t;2xXp@&x#%q|HhNU;3rgR>72Kf8_7?1C@<Q=6@Zn<4==R!@va0U9V>pn>C2+N9!8{N0sX?^xMKNYL@442-TmumGlosC>Y zp=XNxvU**b$BL)O{>`nBsj~3>$|e0YS`=_I{tBg&#;t)~PjkR|jd^2%raNb`1xB%b z`io}5aP0HIoIr9$XjxJE#eUBwt)I_u=}D@qE5^D_*0Yxq=JA>6f%l2rF);oq`^op4 z&oqzEq!mI;KjHUL*>LJm&a`Ew9ljSe9>@pn_2~LCT(2dr-lpA_P7ZYw^f^WSO;u4E zZ#1uLuG>QO48B`wDLa-b3^tu0^T_7WJ}kNVGOnpIRa_Hyf5xcRJ)mTU+8)B^`v18O?*sTOGd!ze|VnfE~a^Y@l|34Vs?!$#`1vHv5ykg(R$t! z3r-$^`73cQjLsGf>r-L9%q#vR2-Lc1)qdjNgZll5*Q9!Y{y$WYo7QJD{;AG6m1urn zA`6Y?%h3dtcEiubiq)Q{R?5 zU@bc-BVHq4VqhlOr7)1yL?K-Ow>rP%c z?~c@bp1I;yFrwA=mffP4g?abJkNj0Upr^w3tQ+gg@1ulu>LRJl|3oY}H7Tiwe@D(h zv+Q$OcF;{_BOW^%2dWyWy;^hZib7-VRo9S=2H({9x!rEshPmuE)vnK76+6gKmc>`b zGl7vpIsdSo7{mCj++fNX`X{&io!A z7uC+iJm&%ro}MRf9QRHSOS)!xJUw*1T6Vkm)P!dvJT*)q^ZJB!+z@NuVd;F}^)mrg zmCvQl)vY7fT)xsf(Ja8+a4J5P`{BXPq5OL!_r$%Of0BEF-b8dXy1VlS_ubFs`)fQ0 z>)1yL?da5~has1Rf-Pq2>F?NXgL!TPn|`AG8a*>l{m5gn>~w(uN1L<<>#+K3*+~iS zI*%R28i+qk@QxOz;e8&wdz%=?k<=ohbfz2P`mw%-U6gQ6%nQn?)+Of}+x2CqTutRY zth3G$&ho7wxt`P6CeCL~yD8yb?K>)bG&y$c$g>8g%W`yH+~Bel%B zYiLGQKvg2OCCtr^-x^yp)oqe?(aH0z+mV4vv&7S{x`brywSd|kt$W(*yrFn56o>bB zoOMrYLacX=GLoMQ=km31^zbcTXB^8WjLpTvuXSgo(}0(vbyKP#PW|&EvGmPLna4{( zv#zt1_~8lDlJAA%Osj$8e$3PX$Fl-{J6g^9_WuoPrwlHiTLZTs@wVDMGS5BoAKh2o zpT&yDwSv~Y0X~y?Vkmx6Ps?X*OPXVQUhP*NKF<`@R`%PL+(ilL=ykBrSC4(3#xTP!*ENY>p!{3+Hjtp z9)A*)i;Cwh*;$I~Wqn21SoOH;+D{q%==JGOi{2S6Pa0ph?g~?#!JIWsHJW4t=z?`3 zS_b+YZleHWhKM zjW7AshJD4aPDr5__&bMIi%0b=>_=xIxAo&-eEqvBodm45sxj#nh0Z3n;*Hgu&a=4; zF`->g>qT^~C>bo@^&Z|5&lxKZN5d@u+L<1t>IRg+OvNxLND`#1gBoF~K>LE}~69N}}GINMLO`&O_|o)>;n702g-Za5R~ z9pyK|_qa5o`bs&AHh*D$g-@Kdo z;#QliX_h%u+hdVIORh$+n01*5cK$V&P>c_wy#c{5I^!6{O7^QlY$ppmB52%3T(Tg=CB=R~ngRz4pPbxygSGWPJB@e&TihNkKk@}sSP z*>va&<11xE;IrdyWy+};GIcGQ=K(9AGiLg{Uv1sU@EK4c=DF3eV#6iZUP85TgY*kH zPP_u0cG-O2seIoM)4r#A*nh7-qRkRN6(;4KSZdYUayF=JMQ4lsMf(zGIQvI|>)lNa z_gHbNuJI(|K6z~-)Rf+Eh!ng5a_V@z!_m%^L7q`PllXQ(=gUM9t?e6u)#r}B1_#Pk*3#^*Lefj^He4mO4bhG4U;Hl}Z z!K`}NZ?ocQhUJmd*n(!C-AQvxmhI_p(bu+z62@Wf@Wpku4Hi9)2+88i<-z>r;y0nZ ze${;^uML``kGco)KGxsTv${D~270JnR&A1DC$v=H$os{bVX?_Y$}jl3H6A;(9%uV^ zUBVo;6y+6TEK5 z@)W-l^kTDK%R8A1EM;0diOqc6{owYf(H|Ae>doqe?9h8I?G;-%acKE7VSrW@=MS4V|HQYd6#Nqq9Dd(p$;f zo=H6OLSj9lDk?$H%EugOpNJ`bUSn~6y%llX`Xi|A{ri;8omK3TuMT}e^q**djv7bd zkbhlXq;&E$S|{s(KCQ%AScN%19iJ9|3UBVoySaa#(#gYb#ABpFI6QfDaYkL*ZoEEx zWa-@H+~DSOM$J2HXda^-NM!bf_>UHm-M{$!u5cZ{m-l-va$}Cgk<6^v?QTgd_o@5n zuKcS$DAO$Z`JU7AgxmZ#shux6y!)X$UBqk6ryR$pR6biX0(7=Qvqy(4^wX$R z-%G|oS@-MTUOb;xrI|WK&n9@KJKR!C`*!WQc0ynS^U7rU4{}s)9oJF?YL1vNptOZwa;sSXRil6o*z!JuqGA@SOsLV9nJYgI)! zmLETj@4axh0C`?t(;Vv=^*%x;^Gcpw>!MMTDa+xt4A11Q;y0EVLHmvUPsld!w|+M8 zsM0ziP6qi}IPi8h`kakWj}xjD!0;>K<X_La8?!AxX5u6fV zv%yK^CpmHao9o{DpNVbUXYDMY2PPL3M)XXSL_5q)(au7@s6NC9+_cWe&e84p<5aDd z>Ysc~$FhiD*KX>#rq^`L5u*#%I%xiFHolLIrxUa(*t91owv`%6?C-9NoB3F+FIG37 z$`LDp&o6Q);Htk(o?~4ltdWnvnQ#+4`ti2MO7O@}t4Xvu_$Ienu4`P_1LgdH)rO9>R8}GrG zdezupeR`Lj0shz6RCVvHsML|AKmNCEkEIiE=<>fz^x_r>-_TuP{aXfjtP_B3F3r)p z`f2dIqG8W&1F~Gov}niY>reAympm)?#+YYf+jd<#C3s12h9(_3oJhIvS(2m)LyUrt|*Ff&zucD+HUY$VeJ*KWMK z&J0t}jIZ;Y{qKtH-f``8z)w=+9i9%=wZc>`*>mY;oep&2-wV2*$-lm))t?5n`=O1` z?-XKXvh&BSU|q zgjG=gqw~M{E=b4no;sFNBhj?is4@R_bdT?^uYZR%?9(YMXZFzrpb%)jNWYks*b$2g zhpF*o*cGgV^Bh4TO1;gtXf^a&@}KoSj(u;aC%*0-)zFQqKJ>EnV>&Fs$28t@3Uq^% zQoa==me}=}Ke-&~<>#0i@oU^=?G&J$MM^)2d?5 z$g+JUx0#d4y@oyMyY!{27omrY_KUeKpYL`@@-LN#pSj)_UrWu%Cz4b7#Pz>mX4q4? zJ-{E@Vb8Y@zc2Fh;U^W0?=@}j{%dE4dj%Cxc)QTQk_eiwwiu$Hmla0Prd-qcy?J*- zwem#Asn&j1a#%2xbo?&e1!4SM_t2E@=QPJkd+&9j-8jF9c~CTy53s4k{qLKb_BW`V zA+lveB;gt2W1Vo*PEfxSqKLt#p!()4uw(2k!-{9y_Pm{Z~kCaRXRU;23M%WdqcKOt!>!4yl)6jROa z`;7NT@vS?f?$-RztGb$m{n^2oaF$0MH6B#{dPsBDjQYuhY~D zCVcnjf%OKhOu^Fb|lM@LY5_@nifc2o(pu+W}cKv<*7teTb)#bG2*VXXzx++XF9| zj%?JV#HyQCwcWQ8E41k5o8TvC4!3T_^*i;7ZP0GY$XLyDnf8ph(q`!N$Ne_!tAumy z_DR+%&flt5fjgji;r*h-oH+0xth(X4bQ)4d za8J$;r-z><0px3>ECA^lzUp#24kK#-tF(nn=%lg&vYj-p7i=D+% zQ$K`H{INs0b~aE&*SZnBHxa{F-LmSI9!gArK=TJZAie<=E_-ir-j;LC(cI2=geYsCX*e_ZsoL%?F1^-t}^roM)vqTrw+9 z)oo$)&y7v*dm^glclPJZa_&kqWTE;u)Z(uNlhd!Vjz@49D=lw{-K6pyL@wE@JAQR; zhMi1bY4pL5#ZEGzp%&rCe+OUhkv>=I+l+aStLoS^^wY1pj#uq?9Nz2P>R_1Iy;;w( zt!J5aDs=^qaay|JHU9DaWYM#G)_+{Q&b{tBVnJryky6on-!Y}_#vfwY=|w|tZj_gJ znc!06ajzU8|Hcd)Kj)@yYptdN9%@KrKK-idcte92>j1dT={2BA-DV?)*+`9a;B^#p zWajBHgH}*;x4VMKGZ$6E2C0IPItjEZe1#cgAePVkgugl}$sfOw+$g_!h?QK!%Imm= zy^Phg%*?}ja=W*T($sbm1V48c6g?vK4r{cVW3RG~N2YD38BRXO1I3m$J37RU!VRkZ zy!;hKLxVmB3u=|Yb!&;|$wVWpYkzAw=lbdx!PXyOPfthejSdCOr_i!O@5MT9ll@R3+XI^0-i+XK_;*$KidijM6)I z|7$GPAHjaEq4m36*Pd!P4biK?)(PsBr2@4z%iX?FqhTk!$RzFz;8PyONk z)^;5$uj7^ulxcS`SO63yO>vjz9@Vcb=V0<$7qxbF>x0}lQZg?Ue${K7)k4ypfUZdB z?M&g%GnDY1KI?esWi4x2e;vcbVX5s^h5-~e&GRrHIK==;Bdl)BAgGOvk&GsVOaPv& za$?uVc3LIE+#R*+M1$J-BfbOr+v@GyY3*E4%aSt|R>?v}qWL7_`6OXwtVRRm&q5{* zkHp7_R0+__KD`t6g@xnixlMkS@51;JHR_}i5X!SMT^UwHd+_N`pio{Tp8WvCEd=#kcb^-gznc^>dM(EIQcLuMh*v$7iQ@W`n)^p=#5 znC1uWmhBID6Sz9EB6tC?$>1fe!nzEHpwGG}^|yrMucC%0a>LxjF`lq&Agx7s!y>%& zb>vP%BlE_w4a9F~6n>KbIXfs2)Q_YtAK>G70&SbnNjIaA zm7;QonRCWq#m_Sjc9+`ACTuHr5MrC01?md)=}pl#CAtlhA-X|g>g#&MEAN_e5LTHE z_ZlL32=BW2&X{ZEb>yN2jy+)f2j<|ygEfv~Ox(gxkpD_;s`lf6UFCHGeVR4EpU|8b zNL8yxmoBjRTx_t`s;AH9JKy%_$YRtkv+hlp1+}qi&8AV&Wx08|L%dvgwRCRU_j2by z6Agopb4;a{+u58W^L0Xb6$WY{SY2w|#+mW3ruEk`41X3!YFJ&JKaQu|FgygqalSvy zGsLPJv$Wb3?mC!G*^2(QcB!@2ut~oeG8CaNi(;KF$z(H{PcYOcK=GnhihI43i@%Ch zO%WK@V=^a-DJ0}TUUq*Ii;myHt^SilZvC+e$GwKN*RV@}!@Q%H)~ti;W>tq+)i67s zG7Q}MG2;bR=(d1@3>&BF0o4lZJEa)C<ZddN8j&k7il@e!yA$=P4C z!>ZH8&Z6ql?l|hNlxs;;^^Q+74#u~6zx6YMiZSnXPac}84=O{Omok=@g6&mZ27ZRs z+oO6&JLHxaH&AS+CAIq@!tq%2``(w~oW%2}!t9{+P#MR6*^XV-PXugU+z&u&K=9@9 zaN2no>pYbFg#0X|o_y(S#CJrh7&h;O-^cVUUP18BK8OT9>K@2DU8zwHbARb$;Je>B zA7394-T+Iky^dX-9TjrX%-hkrYIu}}-67aD9H|bjgn%^rfzKUJm@#ZSFtE5x!04|RRvsu^i ztgA9@%Hi=kTkctP^r5yQ)v_rzOV-)rrKYXu?;FIYYsuBuu#5K^Yb)?;>8(Phug&En zMj98tdHu&G+#2t^E0f(1cfOD*)nD%1+xb-9_ayFH3#!+(ryAB(>y~!9=BsEtng7#l z^$@II771yuwv?qvEp;5VbwLa|q} zUB*EB-fYI;!7*EPGKvm*9QvxMF|j(&Dr<-YdFV4kenER@(g6$qqTz8YJgVnQwz{r& z+-y(hV8P~DWetyXSHmJ&c8~w5Fw*(cbZBpQ9D+x?ZI$mb9EO>L6oKA{CC?FRh&4y8 zo!8Bq4Xqhga_l_x+$-LMQ&bV5-9#A-kASYd-Q#0MUMUA_oq6B?(gP6u>AW&D6Dfu@ z(n1ke(n_dL%VSifIR$Q)-a#G5s=EyBE%vu{x_s&SEDdE4!l)|0SvT2TP*~<-$G5Tb zudZFGbfAFFFx z|0Wc-IDg9iC85PaE2cQcJH*POMGtLjAMU5j2^jjuWB`_4e;viBDpOmG0-mqJ542cp zyjUz%70^`*t{_#wsyAEf&J+IR6n^g-ceM%cc*9{#r|Nf93}hM_-p9jx z?oZ@MH#U|^j80L^J+H#OSVx2HPRRWBdMeL7W}jB>N?fGR)<~=wbF6-i9CbmZCJ1Vw#~X%)_@Y0cuZIG(S;(GPL;O8kGlUY>-?Rp^c(s2 zyY7F=|KDGHhDzYIe3n;!p2=f%@&R5s)tkR_aUknDmyhE(;9td(Q|s}e`#1RrhFJeX c-^!kD%g%@(`AI%P$NS&iU*!GoyT9xHKb@Q?WB>pF literal 0 HcmV?d00001 diff --git a/docs/ARCH/11 - architecture_turnaround/17 - post_f_semantic_integrity_hardening_2026-04-23.md b/docs/ARCH/11 - architecture_turnaround/17 - post_f_semantic_integrity_hardening_2026-04-23.md index cdaf97c..6120ecb 100644 --- a/docs/ARCH/11 - architecture_turnaround/17 - post_f_semantic_integrity_hardening_2026-04-23.md +++ b/docs/ARCH/11 - architecture_turnaround/17 - post_f_semantic_integrity_hardening_2026-04-23.md @@ -154,7 +154,7 @@ This phase is only healthy when the following are true: 5. exact route success cannot silently degrade into a semantically wrong user answer; 6. replay verdict is based first on human business meaning, only then on technical internals. -## Current Status - 2026-04-23 +## Current Status - 2026-04-24 This phase is already active in runtime code and replay-backed. @@ -164,6 +164,10 @@ Materially hardened in this pass: - explicit one-organization open value-flow asks now stop for organization clarification instead of answering a global total under missing scope; - incoming-vs-outgoing money comparisons now defer away from one-sided exact supplier/customer recipes into the bounded bidirectional value-flow discovery path; - document asks with numeric counterparty suffixes such as `Жуковка 51` no longer collapse into bank-operation routing only because the suffix looks like account `51`; +- rejected LLM predecompose rewrites can no longer inject account scope or truncated semantic hints for numeric counterparty suffixes such as `Жуковке 51`; the session state now keeps the counterparty anchor and does not carry `account: 51`; +- explicit raw entity search after a ranking/value-flow dialogue now resets stale assistant/followup scope: `Найди в 1С Группу СВК` becomes `source_signal=raw_text` with `explicit_entity_candidates=["Группа СВК"]`, no stale organization/date/ranking scope in the discovery turn input, and downstream follow-ups then carry the grounded SVK object intentionally; +- open-organization ranked value-flow questions now stay subjectless by design: predicate-shaped entity pollution such as `принёс наибольшую выручку организации в` is discarded, referential organization placeholders such as `эта организация` are resolved through the active organization scope, and the MCP ranking answer overrides exact-lane year-summary replies when the user asked `кто`; +- ranked value-flow answer drafts no longer leak raw English/internal evidence lines into the user-facing response; - VAT exact materialization now survives period-window filtering instead of collapsing into `recipe_visibility_gap`; - confirmed VAT tax-period turns now keep raw month extraction separate from runtime tax-quarter execution, so exact VAT routes do not lose the intended tax period; - post-pivot receivables recovery now preserves the selected open-items recipe without weakening strict account-scope guards for risk replies; @@ -183,6 +187,8 @@ Replay-backed anchors for the current layer include: - `address_truth_harness_phase72_document_to_contracts_year_switch_live_rerun3` - `address_truth_harness_phase80_payments_to_contracts_to_documents_all_time_live_rerun1` - `address_truth_harness_phase82_human_mixed_integrity_status_dialog_post_m23_rerun_documents_scope_bidirectional` +- `address_truth_harness_phase82_human_mixed_integrity_status_dialog_post_f_account_injection_guard_clean_scope` +- `address_truth_harness_post_f_cross_stage_canary_agent_20260424_live5`, accepted `24/24`, and saved into autoruns as `AGENT | Post-F cross-stage semantic integrity canary` (`gen-ag04241406-abe4d8`) ## Honest Remaining Risk diff --git a/docs/ARCH/11 - architecture_turnaround/README.md b/docs/ARCH/11 - architecture_turnaround/README.md index 1c1948a..83b2927 100644 --- a/docs/ARCH/11 - architecture_turnaround/README.md +++ b/docs/ARCH/11 - architecture_turnaround/README.md @@ -36,7 +36,7 @@ This package answers the next question: 16. [16 - data_need_graph_and_open_world_mcp_plan_2026-04-22.md](./16%20-%20data_need_graph_and_open_world_mcp_plan_2026-04-22.md) 17. [17 - post_f_semantic_integrity_hardening_2026-04-23.md](./17%20-%20post_f_semantic_integrity_hardening_2026-04-23.md) -## Current Status Snapshot (2026-04-23) +## Current Status Snapshot (2026-04-24) This package is no longer planning-only. @@ -65,7 +65,7 @@ Current honest status: - pre-multidomain readiness: `~88%` - bounded-autonomy foundation readiness: `~86%` - open-world bounded-autonomy readiness: `~71%` -- graph snapshot after latest rebuild: `5886 nodes`, `12754 edges`, `136 communities` +- graph snapshot after latest rebuild: `5891 nodes`, `12769 edges`, `135 communities` - current breakpoint: - the validated hot paths are no longer structurally broken; - flagship continuity collapse is no longer the primary risk; @@ -91,6 +91,8 @@ Latest live proof now includes: - `address_truth_harness_phase72_document_to_contracts_year_switch_live_rerun3` accepted - `address_truth_harness_phase80_payments_to_contracts_to_documents_all_time_live_rerun1` accepted - `address_truth_harness_phase82_human_mixed_integrity_status_dialog_post_m23_rerun_documents_scope_bidirectional` accepted `19/19` +- `address_truth_harness_phase82_human_mixed_integrity_status_dialog_post_f_account_injection_guard_clean_scope` accepted `19/19`, with the `Жуковке 51` numeric counterparty suffix kept as counterparty scope instead of leaking as account `51` +- `address_truth_harness_post_f_cross_stage_canary_agent_20260424_live5` accepted `24/24`, proving a saved cross-stage AGENT canary across VAT metadata, numeric counterparty suffixes, open-organization value-flow clarification, ranked value-flow year switches, and SVK grounded reset; the saved autorun is `AGENT | Post-F cross-stage semantic integrity canary` (`gen-ag04241406-abe4d8`) - `address_truth_harness_phase11_manual_followup_meta_quality_live_rerun_vatfix` accepted `10/10` - `address_truth_harness_phase20_continuity_stabilization_live_rerun_vatfix` accepted `6/6` - `addressQueryRuntimeM23.test.ts` full semantic/runtime slice accepted `403/403` after Post-F VAT/date-basis, scope-recovery, open value-flow organization clarification, document-vs-bank arbitration, and reply-shape hardening diff --git a/docs/orchestration/address_truth_harness_phase82_human_mixed_integrity_status_dialog.json b/docs/orchestration/address_truth_harness_phase82_human_mixed_integrity_status_dialog.json new file mode 100644 index 0000000..4a5f448 --- /dev/null +++ b/docs/orchestration/address_truth_harness_phase82_human_mixed_integrity_status_dialog.json @@ -0,0 +1,249 @@ +{ + "schema_version": "domain_truth_harness_spec_v1", + "scenario_id": "address_truth_harness_phase82_human_mixed_integrity_status_dialog", + "domain": "address_phase82_human_mixed_integrity_status_dialog", + "title": "ARCH: Post-F Semantic Integrity Hardening mixed human status dialog", + "description": "Human-facing AGENT dialog that mixes the current Post-F repeated-pivot integrity contour with earlier bounded-autonomy contours: repeated counterparty pivots across documents, payments, and contracts; organization-scoped money analytics without a preselected counterparty; and a grounded named-counterparty money chain through incoming, payout, net, documents, and movements. The scenario uses explicit human resets between topics so the assistant must prove both continuity and clean topic switching rather than guessing vague 'continue' turns.", + "bindings": {}, + "steps": [ + { + "step_id": "step_01_documents_by_counterparty", + "title": "Open documents for the counterparty", + "question": "Покажи документы по Жуковке 51.", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)жуковк", + "(?i)документ|сч[её]т|акт|накладн|строк" + ], + "criticality": "critical", + "semantic_tags": ["post_f_integrity_hardening", "documents_by_counterparty", "pivot_seed", "human_dialog"] + }, + { + "step_id": "step_02_payments_by_pronoun_followup", + "title": "Pivot to payments", + "question": "Хорошо, а теперь платежи по нему тоже покажи.", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)жуковк|контрагент", + "(?i)платеж|операц|банк|поступлен|списан" + ], + "criticality": "critical", + "semantic_tags": ["post_f_integrity_hardening", "payments_followup", "counterparty_pronoun_resolution", "human_dialog"] + }, + { + "step_id": "step_03_contracts_after_payments_pivot", + "title": "Pivot to contracts", + "question": "А по нему договоры?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)жуковк|контрагент", + "(?i)договор|контракт|соглаш" + ], + "criticality": "critical", + "semantic_tags": ["post_f_integrity_hardening", "contracts_followup", "second_pivot", "human_dialog"] + }, + { + "step_id": "step_04_documents_after_contracts_pivot", + "title": "Pivot back to documents", + "question": "А по нему документы?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)жуковк|контрагент", + "(?i)документ|сч[её]т|акт|накладн|строк" + ], + "criticality": "critical", + "semantic_tags": ["post_f_integrity_hardening", "documents_followup", "third_pivot", "human_dialog"] + }, + { + "step_id": "step_05_payments_after_third_pivot", + "title": "Pivot back again to payments", + "question": "А по нему платежи?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)жуковк|контрагент", + "(?i)платеж|операц|банк|поступлен|списан" + ], + "criticality": "critical", + "semantic_tags": ["post_f_integrity_hardening", "payments_followup", "fourth_pivot", "human_dialog"] + }, + { + "step_id": "step_06_year_switch_after_fourth_pivot", + "title": "Switch the year after the fourth pivot", + "question": "А за 2021?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)2021", + "(?i)жуковк|контрагент", + "(?i)платеж|операц|банк|поступлен|списан" + ], + "forbidden_answer_patterns": [ + "(?i)метадан", + "(?i)схем", + "(?i)объект[а-я]* 1с" + ], + "criticality": "critical", + "semantic_tags": ["post_f_integrity_hardening", "year_switch_after_fourth_pivot", "payments_followup", "human_dialog"] + }, + { + "step_id": "step_07_open_scope_incoming_total", + "title": "Reset to organization-scoped money analytics without a preselected counterparty", + "question": "С Жуковкой закончили. Теперь нужна другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?", + "allowed_reply_types": ["clarification_required", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)уточн|нужно", + "(?i)организац" + ], + "criticality": "critical", + "semantic_tags": ["organization_scope", "open_scope_total", "topic_reset", "human_dialog"] + }, + { + "step_id": "step_08_open_scope_org_clarification", + "title": "Provide the organization and get the 2020 incoming total", + "question": "По ООО Альтернатива Плюс.", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)2020", + "(?i)входящ|поступлен|получ" + ], + "forbidden_answer_patterns": [ + "(?i)уточните .*контрагент", + "(?i)не найден контрагент", + "(?i)уточните .*организац" + ], + "criticality": "critical", + "semantic_tags": ["organization_scope", "open_scope_total", "organization_clarification", "human_dialog"] + }, + { + "step_id": "step_09_open_scope_all_time_followup", + "title": "Broaden the same organization slice to all available time", + "question": "Понял, тогда за все время.", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)все доступное время|все время|весь период", + "(?i)входящ|поступлен|получ" + ], + "forbidden_answer_patterns": [ + "(?i)за 2020", + "(?i)уточните .*контрагент", + "(?i)уточните .*период", + "(?i)уточните .*организац" + ], + "criticality": "critical", + "semantic_tags": ["organization_scope", "all_time_followup", "human_dialog"] + }, + { + "step_id": "step_10_bidirectional_comparison", + "title": "Ask which money direction is larger for the organization", + "question": "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)2020", + "(?i)входящ|исходящ|получ|заплат|больше" + ], + "criticality": "critical", + "semantic_tags": ["organization_scope", "value_flow_comparison", "human_dialog"] + }, + { + "step_id": "step_11_comparison_year_switch", + "title": "Ask the same comparison for another year", + "question": "А что по ООО Альтернатива Плюс больше уже за 2021 год: входящие или исходящие деньги?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)2021", + "(?i)входящ|исходящ|получ|заплат|больше" + ], + "criticality": "critical", + "semantic_tags": ["organization_scope", "value_flow_comparison", "year_switch", "human_dialog"] + }, + { + "step_id": "step_12_ranking_top_counterparty", + "title": "Ask who brought the most money for the organization", + "question": "И кто больше всего принес денег этой организации в 2020 году?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)2020", + "(?i)кто|контрагент|клиент|принес|доход" + ], + "criticality": "critical", + "semantic_tags": ["organization_scope", "value_flow_ranking", "human_dialog"] + }, + { + "step_id": "step_13_ranking_year_switch", + "title": "Ask the same ranking for another year", + "question": "А в 2021 году?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)2021" + ], + "criticality": "critical", + "semantic_tags": ["organization_scope", "value_flow_ranking", "year_switch", "human_dialog"] + }, + { + "step_id": "step_14_ground_named_counterparty", + "title": "Reset to a named grounded counterparty", + "question": "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК.", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)свк|группа свк|контрагент" + ], + "criticality": "critical", + "semantic_tags": ["grounded_counterparty", "topic_reset", "human_dialog"] + }, + { + "step_id": "step_15_counterparty_incoming_2020", + "title": "Ask how much money was received from the grounded counterparty", + "question": "Сколько получили по нему за 2020 год?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)2020", + "(?i)получ|входящ|поступлен" + ], + "criticality": "critical", + "semantic_tags": ["grounded_counterparty", "incoming_value_flow", "human_dialog"] + }, + { + "step_id": "step_16_counterparty_payout_followup", + "title": "Ask how much was paid to the same grounded counterparty", + "question": "А теперь сколько заплатили?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)заплат|исходящ|списан|платеж" + ], + "criticality": "critical", + "semantic_tags": ["grounded_counterparty", "payout_value_flow", "human_dialog"] + }, + { + "step_id": "step_17_counterparty_net_followup", + "title": "Ask for net after incoming and payout", + "question": "А какое нетто?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)нетто|сальдо|получ|заплат" + ], + "criticality": "critical", + "semantic_tags": ["grounded_counterparty", "net_value_flow", "human_dialog"] + }, + { + "step_id": "step_18_counterparty_documents_pivot", + "title": "Pivot from money to documents for the same counterparty", + "question": "А по документам?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)документ|счет|сч[её]т[- ]?фактур|накладн|акт|строк" + ], + "criticality": "critical", + "semantic_tags": ["grounded_counterparty", "documents_pivot", "human_dialog"] + }, + { + "step_id": "step_19_counterparty_movements_pivot", + "title": "Pivot from documents to movements for the same counterparty", + "question": "А по движениям?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": [ + "(?i)движени|операц|платеж|поступлен|списан|строк" + ], + "criticality": "critical", + "semantic_tags": ["grounded_counterparty", "movements_pivot", "human_dialog"] + } + ] +} diff --git a/docs/orchestration/address_truth_harness_post_f_cross_stage_canary_agent_20260424.json b/docs/orchestration/address_truth_harness_post_f_cross_stage_canary_agent_20260424.json new file mode 100644 index 0000000..0f7ab34 --- /dev/null +++ b/docs/orchestration/address_truth_harness_post_f_cross_stage_canary_agent_20260424.json @@ -0,0 +1,238 @@ +{ + "schema_version": "domain_truth_harness_spec_v1", + "scenario_id": "address_truth_harness_post_f_cross_stage_canary_agent_20260424", + "domain": "address_post_f_cross_stage_canary_agent", + "title": "AGENT | Post-F cross-stage semantic integrity canary", + "description": "Long human-facing AGENT dialog for the end of Post-F Semantic Integrity Hardening. It deliberately crosses older validated contours and the current fix surface in one session: VAT/metadata orientation, movement-to-document pivots, numeric counterparty suffix scope, repeated documents/payments/contracts pivots, organization open-scope clarification, bidirectional value-flow, ranking, grounded SVK counterparty chains, and final document/movement pivots. The goal is to catch stale scope, account injection, wrong post-pivot arbitration, materialization gaps, and regressions in older bounded MCP stages before saving the run into autoruns.", + "bindings": {}, + "steps": [ + { + "step_id": "step_01_vat_metadata_orientation", + "title": "Orient inside VAT objects", + "question": "Мне нужно понять, где в 1С по НДС вообще лежат данные. Какие объекты стоит смотреть по НДС?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)ндс", "(?i)метадан|metadata|документ|регистр|объект"], + "criticality": "critical", + "semantic_tags": ["legacy_phase64", "metadata_surface", "vat_orientation", "cross_stage_canary"] + }, + { + "step_id": "step_02_vat_movements_org_needs_period", + "title": "Choose movement lane and organization", + "question": "Хорошо, тогда покажи движения по ООО Альтернатива Плюс.", + "allowed_reply_types": ["clarification_required", "partial_coverage", "factual_with_explanation"], + "required_answer_patterns_all": ["(?i)движени|регистр|операц|период|уточн"], + "criticality": "critical", + "semantic_tags": ["legacy_phase64", "movement_lane_after_metadata", "organization_scope"] + }, + { + "step_id": "step_03_vat_movements_2020", + "title": "Provide the period", + "question": "За 2020 год.", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)2020", "(?i)ндс|движени|регистр|операц|строк|поступлен|списан"], + "criticality": "critical", + "semantic_tags": ["legacy_phase64", "movement_execution", "period_clarification_resume"] + }, + { + "step_id": "step_04_vat_documents_pivot", + "title": "Pivot from movements to documents", + "question": "А теперь по документам?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)документ|счет|сч[её]т|накладн|акт|строк"], + "forbidden_answer_patterns": ["(?i)уточните .*организац", "(?i)уточните .*период"], + "criticality": "critical", + "semantic_tags": ["legacy_phase64", "document_pivot_after_movement", "scope_reuse"] + }, + { + "step_id": "step_05_vat_documents_year_switch", + "title": "Switch document slice to another year", + "question": "А теперь за 2021 год?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)2021", "(?i)документ|счет|сч[её]т|накладн|акт|строк"], + "forbidden_answer_patterns": ["(?i)уточните .*организац", "(?i)уточните .*период"], + "criticality": "critical", + "semantic_tags": ["legacy_phase64", "year_switch_after_document_pivot"] + }, + { + "step_id": "step_06_vat_documents_all_time", + "title": "Broaden document slice to all available time", + "question": "А теперь за все время?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)все доступное время|все время|весь период|истори", "(?i)документ|счет|сч[её]т|накладн|акт|строк"], + "forbidden_answer_patterns": ["(?i)уточните .*период"], + "criticality": "critical", + "semantic_tags": ["legacy_phase64", "all_time_followup", "document_lane_continuity"] + }, + { + "step_id": "step_07_reset_to_numeric_counterparty_documents", + "title": "Reset to numeric counterparty suffix documents", + "question": "С НДС закончили. Новая тема: покажи документы по Жуковке 51.", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)жуковк", "(?i)документ|счет|сч[её]т|накладн|акт|строк"], + "forbidden_answer_patterns": ["(?i)счет 51", "(?i)account 51"], + "criticality": "critical", + "semantic_tags": ["post_f", "numeric_counterparty_suffix", "account_injection_guard", "topic_reset"] + }, + { + "step_id": "step_08_numeric_counterparty_payments", + "title": "Pivot numeric counterparty to payments", + "question": "Хорошо, а теперь платежи по нему тоже покажи.", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)жуковк|контрагент", "(?i)платеж|операц|банк|поступлен|списан"], + "criticality": "critical", + "semantic_tags": ["post_f", "counterparty_pronoun_resolution", "payments_followup"] + }, + { + "step_id": "step_09_numeric_counterparty_contracts", + "title": "Pivot numeric counterparty to contracts", + "question": "А по нему договоры?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)жуковк|контрагент", "(?i)договор|контракт|соглаш"], + "criticality": "critical", + "semantic_tags": ["post_f", "contracts_followup", "repeated_pivot"] + }, + { + "step_id": "step_10_numeric_counterparty_documents_again", + "title": "Pivot back to documents again", + "question": "А по нему документы?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)жуковк|контрагент", "(?i)документ|счет|сч[её]т|накладн|акт|строк"], + "criticality": "critical", + "semantic_tags": ["post_f", "documents_followup", "repeated_pivot"] + }, + { + "step_id": "step_11_numeric_counterparty_year_switch", + "title": "Switch numeric counterparty active lane to 2021", + "question": "А за 2021?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)2021", "(?i)жуковк|контрагент"], + "criticality": "critical", + "semantic_tags": ["post_f", "year_switch_after_repeated_pivot"] + }, + { + "step_id": "step_12_open_org_money_requires_clarification", + "title": "Reset to open organization-scoped value flow", + "question": "С Жуковкой закончили. Теперь другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?", + "allowed_reply_types": ["clarification_required", "partial_coverage"], + "required_answer_patterns_all": ["(?i)уточн|нужно", "(?i)организац"], + "criticality": "critical", + "semantic_tags": ["post_f", "open_scope_total", "organization_clarification", "topic_reset"] + }, + { + "step_id": "step_13_open_org_clarification_answer", + "title": "Provide organization for open money slice", + "question": "По ООО Альтернатива Плюс.", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)2020|проверенн|строк", "(?i)входящ|поступлен|получ"], + "forbidden_answer_patterns": ["(?i)уточните .*контрагент", "(?i)уточните .*организац"], + "criticality": "critical", + "semantic_tags": ["post_f", "organization_scope", "clarification_resume"] + }, + { + "step_id": "step_14_open_org_all_time", + "title": "Broaden same organization money slice", + "question": "Понял, тогда за все время.", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)все доступное время|все время|весь период|истори", "(?i)входящ|поступлен|получ"], + "forbidden_answer_patterns": ["(?i)уточните .*контрагент", "(?i)уточните .*организац"], + "criticality": "critical", + "semantic_tags": ["post_f", "organization_scope", "all_time_followup"] + }, + { + "step_id": "step_15_open_org_bidirectional_2020", + "title": "Bidirectional comparison for organization", + "question": "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)2020", "(?i)входящ|исходящ|получ|заплат|больше"], + "criticality": "critical", + "semantic_tags": ["post_f", "bidirectional_value_flow", "organization_scope"] + }, + { + "step_id": "step_16_open_org_ranking_2020", + "title": "Ranking after organization comparison", + "question": "И кто больше всего принес денег этой организации в 2020 году?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)2020", "(?i)кто|контрагент|клиент|принес|доход|поступлен"], + "criticality": "critical", + "semantic_tags": ["legacy_phase39", "value_flow_ranking", "organization_scope"] + }, + { + "step_id": "step_17_open_org_ranking_year_switch", + "title": "Ranking year switch", + "question": "А в 2021 году?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)2021"], + "criticality": "critical", + "semantic_tags": ["legacy_phase39", "year_switch", "organization_scope"] + }, + { + "step_id": "step_18_ground_svk_counterparty", + "title": "Reset to grounded SVK counterparty", + "question": "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК.", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)свк", "(?i)контрагент|каталог|1с|заземл"], + "criticality": "critical", + "semantic_tags": ["legacy_phase67", "grounded_counterparty", "topic_reset"] + }, + { + "step_id": "step_19_svk_incoming_2020", + "title": "SVK incoming value flow", + "question": "Сколько получили по нему за 2020 год?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)2020", "(?i)свк|контрагент|входящ|поступлен|получ"], + "forbidden_answer_patterns": ["(?i)жуковк"], + "criticality": "critical", + "semantic_tags": ["legacy_phase67", "grounded_counterparty", "incoming_value_flow"] + }, + { + "step_id": "step_20_svk_payout", + "title": "SVK outgoing value flow", + "question": "А теперь сколько заплатили?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)свк|контрагент|заплат|исходящ|списан|платеж"], + "forbidden_answer_patterns": ["(?i)жуковк"], + "criticality": "critical", + "semantic_tags": ["legacy_phase67", "grounded_counterparty", "payout_value_flow"] + }, + { + "step_id": "step_21_svk_net", + "title": "SVK net value flow", + "question": "А какое нетто?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)свк|контрагент|нетто|сальдо|получ|заплат"], + "forbidden_answer_patterns": ["(?i)жуковк"], + "criticality": "critical", + "semantic_tags": ["legacy_phase67", "grounded_counterparty", "net_value_flow"] + }, + { + "step_id": "step_22_svk_documents_pivot", + "title": "SVK documents pivot", + "question": "А по документам?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)свк|контрагент|документ|счет|сч[её]т|накладн|акт|строк"], + "forbidden_answer_patterns": ["(?i)жуковк"], + "criticality": "critical", + "semantic_tags": ["legacy_phase67", "grounded_counterparty", "documents_pivot"] + }, + { + "step_id": "step_23_svk_movements_pivot", + "title": "SVK movements pivot", + "question": "А по движениям?", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)свк|контрагент|движени|операц|платеж|поступлен|списан|строк"], + "forbidden_answer_patterns": ["(?i)жуковк"], + "criticality": "critical", + "semantic_tags": ["legacy_phase67", "grounded_counterparty", "movements_pivot"] + }, + { + "step_id": "step_24_svk_year_switch", + "title": "SVK year switch", + "question": "А теперь тот же смысл за 2021 год.", + "allowed_reply_types": ["factual", "factual_with_explanation", "partial_coverage"], + "required_answer_patterns_all": ["(?i)2021", "(?i)свк|контрагент"], + "forbidden_answer_patterns": ["(?i)жуковк"], + "criticality": "critical", + "semantic_tags": ["legacy_phase67", "grounded_counterparty", "year_switch"] + } + ] +} diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryAnswerAdapter.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryAnswerAdapter.js index 18a9aab..c52b63e 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryAnswerAdapter.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryAnswerAdapter.js @@ -52,6 +52,14 @@ function isInternalMechanicsLine(value) { function userFacingUnknowns(values) { return uniqueStrings(values).filter((value) => !isInternalMechanicsLine(value)); } +function rankedValueFlowUnknownLines(pilot) { + if (!pilot.derived_ranked_value_flow) { + return userFacingUnknowns(pilot.evidence.unknown_facts); + } + const ranking = pilot.derived_ranked_value_flow; + const period = ranking.period_scope ? `периода ${ranking.period_scope}` : "проверенного окна"; + return [`Полный рейтинг контрагентов вне ${period} этим поиском не подтвержден.`]; +} function userFacingLimitations(values) { return uniqueStrings(values).filter((value) => !isInternalMechanicsLine(value)); } @@ -718,13 +726,15 @@ function buildAssistantMcpDiscoveryAnswerDraft(pilot) { if (monthlyConfirmedLines.length > 0) { pushReason(reasonCodes, "answer_contains_monthly_breakdown"); } - const confirmedLines = derivedValueLine - ? [...pilot.evidence.confirmed_facts, derivedValueLine, ...monthlyConfirmedLines] - : derivedEntityResolutionLine - ? [...pilot.evidence.confirmed_facts, derivedEntityResolutionLine] - : derivedMetadataLine - ? [...pilot.evidence.confirmed_facts, derivedMetadataLine] - : pilot.evidence.confirmed_facts; + const confirmedLines = pilot.derived_ranked_value_flow && derivedValueLine + ? [derivedValueLine] + : derivedValueLine + ? [...pilot.evidence.confirmed_facts, derivedValueLine, ...monthlyConfirmedLines] + : derivedEntityResolutionLine + ? [...pilot.evidence.confirmed_facts, derivedEntityResolutionLine] + : derivedMetadataLine + ? [...pilot.evidence.confirmed_facts, derivedMetadataLine] + : pilot.evidence.confirmed_facts; return { schema_version: exports.ASSISTANT_MCP_DISCOVERY_ANSWER_DRAFT_SCHEMA_VERSION, policy_owner: "assistantMcpDiscoveryAnswerAdapter", @@ -732,7 +742,7 @@ function buildAssistantMcpDiscoveryAnswerDraft(pilot) { headline: headlineFor(mode, pilot), confirmed_lines: uniqueStrings(confirmedLines), inference_lines: uniqueStrings(inferenceLines), - unknown_lines: userFacingUnknowns(pilot.evidence.unknown_facts), + unknown_lines: rankedValueFlowUnknownLines(pilot), limitation_lines: userFacingLimitations([...pilot.query_limitations, ...pilot.evidence.query_limitations]), next_step_line: nextStepFor(mode, pilot), internal_mechanics_allowed: false, diff --git a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryTurnInputAdapter.js b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryTurnInputAdapter.js index 6e69bc6..8581fdb 100644 --- a/llm_normalizer/backend/dist/services/assistantMcpDiscoveryTurnInputAdapter.js +++ b/llm_normalizer/backend/dist/services/assistantMcpDiscoveryTurnInputAdapter.js @@ -59,9 +59,42 @@ function isReferentialEntityPlaceholder(value) { "этом" ]).has((0, addressTextRepair_1.normalizeRussianComparableText)(value)); } +function isReferentialOrganizationPlaceholder(value) { + if (!value) { + return false; + } + return new Set([ + "эта организация", + "этой организации", + "этой организацией", + "эту организацию", + "эта компания", + "этой компании", + "этой компанией", + "эту компанию", + "наша организация", + "нашей организации", + "нашей компанией" + ]).has((0, addressTextRepair_1.normalizeRussianComparableText)(value)); +} +function isValueFlowPredicateEntityCandidate(value) { + if (!value) { + return false; + } + const text = compactLower(value); + const looksLikeRankingPredicate = /(?:прин[её]с|принес|выручк|доходн|больше\s+всего|наибольш)/iu.test(text) && + /(?:организац|компан|ден[её]г|выручк|поступлен|плат[её]ж)/iu.test(text); + if (!looksLikeRankingPredicate) { + return false; + } + return !/(?= 0; index -= 1) { @@ -1226,11 +1286,16 @@ function buildAssistantMcpDiscoveryTurnInput(input) { (clarificationLoopStillNeedsPeriod || openScopeValueFlowWithoutResolvedCounterparty || (valueFlowOrganizationStaysScope && (Boolean(followupSeed.rankingNeed) || bidirectionalValueFlowSignal)))); - const normalizedPredecomposeDateScope = suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(predecomposeDateScope) ? null : predecomposeDateScope; - const normalizedAssistantTurnMeaningDateScope = suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(assistantTurnMeaningDateScope) + const normalizedPredecomposeDateScope = (rawEntitySearchOverridesStaleScope && !currentTurnCarriesExplicitPeriod) || + (suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(predecomposeDateScope)) + ? null + : predecomposeDateScope; + const normalizedAssistantTurnMeaningDateScope = rawEntitySearchOverridesStaleScope || + (suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(assistantTurnMeaningDateScope)) ? null : assistantTurnMeaningDateScope; - const normalizedFollowupDateScope = suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(followupSeed.dateScope) + const normalizedFollowupDateScope = rawEntitySearchOverridesStaleScope || + (suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(followupSeed.dateScope)) ? null : followupSeed.dateScope; const explicitDateScope = rawAllTimeScopeSignal @@ -1277,7 +1342,9 @@ function buildAssistantMcpDiscoveryTurnInput(input) { ? metadataActionFromRawText(rawText) ?? seededAction : rawAction ?? seededAction, asked_aggregation_axis: monthlyAggregationSignal ? "month" : rawAggregationAxis, - seeded_ranking_need: valueFlowSignal && followupSeed.rankingNeed ? followupSeed.rankingNeed : undefined, + seeded_ranking_need: valueFlowSignal && followupSeed.rankingNeed && !rawEntitySearchOverridesStaleScope + ? followupSeed.rankingNeed + : undefined, explicit_entity_candidates: entityCandidates, metadata_ambiguity_entity_sets: metadataAmbiguityLaneClarificationApplicable && followupSeed.metadataAmbiguityEntitySets.length > 0 ? followupSeed.metadataAmbiguityEntitySets @@ -1381,28 +1448,30 @@ function buildAssistantMcpDiscoveryTurnInput(input) { groundedValueFlowFollowupApplicable }); const hasTurnMeaning = Object.keys(cleanTurnMeaning).length > 0; - const sourceSignal = assistantTurnMeaning - ? "assistant_turn_meaning" - : followupDiscoverySeedApplicable || - Boolean(entityResolutionClarificationCandidate) || - effectiveMetadataFollowupSeedApplicable || - metadataAmbiguityLaneClarificationApplicable - ? "followup_context" - : metadataGroundedMovementLaneApplicable + const sourceSignal = rawEntitySearchOverridesStaleScope + ? "raw_text" + : assistantTurnMeaning + ? "assistant_turn_meaning" + : followupDiscoverySeedApplicable || + Boolean(entityResolutionClarificationCandidate) || + effectiveMetadataFollowupSeedApplicable || + metadataAmbiguityLaneClarificationApplicable ? "followup_context" - : metadataGroundedDocumentLaneApplicable + : metadataGroundedMovementLaneApplicable ? "followup_context" - : predecomposeContract - ? "predecompose_contract" - : lifecycleSignal - ? "raw_text" - : valueFlowSignal + : metadataGroundedDocumentLaneApplicable + ? "followup_context" + : predecomposeContract + ? "predecompose_contract" + : lifecycleSignal ? "raw_text" - : entityResolutionSignal + : valueFlowSignal ? "raw_text" - : rawMetadataSignal || effectiveMetadataFollowupSeedApplicable + : entityResolutionSignal ? "raw_text" - : "none"; + : rawMetadataSignal || effectiveMetadataFollowupSeedApplicable + ? "raw_text" + : "none"; if (lifecycleSignal) { pushReason(reasonCodes, "mcp_discovery_lifecycle_signal_detected"); } @@ -1521,7 +1590,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) { normalizedPredecomposeCounterparty) { pushReason(reasonCodes, "mcp_discovery_counterparty_from_predecompose"); } - if (followupSeed.counterparty) { + if (followupSeed.counterparty && !rawEntitySearchOverridesStaleScope) { pushReason(reasonCodes, "mcp_discovery_counterparty_from_followup_context"); } if (followupDateScopeApplied) { diff --git a/llm_normalizer/backend/dist/services/assistantService.js b/llm_normalizer/backend/dist/services/assistantService.js index a96d7f4..55a284f 100644 --- a/llm_normalizer/backend/dist/services/assistantService.js +++ b/llm_normalizer/backend/dist/services/assistantService.js @@ -1932,7 +1932,7 @@ function textMojibakeScoreForAddress(value) { const source = String(value ?? ""); const cyrillic = (source.match(/[А-Яа-яЁё]/g) ?? []).length; const latin = (source.match(/[A-Za-z]/g) ?? []).length; - const hardMarkers = (source.match(/[Ѓѓ‚„…†‡€‰‹ЉЊЌЋЏ�?’“”•–—™љ›њќћџ]/g) ?? []).length; + const hardMarkers = (source.match(/[Ѓѓ‚„…†‡€‰‹ЉЊЌЋЏ\uFFFD?’“”•–—™љ›њќћџ]/g) ?? []).length; const pairMarkers = (source.match(/(?:Р.|С.|Ð.|Ñ.)/g) ?? []).length; const doubleEncodedMarkers = (source.match(/(?:Г[Ђ-џ]|В[Ђ-џ]|Ã.|Â.)/gu) ?? []).length; return cyrillic + latin - hardMarkers * 3 - pairMarkers * 2 - doubleEncodedMarkers * 2; @@ -1942,7 +1942,7 @@ function looksLikeMojibakeForAddress(value) { if (!source.trim()) { return false; } - if (/[Ѓѓ‚„…†‡€‰‹ЉЊЌЋЏ�?’“”•–—™љ›њќћџ]/.test(source)) { + if (/[Ѓѓ‚„…†‡€‰‹ЉЊЌЋЏ\uFFFD?’“”•–—™љ›њќћџ]/.test(source)) { return true; } if ((source.match(/(?:Р.|С.|Ð.|Ñ.)/g) ?? []).length >= 2) { @@ -2173,7 +2173,7 @@ function normalizeCounterpartyForFollowupMatch(value) { return compactWhitespace(repairAddressMojibake(String(value ?? "")) .toLowerCase() .replace(/ё/g, "е") - .replace(/[«»"'`“”„’�?]/g, " ") + .replace(/[«»"'`“”„’\uFFFD?]/g, " ") .replace(/[^a-zа-я0-9\s._-]+/giu, " ")); } function normalizeCounterpartyTokenForFollowupMatch(value) { @@ -2219,7 +2219,7 @@ function extractDisplayedAddressEntityCandidates(replyText, entityType = "unknow if (parts.length >= 2 && /^\d{4}-\d{2}-\d{2}/.test(parts[0] ?? "")) { counterpartyCandidate = parts[1] ?? counterpartyCandidate; } - const cleanedCandidate = compactWhitespace(counterpartyCandidate.replace(/^["'«»“”„`’�?]+|["'«»“”„`’�?]+$/gu, "")); + const cleanedCandidate = compactWhitespace(counterpartyCandidate.replace(/^["'«»“”„`’\uFFFD?]+|["'«»“”„`’\uFFFD?]+$/gu, "")); if (!cleanedCandidate || cleanedCandidate.length < 2) { continue; } @@ -3268,6 +3268,11 @@ function hasSameDateAccountFollowupSignalForPredecompose(text) { /(?:^|\s)по\s+\d{2}(?:[.,]\d{1,2})?(?=$|[\s,.;:!?])/iu.test(source) || /\b\d{2}(?:[.,]\d{1,2})\b/u.test(source)); } +function isCounterpartyDrilldownIntentForPredecompose(intent) { + return intent === "list_documents_by_counterparty" || + intent === "bank_operations_by_counterparty" || + intent === "list_contracts_by_counterparty"; +} function hasPredecomposeDiagnosticUncertaintyLead(text) { const normalized = compactWhitespace(repairAddressMojibake(String(text ?? "")).toLowerCase()); if (!normalized) { @@ -3486,8 +3491,16 @@ async function runAddressLlmPreDecompose(normalizerService, payload, userMessage const sourceHasExplicitAccountAnchor = (0, addressIntentResolver_1.hasAccountNumberAnchor)(repairedSourceMessage || userMessage) || (0, addressIntentResolver_1.hasCompactAccountCodeToken)(repairedSourceMessage || userMessage); const candidateInjectsAccountAnchor = Boolean(toNonEmptyString(candidatePredecomposeContract?.entities?.account)); - if (sourceIntentResolution.intent === "inventory_on_hand_as_of_date" && - candidateIntentResolution.intent === "inventory_on_hand_as_of_date" && + const sourceAnchorQuality = evaluateAddressAnchorQuality(repairedSourceMessage || userMessage); + const candidateAccountInjectedIntoCounterpartyAnchor = isCounterpartyDrilldownIntentForPredecompose(sourceIntentResolution.intent) && + sourceIntentResolution.intent === candidateIntentResolution.intent && + sourceAnchorQuality.anchorType === "counterparty" && + sourceAnchorQuality.quality >= 2 && + !sourceHasExplicitAccountAnchor && + candidateInjectsAccountAnchor; + if (((sourceIntentResolution.intent === "inventory_on_hand_as_of_date" && + candidateIntentResolution.intent === "inventory_on_hand_as_of_date") || + candidateAccountInjectedIntoCounterpartyAnchor) && !sourceHasExplicitAccountAnchor && candidateInjectsAccountAnchor) { return attachAddressPredecomposeContract({ @@ -3500,10 +3513,9 @@ async function runAddressLlmPreDecompose(normalizerService, payload, userMessage reason: "normalized_fragment_rejected_anchor_injection", fallbackRuleHit: null, sanitizedUserMessage, - semanticHints: candidateMeta?.semanticHints ?? null + semanticHints: null }, userMessage); } - const sourceAnchorQuality = evaluateAddressAnchorQuality(repairedSourceMessage || userMessage); const candidateAnchorQuality = evaluateAddressAnchorQuality(candidate); const sameIntentForAnchorSafety = sourceAnchorQuality.intent !== "unknown" && sourceAnchorQuality.intent === candidateAnchorQuality.intent; const sourceSelectedObjectItemAnchorValue = toNonEmptyString((0, addressFilterExtractor_1.extractSelectedObjectQuotedValue)(userMessage)) ?? diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryAnswerAdapter.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryAnswerAdapter.ts index b6d933e..8b8469a 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryAnswerAdapter.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryAnswerAdapter.ts @@ -82,6 +82,15 @@ function userFacingUnknowns(values: string[]): string[] { return uniqueStrings(values).filter((value) => !isInternalMechanicsLine(value)); } +function rankedValueFlowUnknownLines(pilot: AssistantMcpDiscoveryPilotExecutionContract): string[] { + if (!pilot.derived_ranked_value_flow) { + return userFacingUnknowns(pilot.evidence.unknown_facts); + } + const ranking = pilot.derived_ranked_value_flow; + const period = ranking.period_scope ? `периода ${ranking.period_scope}` : "проверенного окна"; + return [`Полный рейтинг контрагентов вне ${period} этим поиском не подтвержден.`]; +} + function userFacingLimitations(values: string[]): string[] { return uniqueStrings(values).filter((value) => !isInternalMechanicsLine(value)); } @@ -856,7 +865,9 @@ export function buildAssistantMcpDiscoveryAnswerDraft( if (monthlyConfirmedLines.length > 0) { pushReason(reasonCodes, "answer_contains_monthly_breakdown"); } - const confirmedLines = derivedValueLine + const confirmedLines = pilot.derived_ranked_value_flow && derivedValueLine + ? [derivedValueLine] + : derivedValueLine ? [...pilot.evidence.confirmed_facts, derivedValueLine, ...monthlyConfirmedLines] : derivedEntityResolutionLine ? [...pilot.evidence.confirmed_facts, derivedEntityResolutionLine] @@ -871,7 +882,7 @@ export function buildAssistantMcpDiscoveryAnswerDraft( headline: headlineFor(mode, pilot), confirmed_lines: uniqueStrings(confirmedLines), inference_lines: uniqueStrings(inferenceLines), - unknown_lines: userFacingUnknowns(pilot.evidence.unknown_facts), + unknown_lines: rankedValueFlowUnknownLines(pilot), limitation_lines: userFacingLimitations([...pilot.query_limitations, ...pilot.evidence.query_limitations]), next_step_line: nextStepFor(mode, pilot), internal_mechanics_allowed: false, diff --git a/llm_normalizer/backend/src/services/assistantMcpDiscoveryTurnInputAdapter.ts b/llm_normalizer/backend/src/services/assistantMcpDiscoveryTurnInputAdapter.ts index 2c5494c..ab358ae 100644 --- a/llm_normalizer/backend/src/services/assistantMcpDiscoveryTurnInputAdapter.ts +++ b/llm_normalizer/backend/src/services/assistantMcpDiscoveryTurnInputAdapter.ts @@ -102,9 +102,46 @@ function isReferentialEntityPlaceholder(value: string): boolean { ]).has(normalizeRussianComparableText(value)); } +function isReferentialOrganizationPlaceholder(value: string | null): boolean { + if (!value) { + return false; + } + return new Set([ + "эта организация", + "этой организации", + "этой организацией", + "эту организацию", + "эта компания", + "этой компании", + "этой компанией", + "эту компанию", + "наша организация", + "нашей организации", + "нашей компанией" + ]).has(normalizeRussianComparableText(value)); +} + +function isValueFlowPredicateEntityCandidate(value: string | null): boolean { + if (!value) { + return false; + } + const text = compactLower(value); + const looksLikeRankingPredicate = + /(?:прин[её]с|принес|выручк|доходн|больше\s+всего|наибольш)/iu.test(text) && + /(?:организац|компан|ден[её]г|выручк|поступлен|плат[её]ж)/iu.test(text); + if (!looksLikeRankingPredicate) { + return false; + } + return !/(? | nul organization: string | null; } { const entities = toRecordObject(predecompose?.entities); + const organization = toNonEmptyString(entities?.organization); return { counterparty: toNonEmptyString(entities?.counterparty), - organization: toNonEmptyString(entities?.organization) + organization: isReferentialOrganizationPlaceholder(organization) ? null : organization }; } @@ -767,7 +811,7 @@ function hasMetadataDownstreamContinuationSignal(text: string): boolean { function hasEntityResolutionSignal(text: string): boolean { const hasSearchVerb = /(?:найд(?:и|ите|ем|у)|поищ(?:и|ите|ем)|найти|поиск|search|find|look\s*up)/iu.test(text); const hasEntityNoun = - /(?:контрагент(?:а|ов)?|поставщик(?:а|ов)?|клиент(?:а|ов)?|counterpart(?:y|ies)|supplier(?:s)?|customer(?:s)?)/iu.test( + /(?:контрагент(?:а|ов|у|ом|е)?|поставщик(?:а|ов|у|ом|е)?|клиент(?:а|ов|у|ом|е)?|counterpart(?:y|ies)|supplier(?:s)?|customer(?:s)?)/iu.test( text ); return hasSearchVerb && hasEntityNoun; @@ -777,8 +821,9 @@ function normalizeEntityResolutionCandidate(value: string): string { return value .replace(/^(?:в\s*1с\s+|в\s+1c\s+|по\s+имени\s+)/iu, "") .replace(/[?!.]+$/gu, "") - .replace(/^(?:контрагент(?:а|ов)?|поставщик(?:а|ов)?|клиент(?:а|ов)?)\s+/iu, "") + .replace(/^(?:контрагент(?:а|ов|у|ом|е)?|поставщик(?:а|ов|у|ом|е)?|клиент(?:а|ов|у|ом|е)?)\s+/iu, "") .replace(/^(?:counterpart(?:y|ies)|supplier(?:s)?|customer(?:s)?)\s+/iu, "") + .replace(/^группу\s+/iu, "Группа ") .replace(/^[«"'\s]+|[»"'\s]+$/gu, "") .replace(/\s+/g, " ") .trim(); @@ -786,8 +831,9 @@ function normalizeEntityResolutionCandidate(value: string): string { function rawEntityResolutionCandidate(text: string): string | null { const patterns = [ - /(?:найд(?:и|ите|ем|у)|поищ(?:и|ите|ем)|найти|search|find|look\s*up)\s+(?:в\s*1с\s+|в\s+1c\s+)?(?:контрагент(?:а|ов)?|поставщик(?:а|ов)?|клиент(?:а|ов)?|counterpart(?:y|ies)|supplier(?:s)?|customer(?:s)?)\s+(.+)$/iu, - /(?:контрагент(?:а|ов)?|поставщик(?:а|ов)?|клиент(?:а|ов)?|counterpart(?:y|ies)|supplier(?:s)?|customer(?:s)?)\s+(.+?)\s+(?:найд(?:и|ите|ем|у)|поищ(?:и|ите|ем)|найти|search|find|look\s*up)\b/iu + /(?:найд(?:и|ите|ем|у)|поищ(?:и|ите|ем)|найти|search|find|look\s*up)\s+(?:в\s*1с\s+|в\s+1c\s+)?(?:контрагент(?:а|ов|у|ом|е)?|поставщик(?:а|ов|у|ом|е)?|клиент(?:а|ов|у|ом|е)?|counterpart(?:y|ies)|supplier(?:s)?|customer(?:s)?)\s+(.+)$/iu, + /(?:найд(?:и|ите|ем|у)|поищ(?:и|ите|ем)|найти|search|find|look\s*up)\s+(?:в\s*1с\s+|в\s+1c\s+)(.+)$/iu, + /(?:контрагент(?:а|ов|у|ом|е)?|поставщик(?:а|ов|у|ом|е)?|клиент(?:а|ов|у|ом|е)?|counterpart(?:y|ies)|supplier(?:s)?|customer(?:s)?)\s+(.+?)\s+(?:найд(?:и|ите|ем|у)|поищ(?:и|ите|ем)|найти|search|find|look\s*up)\b/iu ]; for (const pattern of patterns) { const match = text.match(pattern); @@ -1085,6 +1131,7 @@ export function buildAssistantMcpDiscoveryTurnInput( : null; const entityResolutionSignal = rawEntityResolutionSignal || Boolean(rawEntityCandidate) || Boolean(entityResolutionClarificationCandidate); + const rawEntitySearchOverridesStaleScope = Boolean(rawEntityCandidate && entityResolutionSignal); const rawDomain = toNonEmptyString(assistantTurnMeaning?.asked_domain_family); const rawAction = toNonEmptyString(assistantTurnMeaning?.asked_action_family); const rawAggregationAxis = toNonEmptyString(assistantTurnMeaning?.asked_aggregation_axis); @@ -1105,11 +1152,17 @@ export function buildAssistantMcpDiscoveryTurnInput( hasMovementEvidenceFollowupSignal(rawText) || hasPronounMovementEvidenceFollowupSignal(rawText); const assistantTurnMeaningDateScope = toNonEmptyString(assistantTurnMeaning?.explicit_date_scope); - const assistantTurnMeaningOrganizationScope = toNonEmptyString(assistantTurnMeaning?.explicit_organization_scope); + const rawAssistantTurnMeaningOrganizationScope = toNonEmptyString(assistantTurnMeaning?.explicit_organization_scope); + const assistantTurnMeaningOrganizationScope = isReferentialOrganizationPlaceholder( + rawAssistantTurnMeaningOrganizationScope + ) + ? null + : rawAssistantTurnMeaningOrganizationScope; const rawOrganizationMentionSignal = hasOrganizationScopeSignalUtf8(rawText); const rawOrganizationScope = extractOrganizationScopeFromRawText(rawUserText ?? rawEffectiveText ?? rawSignalSourceText); + const currentTurnFreshOrganizationScope = rawOrganizationScope ?? predecomposeEntities.organization; const currentTurnOrganizationScope = - rawOrganizationScope ?? predecomposeEntities.organization ?? assistantTurnMeaningOrganizationScope; + currentTurnFreshOrganizationScope ?? assistantTurnMeaningOrganizationScope; const explicitOrganizationScopeSignal = Boolean(rawOrganizationMentionSignal && currentTurnOrganizationScope); const organizationClarificationFollowupApplicable = Boolean( followupSeed.domain === "counterparty_value" && @@ -1492,7 +1545,9 @@ export function buildAssistantMcpDiscoveryTurnInput( metadataGroundedMovementLaneApplicable) ); const metadataLaneScopeHint = - explicitCurrentCounterpartyOverridesFollowupEntity + rawEntitySearchOverridesStaleScope + ? null + : explicitCurrentCounterpartyOverridesFollowupEntity ? null : rawMetadataScopeHint ?? followupSeed.metadataScopeHint ?? @@ -1506,6 +1561,8 @@ export function buildAssistantMcpDiscoveryTurnInput( ); const groundedFollowupEntity = metadataScopedLaneWithoutSubject ? null + : rawEntitySearchOverridesStaleScope + ? null : explicitCurrentCounterpartyOverridesFollowupEntity ? null : followupSeed.counterparty ?? followupSeed.discoveryEntity; @@ -1514,10 +1571,16 @@ export function buildAssistantMcpDiscoveryTurnInput( pushNormalizedEntityResolutionCandidate(entityCandidates, entityResolutionClarificationCandidate); pushNormalizedEntityResolutionCandidate(entityCandidates, rawEntityCandidate); for (const candidate of collectEntityCandidates(assistantTurnMeaning?.explicit_entity_candidates)) { - pushNormalizedEntityResolutionCandidate(entityCandidates, candidate); + if (!rawEntitySearchOverridesStaleScope || sameScopedName(candidate, rawEntityCandidate)) { + pushNormalizedEntityResolutionCandidate(entityCandidates, candidate); + } + } + if (!rawEntitySearchOverridesStaleScope || sameScopedName(normalizedPredecomposeCounterparty, rawEntityCandidate)) { + pushNormalizedEntityResolutionCandidate(entityCandidates, normalizedPredecomposeCounterparty); + } + if (!rawEntitySearchOverridesStaleScope) { + pushNormalizedEntityResolutionCandidate(entityCandidates, followupSeed.counterparty); } - pushNormalizedEntityResolutionCandidate(entityCandidates, normalizedPredecomposeCounterparty); - pushNormalizedEntityResolutionCandidate(entityCandidates, followupSeed.counterparty); } else { if (groundedFollowupEntity) { pushUnique(entityCandidates, groundedFollowupEntity); @@ -1562,8 +1625,11 @@ export function buildAssistantMcpDiscoveryTurnInput( pushUnique(entityCandidates, followupSeed.organization); } const explicitOrganizationScope = - valueFlowOrganizationStaysScope || !openScopeValueFlowWithoutCounterparty - ? currentTurnOrganizationScope ?? followupSeed.organization + rawEntitySearchOverridesStaleScope && !currentTurnFreshOrganizationScope + ? null + : valueFlowOrganizationStaysScope || !openScopeValueFlowWithoutCounterparty + ? (rawEntitySearchOverridesStaleScope ? currentTurnFreshOrganizationScope : currentTurnOrganizationScope) ?? + followupSeed.organization : null; if ( explicitCurrentCounterpartyCandidate && @@ -1609,13 +1675,18 @@ export function buildAssistantMcpDiscoveryTurnInput( (valueFlowOrganizationStaysScope && (Boolean(followupSeed.rankingNeed) || bidirectionalValueFlowSignal))) ); const normalizedPredecomposeDateScope = - suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(predecomposeDateScope) ? null : predecomposeDateScope; + (rawEntitySearchOverridesStaleScope && !currentTurnCarriesExplicitPeriod) || + (suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(predecomposeDateScope)) + ? null + : predecomposeDateScope; const normalizedAssistantTurnMeaningDateScope = - suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(assistantTurnMeaningDateScope) + rawEntitySearchOverridesStaleScope || + (suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(assistantTurnMeaningDateScope)) ? null : assistantTurnMeaningDateScope; const normalizedFollowupDateScope = - suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(followupSeed.dateScope) + rawEntitySearchOverridesStaleScope || + (suppressImplicitCurrentDateScope && isImplicitCurrentDateScope(followupSeed.dateScope)) ? null : followupSeed.dateScope; const explicitDateScope = @@ -1670,7 +1741,9 @@ export function buildAssistantMcpDiscoveryTurnInput( : rawAction ?? seededAction, asked_aggregation_axis: monthlyAggregationSignal ? "month" : rawAggregationAxis, seeded_ranking_need: - valueFlowSignal && followupSeed.rankingNeed ? followupSeed.rankingNeed : undefined, + valueFlowSignal && followupSeed.rankingNeed && !rawEntitySearchOverridesStaleScope + ? followupSeed.rankingNeed + : undefined, explicit_entity_candidates: entityCandidates, metadata_ambiguity_entity_sets: metadataAmbiguityLaneClarificationApplicable && followupSeed.metadataAmbiguityEntitySets.length > 0 @@ -1782,9 +1855,11 @@ export function buildAssistantMcpDiscoveryTurnInput( groundedValueFlowFollowupApplicable }); const hasTurnMeaning = Object.keys(cleanTurnMeaning).length > 0; - const sourceSignal: AssistantMcpDiscoveryTurnInputSource = assistantTurnMeaning - ? "assistant_turn_meaning" - : followupDiscoverySeedApplicable || + const sourceSignal: AssistantMcpDiscoveryTurnInputSource = rawEntitySearchOverridesStaleScope + ? "raw_text" + : assistantTurnMeaning + ? "assistant_turn_meaning" + : followupDiscoverySeedApplicable || Boolean(entityResolutionClarificationCandidate) || effectiveMetadataFollowupSeedApplicable || metadataAmbiguityLaneClarificationApplicable @@ -1925,7 +2000,7 @@ export function buildAssistantMcpDiscoveryTurnInput( ) { pushReason(reasonCodes, "mcp_discovery_counterparty_from_predecompose"); } - if (followupSeed.counterparty) { + if (followupSeed.counterparty && !rawEntitySearchOverridesStaleScope) { pushReason(reasonCodes, "mcp_discovery_counterparty_from_followup_context"); } if (followupDateScopeApplied) { diff --git a/llm_normalizer/backend/src/services/assistantService.ts b/llm_normalizer/backend/src/services/assistantService.ts index cc2b15c..726ba0c 100644 --- a/llm_normalizer/backend/src/services/assistantService.ts +++ b/llm_normalizer/backend/src/services/assistantService.ts @@ -1888,7 +1888,7 @@ function textMojibakeScoreForAddress(value) { const source = String(value ?? ""); const cyrillic = (source.match(/[А-Яа-яЁё]/g) ?? []).length; const latin = (source.match(/[A-Za-z]/g) ?? []).length; - const hardMarkers = (source.match(/[Ѓѓ‚„…†‡€‰‹ЉЊЌЋЏ�?’“”•–—™љ›њќћџ]/g) ?? []).length; + const hardMarkers = (source.match(/[Ѓѓ‚„…†‡€‰‹ЉЊЌЋЏ\uFFFD?’“”•–—™љ›њќћџ]/g) ?? []).length; const pairMarkers = (source.match(/(?:Р.|С.|Ð.|Ñ.)/g) ?? []).length; const doubleEncodedMarkers = (source.match(/(?:Г[Ђ-џ]|В[Ђ-џ]|Ã.|Â.)/gu) ?? []).length; return cyrillic + latin - hardMarkers * 3 - pairMarkers * 2 - doubleEncodedMarkers * 2; @@ -1898,7 +1898,7 @@ function looksLikeMojibakeForAddress(value) { if (!source.trim()) { return false; } - if (/[Ѓѓ‚„…†‡€‰‹ЉЊЌЋЏ�?’“”•–—™љ›њќћџ]/.test(source)) { + if (/[Ѓѓ‚„…†‡€‰‹ЉЊЌЋЏ\uFFFD?’“”•–—™љ›њќћџ]/.test(source)) { return true; } if ((source.match(/(?:Р.|С.|Ð.|Ñ.)/g) ?? []).length >= 2) { @@ -2129,7 +2129,7 @@ function normalizeCounterpartyForFollowupMatch(value) { return compactWhitespace(repairAddressMojibake(String(value ?? "")) .toLowerCase() .replace(/ё/g, "е") - .replace(/[«»"'`“”„’�?]/g, " ") + .replace(/[«»"'`“”„’\uFFFD?]/g, " ") .replace(/[^a-zа-я0-9\s._-]+/giu, " ")); } function normalizeCounterpartyTokenForFollowupMatch(value) { @@ -2175,7 +2175,7 @@ function extractDisplayedAddressEntityCandidates(replyText, entityType = "unknow if (parts.length >= 2 && /^\d{4}-\d{2}-\d{2}/.test(parts[0] ?? "")) { counterpartyCandidate = parts[1] ?? counterpartyCandidate; } - const cleanedCandidate = compactWhitespace(counterpartyCandidate.replace(/^["'«»“”„`’�?]+|["'«»“”„`’�?]+$/gu, "")); + const cleanedCandidate = compactWhitespace(counterpartyCandidate.replace(/^["'«»“”„`’\uFFFD?]+|["'«»“”„`’\uFFFD?]+$/gu, "")); if (!cleanedCandidate || cleanedCandidate.length < 2) { continue; } @@ -3224,6 +3224,11 @@ function hasSameDateAccountFollowupSignalForPredecompose(text) { /(?:^|\s)по\s+\d{2}(?:[.,]\d{1,2})?(?=$|[\s,.;:!?])/iu.test(source) || /\b\d{2}(?:[.,]\d{1,2})\b/u.test(source)); } +function isCounterpartyDrilldownIntentForPredecompose(intent) { + return intent === "list_documents_by_counterparty" || + intent === "bank_operations_by_counterparty" || + intent === "list_contracts_by_counterparty"; +} function hasPredecomposeDiagnosticUncertaintyLead(text) { const normalized = compactWhitespace(repairAddressMojibake(String(text ?? "")).toLowerCase()); if (!normalized) { @@ -3442,8 +3447,16 @@ async function runAddressLlmPreDecompose(normalizerService, payload, userMessage const sourceHasExplicitAccountAnchor = (0, addressIntentResolver_1.hasAccountNumberAnchor)(repairedSourceMessage || userMessage) || (0, addressIntentResolver_1.hasCompactAccountCodeToken)(repairedSourceMessage || userMessage); const candidateInjectsAccountAnchor = Boolean(toNonEmptyString(candidatePredecomposeContract?.entities?.account)); - if (sourceIntentResolution.intent === "inventory_on_hand_as_of_date" && - candidateIntentResolution.intent === "inventory_on_hand_as_of_date" && + const sourceAnchorQuality = evaluateAddressAnchorQuality(repairedSourceMessage || userMessage); + const candidateAccountInjectedIntoCounterpartyAnchor = isCounterpartyDrilldownIntentForPredecompose(sourceIntentResolution.intent) && + sourceIntentResolution.intent === candidateIntentResolution.intent && + sourceAnchorQuality.anchorType === "counterparty" && + sourceAnchorQuality.quality >= 2 && + !sourceHasExplicitAccountAnchor && + candidateInjectsAccountAnchor; + if (((sourceIntentResolution.intent === "inventory_on_hand_as_of_date" && + candidateIntentResolution.intent === "inventory_on_hand_as_of_date") || + candidateAccountInjectedIntoCounterpartyAnchor) && !sourceHasExplicitAccountAnchor && candidateInjectsAccountAnchor) { return attachAddressPredecomposeContract({ @@ -3456,10 +3469,9 @@ async function runAddressLlmPreDecompose(normalizerService, payload, userMessage reason: "normalized_fragment_rejected_anchor_injection", fallbackRuleHit: null, sanitizedUserMessage, - semanticHints: candidateMeta?.semanticHints ?? null + semanticHints: null }, userMessage); } - const sourceAnchorQuality = evaluateAddressAnchorQuality(repairedSourceMessage || userMessage); const candidateAnchorQuality = evaluateAddressAnchorQuality(candidate); const sameIntentForAnchorSafety = sourceAnchorQuality.intent !== "unknown" && sourceAnchorQuality.intent === candidateAnchorQuality.intent; const sourceSelectedObjectItemAnchorValue = toNonEmptyString((0, addressFilterExtractor_1.extractSelectedObjectQuotedValue)(userMessage)) ?? diff --git a/llm_normalizer/backend/tests/assistantAddressLlmPredecompose.test.ts b/llm_normalizer/backend/tests/assistantAddressLlmPredecompose.test.ts index 5b78dad..7152dd8 100644 --- a/llm_normalizer/backend/tests/assistantAddressLlmPredecompose.test.ts +++ b/llm_normalizer/backend/tests/assistantAddressLlmPredecompose.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from "vitest"; +import { describe, expect, it, vi } from "vitest"; import { AssistantService } from "../src/services/assistantService"; import { AssistantSessionStore } from "../src/services/assistantSessionStore"; @@ -1444,6 +1444,102 @@ describe("assistant address llm pre-decompose candidate preference", () => { expect(response.debug?.fallback_rule_hit).toBe("documents_counterparty_year_rewrite"); }); + it("rejects account injection when LLM truncates a numeric counterparty suffix", async () => { + const calls: Array<{ message: string }> = []; + const addressQueryService = { + tryHandle: vi.fn(async (message: string) => { + calls.push({ message }); + return buildAddressLaneResult(message); + }) + } as any; + + const normalizerService = { + normalize: vi.fn(async () => ({ + trace_id: "norm-predecompose-counterparty-suffix-account-injection", + ok: true, + normalized: { + schema_version: "normalized_query_v2_0_2", + user_message_raw: "Покажи документы по Жуковке 51.", + message_in_scope: true, + scope_confidence: "high", + contains_multiple_tasks: false, + fragments: [ + { + fragment_id: "F1", + raw_fragment_text: "Покажи документы по Жуковке 51.", + normalized_fragment_text: "Показать документы, связанные с контрагентом Жуковка по счету 51", + domain_relevance: "in_scope", + business_scope: "company_specific_accounting", + entity_hints: ["Жуковка"], + account_hints: ["51"], + document_hints: ["документы"], + register_hints: [], + semantic_hints: { + scope_target_kind: "counterparty", + scope_target_text: "Жуковка", + date_scope_kind: "implicit_current", + self_scope_detected: false, + selected_object_scope_detected: false + }, + time_scope: { type: "unspecified", value: null, confidence: "low" }, + flags: { + has_multi_entity_scope: false, + asks_for_chain_explanation: false, + asks_for_ranking_or_top: false, + asks_for_period_summary: false, + asks_for_rule_check: false, + asks_for_anomaly_scan: false, + asks_for_exact_object_trace: false, + asks_for_evidence: false, + mentions_period_close_context: false + }, + candidate_labels: ["simple_factual"], + confidence: "high", + execution_readiness: "executable", + clarification_reason: null, + soft_assumption_used: [], + route_status: "routed", + no_route_reason: null + } + ], + discarded_fragments: [], + global_notes: { needs_clarification: false, clarification_reason: null } + }, + raw_model_output: null, + validation: { passed: true, errors: [] }, + usage: { input_tokens: 1, output_tokens: 1, total_tokens: 2 }, + latency_ms: 10, + prompt_version: "normalizer_v2_0_2", + schema_version: "v2_0_2", + request_count_for_case: 1 + })) + } as any; + + const sessions = new AssistantSessionStore(); + const service = new AssistantService( + normalizerService, + sessions as any, + {} as any, + { persistSession: vi.fn() } as any, + addressQueryService + ); + + const response = await service.handleMessage({ + session_id: `asst-predecompose-counterparty-suffix-${Date.now()}`, + user_message: "Покажи документы по Жуковке 51.", + llmProvider: "local", + useMock: false + } as any); + + expect(response.ok).toBe(true); + expect(calls).toHaveLength(1); + expect(calls[0].message).toBe("Покажи документы по Жуковке 51."); + expect(response.debug?.llm_decomposition_applied).toBe(false); + expect(response.debug?.llm_decomposition_reason).toBe("normalized_fragment_rejected_anchor_injection"); + expect(response.debug?.llm_predecompose_contract?.entities?.account).toBeNull(); + expect(response.debug?.llm_predecompose_contract?.entities?.counterparty).toBe("Жуковке 51"); + }); + it("rewrites payment-style counterparty phrasing to bank operations", async () => { const calls: Array<{ message: string }> = []; const addressQueryService = { diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryAnswerAdapter.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryAnswerAdapter.test.ts index 27a0dc0..f7a4771 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryAnswerAdapter.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryAnswerAdapter.test.ts @@ -341,6 +341,62 @@ describe("assistant MCP discovery answer adapter", () => { expect(draft.next_step_line).toContain("организац"); }); + it("renders confirmed ranked value-flow without raw technical evidence lines", async () => { + const planner = planAssistantMcpDiscovery({ + dataNeedGraph: { + schema_version: "assistant_data_need_graph_v1", + policy_owner: "assistantMcpDiscoveryDataNeedGraph", + subject_candidates: [], + business_fact_family: "value_flow", + action_family: "turnover", + aggregation_need: null, + time_scope_need: "explicit_period", + comparison_need: null, + ranking_need: "top_desc", + proof_expectation: "coverage_checked_fact", + clarification_gaps: [], + decomposition_candidates: ["collect_scoped_movements", "aggregate_ranked_axis_values", "probe_coverage"], + forbidden_overclaim_flags: ["no_raw_model_claims", "no_unchecked_fact_totals"], + reason_codes: ["data_need_graph_built", "data_need_graph_ranking_top_desc"] + }, + turnMeaning: { + asked_domain_family: "counterparty_value", + asked_action_family: "turnover", + explicit_organization_scope: "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441", + explicit_date_scope: "2020", + unsupported_but_understood_family: "counterparty_value_or_turnover" + } + }); + const pilot = await executeAssistantMcpDiscoveryPilot( + planner, + buildDeps([ + { + Period: "2020-01-15T00:00:00", + Amount: 12000, + Counterparty: "\u0421\u0411\u0415\u0420\u0411\u0410\u041d\u041a, \u041f\u0410\u041e", + Organization: "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441" + }, + { + Period: "2020-02-20T00:00:00", + Amount: 5000, + Counterparty: "\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a", + Organization: "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441" + } + ]) + ); + + const draft = buildAssistantMcpDiscoveryAnswerDraft(pilot); + const userText = [...draft.confirmed_lines, ...draft.inference_lines, ...draft.unknown_lines].join("\n"); + + expect(draft.answer_mode).toBe("confirmed_with_bounded_inference"); + expect(draft.confirmed_lines).toHaveLength(1); + expect(userText).toContain("\u0411\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0434\u0435\u043d\u0435\u0433 \u043f\u0440\u0438\u043d\u0451\u0441 \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442"); + expect(userText).toContain("\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441"); + expect(userText).not.toContain("1C incoming value-flow"); + expect(userText).not.toContain("Full ranking outside"); + expect(draft.unknown_lines[0]).toContain("\u041f\u043e\u043b\u043d\u044b\u0439 \u0440\u0435\u0439\u0442\u0438\u043d\u0433"); + }); + it("asks for both organization and period when an open total still misses both axes", async () => { const planner = planAssistantMcpDiscovery({ dataNeedGraph: { diff --git a/llm_normalizer/backend/tests/assistantMcpDiscoveryTurnInputAdapter.test.ts b/llm_normalizer/backend/tests/assistantMcpDiscoveryTurnInputAdapter.test.ts index 7616e01..90bf191 100644 --- a/llm_normalizer/backend/tests/assistantMcpDiscoveryTurnInputAdapter.test.ts +++ b/llm_normalizer/backend/tests/assistantMcpDiscoveryTurnInputAdapter.test.ts @@ -1426,6 +1426,45 @@ describe("assistant MCP discovery turn input adapter", () => { ); }); + it("lets an explicit current entity search override stale ranking follow-up scope", () => { + const staleEntity = "\u043f\u0440\u0438\u043d\u0451\u0441 \u043d\u0430\u0438\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0432\u044b\u0440\u0443\u0447\u043a\u0443 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0432"; + const result = buildAssistantMcpDiscoveryTurnInput({ + userMessage: + "\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0442\u0435\u043c\u0430 \u043f\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 \u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0443. \u041d\u0430\u0439\u0434\u0438 \u0432 1\u0421 \u0413\u0440\u0443\u043f\u043f\u0443 \u0421\u0412\u041a.", + assistantTurnMeaning: { + asked_domain_family: "entity_resolution", + asked_action_family: "search_business_entity", + explicit_entity_candidates: [staleEntity], + explicit_organization_scope: "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441", + explicit_date_scope: "2021", + unsupported_but_understood_family: "entity_resolution", + stale_replay_forbidden: true + }, + followupContext: { + previous_discovery_pilot_scope: "counterparty_value_flow_query_movements_v1", + previous_discovery_ranking_need: "top_desc", + previous_filters: { + organization: "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441", + counterparty: staleEntity, + period_from: "2021-01-01", + period_to: "2021-12-31" + } + } + }); + + expect(result.adapter_status).toBe("ready"); + expect(result.should_run_discovery).toBe(true); + expect(result.source_signal).toBe("raw_text"); + expect(result.turn_meaning_ref?.explicit_entity_candidates).toEqual(["\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a"]); + expect(result.turn_meaning_ref?.metadata_scope_hint).toBeUndefined(); + expect(result.turn_meaning_ref?.explicit_organization_scope).toBeUndefined(); + expect(result.turn_meaning_ref?.explicit_date_scope).toBeUndefined(); + expect(result.turn_meaning_ref?.seeded_ranking_need).toBeUndefined(); + expect(result.data_need_graph?.subject_candidates).toEqual(["\u0413\u0440\u0443\u043f\u043f\u0430 \u0421\u0412\u041a"]); + expect(result.reason_codes).toContain("mcp_discovery_entity_scope_from_raw_entity_search"); + expect(result.reason_codes).not.toContain("mcp_discovery_counterparty_from_followup_context"); + }); + it("marks top-value wording as a ranking data need without inventing a missing subject gap", () => { const result = buildAssistantMcpDiscoveryTurnInput({ userMessage: "кто больше всего принес денег в 2020" @@ -1444,6 +1483,46 @@ describe("assistant MCP discovery turn input adapter", () => { ]); }); + it("keeps open organization ranking subjectless when assistant meaning invents a predicate-shaped entity", () => { + const result = buildAssistantMcpDiscoveryTurnInput({ + userMessage: + "\u0418 \u043a\u0442\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u0438\u043d\u0435\u0441 \u0434\u0435\u043d\u0435\u0433 \u044d\u0442\u043e\u0439 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 2020 \u0433\u043e\u0434\u0443?", + assistantTurnMeaning: { + asked_domain_family: "counterparty_value", + asked_action_family: "turnover", + explicit_entity_candidates: [ + "\u043f\u0440\u0438\u043d\u0451\u0441 \u043d\u0430\u0438\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0432\u044b\u0440\u0443\u0447\u043a\u0443 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0432" + ], + explicit_organization_scope: "\u044d\u0442\u0430 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u044f", + explicit_date_scope: "2020", + unsupported_but_understood_family: "counterparty_value_or_turnover", + stale_replay_forbidden: true + }, + predecomposeContract: { + entities: { + organization: "\u044d\u0442\u0430 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u044f" + } + }, + followupContext: { + previous_discovery_pilot_scope: "counterparty_value_flow_query_movements_v1", + previous_filters: { + organization: "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441" + } + } + }); + + expect(result.adapter_status).toBe("ready"); + expect(result.should_run_discovery).toBe(true); + expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined(); + expect(result.turn_meaning_ref?.explicit_organization_scope).toBe( + "\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441" + ); + expect(result.turn_meaning_ref?.explicit_date_scope).toBe("2020"); + expect(result.data_need_graph?.subject_candidates).toEqual([]); + expect(result.data_need_graph?.ranking_need).toBe("top_desc"); + expect(result.data_need_graph?.decomposition_candidates).toContain("aggregate_ranked_axis_values"); + }); + it("keeps organization as scope for open bidirectional comparison wording instead of inventing a subject candidate", () => { const result = buildAssistantMcpDiscoveryTurnInput({ userMessage: "что больше: входящие или исходящие деньги за 2020 год по ООО Альтернатива Плюс?", diff --git a/llm_normalizer/data/autorun_generators/history.json b/llm_normalizer/data/autorun_generators/history.json index c8b783d..1f0fe38 100644 --- a/llm_normalizer/data/autorun_generators/history.json +++ b/llm_normalizer/data/autorun_generators/history.json @@ -1,4 +1,172 @@ [ + { + "generation_id": "gen-ag04241406-abe4d8", + "created_at": "2026-04-24T14:06:30+00:00", + "mode": "saved_user_sessions", + "title": "AGENT | Post-F cross-stage semantic integrity canary", + "count": 24, + "domain": "address_post_f_cross_stage_canary_agent", + "questions": [ + "Мне нужно понять, где в 1С по НДС вообще лежат данные. Какие объекты стоит смотреть по НДС?", + "Хорошо, тогда покажи движения по ООО Альтернатива Плюс.", + "За 2020 год.", + "А теперь по документам?", + "А теперь за 2021 год?", + "А теперь за все время?", + "С НДС закончили. Новая тема: покажи документы по Жуковке 51.", + "Хорошо, а теперь платежи по нему тоже покажи.", + "А по нему договоры?", + "А по нему документы?", + "А за 2021?", + "С Жуковкой закончили. Теперь другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?", + "По ООО Альтернатива Плюс.", + "Понял, тогда за все время.", + "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?", + "И кто больше всего принес денег этой организации в 2020 году?", + "А в 2021 году?", + "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК.", + "Сколько получили по нему за 2020 год?", + "А теперь сколько заплатили?", + "А какое нетто?", + "А по документам?", + "А по движениям?", + "А теперь тот же смысл за 2021 год." + ], + "generated_by": "codex_agent", + "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260424140630_gen-ag04241406-abe4d8.json", + "context": { + "llm_provider": null, + "model": null, + "assistant_prompt_version": null, + "decomposition_prompt_version": null, + "prompt_fingerprint": null, + "autogen_personality_id": null, + "autogen_personality_prompt": null, + "source_session_id": null, + "saved_session_file": "assistant_saved_session_20260424140630_gen-ag04241406-abe4d8.json", + "saved_case_set_kind": "agent_semantic_scenario", + "agent_run": true, + "agent_focus": "cross-stage canary: VAT metadata, numeric counterparty suffix, open organization value-flow, SVK grounded reset", + "architecture_phase": "Post-F Semantic Integrity Hardening", + "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_post_f_cross_stage_canary_agent_20260424.json", + "scenario_id": "address_truth_harness_post_f_cross_stage_canary_agent_20260424", + "semantic_tags": [ + "account_injection_guard", + "all_time_followup", + "bidirectional_value_flow", + "clarification_resume", + "contracts_followup", + "counterparty_pronoun_resolution", + "cross_stage_canary", + "document_lane_continuity", + "document_pivot_after_movement", + "documents_followup", + "documents_pivot", + "grounded_counterparty", + "incoming_value_flow", + "legacy_phase39", + "legacy_phase64", + "legacy_phase67", + "metadata_surface", + "movement_execution", + "movement_lane_after_metadata", + "movements_pivot", + "net_value_flow", + "numeric_counterparty_suffix", + "open_scope_total", + "organization_clarification", + "organization_scope", + "payments_followup", + "payout_value_flow", + "period_clarification_resume", + "post_f", + "repeated_pivot", + "scope_reuse", + "topic_reset", + "value_flow_ranking", + "vat_orientation", + "year_switch", + "year_switch_after_document_pivot", + "year_switch_after_repeated_pivot" + ] + } + }, + { + "generation_id": "gen-ag04231844-8e552a", + "created_at": "2026-04-23T18:44:25+00:00", + "mode": "saved_user_sessions", + "title": "AGENT | ARCH: Post-F Semantic Integrity Hardening | Смешанный живой диалог: repeated pivots, орг-срез и СВК", + "count": 19, + "domain": "address_phase82_human_mixed_integrity_status_dialog", + "questions": [ + "Покажи документы по Жуковке 51.", + "Хорошо, а теперь платежи по нему тоже покажи.", + "А по нему договоры?", + "А по нему документы?", + "А по нему платежи?", + "А за 2021?", + "С Жуковкой закончили. Теперь нужна другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?", + "По ООО Альтернатива Плюс.", + "Понял, тогда за все время.", + "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?", + "А что по ООО Альтернатива Плюс больше уже за 2021 год: входящие или исходящие деньги?", + "И кто больше всего принес денег этой организации в 2020 году?", + "А в 2021 году?", + "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК.", + "Сколько получили по нему за 2020 год?", + "А теперь сколько заплатили?", + "А какое нетто?", + "А по документам?", + "А по движениям?" + ], + "generated_by": "codex_agent", + "saved_case_set_file": "assistant_autogen_saved_user_sessions_20260423184425_gen-ag04231844-8e552a.json", + "context": { + "llm_provider": null, + "model": null, + "assistant_prompt_version": null, + "decomposition_prompt_version": null, + "prompt_fingerprint": null, + "autogen_personality_id": null, + "autogen_personality_prompt": null, + "source_session_id": null, + "saved_session_file": "assistant_saved_session_20260423184425_gen-ag04231844-8e552a.json", + "saved_case_set_kind": "agent_semantic_scenario", + "agent_run": true, + "agent_focus": "Post-F repeated pivots + open-scope organization money + grounded SVK counterparty chain", + "architecture_phase": "turnaround_11", + "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase82_human_mixed_integrity_status_dialog.json", + "scenario_id": "address_truth_harness_phase82_human_mixed_integrity_status_dialog", + "semantic_tags": [ + "all_time_followup", + "contracts_followup", + "counterparty_pronoun_resolution", + "documents_by_counterparty", + "documents_followup", + "documents_pivot", + "fourth_pivot", + "grounded_counterparty", + "human_dialog", + "incoming_value_flow", + "movements_pivot", + "net_value_flow", + "open_scope_total", + "organization_clarification", + "organization_scope", + "payments_followup", + "payout_value_flow", + "pivot_seed", + "post_f_integrity_hardening", + "second_pivot", + "third_pivot", + "topic_reset", + "value_flow_comparison", + "value_flow_ranking", + "year_switch", + "year_switch_after_fourth_pivot" + ] + } + }, { "generation_id": "gen-ag04231336-3d4cc9", "created_at": "2026-04-23T13:36:22+00:00", diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260423184425_gen-ag04231844-8e552a.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260423184425_gen-ag04231844-8e552a.json new file mode 100644 index 0000000..3d348a2 --- /dev/null +++ b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260423184425_gen-ag04231844-8e552a.json @@ -0,0 +1,281 @@ +{ + "saved_at": "2026-04-23T18:44:25+00:00", + "generation_id": "gen-ag04231844-8e552a", + "mode": "saved_user_sessions", + "title": "AGENT | ARCH: Post-F Semantic Integrity Hardening | Смешанный живой диалог: repeated pivots, орг-срез и СВК", + "agent_run": true, + "questions": [ + "Покажи документы по Жуковке 51.", + "Хорошо, а теперь платежи по нему тоже покажи.", + "А по нему договоры?", + "А по нему документы?", + "А по нему платежи?", + "А за 2021?", + "С Жуковкой закончили. Теперь нужна другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?", + "По ООО Альтернатива Плюс.", + "Понял, тогда за все время.", + "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?", + "А что по ООО Альтернатива Плюс больше уже за 2021 год: входящие или исходящие деньги?", + "И кто больше всего принес денег этой организации в 2020 году?", + "А в 2021 году?", + "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК.", + "Сколько получили по нему за 2020 год?", + "А теперь сколько заплатили?", + "А какое нетто?", + "А по документам?", + "А по движениям?" + ], + "metadata": { + "assistant_prompt_version": null, + "decomposition_prompt_version": null, + "prompt_fingerprint": null, + "agent_focus": "Post-F repeated pivots + open-scope organization money + grounded SVK counterparty chain", + "architecture_phase": "turnaround_11", + "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase82_human_mixed_integrity_status_dialog.json", + "scenario_id": "address_truth_harness_phase82_human_mixed_integrity_status_dialog", + "semantic_tags": [ + "all_time_followup", + "contracts_followup", + "counterparty_pronoun_resolution", + "documents_by_counterparty", + "documents_followup", + "documents_pivot", + "fourth_pivot", + "grounded_counterparty", + "human_dialog", + "incoming_value_flow", + "movements_pivot", + "net_value_flow", + "open_scope_total", + "organization_clarification", + "organization_scope", + "payments_followup", + "payout_value_flow", + "pivot_seed", + "post_f_integrity_hardening", + "second_pivot", + "third_pivot", + "topic_reset", + "value_flow_comparison", + "value_flow_ranking", + "year_switch", + "year_switch_after_fourth_pivot" + ] + }, + "source_session_id": null, + "session": { + "session_id": null, + "mode": "agent_semantic_run", + "items": [ + { + "message_id": "agent-user-001", + "role": "user", + "text": "Покажи документы по Жуковке 51.", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-002", + "role": "user", + "text": "Хорошо, а теперь платежи по нему тоже покажи.", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-003", + "role": "user", + "text": "А по нему договоры?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-004", + "role": "user", + "text": "А по нему документы?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-005", + "role": "user", + "text": "А по нему платежи?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-006", + "role": "user", + "text": "А за 2021?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-007", + "role": "user", + "text": "С Жуковкой закончили. Теперь нужна другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-008", + "role": "user", + "text": "По ООО Альтернатива Плюс.", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-009", + "role": "user", + "text": "Понял, тогда за все время.", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-010", + "role": "user", + "text": "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-011", + "role": "user", + "text": "А что по ООО Альтернатива Плюс больше уже за 2021 год: входящие или исходящие деньги?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-012", + "role": "user", + "text": "И кто больше всего принес денег этой организации в 2020 году?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-013", + "role": "user", + "text": "А в 2021 году?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-014", + "role": "user", + "text": "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК.", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-015", + "role": "user", + "text": "Сколько получили по нему за 2020 год?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-016", + "role": "user", + "text": "А теперь сколько заплатили?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-017", + "role": "user", + "text": "А какое нетто?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-018", + "role": "user", + "text": "А по документам?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-019", + "role": "user", + "text": "А по движениям?", + "created_at": "2026-04-23T18:44:25+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + } + ], + "agent_run": true, + "metadata": { + "assistant_prompt_version": null, + "decomposition_prompt_version": null, + "prompt_fingerprint": null, + "agent_focus": "Post-F repeated pivots + open-scope organization money + grounded SVK counterparty chain", + "architecture_phase": "turnaround_11", + "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_phase82_human_mixed_integrity_status_dialog.json", + "scenario_id": "address_truth_harness_phase82_human_mixed_integrity_status_dialog", + "semantic_tags": [ + "all_time_followup", + "contracts_followup", + "counterparty_pronoun_resolution", + "documents_by_counterparty", + "documents_followup", + "documents_pivot", + "fourth_pivot", + "grounded_counterparty", + "human_dialog", + "incoming_value_flow", + "movements_pivot", + "net_value_flow", + "open_scope_total", + "organization_clarification", + "organization_scope", + "payments_followup", + "payout_value_flow", + "pivot_seed", + "post_f_integrity_hardening", + "second_pivot", + "third_pivot", + "topic_reset", + "value_flow_comparison", + "value_flow_ranking", + "year_switch", + "year_switch_after_fourth_pivot" + ] + } + } +} diff --git a/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260424140630_gen-ag04241406-abe4d8.json b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260424140630_gen-ag04241406-abe4d8.json new file mode 100644 index 0000000..ea511d0 --- /dev/null +++ b/llm_normalizer/data/autorun_generators/saved_sessions/assistant_saved_session_20260424140630_gen-ag04241406-abe4d8.json @@ -0,0 +1,353 @@ +{ + "saved_at": "2026-04-24T14:06:30+00:00", + "generation_id": "gen-ag04241406-abe4d8", + "mode": "saved_user_sessions", + "title": "AGENT | Post-F cross-stage semantic integrity canary", + "agent_run": true, + "questions": [ + "Мне нужно понять, где в 1С по НДС вообще лежат данные. Какие объекты стоит смотреть по НДС?", + "Хорошо, тогда покажи движения по ООО Альтернатива Плюс.", + "За 2020 год.", + "А теперь по документам?", + "А теперь за 2021 год?", + "А теперь за все время?", + "С НДС закончили. Новая тема: покажи документы по Жуковке 51.", + "Хорошо, а теперь платежи по нему тоже покажи.", + "А по нему договоры?", + "А по нему документы?", + "А за 2021?", + "С Жуковкой закончили. Теперь другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?", + "По ООО Альтернатива Плюс.", + "Понял, тогда за все время.", + "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?", + "И кто больше всего принес денег этой организации в 2020 году?", + "А в 2021 году?", + "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК.", + "Сколько получили по нему за 2020 год?", + "А теперь сколько заплатили?", + "А какое нетто?", + "А по документам?", + "А по движениям?", + "А теперь тот же смысл за 2021 год." + ], + "metadata": { + "assistant_prompt_version": null, + "decomposition_prompt_version": null, + "prompt_fingerprint": null, + "agent_focus": "cross-stage canary: VAT metadata, numeric counterparty suffix, open organization value-flow, SVK grounded reset", + "architecture_phase": "Post-F Semantic Integrity Hardening", + "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_post_f_cross_stage_canary_agent_20260424.json", + "scenario_id": "address_truth_harness_post_f_cross_stage_canary_agent_20260424", + "semantic_tags": [ + "account_injection_guard", + "all_time_followup", + "bidirectional_value_flow", + "clarification_resume", + "contracts_followup", + "counterparty_pronoun_resolution", + "cross_stage_canary", + "document_lane_continuity", + "document_pivot_after_movement", + "documents_followup", + "documents_pivot", + "grounded_counterparty", + "incoming_value_flow", + "legacy_phase39", + "legacy_phase64", + "legacy_phase67", + "metadata_surface", + "movement_execution", + "movement_lane_after_metadata", + "movements_pivot", + "net_value_flow", + "numeric_counterparty_suffix", + "open_scope_total", + "organization_clarification", + "organization_scope", + "payments_followup", + "payout_value_flow", + "period_clarification_resume", + "post_f", + "repeated_pivot", + "scope_reuse", + "topic_reset", + "value_flow_ranking", + "vat_orientation", + "year_switch", + "year_switch_after_document_pivot", + "year_switch_after_repeated_pivot" + ] + }, + "source_session_id": null, + "session": { + "session_id": null, + "mode": "agent_semantic_run", + "items": [ + { + "message_id": "agent-user-001", + "role": "user", + "text": "Мне нужно понять, где в 1С по НДС вообще лежат данные. Какие объекты стоит смотреть по НДС?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-002", + "role": "user", + "text": "Хорошо, тогда покажи движения по ООО Альтернатива Плюс.", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-003", + "role": "user", + "text": "За 2020 год.", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-004", + "role": "user", + "text": "А теперь по документам?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-005", + "role": "user", + "text": "А теперь за 2021 год?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-006", + "role": "user", + "text": "А теперь за все время?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-007", + "role": "user", + "text": "С НДС закончили. Новая тема: покажи документы по Жуковке 51.", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-008", + "role": "user", + "text": "Хорошо, а теперь платежи по нему тоже покажи.", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-009", + "role": "user", + "text": "А по нему договоры?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-010", + "role": "user", + "text": "А по нему документы?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-011", + "role": "user", + "text": "А за 2021?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-012", + "role": "user", + "text": "С Жуковкой закончили. Теперь другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-013", + "role": "user", + "text": "По ООО Альтернатива Плюс.", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-014", + "role": "user", + "text": "Понял, тогда за все время.", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-015", + "role": "user", + "text": "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-016", + "role": "user", + "text": "И кто больше всего принес денег этой организации в 2020 году?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-017", + "role": "user", + "text": "А в 2021 году?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-018", + "role": "user", + "text": "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК.", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-019", + "role": "user", + "text": "Сколько получили по нему за 2020 год?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-020", + "role": "user", + "text": "А теперь сколько заплатили?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-021", + "role": "user", + "text": "А какое нетто?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-022", + "role": "user", + "text": "А по документам?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-023", + "role": "user", + "text": "А по движениям?", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + }, + { + "message_id": "agent-user-024", + "role": "user", + "text": "А теперь тот же смысл за 2021 год.", + "created_at": "2026-04-24T14:06:30+00:00", + "reply_type": null, + "trace_id": null, + "debug": null + } + ], + "agent_run": true, + "metadata": { + "assistant_prompt_version": null, + "decomposition_prompt_version": null, + "prompt_fingerprint": null, + "agent_focus": "cross-stage canary: VAT metadata, numeric counterparty suffix, open organization value-flow, SVK grounded reset", + "architecture_phase": "Post-F Semantic Integrity Hardening", + "source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_post_f_cross_stage_canary_agent_20260424.json", + "scenario_id": "address_truth_harness_post_f_cross_stage_canary_agent_20260424", + "semantic_tags": [ + "account_injection_guard", + "all_time_followup", + "bidirectional_value_flow", + "clarification_resume", + "contracts_followup", + "counterparty_pronoun_resolution", + "cross_stage_canary", + "document_lane_continuity", + "document_pivot_after_movement", + "documents_followup", + "documents_pivot", + "grounded_counterparty", + "incoming_value_flow", + "legacy_phase39", + "legacy_phase64", + "legacy_phase67", + "metadata_surface", + "movement_execution", + "movement_lane_after_metadata", + "movements_pivot", + "net_value_flow", + "numeric_counterparty_suffix", + "open_scope_total", + "organization_clarification", + "organization_scope", + "payments_followup", + "payout_value_flow", + "period_clarification_resume", + "post_f", + "repeated_pivot", + "scope_reuse", + "topic_reset", + "value_flow_ranking", + "vat_orientation", + "year_switch", + "year_switch_after_document_pivot", + "year_switch_after_repeated_pivot" + ] + } + } +} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260423184425_gen-ag04231844-8e552a.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260423184425_gen-ag04231844-8e552a.json new file mode 100644 index 0000000..9c561de --- /dev/null +++ b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260423184425_gen-ag04231844-8e552a.json @@ -0,0 +1,82 @@ +{ + "suite_id": "assistant_saved_session_gen-ag04231844-8e552a", + "suite_version": "0.1.0", + "schema_version": "assistant_saved_session_suite_v0_1", + "generated_at": "2026-04-23T18:44:25+00:00", + "generation_id": "gen-ag04231844-8e552a", + "mode": "saved_user_sessions", + "title": "AGENT | ARCH: Post-F Semantic Integrity Hardening | Смешанный живой диалог: repeated pivots, орг-срез и СВК", + "domain": "address_phase82_human_mixed_integrity_status_dialog", + "scenario_count": 1, + "case_ids": [ + "SAVED-001" + ], + "cases": [ + { + "case_id": "SAVED-001", + "scenario_tag": "agent_saved_user_sessions", + "title": "AGENT | ARCH: Post-F Semantic Integrity Hardening | Смешанный живой диалог: repeated pivots, орг-срез и СВК", + "question_type": "followup", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Покажи документы по Жуковке 51." + }, + { + "user_message": "Хорошо, а теперь платежи по нему тоже покажи." + }, + { + "user_message": "А по нему договоры?" + }, + { + "user_message": "А по нему документы?" + }, + { + "user_message": "А по нему платежи?" + }, + { + "user_message": "А за 2021?" + }, + { + "user_message": "С Жуковкой закончили. Теперь нужна другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?" + }, + { + "user_message": "По ООО Альтернатива Плюс." + }, + { + "user_message": "Понял, тогда за все время." + }, + { + "user_message": "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?" + }, + { + "user_message": "А что по ООО Альтернатива Плюс больше уже за 2021 год: входящие или исходящие деньги?" + }, + { + "user_message": "И кто больше всего принес денег этой организации в 2020 году?" + }, + { + "user_message": "А в 2021 году?" + }, + { + "user_message": "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК." + }, + { + "user_message": "Сколько получили по нему за 2020 год?" + }, + { + "user_message": "А теперь сколько заплатили?" + }, + { + "user_message": "А какое нетто?" + }, + { + "user_message": "А по документам?" + }, + { + "user_message": "А по движениям?" + } + ] + } + ] +} diff --git a/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260424140630_gen-ag04241406-abe4d8.json b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260424140630_gen-ag04241406-abe4d8.json new file mode 100644 index 0000000..49fa7b3 --- /dev/null +++ b/llm_normalizer/data/eval_cases/assistant_autogen_saved_user_sessions_20260424140630_gen-ag04241406-abe4d8.json @@ -0,0 +1,97 @@ +{ + "suite_id": "assistant_saved_session_gen-ag04241406-abe4d8", + "suite_version": "0.1.0", + "schema_version": "assistant_saved_session_suite_v0_1", + "generated_at": "2026-04-24T14:06:30+00:00", + "generation_id": "gen-ag04241406-abe4d8", + "mode": "saved_user_sessions", + "title": "AGENT | Post-F cross-stage semantic integrity canary", + "domain": "address_post_f_cross_stage_canary_agent", + "scenario_count": 1, + "case_ids": [ + "SAVED-001" + ], + "cases": [ + { + "case_id": "SAVED-001", + "scenario_tag": "agent_saved_user_sessions", + "title": "AGENT | Post-F cross-stage semantic integrity canary", + "question_type": "followup", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Мне нужно понять, где в 1С по НДС вообще лежат данные. Какие объекты стоит смотреть по НДС?" + }, + { + "user_message": "Хорошо, тогда покажи движения по ООО Альтернатива Плюс." + }, + { + "user_message": "За 2020 год." + }, + { + "user_message": "А теперь по документам?" + }, + { + "user_message": "А теперь за 2021 год?" + }, + { + "user_message": "А теперь за все время?" + }, + { + "user_message": "С НДС закончили. Новая тема: покажи документы по Жуковке 51." + }, + { + "user_message": "Хорошо, а теперь платежи по нему тоже покажи." + }, + { + "user_message": "А по нему договоры?" + }, + { + "user_message": "А по нему документы?" + }, + { + "user_message": "А за 2021?" + }, + { + "user_message": "С Жуковкой закончили. Теперь другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?" + }, + { + "user_message": "По ООО Альтернатива Плюс." + }, + { + "user_message": "Понял, тогда за все время." + }, + { + "user_message": "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?" + }, + { + "user_message": "И кто больше всего принес денег этой организации в 2020 году?" + }, + { + "user_message": "А в 2021 году?" + }, + { + "user_message": "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК." + }, + { + "user_message": "Сколько получили по нему за 2020 год?" + }, + { + "user_message": "А теперь сколько заплатили?" + }, + { + "user_message": "А какое нетто?" + }, + { + "user_message": "А по документам?" + }, + { + "user_message": "А по движениям?" + }, + { + "user_message": "А теперь тот же смысл за 2021 год." + } + ] + } + ] +} diff --git a/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-C4l-4Yfuqm.json b/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-C4l-4Yfuqm.json new file mode 100644 index 0000000..708bf35 --- /dev/null +++ b/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-C4l-4Yfuqm.json @@ -0,0 +1,78 @@ +{ + "suite_id": "assistant_saved_session_runtime_job-C4l-4Yfuqm", + "suite_version": "0.1.0", + "schema_version": "assistant_saved_session_runtime_v0_1", + "title": "AGENT | ARCH: Post-F Semantic Integrity Hardening | Смешанный живой диалог: repeated pivots, орг-срез и СВК", + "scenario_count": 1, + "case_ids": [ + "SAVED-001" + ], + "cases": [ + { + "case_id": "SAVED-001", + "scenario_tag": "saved_user_sessions_runtime", + "title": "AGENT | ARCH: Post-F Semantic Integrity Hardening | Смешанный живой диалог: repeated pivots, орг-срез и СВК", + "question_type": "followup", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Покажи документы по Жуковке 51." + }, + { + "user_message": "Хорошо, а теперь платежи по нему тоже покажи." + }, + { + "user_message": "А по нему договоры?" + }, + { + "user_message": "А по нему документы?" + }, + { + "user_message": "А по нему платежи?" + }, + { + "user_message": "А за 2021?" + }, + { + "user_message": "С Жуковкой закончили. Теперь нужна другая задача: быстрый денежный срез по одной организации. Если для ответа нужна организация, просто уточни ее. Сколько вообще входящих денег было за 2020 год?" + }, + { + "user_message": "По ООО Альтернатива Плюс." + }, + { + "user_message": "Понял, тогда за все время." + }, + { + "user_message": "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?" + }, + { + "user_message": "А что по ООО Альтернатива Плюс больше уже за 2021 год: входящие или исходящие деньги?" + }, + { + "user_message": "И кто больше всего принес денег этой организации в 2020 году?" + }, + { + "user_message": "А в 2021 году?" + }, + { + "user_message": "Теперь отдельная тема по конкретному контрагенту. Найди в 1С Группу СВК." + }, + { + "user_message": "Сколько получили по нему за 2020 год?" + }, + { + "user_message": "А теперь сколько заплатили?" + }, + { + "user_message": "А какое нетто?" + }, + { + "user_message": "А по документам?" + }, + { + "user_message": "А по движениям?" + } + ] + } + ] +} \ No newline at end of file diff --git a/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-FvKPQG152c.json b/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-FvKPQG152c.json new file mode 100644 index 0000000..6b9b425 --- /dev/null +++ b/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-FvKPQG152c.json @@ -0,0 +1,123 @@ +{ + "suite_id": "assistant_saved_session_runtime_job-FvKPQG152c", + "suite_version": "0.1.0", + "schema_version": "assistant_saved_session_runtime_v0_1", + "title": "БОЛЬШОЙ ОБЩИЙ Ручная сессия 16.04.2026, 21:26:06", + "scenario_count": 1, + "case_ids": [ + "SAVED-001" + ], + "cases": [ + { + "case_id": "SAVED-001", + "scenario_tag": "saved_user_sessions_runtime", + "title": "БОЛЬШОЙ ОБЩИЙ Ручная сессия 16.04.2026, 21:26:06", + "question_type": "followup", + "broadness_level": "medium", + "turns": [ + { + "user_message": "приветик - че как там дела" + }, + { + "user_message": "расскажи что можешь интересного" + }, + { + "user_message": "кайф - что там на складе по остаткам?" + }, + { + "user_message": "АЛЬТЕРНАТИВА" + }, + { + "user_message": "а исторические остатки на другие даты умеешь?" + }, + { + "user_message": "давай на июль 2017" + }, + { + "user_message": "март 2016" + }, + { + "user_message": "По выбранному объекту \"Рабочая станция универсального специалиста (индивидуальное изготовление)\": где взяли это?" + }, + { + "user_message": "а кому продали?" + }, + { + "user_message": "у тебя написано кто контрагент: рабочая станция - это ошибка?" + }, + { + "user_message": "ндс можешь прикинуть на дату покупки рабочей станции?" + }, + { + "user_message": "а какой ндс мы должны сгрузить на март 2020?" + }, + { + "user_message": "прикинь какой ндс нам надо заплатить на февраль 2017" + }, + { + "user_message": "кто у нас самый доходный клиент за все время" + }, + { + "user_message": "кто нам должен денег на май 2017" + }, + { + "user_message": "а какой ндс мы должны примерно заплатить за этот период?" + }, + { + "user_message": "мы должны комуто денег на сегодня?" + }, + { + "user_message": "а нам?" + }, + { + "user_message": "какой у нас самый доходный год" + }, + { + "user_message": "а за 2017 мы скок заработали?" + }, + { + "user_message": "сколько вообще денег мы заработали за все время?" + }, + { + "user_message": "ты умеешь считать дельту по договорам?" + }, + { + "user_message": "по чепурнову покажи все доки" + }, + { + "user_message": "а по свк" + }, + { + "user_message": "а сейчас у нас есть что на складе?" + }, + { + "user_message": "что нам отгружал чепурнов? какой товар или услугу?" + }, + { + "user_message": "какие остатки на складе на сегодня" + }, + { + "user_message": "остатки на март 2016" + }, + { + "user_message": "хвосты покажи по счету 60 на август 2022" + }, + { + "user_message": "Есть ли остатки товара, которые закупались очень давно" + }, + { + "user_message": "Какие конкретно номенклатуры формируют остаток по складу на май 2020" + }, + { + "user_message": "а по Альтернативе Плюс сколько лет активности в базе 1С?" + }, + { + "user_message": "Как ты оценишь деятельность компании?" + }, + { + "user_message": "какое нетто по деньгам с Группа СВК за 2020 год: сколько получили и сколько заплатили?" + } + ] + } + ] +} \ No newline at end of file diff --git a/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-IYhHuIIG_n.json b/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-IYhHuIIG_n.json new file mode 100644 index 0000000..96f8b40 --- /dev/null +++ b/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-IYhHuIIG_n.json @@ -0,0 +1,42 @@ +{ + "suite_id": "assistant_saved_session_runtime_job-IYhHuIIG_n", + "suite_version": "0.1.0", + "schema_version": "assistant_saved_session_runtime_v0_1", + "title": "AGENT | Живой диалог по организации: денежный срез, сравнение и рейтинг", + "scenario_count": 1, + "case_ids": [ + "SAVED-001" + ], + "cases": [ + { + "case_id": "SAVED-001", + "scenario_tag": "saved_user_sessions_runtime", + "title": "AGENT | Живой диалог по организации: денежный срез, сравнение и рейтинг", + "question_type": "followup", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Хочу быстрый денежный срез по одной организации без привязки к контрагенту. Сколько вообще входящих денег было за 2020 год?" + }, + { + "user_message": "По ООО Альтернатива Плюс." + }, + { + "user_message": "Понял, тогда за все время." + }, + { + "user_message": "Хорошо. А что по ООО Альтернатива Плюс больше в 2020 году: входящие или исходящие деньги?" + }, + { + "user_message": "А что по ООО Альтернатива Плюс больше уже за 2021 год: входящие или исходящие деньги?" + }, + { + "user_message": "И кто больше всего принес денег этой организации в 2020 году?" + }, + { + "user_message": "А в 2021 году?" + } + ] + } + ] +} \ No newline at end of file diff --git a/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-LndQtjGZU3.json b/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-LndQtjGZU3.json new file mode 100644 index 0000000..2ae1a28 --- /dev/null +++ b/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-LndQtjGZU3.json @@ -0,0 +1,123 @@ +{ + "suite_id": "assistant_saved_session_runtime_job-LndQtjGZU3", + "suite_version": "0.1.0", + "schema_version": "assistant_saved_session_runtime_v0_1", + "title": "БОЛЬШОЙ ОБЩИЙ Ручная сессия 16.04.2026, 21:26:06", + "scenario_count": 1, + "case_ids": [ + "SAVED-001" + ], + "cases": [ + { + "case_id": "SAVED-001", + "scenario_tag": "saved_user_sessions_runtime", + "title": "БОЛЬШОЙ ОБЩИЙ Ручная сессия 16.04.2026, 21:26:06", + "question_type": "followup", + "broadness_level": "medium", + "turns": [ + { + "user_message": "приветик - че как там дела" + }, + { + "user_message": "расскажи что можешь интересного" + }, + { + "user_message": "кайф - что там на складе по остаткам?" + }, + { + "user_message": "АЛЬТЕРНАТИВА" + }, + { + "user_message": "а исторические остатки на другие даты умеешь?" + }, + { + "user_message": "давай на июль 2017" + }, + { + "user_message": "март 2016" + }, + { + "user_message": "По выбранному объекту \"Рабочая станция универсального специалиста (индивидуальное изготовление)\": где взяли это?" + }, + { + "user_message": "а кому продали?" + }, + { + "user_message": "у тебя написано кто контрагент: рабочая станция - это ошибка?" + }, + { + "user_message": "ндс можешь прикинуть на дату покупки рабочей станции?" + }, + { + "user_message": "а какой ндс мы должны сгрузить на март 2020?" + }, + { + "user_message": "прикинь какой ндс нам надо заплатить на февраль 2017" + }, + { + "user_message": "кто у нас самый доходный клиент за все время" + }, + { + "user_message": "кто нам должен денег на май 2017" + }, + { + "user_message": "а какой ндс мы должны примерно заплатить за этот период?" + }, + { + "user_message": "мы должны комуто денег на сегодня?" + }, + { + "user_message": "а нам?" + }, + { + "user_message": "какой у нас самый доходный год" + }, + { + "user_message": "а за 2017 мы скок заработали?" + }, + { + "user_message": "сколько вообще денег мы заработали за все время?" + }, + { + "user_message": "ты умеешь считать дельту по договорам?" + }, + { + "user_message": "по чепурнову покажи все доки" + }, + { + "user_message": "а по свк" + }, + { + "user_message": "а сейчас у нас есть что на складе?" + }, + { + "user_message": "что нам отгружал чепурнов? какой товар или услугу?" + }, + { + "user_message": "какие остатки на складе на сегодня" + }, + { + "user_message": "остатки на март 2016" + }, + { + "user_message": "хвосты покажи по счету 60 на август 2022" + }, + { + "user_message": "Есть ли остатки товара, которые закупались очень давно" + }, + { + "user_message": "Какие конкретно номенклатуры формируют остаток по складу на май 2020" + }, + { + "user_message": "а по Альтернативе Плюс сколько лет активности в базе 1С?" + }, + { + "user_message": "Как ты оценишь деятельность компании?" + }, + { + "user_message": "какое нетто по деньгам с Группа СВК за 2020 год: сколько получили и сколько заплатили?" + } + ] + } + ] +} \ No newline at end of file diff --git a/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-X1z7AFW_Nq.json b/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-X1z7AFW_Nq.json new file mode 100644 index 0000000..8a599be --- /dev/null +++ b/llm_normalizer/data/eval_cases/assistant_saved_session_runtime_job-X1z7AFW_Nq.json @@ -0,0 +1,42 @@ +{ + "suite_id": "assistant_saved_session_runtime_job-X1z7AFW_Nq", + "suite_version": "0.1.0", + "schema_version": "assistant_saved_session_runtime_v0_1", + "title": "AGENT | Живой диалог по СВК: деньги, нетто, документы и движения", + "scenario_count": 1, + "case_ids": [ + "SAVED-001" + ], + "cases": [ + { + "case_id": "SAVED-001", + "scenario_tag": "saved_user_sessions_runtime", + "title": "AGENT | Живой диалог по СВК: деньги, нетто, документы и движения", + "question_type": "followup", + "broadness_level": "medium", + "turns": [ + { + "user_message": "Хочу проверить одного контрагента. Найди в 1С Группу СВК." + }, + { + "user_message": "Посмотри, сколько денег мы получили от него за 2020 год." + }, + { + "user_message": "А теперь сколько мы ему заплатили?" + }, + { + "user_message": "А какое получилось нетто?" + }, + { + "user_message": "А по документам?" + }, + { + "user_message": "А по движениям?" + }, + { + "user_message": "А теперь за 2021 год?" + } + ] + } + ] +} \ No newline at end of file