feat(web-shell): add transcript contract prevalidation - #9388
Conversation
Freeze reproducible evidence for current transcript paths before any VS Code or HTML export production migration. - Add versioned fixtures, closed export schema, and capability gates - Probe direct-daemon and ACP identity under partial history prepend - Preserve raw adapter semantics and full write_file Turn Output diffs - Document the two-MR architecture, security constraints, and blockers
|
Thanks for the PR — and for the rework: this is the evidence-only split of #9355 that review there asked about, and the ~3.1k lines of production-shaped surface (export builder, probes, wire-format fields) are indeed gone. A few honest gate observations before anyone goes deeper.
⏸️ Flagging these for discussion before diving deeper — and escalating the direction call to @wenshao @pomelo-nwu: the prevalidation-before-migration question was deferred on #9355 and never answered; this PR is much smaller and cleaner, but the question is the same. Stopping the pipeline here per the gate rules; a maintainer's direction (or a re-run via 中文说明感谢贡献——也感谢这次重构:这正是 #9355 评审中询问的"纯证据"拆分版本,约 3.1k 行生产形态的代码(export builder、probe、wire-format 字段)确实都移除了。在深入之前,给出几点如实的门禁观察。
⏸️ 先提出讨论,再深入看代码——并将方向决策转交 @wenshao @pomelo-nwu:预验证先于迁移的问题在 #9355 上已被转交且从未得到答复;本 PR 更小更干净,但问题相同。按门禁规则在此停止流水线;待 maintainer 给出方向后(或届时通过 — Qwen Code · qwen3.8-max Reviewed at |
🖼️ web-shell visual previewRendered against a mock daemon (no real backend): the PR base vs this PR head Screenshots · before / afterFull-resolution recordings (.webm) are attached to the workflow run. — Qwen Code · web-shell visuals |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not explored to full depth (tool budget reached): "agent 3b": repo-root npm run typecheck across all workspaces was not run; I verified web-shell's and integration-tests' typecheck programs individually instead..
中文说明
未探索到全部深度(达到工具调用预算):"agent 3b":repo-root npm run typecheck across all workspaces was not run; I verified web-shell's and integration-tests' typecheck programs individually instead.。
— qwen3.8-max via Qwen Code /review (v0.21.13)
Make the evidence-only contract suite enforce the review assumptions it documents while preserving the existing runtime transcript behavior. - Run the contract suite in the required no-AK integration job - Fail closed on ambiguous identity probes and deduplicate gate kinds - Enforce manifest, hash, export safety, and renderer version boundaries - Cover visible transcript text and stable Desktop packaging semantics - Record the complete PR comment evaluation and verification outcome
|
Addressed all 11 actionable inline findings in commit 494fa98 and resolved the corresponding threads after replying with per-finding evidence. Key outcomes:
The complete Chinese evaluation, including the original comments and diff annotations, is committed as Regarding the direction question in #issuecomment-5324569450: this remains an evidence-only MR. It does not add a production transcript model, export builder, document mode, VS Code timeline migration, protocol fields, or transport selection. The two partial-prepend identity candidates intentionally remain FAIL and @qwen-code /review |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestions are inline.
Deferred under the convergence posture (round 2, not a blocker) — recorded, not requested in this round:
integration-tests/fixtures/chat-transcript-contract/v1/schema/export-transcript-document-v1.schema.json:381 — [probe] Frozen schema's base64 guards admit undecodable payloads (rasterImage.data :381, thumbnailUrl :626) — anchored on code unc…docs/design/web-shell/chat-transcript-contract-prevalidation.md:658 — [review] §12.1's MR1 whitelist excludes web-shell production code, yet this PR modifies three web-shell production files it never disclosesdocs/design/web-shell/chat-transcript-contract-prevalidation.md:190 — [review] §5.2's must-express semantics table omits the debug block kind the baseline renders user-visibledocs/design/web-shell/chat-transcript-contract-prevalidation.md:650 — [review] §11.3 prescribes 8 capability-matrix fields; the shipped matrix has 5 columnsintegration-tests/fixtures/chat-transcript-contract/v1/schema/export-transcript-document-v1.schema.json:725 — [probe] Required exportedAt is guarded only by annotation-only format: date-time (no minLength/pattern, no format-asserting valida…integration-tests/chat-transcript-contract.test.ts:32 — [probe] manifest.expectedDiagnostics floats free of the probe output — pinned only against a duplicated hardcoded literaldocs/design/web-shell/chat-transcript-contract-prevalidation.md:316 — [review] §8's TranscriptRenderedItemEvidence interface is declared mandatory but never instantiated; its layer has no matrix row, fixture field, or probeintegration-tests/chat-transcript-contract.test.ts:324 — [review] additionalProperties closure asserted only on the two top-level objects, never on any $defs entrydocs/design/web-shell/chat-transcript-contract-prevalidation.md:652 — [probe] §11.3's closed Gate vocabulary is contradicted by the frozen matrix's hedged 'PASS foundation only' Desktop-reuse cell (1 of 9 rows violates)
中文说明
已审查——无阻断问题。 建议见行内评论。
收敛姿态下延后(第 2 轮,非阻断)——已记录,本轮不要求修改:共 9 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.21.13)
|
Round 2 review suggestions are addressed in 34e7a7f. All seven inline threads have individual replies and are resolved. Local verification passed: transcript contract tests (5/5), integration TypeScript compilation, CI wiring tests (9 passed, 1 skipped), repository typecheck, ESLint, Prettier, and the complete no-AK integration gate (13 files, 146 tests). The generated evaluation report was removed from the PR and retained only in the ignored local review-artifact directory. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not explored to full depth (tool budget reached): "agent 4": none — no check was cut short..
Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted.
Deferred under the convergence posture (round 3, not a blocker) — recorded, not requested in this round:
integration-tests/chat-transcript-contract.test.ts:382 — [review] forbidden-field scan has no positive control on the schema walkerintegration-tests/chat-transcript-contract.test.ts:294 — [review] fail-first gate alarm fires with a context-free assertion messageintegration-tests/chat-transcript-contract.test.ts:415 — [review] hash-lock assertion does not name the drifted fixture fileintegration-tests/chat-transcript-contract.test.ts:505 — [probe] planted canary raw payload is pinned by no assertion
中文说明
未探索到全部深度(达到工具调用预算):"agent 4":none — no check was cut short.。
未检查(工具限制,非阻断):the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted。
收敛姿态下延后(第 3 轮,非阻断)——已记录,本轮不要求修改:共 4 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.21.13)
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestions are inline.
Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted.
Deferred under the convergence posture (round 3, not a blocker) — recorded, not requested in this round:
integration-tests/fixtures/chat-transcript-contract/v1/schema/export-transcript-document-v1.schema.json:337 — [review] errorKind 16-entry enum duplicated verbatim across statusBlock and errorBlockintegration-tests/chat-transcript-contract.test.ts:271 — [probe] probeIdentity's 'Missing complete identity probe block' fail-closed branch has no testintegration-tests/chat-transcript-contract.test.ts:294 — [review] fail-first tripwire expect carries no diagnostic message for the MR2 gate-flip failureintegration-tests/chat-transcript-contract.test.ts:273 — [probe] probe compares block IDs only across reductions while design doc §7.5 claims provenance is compareddocs/design/web-shell/chat-transcript-contract-prevalidation.md:670 — [probe] §12.1 MR1 whitelist omits the six production/CI files this diff actually changes
中文说明
已审查——无阻断问题。 建议见行内评论。
未检查(工具限制,非阻断):the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted。
收敛姿态下延后(第 3 轮,非阻断)——已记录,本轮不要求修改:共 5 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.21.13)
Keep transcript contract prevalidation at the evidence level it can actually prove. The previous source-text assertion could both reject equivalent formatting and pass unreachable packaging code. - Remove the Desktop script parser and its false behavioral claim - Mark installed-artifact verification as deferred to Desktop smoke tests - Clarify MR1 matrix, CI wiring, and provenance evidence boundaries - Refresh the hash-locked capability matrix fixture Note: This does not change Web Shell or Desktop production behavior.
|
Regarding #9388 (comment): @danialzivehdadr, thanks for the comment. I could not identify a connection between the reported phone/upload behavior and this transcript-contract prevalidation PR. Please open a separate issue with the device and OS, exact page or URL, reproduction steps, expected behavior, actual behavior, and any screenshot or log. This PR does not change mobile upload behavior. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted.
Deferred under the convergence posture (round 4, not a blocker) — recorded, not requested in this round:
integration-tests/chat-transcript-contract.test.ts:487 — [probe] runtime-raw-compatibility pin uses toMatchObject subset matching; added fields on rawInput/rawOutput go unseenintegration-tests/chat-transcript-contract.test.ts:276 — [probe] fail-first gate tripwire assertion carries no diagnostic messageintegration-tests/chat-transcript-contract.test.ts:397 — [probe] fixture hash-lock assertion does not name the drifted fixture fileintegration-tests/chat-transcript-contract.test.ts:15 — [probe] web-shell nodenext import closure carries no marker of the dual module-resolution regime
中文说明
未检查(工具限制,非阻断):the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted。
收敛姿态下延后(第 4 轮,非阻断)——已记录,本轮不要求修改:共 4 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.21.14)
|
Follow-up on the round-4 review's CI downgrade:
@qwen-code /review |
|
@qwen-code /review |
|
Qwen Code review request accepted. Review is queued in workflow run. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No blocking issues. LGTM! ✅
Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted.
Deferred under the convergence posture (round 5, not a blocker) — recorded, not requested in this round:
integration-tests/chat-transcript-contract.test.ts:343 — [probe] Lock test pins only a hand-picked subset of the frozen schema's security semantics; unpinned widening vectors pass once MR2 legitimately rotates the fixture hashesintegration-tests/chat-transcript-contract.test.ts:276 — [probe] Fail-first gate pivot is a bare unnamed assertion; the good-news failure carries no breadcrumb to the documented gate-flip procedureintegration-tests/chat-transcript-contract.test.ts:531 — [probe] Set-valued gate evidence is locked with order-sensitive equality, making reducer block-emission order an implicit contract termdocs/design/web-shell/chat-transcript-contract-prevalidation.md:356 — [review] §9.2 still claims MR1 establishes Desktop baseline evidence via source-wiring assertions, which the final commit removedintegration-tests/fixtures/chat-transcript-contract/v1/schema/export-transcript-document-v1.schema.json:172 — [probe] Design doc §10.5 promises charset-AND-length constraints for opaque IDs; the frozen schema encodes only lengthintegration-tests/fixtures/chat-transcript-contract/v1/capability-matrix.md:15 — [review] Hash-locked capability matrix names the future VS Code path a 'shared ChatPanel contract', terminology the design doc explicitly supersedes
中文说明
无阻断问题。LGTM!✅
未检查(工具限制,非阻断):the executable-script lint — .github/workflows/ci.yml: actionlint embedded-shell source mapping is not yet supported — not linted。
收敛姿态下延后(第 5 轮,非阻断)——已记录,本轮不要求修改:共 6 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.21.14)
yiliang114
left a comment
There was a problem hiding this comment.
Reviewed the design doc and the code changes (types.ts, toolClassification.ts, todos.ts, transcriptToMessages adapter).
Approve. This is MR1 (contract prevalidation) of a two-MR plan; the design doc is a single authoritative source with an explicit fail-closed gate (overall: "fail") and no production type changes yet. The one production-code change I verified — the write_file diff test ensuring the complete diff is kept when a preview is also present — is a correctness fix in the transcript adapter, not a behavior change.
0 unresolved threads, REVIEW_REQUIRED.
yiliang114
left a comment
There was a problem hiding this comment.
The ordinal-ID failure still looks real, but I found one direct-daemon fixture mismatch inline. Non-blocking ponytail follow-up for later cleanup: Git already locks fixture bytes, so the manifest schema/hash harness can go, as can the 57-line self-test of the private probe helper. The broader MR2 schema/matrix deferral is already captured in the triage thread.
| @@ -0,0 +1,5 @@ | |||
| {"id":10,"v":1,"type":"session_update","data":{"update":{"sessionUpdate":"user_message_chunk","content":{"type":"text","text":"Inspect the contract"}}}} | |||
There was a problem hiding this comment.
[P2] Exercise producer-shaped direct-daemon frames
This fixture wraps the ACP payloads but drops the provenance emitted by the named direct-daemon path. Live BridgeClient.prepareSessionUpdateFrames() spreads activePromptId onto session_update frames (and the user echo carries promptId), while persisted replay stamps _meta.qwenTranscript.sourceRecordIds; normalizeDaemonEvent() preserves both. Because probeIdentity() treats either field as native text identity, the frozen directDaemon.missingNativeTextIdentity result is produced only by these synthetic frames.
The ordinal block IDs still drift, so the overall FAIL can stay. Could we make this fixture producer-shaped and update the direct provenance expectation? If the intended blocker is missing stable segment identity, the probe should check that explicitly instead of defining promptId/sourceRecordIds as sufficient and then omitting them here.
|
Released in v0.21.15. |
What this PR does
This PR establishes the evidence-only first stage of a shared chat transcript contract for Web/Qwen Server, Qwen Tauri Desktop, VS Code, and HTML Export. It freezes deterministic synthetic fixtures, hashes, a closed V1 export schema, and a capability matrix; verifies the existing ChatRecord projection and default Web Shell interactive/read-only raw semantics; and adds a regression for preserving the complete
write_fileTurn Output diff when a safe preview is also present.It also probes the current direct-daemon and ACP candidates under partial history prepend. Both candidates reproducibly fail the stable identity gate, so the overall result remains
failandselectedVscodePathremainsnull. No VS Code timeline migration, export builder, document render mode, protocol field, or production stable-identity projector is included. The accompanying overall design defines those MR2 responsibilities without introducing a second runtime message model in MR1.Why it's needed
The future VS Code and HTML Export migrations need a repeatable contract before they can safely reuse the Web Shell transcript renderer. The current direct-daemon and ACP paths derive ordinal block identities that change when earlier history is prepended, while export also requires an explicitly versioned and allowlisted boundary that cannot expose runtime raw payloads. Recording these facts as deterministic evidence prevents a green test run from being mistaken for migration readiness and keeps production changes out of the prevalidation stage.
Reviewer Test Plan
How to verify
overall: "fail", with both direct-daemon and ACP markedfailand no VS Code path selected.write_fileblock containing both full raw content and a shortened preview to produce the complete Turn Output diff from the raw content.Evidence (Before & After)
Tested on
Environment (optional)
Risk & Scope
Linked Issues
#9387
中文说明
What this PR does
本 PR 建立 Web/Qwen Server、Qwen Tauri Desktop、VS Code 与 HTML Export 共享聊天 transcript 契约的第一阶段纯证据基础。它冻结确定性的合成 fixtures、hash、封闭的 V1 导出 schema 和 capability matrix;验证现有 ChatRecord 投影以及 Web Shell 默认 interactive/read-only 模式的 raw 语义;并增加回归覆盖,确保同时存在安全 preview 时,
write_file的 Turn Output 仍保留完整文件 diff。它还在 partial history prepend 场景下探测当前 direct-daemon 和 ACP 两条候选路径。两者都能稳定复现 stable identity 门禁失败,因此整体结果继续保持
fail,selectedVscodePath继续保持null。本 PR 不包含 VS Code 时间线迁移、export builder、document render mode、协议字段或生产 stable-identity projector。配套的唯一总体设计定义了这些 MR2 职责,但 MR1 不会引入第二套运行时消息模型。Why it's needed
未来的 VS Code 与 HTML Export 迁移需要先建立可重复的契约证据,才能安全复用 Web Shell transcript renderer。当前 direct-daemon 和 ACP 路径生成的 ordinal block identity 会在 prepend 更早历史时发生变化,而导出路径还需要一个明确版本化且基于 allowlist 的边界,以避免暴露 runtime raw payload。将这些事实记录为确定性证据,可以防止把测试绿色误认为迁移已经就绪,并避免在预验证阶段引入生产改动。
Reviewer Test Plan
How to verify
overall: "fail",direct-daemon 和 ACP 都应为fail,并且不选择任何 VS Code 路径。write_fileblock 会使用 raw content 生成完整的 Turn Output diff。Evidence (Before & After)
N/A — 本 PR 增加契约证据和回归覆盖,不包含用户可见的 UI 变化。源文档未提供截图、录屏或 before/after 日志。
Tested on
Environment (optional)
N/A — 源文档记录了这些验证命令已经执行,但没有提供 runtime、sandbox 或操作系统信息。
Risk & Scope
Linked Issues
N/A