Repository navigation
Release readiness: merge dev (42 commits, RAG-D3/D4 + V104–V110 + GA continuation + review-fix-01) - #22
Conversation
… and complete real gemini acceptance
… python proxy side effects
…y real isolated integration
…d guard review markdown
…cklist, and freeze v2
…w checklist into 8 batches
…and v2-revised evaluation assets
- F01: enhance RetrievalAcceptanceGateValidator with strict checks on codeHashes, requirementsLockSha256, modelTag, profileId, and numerical ratio ranges [0.0, 1.0]; adjust SharedRetrievalIntegrationTest to validate acceptance gates before creating fixture rows. - F19: ensure SharedRetrievalIntegrationTest passes raw Top-8 ordered results without premature deduplication to RetrievalQualityScorer; preserve original ranking positions for MRR and pass real forbiddenAliases. - F05: decouple NEAR_NO_ANSWER diagnostic observations from strict zero-hit requirements while maintaining zero tolerance on stale version and permission isolation leaks. - Source & Label corrections: restore synthetic document IDs CHK-801 (R00), SEC-802 (R01), PERF-804 (R03); revise R00 chunking text to match chunks.py (target=1200, no overlap, UTF-16 code units); include X-Spec-Agent-Internal-Token in R01 text; restore multi-source queries B041, B043, B045, B046. - F14 & F22: introduce atomic CAS RetrievalExecutionClaimManager preventing concurrent/repeated candidate claims; track 17 code/migration files in acceptance-freeze.v2.1.json. - Audit & Tooling: update audit_retrieval_acceptance.py and test suite to support v2.1 candidate and freeze assets; all candidate query execution remains strictly 0 and review status remains PENDING.
… acceptance assets per Sol round 3 review - Gate Fail-Closed: RetrievalAcceptanceGateValidator strictly enforces candidate/freeze file presence, execution configuration comparison (qwen3-embedding:0.6b, profileId, rrfK=60, maxVectorDistance=0.50, maxItems=8, maxChars=8000), non-null pureNoAnswerZeroHitCorrectness ratio, and non-negative leak counts before any DB fixture or Python process is initialized. - Atomic First-Run Claim: Wire RetrievalExecutionClaimManager.claimFirstRun into SharedRetrievalIntegrationTest pre-fixture setup; enforce immutable terminal states (COMPLETED_PASS, COMPLETED_FAIL, INTERRUPTED_OR_ERROR) and generate unique runId receipts. - Single Truth Scorer: Unify top-level report metrics (mrr, recallAt8, multiSourceAllOfCoverage, zeroHitCorrectness, leaks) with RetrievalQualityScorer; verify 8th rank MRR yields strictly 0.125 (1/8). - v2.2 Acceptance Assets: Generate acceptance-candidate.v2.2.json, acceptance-freeze.v2.2.json, ACCEPTANCE_HUMAN_REVIEW.v2.2.md, and HUMAN_REVIEW_DECISION_CHECKLIST.v2.2.md; eliminate 'bidirectional handshake' wording in R01/B036 in favor of unidirectional X-Spec-Agent-Internal-Token header verification; align review notes for B041, B043, B045, B046. - 20-File Freeze Tracking: Track all 20 core retrieval, RPC, security, evaluation, migration, and build files + requirements.lock in v2.2 freeze with 0 drift. - Audit & Tooling: Update audit_retrieval_acceptance.py and test_audit_retrieval_acceptance.py to audit v2.2 asset; official candidate query execution remains strictly 0 and human approval remains PENDING.
A real Gemini State Update rejected every CONFIRMED claim that cited the answer being processed: the cycle persists that immutable Answer and lists it in allowedSourceRefs/retrievedContext before the model call, but it is not lineage yet. The validator now accepts only the current route's own USER_AUTHORED ANSWER source; external evidence, other routes and assumption/unresolved memory still cannot confirm. Adds an opt-in Model Service V2-Live acceptance that drives a real Gemini Custom connection through CHAT/STRUCTURED/NATIVE_TOOLS, a real project Agent answer cycle and a real GA native tool round trip, plus capability invalidation, revalidation and delete isolation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root causes of the failing run 39951411922, each fixed at its origin rather than at the symptom: - e2e/provider-screenshots.spec.ts still drove the removed built-in OpenRouter card, and the Custom flow it exercised had been replaced by the "+" dialog. Migrated to the current UI: two built-ins, arbitrary Custom connections created/edited/switched/deleted, multiple coexisting connections, and an explicit assertion that no built-in OpenRouter entry exists. OpenRouter survives only as an ordinary Custom example. - Two GA tests rebound to "OPENROUTER", which ModelProvider no longer contains. GaExecutionStore validates the provider before the state fence, so the tests threw IllegalArgumentException and never reached the immutability assertions they exist to prove. Fixtures now rebind to KILO: legal, and genuinely different from the frozen OPENCODE_ZEN. No production behaviour changed. - C16CrossProcessWorkerAcceptanceTest switched the database-wide runtime_execution_mode row to PER_TASK, then its teardown threw on DELETE FROM retrieval_index_generations: retrieval_scope_grants holds an index_generation FK with no ON DELETE action. The mode rollback sat after that statement, so the row stayed PER_TASK and 20 later contexts were refused by ExecutionModeAdmission, cascading into 171 more via the poisoned context cache. Grants are now deleted first, TOUCHED is snapshotted and cleared before deletion, and the mode rollback moved to finally so it cannot depend on cleanup succeeding. The production admission guard is untouched; the same latent teardown omission is corrected in the two sibling tests. - IsolatedMigrationAcceptanceTest scenario D named its synthetic failure migration V104, colliding with the shipped V104, so Flyway refused with "more than one migration with version 104" and the scenario proved nothing about rollback. Moved to V110, and the scenario now applies the whole shipped chain and asserts history is unchanged relative to its own baseline. - LegacyModelConnectionMigrator copied the old singleton's validated_revision/validated_at. V108 scrubs such rows once at upgrade, but the migrator is an ApplicationRunner that imports after Flyway on every start, so later imports were never scrubbed and could be activated with zero capability proof. Import no longer inherits validated state; V109 scrubs already-imported rows that lack a current revision STRUCTURED=VERIFIED proof; requireActivatable additionally demands that proof, so no path can activate without a current one. Credentials, endpoints, models and revisions are untouched. Verified on a purpose-built isolated database (never the dev or shared test database): test 2585/0 failed/41 skipped, testDatabaseIntegration 980/0 failed/41 skipped, frontend unit 987 passed, typecheck and build clean, Playwright 92 passed/4 skipped/0 failed. Every skip is an explicit environment opt-in. No live provider was called. Co-Authored-By: Claude Code <noreply@anthropic.com>
… tools Project Agent: bridge ModelOutputContract.JsonObject through a versioned host JSON envelope (anthropic-json-envelope.v1) on the official GA field output_config.format; strict unwrap validates completed stop reasons, a single json string field, duplicate keys, trailing tokens, unicode and size bounds, and returns only the normalized inner object - the envelope is never a decision output and malformed shapes fail closed without fallback. Global Assistant: new AnthropicGaNativeTransport + GaAnthropicMessagesAdapter provide the native tool_use/tool_result two-round protocol (ids preserved verbatim, results merged into one following user message, tool_choice mapped to none/auto/any with disable_parallel_tool_use). Text-then-tool_use is the only supported mixed shape; text after tool_use and thinking blocks accompanying executable calls are rejected at parse time before any ToolCall is released. Thinking material never reaches responses, ledgers, wire or checkpoints; no Anthropic sidecar is introduced. Qualification: CHAT/STRUCTURED/NATIVE_TOOLS now probe Anthropic connections through the same (org, UUID, revision, capability) records; the activation gate still requires STRUCTURED=VERIFIED. Legacy single registrations may TEXT_CHAT but never inherit native qualification. Tests: strict FakeAnthropicMessagesProvider (inbound protocol assertions), adapter/transport/routing/resolver unit tests, database end-to-end suites for both agents plus a full qualification flow. Local regression: test 2654/0/41, testDatabaseIntegration 1005/0/41, python 344, tools 239, cross-language green, frontend green. LIVE_NOT_RUN.
…review gaps Cross-stage review of MS-C1/C2/C3 found the Chat Completions native tool qualification probe still ran a hand-rolled HTTP path while Responses and Anthropic already used their production transports. probeNativeTools now routes all three formats through the same native transports the GA execution uses (frozen binding checks, stream:false shape, safety diagnostics), verified live against the Gemini OpenAI-compatible endpoint (4 requests, free tier, three capabilities VERIFIED). Also: legacy Custom maskedKey no longer echoes keys of 4 chars or fewer (aligned with ModelProvidersService), and the Anthropic protocol adapter merges every system message into the top-level system field instead of silently demoting the 2nd+ to user messages.
…ity matrix Independent review across MS-C1/C2/C3, three fixed defects (P1 probe transport unification, P2 short-key masking, P2 system merge), the reusable protocol compatibility matrix, full local regression counts, and a 4-request live verification of the repaired probe path against the Gemini OpenAI-compatible endpoint. Anthropic official endpoint remains LIVE_NOT_RUN (no credential available).
…rt path R1-A: the legacy Custom status boundary trusted the persisted masked_suffix column, so a weak-masking-era row (api key of 4 chars or fewer stored verbatim as its own suffix) disclosed the whole key as "••••abcd". status() and the key-rotation-free save path now rederive the mask from the actual key, so short historical keys surface null, long keys keep the last four chars only, unchanged saves neither rewrite the row nor bump configRevision, and any content-changing save rewrites the persisted suffix to the safe value. A 9-case suite drives old-shaped rows through the real status()/save() boundary, including JSON serialization assertions. R1-B: the stream:false assertion could not distinguish the pre-fix bypass probe from the production transports. CompatibilityProbeService now creates its three probe transports through package-private factory methods (the production implementations unchanged), and the harness test verifies via spy that each protocol's probe drives its own production transport factory exactly twice (both rounds) and never the others. Differential verification: temporarily restoring the F-1 bypass branch fails the new assertion (newChatCompletionsTransport wanted 2, was 0) while stream:false stays green, proving the old assertion had no discriminating power.
… probe path proof
…key masking primitives Cluster 1 - GA response contract validation: The three protocol adapters (GaChatCompletionsAdapter, GaAnthropicMessagesAdapter, GaResponsesAdapter) each carried a byte-identical implementation of the same safety invariants (tool_choice consistency, catalog-authorized tool names, no replayed tool call ids), two of them with zero test coverage. The rule now has a single owner in the contract layer (GaResponseContractValidator); all three adapters delegate with their public API unchanged and the six transport call sites untouched. GaNativeModelBroker's authoritative re-check calls the contract layer directly, removing the only assistant.api -> model.provider reference, and a new ArchUnit guard (red first against the pre-fix broker, green after) keeps that boundary enforced. Rejection-path tests now cover the shared implementation directly, closing the Anthropic/Responses coverage gap. Cluster 2 - Model Settings redundancy and key masking: Removed the redundant selectedModel comparison inside ModelProvidersService.update (recorded by MS-CROSS; pure boolean simplification). The key-masking primitives previously maintained four times (suffix, with Kilo/OpenCode returning empty string for short keys while the others returned null) plus duplicated hasKey and equalsNullable helpers now live in ApiKeyMasking with the MS-CROSS-R1 semantics (short keys yield null). The empty-string-to-null storage change is proven externally equivalent at every read point (both masks normalize blank/null) and locked by the existing Kilo/LegacyShortKeyMasking suites; intentionally different mask formats and the origin guards are left as-is. Behavior equivalence is locked by the existing suites (testOffline 487/0, full test 2676, testDatabaseIntegration 1005/0 on an isolated database, testCrossLanguage 2/0, evalBFast 166/0, ArchUnit 65/0, Python pytest 344/0, frontend typecheck/unit/build) plus 11 new protective tests. Evidence under docs/acceptance-evidence/arch-quality-01-20261025/. LIVE_NOT_RUN.
…col version sources 簇 A:ContractDiagnostic 与安全提取原语收敛到 contracts/diagnostics.py, state_update/artifact 引擎失败路径补齐结构化诊断并去除异常文本中的 模型输出嵌入;簇 B:WAIT dependencyRef 判定收敛为 wait_payload_matches_contract 单一原语,生产拒绝与信封自检共享; 簇 C:GA 协议版本字面量以 Final 常量单一来源化,/health 公告、事件 发送与 broker 请求全部引用常量。异常类名、HTTP 状态码与机器码 词汇表不变,Java 错误映射不受影响。
…t in acceptance evidence
- RUNBOOK 默认引擎段落:默认值已是 langchain-ga.v1/python-rag.v1, java-legacy.v1 已删除;回滚段补回滚目标限定 - C16_WAIT_V4.md 与 v2/README.md:真实数据库/跨进程/E2E 验收已由 c16-real-integration-20261021 在隔离环境完成,回写事实对应关系 - C16_RETRIEVAL_READINESS_ADAPTER.md:状态行与发布门槛段按真实集成 证据更新,首版 NOT RUN 断言按原文保留为历史 历史证据与冻结资产未改动;adapter delivery.md 的 Superseded 标注 位于未跟踪 WIP 目录内,随该目录由 owner 处置。
- A0 文档真实性修复差异清单(a0-doc-fact-fixes) - A1 RAG 68 条人工审批交接清单(rag-human-review-handoff) - A2 dev→main PR 就绪检查与 tree-hash 核验方案(pr-readiness) - A3 全链路验证结果与 CI 证据(a3-verification) - A4 DB 中断恢复验收清单(db-outage-recovery-acceptance) - 最终裁决 READY_FOR_MERGE_REVIEW(summary):代码集成就绪, 生产发布就绪否,人工待办分列
BangShou1st
left a comment
There was a problem hiding this comment.
对 PR #22(HEAD 25902a55b226b8e32e49534278222d3fbfa4f321)的只读集成审查。结论:暂不建议合并,需处理下列门禁不一致;没有执行 merge、未修改代码或 WIP。
[P1] 已激活 UUID CUSTOM 连接在复验失败后,仍可被新 GA Run 接纳。
复核调用链:
ModelConnectionCapabilities.verify()在探测失败时,把当前 revision 的STRUCTURED状态 UPSERT 为TEMPORARILY_UNAVAILABLE。ModelProvidersService.validate()仅在STRUCTURED=VERIFIED时调用markValidated,但失败时没有清除历史validated_revision。CustomProviderSettingsService.connectionSettings()只检查row.validated(),没有检查相同 org/UUID/revision 下的STRUCTURED=VERIFIED。GaExecutionModelTargetResolver.resolveCustom(true, selectedId)为新 Run 调用requireRuntimeSettings(selectedId)并返回Ready;项目推理ActiveModelTargetService亦经此路径。与此同时,ModelProvidersService.requireActivatable()已明确要求当前 STRUCTURED proof。于是出现“激活门禁拒绝/运行时或新 GA 准备阶段放行”的分歧。
建议:把当前修订号的 STRUCTURED=VERIFIED 检查落实在 UUID 连接的准备/运行时解析边界,或在复验降级时原子地清除相应的历史 validated 标记,并增加回归:先 VERIFIED+activate,再模拟 provider 复验失败,确认新 GA Run 和 Agent 解析 fail-closed;同时保留已冻结 Run 的设计语义,避免无意改变既有执行。相关位置:backend/src/main/java/com/specagent/modelsettings/{ModelConnectionCapabilities.java,ModelProvidersService.java,CustomProviderSettingsService.java}、backend/src/main/java/com/specagent/assistant/runtime/GaExecutionModelTargetResolver.java。
[P2] 评审元数据待同步。 PR 描述仍写 38 commits,但 GitHub 当前 main...dev 是 40 ahead / 0 behind、354 files;efbe11a..25902a5 两次变更仅 docs/证据。最终合并前需锁定 PR head 和 main base SHA 后再核验 tree-hash。另 a3-verification.md 中 skipped 分类标注数量相加为 43(25+11+1+5+1),与实际报告的 41 不符,请核对具体计数,不改变原始测试事实。
CI 范围: 40152643427 的 10 job 为 success(旧代码 HEAD efbe11a);当前 PR HEAD 的 40165818065 在本次审查时仍执行中(backend/brain/frontend/cross-language/eval-baseline 等已 success,e2e 仍在跑)。不能在当前 HEAD 的必需检查最终完成前授权合并。
V104–V110 迁移的脚本级依赖、约束与提交范围已抽查,未见明确 P0;RAG 人审与 DB 中断演练仍为生产发布阻断,不可用此次 review 代签。请在修复或书面确认 P1 的设计意图、回归证据齐备且 PR HEAD 检查完成后重新裁决合并。
|
补充 PR #22 审查状态(同一 HEAD |
PR #22 Review 5641753298 P1:同一 config_revision 下复验失败把 STRUCTURED 降级为 TEMPORARILY_UNAVAILABLE,但历史 validated_revision 不清除;运行时 新 Run 准入(requireRuntimeSettings()/requireRuntimeSettings(UUID) -> connectionSettings(id, null))此前仅凭过期 validated 标志放行,与激活门禁 requireActivatable()(要求当前 STRUCTURED=VERIFIED)结论分歧。 修复:connectionSettings 在 revision == null(新 Run 路径)统一要求当前 (org, UUID, config_revision) 的 STRUCTURED=VERIFIED——与激活门禁同一权威 能力来源;revision != null 的冻结绑定路径按设计契约不重复施加能力门禁, 降级不误杀已合法冻结的 Run;不采用清除 validated_revision 的方案。 回归:三个测试类新增 4 用例(降级后新 GA Run 与 Project Agent Run 拒绝、 直接读取不绕门禁、冻结语义不变、恢复准入、身份/org/revision 不继承、 NATIVE_TOOLS 不替代 STRUCTURED、无凭据泄漏);修复前红灯复现,修复后全绿。 P2:a3-verification.md skipped 分类勘误(GaExec 25->23,分项和 41 与总数一致)。 本地验证(隔离库+Fake Provider):testOffline 489/0/0;test 2680/0/41; testDatabaseIntegration 1007/0/41(skips 均为显式环境门控)。 证据:docs/acceptance-evidence/pr-22-review-fix-01-20261025/
|
PR-22-REVIEW-FIX-01 — 对 Review 5641753298 的逐项回应(commit [P1] STRUCTURED 资格降级后运行时门禁放行 —— 复核成立,已修复。
[P2] 评审元数据 —— 已核实并勘误。
CI:新 HEAD 未执行 merge;RAG 人审与 DB 中断演练等生产发布阻断事项不变。 |
|
PR-22-REVIEW-FIX-01 最终状态
|
PR #22 受控合并尝试结果:BLOCKED(未合并)
代码集成因规则配置冲突阻断;生产发布继续被 RAG 人审、最终发布 jar DB outage 验收和生产切换授权阻断。 |
|
PR #22 已合并(merge commit
|
Summary
RELEASE-READINESS-01 发布就绪性收敛的受控合并请求,含 PR-22-REVIEW-FIX-01 审查修复。dev 领先 main 42 提交(main 无独有提交,零分叉;以 GitHub
main...dev实时计数为准),内容为 RAG-D3/D4 系列、model-service 系列(含 V104–V110 七个 Flyway 迁移)、GA continuation/协议修复、CI-R1、arch-quality-01/02、文档治理与 Review5641753298P1/P2 定向修复。状态:READY_FOR_MERGE_REVIEW —— 等待人工合并决策,不自动合并;最终合并以最新 HEAD CI 完成为准。
验证证据
bc1140e,代码 =efbe11a基线,见docs/acceptance-evidence/release-readiness-01-20261025/a3-verification.md):efbe11arun 40152643427、25902a5run 40165818065 均 10 job 全绿(历史基线证据)Review 修复(PR-22-REVIEW-FIX-01,
906ee3c)validated_revision放行;connectionSettings新 Run 路径统一要求当前 (org, UUID, config_revision)STRUCTURED=VERIFIED(与激活门禁同源)。冻结绑定路径按设计契约不重复施加能力门禁,语义不变;未采用清除validated_revision方案(避免误杀冻结 Run)。spec_agent_p3b_live_pr22fix_20261025+ Fake Provider,红→绿复现):testOffline 489/0/0;test 2680/0/41;testDatabaseIntegration 1007/0/41(新增 4 回归用例;skips 均为显式环境门控)。docs/acceptance-evidence/pr-22-review-fix-01-20261025/(audit / fix-summary / verification / pr-review / summary)。906ee3cCI:runs 40170687660 / 40170691663 各 10/10 job 全绿;最终 HEAD13d7e9f(仅 docs 证据回填)CI 以其 run 最终结论为准(历史 10/10 仅为旧基线)。数据库迁移(V104–V110)
顺序依赖成立;V106 不可变触发器、V108/V109 清洗继承验证标记均为 fail-closed 方向;失败整体回滚;已在隔离库真实应用并通过迁移专项测试(IsolatedMigration/V94V95/V99)。升级提示:V108/V109 后无能力证明的 CUSTOM 连接需重新验证才可激活(预期行为)。
合并核验(merge 时执行,禁 squash)
git rev-parse origin/dev^{tree} # 合并后 origin/main^{tree} 必须等于此值 git diff --stat origin/main origin/dev # 必须为空已知风险(audit P1,合并评审输入)
人工待办(不阻塞本 PR,阻塞生产发布)
rag-human-review-handoff.md)db-outage-recovery-acceptance.md)发布限制
本 PR 合并 = 代码集成就绪;生产发布需上述人工待办关闭并取得 owner 生产切换授权,两种就绪不得混用。不修改 main、不强推、不绕过分支保护;合并模式必须为 merge commit。