diff --git a/.github/scripts/vsixPolicy.mjs b/.github/scripts/vsixPolicy.mjs index bfe9b1ff..5564194e 100644 --- a/.github/scripts/vsixPolicy.mjs +++ b/.github/scripts/vsixPolicy.mjs @@ -18,6 +18,10 @@ const FORBIDDEN_ENTRY_PATTERNS = [ /^extension\/node_modules(?:\/|$)/i, /^extension\/issue87-.*\.cjs$/i, /^extension\/out\/claudeIncrementalPrototype\.js$/i, + /^extension\/out\/adviceEffectiveness\/(?:evidencePreparation|feedback|legacyBridge|legacyPersonalization|modelExperiment)\.js$/i, + /^extension\/out\/(?:adviceDemoSample|adviceSummary)\.js$/i, + /^extension\/(?:AI-ADVICE-.*V2\.3\.1|V2\.3\.1-CANDIDATE-CONTRACT(?:\.zh-CN)?)\.md$/i, + /^extension\/CLAUDE-COLD-AB-V2\.3\.1(?:\.zh-CN)?\.md$/i, /(?:^|\/)\.env(?:\.|$)/i, /\.(?:pem|key|p12|pfx)$/i, ]; diff --git a/.github/scripts/vsixPolicy.test.mjs b/.github/scripts/vsixPolicy.test.mjs index 8b95bf91..0fbc97b9 100644 --- a/.github/scripts/vsixPolicy.test.mjs +++ b/.github/scripts/vsixPolicy.test.mjs @@ -73,6 +73,26 @@ test('VSIX policy rejects internal Superpowers review material', () => { ); }); +test('VSIX policy rejects dormant v2.3.1 preparation seams and review documents', () => { + for (const entry of [ + 'extension/out/adviceEffectiveness/evidencePreparation.js', + 'extension/out/adviceEffectiveness/feedback.js', + 'extension/out/adviceEffectiveness/legacyBridge.js', + 'extension/out/adviceEffectiveness/legacyPersonalization.js', + 'extension/out/adviceEffectiveness/modelExperiment.js', + 'extension/out/adviceDemoSample.js', + 'extension/out/adviceSummary.js', + 'extension/AI-ADVICE-INTEGRATION-V2.3.1.md', + 'extension/V2.3.1-CANDIDATE-CONTRACT.zh-CN.md', + ]) { + assert.throws( + () => assertSafeVsixEntries([...minimalEntries, entry]), + /forbidden VSIX entry/, + entry, + ); + } +}); + test('VSIX policy rejects unsafe or non-canonical archive paths', () => { for (const entry of [ '/extension/out/extra.js', diff --git a/.vscodeignore b/.vscodeignore index ec2a3674..ce7fa89c 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -20,6 +20,16 @@ CONTRIBUTING.md probe-*.mjs issue87-*.cjs out/claudeIncrementalPrototype.js +out/adviceEffectiveness/evidencePreparation.js +out/adviceEffectiveness/feedback.js +out/adviceEffectiveness/legacyBridge.js +out/adviceEffectiveness/legacyPersonalization.js +out/adviceEffectiveness/modelExperiment.js +out/adviceDemoSample.js +out/adviceSummary.js +AI-ADVICE-*V2.3.1*.md +CLAUDE-COLD-AB-V2.3.1*.md +V2.3.1-CANDIDATE-CONTRACT*.md docs/** .gitignore diff --git a/AGENTS.zh-CN.md b/AGENTS.zh-CN.md index 524e0cab..86e2e667 100644 --- a/AGENTS.zh-CN.md +++ b/AGENTS.zh-CN.md @@ -177,3 +177,9 @@ Co-authored-by: OpenAI Codex <215057067+openai-codex[bot]@users.noreply.github.c ``` - comment-only 的受控 first-pass automation 与 maintainer-only 的高权限 mention workflow 必须保持分离。 + +## Codex 工具适配 + +浏览器操作使用当前可用的 Codex browser/computer-use 工具;原文中的 Claude MCP +工具名称只描述操作意图,不能直接调用。提问按当前模式使用可用工具;Git 操作仍须 +获得当次明确授权。 diff --git a/AI-ADVICE-EFFECTIVENESS-V2.3.1.md b/AI-ADVICE-EFFECTIVENESS-V2.3.1.md new file mode 100644 index 00000000..0f8d8ee0 --- /dev/null +++ b/AI-ADVICE-EFFECTIVENESS-V2.3.1.md @@ -0,0 +1,132 @@ +# v2.3.1 AI 建议有效性:候选实现说明 + +## 状态与边界 + +当前 worktree 是从正式 `v2.3.0` 基线选择性移植并继续收敛的 v2.3.1 本地候选;版本号、 +release workflow 与发布入口保持不变,尚未发布。 + +候选代码已经进入 `extension.ts`、`webview.ts` 与生产 VSIX 路径,但相关功能默认关闭。 +关闭、隐藏或未授权时不创建 AI timer、watcher、worker、network 或额外日志扫描。启用后, +只有用户先检查完整请求预览、再另行点击“发送”,才会调用现有用户配置的 BYOK endpoint。 +旧 `Get AI Advice` 命令仅打开这一统一界面;Prompt Optimizer 也使用同一 prepare → preview → +explicit Send → strict parse → local feedback 边界,不再保留一次性持久授权或宽松 parser fallback。 + +## 新增核心 + +### `src/adviceEffectiveness/contract.ts` + +`AdviceContract` 是 provider-neutral 的 v1 契约,统一保存: + +- host 生成的本地 observation 与 evidence; +- direct / correlational / proxy 证据强度; +- AI 只能引用已有证据的 explanation; +- 带 `when` 与 stop condition 的 conditional action; +- 带最小可比任务数与质量 guardrail 的 success criterion; +- host 盖章的 privacy、source、confidence、quality flags 与 provenance。 + +模型不能提供 observation、evidence、privacy 或 provenance。`createAdviceContract()` +只在整个引用图和隐私声明一致时返回 `{ ok: true }`。空 recommendations 是合法的 +“没有足够证据下结论”,不会自动补通用建议。 + +### `src/adviceEffectiveness/payload.ts` + +`buildAdviceAggregateSnapshot()` 只消费现有 `UsageData` aggregate,并通过 allow-list +重建 DTO。完整/自定义 model ID 被压成 `opus / sonnet / haiku / fable / other`;raw +record、project label/path、cwd、session、prompt、response、credential 没有目标字段。 +可远程发送的 metric 还有单独 allow-list;新增 metric 必须经过显式隐私评审。low/unknown +confidence 或仍带 quality flag 的 source 会在 payload 生成前失败,不会要求模型填补缺口。 + +`prepareAdvicePayload()` 默认生成 `aggregates-only` 的内层 evidence body,且序列化结果中完全没有 +`promptSamples` key。只有调用者额外提供: + +```ts +{ consent: 'explicit', samples: [{ text: '...' }] } +``` + +才会加入受数量、单条长度和总长度限制的 prompt 文本;sample 上的 `cwd` 等多余字段仍会被 +丢弃。`advice.userContext` 与 prompt sample 共用独立于 aggregate 的 personalization consent; +未授权时两者都不进入 body,授权后必须逐字出现在完整预览中。 + +生产路径再由 `preparedRequest.ts` 把内层 evidence body 封装为完整 Anthropic / OpenAI-compatible +provider HTTP JSON body。该 body 只序列化一次,生成 host-retained `PreparedAiInvocation`、 +`canonicalBytes` 与 SHA-256;预览从同一 bytes 解码,实际发送和同一次发送内的 retry / curl +fallback 继续复用该 Prepared bytes。API key 只在发送边界加入 header,不进入预览 body。 + +### `src/adviceEffectiveness/versionedPersistence.ts` + +生产反馈统一写入 `ccu.adviceEffectiveness.localState` v2 envelope,只接受 +`helpful / not-helpful / applied`、格式验证后的 advice/recommendation ID 与本地 epoch 时间。 +它不接受自由文本、prompt、payload、解释、endpoint、path 或 session ID。helpful 与 +not-helpful 互斥,applied 独立;再次点击已选状态会撤回并在全部状态清空时删除该条记录。 +Advice 的每条 recommendation 与 Prompt Optimizer 的每次结果都走同一个写入函数。 +损坏、未知版本或带额外字段的数据 fail closed,写失败后不会用旧快照覆盖新决定。 + +### `src/adviceEffectiveness/comparison.ts` + +`compareAdviceEffectiveness()` 是无时间/IO 依赖的 paired comparison。只有以下条件全部 +满足,才可能返回 `improved`: + +- task kind、complexity、provider、model family、effort、metric definition、单位、方向、 + quality rubric 在 pair 内和 cohort 间一致; +- coverage complete,confidence 不是 low/unknown,无未允许的 quality flag; +- 达到预先声明的最小 pair 数,数值均为有限值且 baseline 非零; +- before/after 质量证据已知,after 全部通过 rubric; +- 主指标达到阈值,同时 minimum quality 与最大允许退化两个 guardrail 都守住。 + +任何可比性、覆盖、置信度、数值或质量证据问题都返回 `insufficient-evidence`。主指标 +改善但质量退化返回 `quality-guardrail-failed`;没有达到预设幅度只返回 +`no-demonstrated-improvement`,不声称建议造成伤害或收益。 + +`comparisonPairing.ts`、`comparisonProduction.ts` 与 `comparisonResult.ts` 把这条纯比较边界接入 +真实、已净化的 provider/task-level 物化 aggregate。只有 scope、task kind、complexity、provider、 +model、effort、metric definition 与 quality rubric 全部相同,且 applied 时间能可靠划分前后时, +才形成 comparable pair。版本化 result envelope 只保存 schema、provider、measurement / recommendation +version、guardrail、replay eligibility、sample 与 result;prompt、response、session、path、正文和未知字段 +没有目标字段。无可靠 pair 时 UI 明确显示“证据不足”。 + +### `src/adviceEffectiveness/structuredOutput.ts` + +`parseStructuredAdviceOutput()` 只接受一个严格 JSON 值,并逐层拒绝未知/缺失字段、错误 +schema version、非法枚举、超长/超量内容、重复 ID、空 action/criterion 和未知证据引用。 +任一 recommendation 非法会拒绝整批。它不会剥 Markdown fence、修 JSON、接受尾随 prose、 +返回 partial batch,或把 raw 输出 fallback 成看似有效的建议;错误结果也不回显 raw 模型 +正文。`recommendations: []` 是明确的 no-conclusion 成功结果。 + +## 当前生产闭环 + +1. **本地证据**:Claude 只消费 `claudeIncrementalIndex` 已物化的同窗口 aggregate / session + summary;Codex 只消费现有结构化数值 insight 与任务级物化 aggregate,不新增日志扫描器。 +2. **独立 consent**:Advice 的 aggregate consent 与 prompt-personalization consent 分开持久化; + 默认是 aggregates-only。Optimizer 只包含用户主动粘贴的 draft,不使用持久网络授权。 +3. **exact preview / explicit Send**:host 保留完整 Prepared provider body;Webview 只持有 opaque + snapshot ID、精确 body、byte count、content type、data mode 与 SHA-256。只有另行 Send 点击会联网。 +4. **唯一生产 sender**:Advice 与 Optimizer 都进入 `sendPreparedModelRequest()` → + `sendPreparedAiInvocation()`,且只能使用配置的 BYOK key / endpoint。 +5. **strict response**:Advice 只接受 exact-shape JSON 与已知 evidence references;Optimizer 只接受 + 完整 marker / 三行 settings contract。任一失败都不显示 raw 或自由文本 fallback。 +6. **可撤销本地 feedback**:每条 Advice recommendation 和 Optimizer result 共用 v2 bounded ledger; + 不接 analytics、telemetry、contribution endpoint 或 advice payload。 +7. **有效性评估**:只有 applied 后出现严格可比的前后任务时才写 pair / result envelope;否则显示 + `insufficient-evidence`。结果是受控描述性证据,不是因果证明。 + +## 排除项与剩余边界 + +- `claudeCodeUsage.getAdvice` 只打开统一 Content 界面,不再构建旧 summary 或直接调用模型。 +- `legacyBridge.ts`、`adviceSummary.ts`、旧 demo / personalization / experiment 准备模块被排除出 VSIX, + 且 `extension.ts` / `webview.ts` 没有生产调用点;它们不能成为默认或第三条 sender。 +- 生产 backend 固定为 BYOK `api`。Claude Code OAuth/subscription 凭据仅服务既有 quota/usage, + 不用于 Advice 或 Optimizer,也不存在后台模型请求。 +- Codex remote advice 仍保持关闭;Codex recommendation 与 comparison 使用本地结构数据。 +- comparison 不做显著性或因果识别;缺少可靠 cohort、质量证据或最小样本时保持证据不足。 +- feedback 不存自由文本、不同步、不发 telemetry;Optimizer feedback 当前不触发 comparable-task comparison。 + +## 验证 + +测试平铺在 `src/test/` 与 `tests/ui/`,覆盖契约引用、完整 Prepared preview/send object identity、 +默认 aggregates-only、prompt 独立 opt-in、Optimizer 关闭态与严格 parser、敌意隐私字段注入、 +可撤销本地 feedback、真实 pairing / 版本化 result envelope、可比性 / quality guardrail 以及 +未知字段 fail-closed。候选验证仍按仓库流程运行: + +```bash +npm test +``` diff --git a/AI-ADVICE-INTEGRATION-DESIGN-V2.3.1.md b/AI-ADVICE-INTEGRATION-DESIGN-V2.3.1.md new file mode 100644 index 00000000..53fb5e0b --- /dev/null +++ b/AI-ADVICE-INTEGRATION-DESIGN-V2.3.1.md @@ -0,0 +1,120 @@ +# v2.3.1 AI Advice Effectiveness: Experimental UI Design Plan + +> Status: v2.3.1 integration candidate only. The feature flag is off by default; +> this document is not a current-release commitment. + +## Goal and boundaries + +The UI answers one question: can a user see which local evidence supports an +advice candidate, exactly what would leave the device, and how effectiveness +would be judged before opting in? It extends the existing AI Advice and Prompt +Optimizer cards on the Content tab instead of adding a third top-level entry. + +Both features are off by default and create no AI network work while disabled. +When enabled, AI Advice and Prompt Optimizer use the same interaction grammar: +prepare a complete provider HTTP JSON body, preview its exact UTF-8 bytes, require +a separate explicit Send click, strictly parse the response, and offer reversible +local helpful / not-helpful / applied feedback. There is no automatic or default +model request. + +## Visual system + +- **Color:** use existing VS Code theme tokens only. Background and copy use + `--vscode-editor-background` / `--vscode-foreground`; borders and secondary + copy use `--vscode-panel-border` / `--vscode-descriptionForeground`; actions + and focus use `--vscode-button-background` / `--vscode-focusBorder`; the + snapshot uses `--vscode-editorWidget-background`. Light+ and Dark+ remain + host-owned, with no new gradient or hard-coded brand accent. +- **Type:** explanatory copy uses `--vscode-font-family` at the existing 13px + density. Metrics, byte counts, and JSON use `--vscode-editor-font-family`. + Small 10–11px status stamps never carry meaning by color alone. +- **Spacing:** reuse `.action-card`, `.model-details-stacked`, and the existing + button/input rhythm. Avoid a new oversized KPI-card language. +- **Signature:** one continuous evidence spine joins five ordered stages. The + sealed snapshot header reads `SEALED · N BYTES · SHA-256`, and its body is + decoded verbatim from the same canonical UTF-8 bytes. + +## Information architecture and wireframe + +Wide layout: + +```text +┌ AI advice effectiveness (experimental) ──────────────────────────┐ +│ [Observed] ─── [Evidence] ─── [Advice] ─── [Action] ─── [Result] │ +│ values strength conditional local feedback │ +│ sample/guardrail│ +│ │ +│ □ Allow aggregates only □ Allow prompt samples (separate, off) │ +│ [Create sealed snapshot] │ +│ ▾ SEALED · 1248 BYTES · SHA-256 · AGGREGATES ONLY │ +│ {"schemaVersion":1,...} │ +│ [Send prepared request] (disabled until a valid preview exists) │ +│ Helpful ○ Not helpful ○ Applied ○ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +At narrow widths the five stages stack vertically and the spine becomes a left +rail. Consent controls and actions wrap naturally. JSON scrolls horizontally; +actual transmitted bytes are never compressed or elided. + +## Interaction and accessibility + +- Aggregate consent and prompt-personalization consent are separate values in + version-migrated VS Code `globalState`. Both start off; prompt consent is + disabled until aggregate consent is selected. Every included prompt is + visible in the sealed snapshot. +- “Create sealed snapshot” asks the extension host to prepare the object. The + host rechecks the flag and consent, serializes the complete provider body once, + and retains its canonical UTF-8 bytes. Preview text, byte count, and SHA-256 all + come from that object. The separately clicked Send action resolves the opaque + snapshot ID and passes the same Prepared object to the sole production BYOK + transport; it cannot rebuild a request from webview text. +- Prompt Optimizer has the same preview and Send stages. Its body contains only + the pasted draft plus the fixed optimizer system instruction and configured + model fields; it has no persistent “first-run authorization.” +- Advice output uses the strict evidence-referencing JSON parser. Optimizer output + uses its strict marker/settings parser. Neither repairs malformed output or + falls back to free-form prose. +- Helpful / not helpful / applied are native buttons with `aria-pressed` for + every advice recommendation and for an Optimizer result. Selecting an active + button again withdraws that value. Helpful and not helpful are mutually + exclusive; applied is independent. All mutations use the same bounded local + `globalState` envelope and never enter a remote payload. +- Every action is keyboard reachable. Headings, lists, `fieldset` / `legend`, + `aria-live`, and VS Code focus tokens give screen-reader and focus semantics. + Consent, disclosure, and provider UI state survive a webview reload. +- The result stage says “insufficient evidence” until comparable sample and + quality guardrails are met; a one-off movement is never called effective. + +## Content and privacy rules + +- The default route carries same-window aggregate numbers, coarse model families, + allow-listed metrics, confidence, and evidence references only. It never accepts + or serializes raw sessions, per-record data, prompts, responses, project paths, + cwd values, or stable session IDs. +- Long sessions use elapsed-duration as a proxy; large context uses numeric token + thresholds. A conditional “start a new session / `/clear` at a stable task + boundary” action appears only when deterministic thresholds and sample rules pass. +- Topic drift is semantic. It may enter the AI Advice model request only after + separate prompt-personalization consent, with every included prompt visible in + the exact preview. The host never infers drift from body-free signals. +- Strict parse failure, unknown persistence versions, damaged state, or incomplete + evidence closes the result and never produces a permissive fallback suggestion. +- `claudeCodeUsage.getAdvice` only reveals the unified Content surface. It does + not call a model, build a legacy summary, or open a separate Markdown result. +- `legacyBridge.ts`, `adviceSummary.ts`, and the demo/preparation modules have no + production import and are excluded from the VSIX. They are neither a default + transport nor a third sender. +- Only the configured Anthropic/OpenAI-compatible BYOK endpoint may receive these + requests. Claude Code OAuth/subscription credentials are not an AI backend, and + no preview, refresh, timer, or background task sends a model request. + +## Design critique and revision + +An early direction risked becoming another generic dashboard and a third isolated +experience. The revision embeds the evidence chain in the existing Advice card and +applies the same preview, Send, strict-result, and feedback grammar to Prompt +Optimizer. The only new visual signature is the sealed byte snapshot because it +directly supports privacy review. Narrow layouts, keyboard use, screen readers, and +theme changes remain candidate checks; with either feature disabled, its host +message seam fails closed and creates no AI network resource. diff --git a/AI-ADVICE-INTEGRATION-DESIGN-V2.3.1.zh-CN.md b/AI-ADVICE-INTEGRATION-DESIGN-V2.3.1.zh-CN.md new file mode 100644 index 00000000..2d1ab032 --- /dev/null +++ b/AI-ADVICE-INTEGRATION-DESIGN-V2.3.1.zh-CN.md @@ -0,0 +1,92 @@ +# v2.3.1 AI 建议有效性:实验界面设计计划 + +> 状态:仅用于 v2.3.1 候选集成。功能开关默认关闭;本文不代表当前发布承诺。 + +## 设计目标与边界 + +界面服务于一个明确问题:用户能否先看清“哪些本地证据支持哪条建议、若继续会发送什么、 +应用后怎样判断是否有效”,再决定是否参与实验。它扩展 Content 页已有的 AI Advice 与 Prompt +Optimizer 卡片,不增加第三个顶层入口。 + +两项功能都默认关闭,关闭时不创建任何 AI 网络工作。启用后,AI Advice 与 Prompt Optimizer +使用同一种交互语法:准备完整 provider HTTP JSON body、精确预览其 UTF-8 bytes、要求用户另行 +明确点击“发送”、严格解析响应,并提供可撤销的本地“有用 / 无用 / 已应用”反馈。不存在自动或 +默认模型请求。 + +## 视觉系统 + +- **颜色**:只使用现有 VS Code 主题令牌。背景与正文使用 + `--vscode-editor-background` / `--vscode-foreground`;边界和次级文本使用 + `--vscode-panel-border` / `--vscode-descriptionForeground`;交互和焦点使用 + `--vscode-button-background` / `--vscode-focusBorder`;快照使用 + `--vscode-editorWidget-background` 与编辑器等宽字体。Light+ 与 Dark+ 均由宿主主题决定, + 不引入品牌外的渐变或硬编码强调色。 +- **字体**:说明文字沿用 `--vscode-font-family` 与现有 13px 密度;指标、字节数和 JSON + 使用 `--vscode-editor-font-family`。小型状态章保持 10–11px,但不承载唯一语义。 +- **空间**:沿用 `.action-card`、`.model-details-stacked`、现有按钮与输入组件的间距, + 保持 Content 页的信息密度,不新增“大号 KPI 卡片”风格。 +- **标志性元素**:一条连续的“证据脊柱”连接五个有序阶段;密封快照标题显示 + `SEALED · N BYTES · SHA-256`,正文逐字呈现同一组 canonical UTF-8 bytes。 + +## 信息架构与草图 + +宽屏: + +```text +┌ AI 建议有效性(实验)──────────────────────────────────────────────┐ +│ [观察] ─── [证据] ─── [建议] ─── [行动] ─── [结果] │ +│ 数值 强度 有条件 本地反馈 样本/质量护栏 │ +│ │ +│ □ 仅允许聚合数据 □ 允许附加用户 prompt(默认关,独立同意) │ +│ [生成密封快照] │ +│ ▾ SEALED · 1248 BYTES · SHA-256 · AGGREGATES ONLY │ +│ {"schemaVersion":1,...} │ +│ [发送已准备请求](只有有效预览后才启用) │ +│ 有用 ○ 无用 ○ 已应用 ○ │ +└──────────────────────────────────────────────────────────────────┘ +``` + +窄屏时五个阶段改为纵向排列,脊柱成为左侧竖线;同意项和按钮自然换行,JSON 区域横向滚动, +不压缩或省略发送字节。 + +## 交互与可访问性 + +- 两项同意分开保存于带版本迁移的 VS Code `globalState`:聚合数据默认未同意;prompt 个性化默认关闭, + 且只有聚合同意后才可选择。prompt 的正文必然出现在密封快照中。 +- “生成密封快照”只向 extension host 请求准备对象。host 再次验证实验开关与同意状态,只序列化 + 一次完整 provider body,并保留 canonical UTF-8 bytes;预览正文、byte count 与 SHA-256 都由 + 该对象派生。用户另行点击“发送”后,host 才通过 opaque snapshot ID 取回同一个 Prepared 对象, + 交给唯一生产 BYOK transport;不能从 webview 文本重建请求。 +- Prompt Optimizer 使用相同的预览与发送阶段。其 body 只包含用户粘贴的 draft、固定 optimizer + system instruction 与已配置模型字段;不存在持久的“首次运行授权”。 +- Advice 输出只进入严格的 evidence-reference JSON parser;Optimizer 输出只进入严格的 marker / settings + parser。两者都不修复畸形输出,也不 fallback 到自由文本。 +- 每条 Advice recommendation 和每次 Optimizer 结果都使用原生 `