docs: replace vague provenance prose with recorded facts
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/proposed/feature/2026-07-06-recallable-compaction.md
|
||||
2026-07-06-recallable-compaction.md: ed5491e642ea7ac99fd9f4ba071a61e655f968d3
|
||||
2026-07-06-recallable-compaction.zh.md: dabc606d0056e91f9ac473de6f166083bcee25e8
|
||||
2026-07-06-recallable-compaction.md: 6f7baedeaae0038b7f5106cd5fc4e23bdfbbd8dd
|
||||
2026-07-06-recallable-compaction.zh.md: cbf8b4a3843ca35647cc569255dfe9d26b45b988
|
||||
|
||||
@@ -6,7 +6,7 @@ English | [中文](2026-07-06-recallable-compaction.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
Compaction is a one-way door. The summary the model sees carries no reference to what it shadows — the `shadowedRange` provenance lives only on the log-only `compact/summary` event — and no tool lets the model read a shadowed span back. Whatever the summarizer drops is gone from the model's reachable world, even though the append-only log holds every byte. Repeated compaction compounds this: the head checkpoint is rewritten every pass, so the request prefix takes a full prompt-cache miss each time, and earlier summaries are re-summarized generation after generation.
|
||||
Compaction is irreversible from the model's current context. The summary the model sees carries no reference to what it shadows — `shadowedRange` lives only on the log-only `compact/summary` event — and no tool lets the model read a shadowed span back. Whatever the summarizer drops is unavailable to the model, even though the append-only log holds every byte. Repeated compaction compounds this: the head checkpoint is rewritten every pass, so the request prefix takes a full prompt-cache miss each time, and earlier summaries are re-summarized generation after generation.
|
||||
|
||||
The root cause is one artifact playing two conflicting roles. An **index** wants to be frozen, chronological, and cheap; the model's **working memory** wants a global view, re-prioritization, and mutability. A single summary can be neither well.
|
||||
|
||||
@@ -22,7 +22,7 @@ Newly stale history splits into chunks by deterministic policy: accumulate towar
|
||||
|
||||
- two or three lines of what happened;
|
||||
- a keyword line of low-frequency literal anchors — exact error strings, values, config keys — grouped by kind;
|
||||
- a code-composed footer: `[checkpoint c<summarySeq>: shadows conversation span #<start>–#<end>; originals retrievable via history_read]`. Pointers are assembled from provenance, never model-authored.
|
||||
- a code-composed footer: `[checkpoint c<summarySeq>: shadows conversation span #<start>–#<end>; originals retrievable via history_read]`. Code assembles these pointers from the `compact/summary` seq and `shadowedRange`; the model never writes them.
|
||||
|
||||
A committed stub is never rewritten and never re-enters a later compaction region. A stub call's input is layered: the fixed preamble and the byte-identical pass-start state checkpoint (the shared prefix across all calls in the phase), then the keyword lines of all previously committed stubs — so a new entry indexes what is distinctive to its chunk instead of repeating the directory — the one or two most recent committed stubs for chronological continuity, and the slice itself. Sibling stubs from the same pass are not inputs (the concurrent phase forbids it; turn-aligned boundaries carry local continuity instead), and the state checkpoint is background only, never material to summarize into the stub. A slice consisting of recalled content is stubbed by code alone — a pointer line, no LLM call. A failed stub call degrades the same way: its slice gets a code-only pointer stub and the pass continues, making the state rewrite the only hard LLM dependency in a pass.
|
||||
|
||||
@@ -46,7 +46,7 @@ A new package `@deepseek-ai/dsh-tool-recall` (consumer-only, over the `dsh-sessi
|
||||
- `history_read(checkpoint, offset?)` — renders the shadowed span of any checkpoint in the log, including superseded ones, as `User:`/`Assistant:`/`Tool result:` transcript, paginated by a configured budget with a continuation cursor.
|
||||
- `history_search(query, checkpoint?, limit?)` — case-insensitive literal scan over every shadowed span; returns snippets with checkpoint ids and coverage metadata (`scanned`/`matched`/`truncated`). The zero-match hint notes the scan is literal and points at direct `history_read` of a plausible checkpoint.
|
||||
|
||||
Both read `exec.agent.session.events` (the tool-todo access pattern; non-agent callers rejected), render only surface-type message events, and return ordinary `tool/result`s — recalled bytes land at the context tail, logged, so reconstructability holds with no special casing. There is no new storage and no sidecar index: the session log is the archive, `compact/summary` provenance is the index metadata, and the tools are a read path over both. The tool schemas and the package's one system-prompt section are static strings; checkpoint ids reach the model only through footers. The transcript renderer moves from `compact-basic` into `dsh-session`, shared by summarizer and tools.
|
||||
Both read `exec.agent.session.events` (the tool-todo access pattern; non-agent callers rejected), render only surface-type message events, and return ordinary `tool/result`s — recalled bytes land at the context tail, logged, so reconstructability holds with no special casing. There is no new storage and no sidecar index: the session log stores the content, `compact/summary.shadowedRange` and `shadowedSeqs` identify what each checkpoint replaced, and the tools read both. The tool schemas and the package's one system-prompt section are static strings; checkpoint ids reach the model only through footers. The transcript renderer moves from `compact-basic` into `dsh-session`, shared by summarizer and tools.
|
||||
|
||||
### Cache and cost
|
||||
|
||||
@@ -94,7 +94,7 @@ Specified during review, deferred until observation calls for them:
|
||||
## Acceptance criteria
|
||||
|
||||
- Auto-compaction over a long session yields `[stubs…][state][tail]` after every completed pass; prior stubs stay byte-identical across passes; committed stubs never fall inside a later region; the superseded state checkpoint folds without a tombstone, renders labeled, and stays reachable and searchable through the two-hop chain.
|
||||
- Every checkpoint's surface text ends with the deterministic footer; footers round-trip through replay byte-identically; the state checkpoint's provenance records its wider input range.
|
||||
- Every checkpoint's surface text ends with the deterministic footer; footers round-trip through replay byte-identically; the state checkpoint's `shadowedRange` records its wider input range.
|
||||
- Nothing commits before all summaries exist and the guard passes on like-for-like accounting; a guard failure commits nothing and does not fail the turn; a mid-commit kill resumed at the next pre-step completes the pass with the state region committed unconditionally, merge base read from the log; a legacy head checkpoint is adopted as state-class.
|
||||
- `history_read` renders any logged checkpoint's span under budget with a working cursor; `history_search` covers every shadowed span with checkpoint-id snippets and coverage metadata, asserted in particular by finding content that exists only in a span shadowed by a superseded state checkpoint — the regression pin for trailing-slice reachability; both reject non-agent callers and never-existing ids or orphaned `compact/start` with typed errors; recalled content appears as ordinary `tool/result`s; request-reconstruction invariants pass over sessions with compaction plus recall; one keyless snapshot scenario covers compact-then-recall end to end; tool schemas and the prompt section are byte-identical across passes.
|
||||
- On the long-horizon bench suite: task success does not regress against `compact-basic` at equal budgets; a handoff-fidelity probe (restate K known decisions and constraints after a pass) scores no worse; recall usage frequency and hit usefulness are reported per run via the dsh bench report pipeline, alongside the stub-directory attention measurement and cache-hit telemetry.
|
||||
|
||||
@@ -6,7 +6,7 @@ Status: proposed
|
||||
|
||||
## 问题
|
||||
|
||||
压缩(compaction)是一扇单向门。模型看到的摘要没有指向被其遮蔽内容的引用,因为 `shadowedRange` 来源只存在于仅写入日志、模型不可见的 `compact/summary` 事件上,也没有工具能让模型重新读取被遮蔽的区段。即使仅追加日志仍保存每一个字节,摘要器丢弃的内容也会离开模型可触达的世界。重复压缩会进一步放大问题:每一轮都会重写头部检查点,因此请求前缀每次都会完全失去提示词缓存命中,而更早的摘要也会一代又一代地被重新摘要。
|
||||
压缩(compaction)对模型的当前上下文不可逆。模型看到的摘要没有指向被其遮蔽内容的引用,因为 `shadowedRange` 只存在于仅写入日志、模型不可见的 `compact/summary` 事件上,也没有工具能让模型重新读取被遮蔽的区段。即使仅追加日志仍保存每一个字节,摘要器丢弃的内容也对模型不可用。重复压缩会进一步加重这些结果:每一轮都会重写头部检查点,因此请求前缀每次都会完全失去提示词缓存命中,而更早的摘要也会在后续每一轮中重新生成摘要。
|
||||
|
||||
根本原因是一个产物承担了两个互相冲突的角色。**索引** 需要冻结、按时间排序且成本低廉;模型的**工作记忆** 则需要全局视图、重新确定优先级并且可变。单一摘要无法同时胜任两者。
|
||||
|
||||
@@ -22,7 +22,7 @@ Status: proposed
|
||||
|
||||
- 用两三行说明发生了什么;
|
||||
- 用一行关键词记录低频字面锚点,例如确切的错误字符串、值和配置键,并按类别分组;
|
||||
- 由代码组装页脚:`[checkpoint c<summarySeq>: shadows conversation span #<start>–#<end>; originals retrievable via history_read]`。指针根据来源组装,绝不由模型编写。
|
||||
- 由代码组装页脚:`[checkpoint c<summarySeq>: shadows conversation span #<start>–#<end>; originals retrievable via history_read]`。代码根据 `compact/summary` seq 和 `shadowedRange` 组装这些指针,模型绝不会编写它们。
|
||||
|
||||
已经提交的存根永不重写,也绝不再次进入之后的压缩区域。存根调用采用分层输入:固定前导内容与逐字节相同的本轮开始状态检查点(该阶段所有调用共享的前缀);随后是先前所有已提交存根的关键词行,使新条目索引其分片的独特内容,而不是重复整个目录;再加最近一两个已提交存根以维持时间连续性;最后是切片本身。同一轮中的同级存根不作为输入,因为并发阶段禁止这种依赖,而与轮次对齐的边界已经维持局部连续性。状态检查点只作为背景,绝不能成为存根需要总结的材料。完全由回溯内容构成的切片只通过代码生成存根,即只写一行指针,不调用 LLM(大语言模型)。存根调用失败时采用相同降级方式:其切片获得一个仅由代码生成的指针存根,本轮继续执行,使状态重写成为一轮中唯一的强制 LLM 依赖。
|
||||
|
||||
@@ -46,7 +46,7 @@ Status: proposed
|
||||
- `history_read(checkpoint, offset?)`:把日志中任意检查点(包括已被取代的检查点)遮蔽的区段渲染为 `User:`/`Assistant:`/`Tool result:` transcript(文本记录),并按配置预算分页,提供续传游标。
|
||||
- `history_search(query, checkpoint?, limit?)`:对每个被遮蔽区段进行不区分大小写的字面量扫描;返回带检查点 id 的片段与覆盖元数据(`scanned`/`matched`/`truncated`)。零匹配提示会说明扫描按字面量执行,并建议对可能的检查点直接使用 `history_read`。
|
||||
|
||||
两个工具都读取 `exec.agent.session.events`(沿用 tool-todo 访问模式;拒绝非 agent(智能体)调用方),只渲染表面类型的消息事件,并返回普通 `tool/result`:回溯字节会进入上下文尾部并记录到日志,因此无需特殊处理即可满足可重建性。系统不增加新存储或伴随索引:会话日志是归档,`compact/summary` 来源是索引元数据,而这些工具是两者之上的读取路径。工具 schema 与该包唯一的系统提示词章节都是静态字符串;检查点 id 只会通过页脚抵达模型。transcript 渲染器从 `compact-basic` 移入 `dsh-session`,供摘要器与工具共享。
|
||||
两个工具都读取 `exec.agent.session.events`(沿用 tool-todo 访问模式;拒绝非 agent(智能体)调用方),只渲染表面类型的消息事件,并返回普通 `tool/result`:回溯字节会进入上下文尾部并记录到日志,因此无需特殊处理即可满足可重建性。系统不增加新存储或伴随索引:会话日志存储内容,`compact/summary.shadowedRange` 和 `shadowedSeqs` 指明每个检查点替换了什么,这些工具读取两者。工具 schema 与该包唯一的系统提示词章节都是静态字符串;检查点 id 只会通过页脚抵达模型。transcript 渲染器从 `compact-basic` 移入 `dsh-session`,供摘要器与工具共享。
|
||||
|
||||
### 缓存与成本
|
||||
|
||||
@@ -94,7 +94,7 @@ Status: proposed
|
||||
## 验收标准
|
||||
|
||||
- 长会话自动压缩后,每一轮完成时都会得到 `[stubs…][state][tail]`;先前存根在各轮之间保持逐字节相同;已提交存根绝不落入后续区域;被取代的状态检查点无需墓碑即可折入历史,渲染时带有标签,并可通过两跳链路触达和搜索。
|
||||
- 每个检查点的表面文本都以确定性页脚结束;页脚通过回放逐字节往返;状态检查点的来源记录其更宽的输入范围。
|
||||
- 每个检查点的表面文本都以确定性页脚结束;页脚通过回放逐字节往返;状态检查点的 `shadowedRange` 记录其更宽的输入范围。
|
||||
- 在全部摘要就绪且保护逻辑通过同类核算前,不提交任何内容;保护失败不会提交任何内容,也不会让轮次失败;提交中途被终止后,下一次 pre-step 会恢复处理,从日志读取合并基线,并无条件提交状态区域以完成本轮;旧版头部检查点会被视为状态类。
|
||||
- `history_read` 在预算内渲染任意已记录检查点的区段,并提供可用游标;`history_search` 覆盖每个被遮蔽区段,返回带检查点 id 的片段与覆盖元数据,测试尤其要能找到只存在于被已取代状态检查点遮蔽区段中的内容,这是锁定尾随切片可达性的回归用例;两个工具都会拒绝非 agent 调用方,并对从未存在的 id 或遗留 `compact/start` 返回类型化错误;回溯内容作为普通 `tool/result` 出现;请求重建不变量会在同时包含压缩与回溯的会话上通过;一项无密钥快照场景端到端覆盖先压缩再回溯;工具 schema 与提示词章节在各轮之间逐字节相同。
|
||||
- 在长时间跨度 bench 套件中:任务成功率在预算相同的条件下不低于 `compact-basic`;交接保真探针(在一轮后重新陈述 K 项已知决策和约束)的得分不降低;每次运行都通过 dsh bench 报告流水线汇报回溯使用频率和命中有效性,并同时报告存根目录注意力度量与缓存命中遥测。
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/proposed/feature/2026-07-08-interactive-side-sessions.md
|
||||
2026-07-08-interactive-side-sessions.md: dfd325babe215782c9c1cbec3fd9f874783af7ab
|
||||
2026-07-08-interactive-side-sessions.zh.md: a1441cfe12df933855c7b9fe08c5e09f9e6107d3
|
||||
2026-07-08-interactive-side-sessions.md: 228380ca2d3d7b2efeb37e713574e1863ce17f38
|
||||
2026-07-08-interactive-side-sessions.zh.md: f4e3bfdddff16fe687f2637b3626e7e1382eba61
|
||||
|
||||
@@ -6,7 +6,7 @@ English | [中文](2026-07-08-interactive-side-sessions.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
A user may want to explore a question from a live session without changing its main context. Existing primitives do not expose that product shape: [session-store fork](../../implemented/feature/2026-06-30-session-store-fork-api.md) creates an unattached session, while [fork subagents](../../implemented/feature/2026-06-21-subagent-capability-seam.md) are model-driven tasks whose transcript collapses into one tool result. Neither gives the user a separate conversation, and neither records a conclusion back into the parent with provenance.
|
||||
A user may want to explore a question from a live session without changing its main context. Existing primitives do not expose that product shape: [session-store fork](../../implemented/feature/2026-06-30-session-store-fork-api.md) creates an unattached session, while [fork subagents](../../implemented/feature/2026-06-21-subagent-capability-seam.md) are model-driven tasks whose transcript collapses into one tool result. Neither gives the user a separate conversation, and neither records a conclusion in the parent together with the side session that produced it.
|
||||
|
||||
## Proposal
|
||||
|
||||
@@ -23,7 +23,7 @@ Rewind productization, session-tree views, a model-facing side-session tool, and
|
||||
|
||||
- **Use the subagent seam:** rejected because side sessions are user-driven, client-visible, and may outlive a parent turn; subagents are model-driven runs returning one tool result.
|
||||
- **Change the child system prompt:** rejected by default because any byte change invalidates the prefix cache from token zero. Deployments may still prefer that stronger separation.
|
||||
- **Add `sidechat/*` events:** deferred because a sourced `context/message` already provides durability, provenance, and replay. A dedicated event is justified only by a surface that needs distinct rendering.
|
||||
- **Add `sidechat/*` events:** deferred because a sourced `context/message` already records the content, producer, and replay input durably. A dedicated event is justified only by a surface that needs distinct rendering.
|
||||
- **Bind a protocol surface now:** rejected because current UIs are client-owned. Live presentation must eventually derive from the durable message so replay renders the same record.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
@@ -6,7 +6,7 @@ Status: proposed
|
||||
|
||||
## 问题
|
||||
|
||||
用户可能希望在不改变当前会话主上下文的前提下,探索一个来自活跃会话的问题。现有原语无法提供这种产品形态:[会话存储 fork](../../implemented/feature/2026-06-30-session-store-fork-api.md)创建的是一个无关联的会话,而 [fork subagent](../../implemented/feature/2026-06-21-subagent-capability-seam.md)是模型驱动的任务,其 transcript(文本记录)会折叠为一条工具结果。两者都不能给用户一个独立的对话,也都不能将结论带着出处信息记录回父会话。
|
||||
用户可能希望在不改变当前会话主上下文的前提下,探索一个来自活跃会话的问题。现有原语无法提供这种产品形态:[会话存储 fork](../../implemented/feature/2026-06-30-session-store-fork-api.md)创建的是一个无关联的会话,而 [fork subagent](../../implemented/feature/2026-06-21-subagent-capability-seam.md)是模型驱动的任务,其 transcript(文本记录)会折叠为一条工具结果。两者都不能给用户一个独立的对话,也都不能在父会话中同时记录结论和产生该结论的侧会话。
|
||||
|
||||
## 提案
|
||||
|
||||
@@ -23,7 +23,7 @@ Status: proposed
|
||||
|
||||
- **使用 subagent seam:** 否决。侧会话是用户驱动的、客户端可见的,且可能存活超过父会话的一个轮次;subagent 是模型驱动的运行,返回一条工具结果。
|
||||
- **修改子会话的系统提示词:** 默认否决,因为任何字节变化都会从第零个 token 起使前缀缓存失效。部署方仍可选择这种更强的隔离方式。
|
||||
- **新增 `sidechat/*` 事件:** 延后。插件来源的 `context/message` 已提供持久性、出处与回放能力;只有当某个界面需要差异化渲染时,专用事件才有正当理由。
|
||||
- **新增 `sidechat/*` 事件:** 延后。已标注来源的 `context/message` 已经持久记录内容、生产方和回放输入;只有当某个界面需要差异化渲染时,专用事件才有正当理由。
|
||||
- **现在就绑定一个协议界面:** 否决。当前 UI 由客户端拥有。实时呈现最终必须从持久消息派生,以使回放渲染出相同的记录。
|
||||
|
||||
## 验收标准
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/proposed/process/2026-07-13-human-review-skill-maintenance.md
|
||||
2026-07-13-human-review-skill-maintenance.md: 76391bd110b7a86b194a9340ffcf7cc4602d1d2e
|
||||
2026-07-13-human-review-skill-maintenance.zh.md: 8ebff759cf29fa7773e4b883f83c231f88e153d2
|
||||
2026-07-13-human-review-skill-maintenance.md: b741c8b595fcd36613cb246af483863d1e056697
|
||||
2026-07-13-human-review-skill-maintenance.zh.md: 1c00577fdb08c30b1fff794c08da20ec38891de1
|
||||
|
||||
@@ -10,13 +10,13 @@ The `dsh-code-review` skill records failure modes that require reviewer judgment
|
||||
|
||||
## Proposal
|
||||
|
||||
Periodic out-of-repo maintenance. A private tool, kept on the skill maintainer's machine rather than committed to this repository, runs against a clean full-history checkout at refreshed `origin/master`. The intended scheduler runs daily with a two-UTC-day overlap; manual runs accept another `--since` duration or repeated `--pr` arguments for an explicit set. The scan is idempotent against the current skill and stores no repository cursor. The only repository file changed by promotion is [.agents/skills/dsh-code-review/SKILL.md](../../../skills/dsh-code-review/SKILL.md); the draft PR carries a provenance summary so reviewers can audit the source feedback and adoption evidence without the private adapter logs.
|
||||
Periodic out-of-repo maintenance. A private tool, kept on the skill maintainer's machine rather than committed to this repository, runs against a clean full-history checkout at refreshed `origin/master`. The intended scheduler runs daily with a two-UTC-day overlap; manual runs accept another `--since` duration or repeated `--pr` arguments for an explicit set. The scan is idempotent against the current skill and stores no repository cursor. The only repository file changed by promotion is [.agents/skills/dsh-code-review/SKILL.md](../../../skills/dsh-code-review/SKILL.md); the draft PR lists the source feedback URLs or IDs and adoption evidence without exposing the private adapter logs.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["Maintainer or scheduler runs the tool on origin/master"] --> B["List PRs merged in the overlap window"]
|
||||
B --> C["Collect pre-merge User feedback and final PR evidence"]
|
||||
C --> D["Two reviewers verify provenance and adoption"]
|
||||
C --> D["Two reviewers verify the author and adoption"]
|
||||
D --> E{"Both confirm human-authored and adopted?"}
|
||||
E -- "No" --> F["Exclude or retain as unresolved"]
|
||||
E -- "Yes" --> G["Two reviewers classify against the current skill"]
|
||||
@@ -38,7 +38,7 @@ Each feedback item carries a stable source ID and bounded change evidence. When
|
||||
|
||||
### Dual-reviewer classification and drafting
|
||||
|
||||
Two independently configured reviewer adapters classify every eligible item by provenance (`human-authored`, `forwarded-automation`, or `unclear`) and adoption (`adopted`, `rejected`, or `unclear`). Only matching `human-authored` plus `adopted` verdicts proceed. The adopted set then receives a second independent classification against the current skill: candidate, already covered, implementation-specific, or not feedback. A singleton may qualify; recurrence is not required. Disagreement receives one bounded re-evaluation and remains visible in run artifacts if unresolved. A single batch whose adapter output fails schema or id validation is failed closed at the batch level — every feedback item in it is marked unclear and routed to `excluded` — rather than aborting the whole run; the offending raw output is preserved under the run's private artifacts for debugging. If either adapter returns no valid result for any nonempty batch in an operation, the run exits non-zero and emits a failure record instead of reporting “no candidate.”
|
||||
Two independently configured reviewer adapters classify who authored every eligible item (`human-authored`, `forwarded-automation`, or `unclear`) and whether the change adopted it (`adopted`, `rejected`, or `unclear`). Only matching `human-authored` plus `adopted` verdicts proceed. The adopted set then receives a second independent classification against the current skill: candidate, already covered, implementation-specific, or not feedback. A singleton may qualify; recurrence is not required. Disagreement receives one bounded re-evaluation and remains visible in run artifacts if unresolved. A single batch whose adapter output fails schema or id validation is failed closed at the batch level — every feedback item in it is marked unclear and routed to `excluded` — rather than aborting the whole run; the offending raw output is preserved under the run's private artifacts for debugging. If either adapter returns no valid result for any nonempty batch in an operation, the run exits non-zero and emits a failure record instead of reporting “no candidate.”
|
||||
|
||||
The primary adapter drafts from structured agreed guidance, never raw review text. It remains tool-free and read-only by adapter-author contract: it returns complete candidate file content, which the tool validates before writing the sole target. Both adapters then review the same complete skill diff; blocking findings return to a bounded revision loop, and both must approve the same revision. The tool rejects staged changes and edits outside the target skill both before running the documentation and lint gates and again before reporting success, so a gate or concurrent process that adds another path cannot slip through. It restores its own write on failure using best-effort compare-and-swap so a concurrent maintainer edit is not overwritten. On success it saves a candidate bundle containing the source `origin/master` commit, source skill blob ID, reviewed diff, complete candidate, source feedback IDs and URLs, landed evidence ranges, adapter verdicts, and gate results; it never commits, pushes, opens, or merges a PR.
|
||||
|
||||
@@ -48,21 +48,21 @@ Each private executable receives a byte-bounded, versioned JSON request on stdin
|
||||
|
||||
### Promotion contract
|
||||
|
||||
The promote helper starts from a clean checkout at refreshed `origin/master` and refuses to apply a candidate when the current skill blob differs from the bundle's recorded source blob. The operator then reruns the maintenance analysis or manually rebases the diff and repeats the candidate review; the helper never replaces a newer `SKILL.md` with stale complete-file output. After applying a current candidate, it opens a draft PR whose body lists the source feedback URLs or IDs, the landed commit range used as adoption evidence, the originating run, gate results, and any operator edits. Raw adapter prompts and responses remain private, but repository reviewers receive enough provenance to judge whether each proposed rule follows from adopted human feedback.
|
||||
The promote helper starts from a clean checkout at refreshed `origin/master` and refuses to apply a candidate when the current skill blob differs from the bundle's recorded source blob. The operator then reruns the maintenance analysis or manually rebases the diff and repeats the candidate review; the helper never replaces a newer `SKILL.md` with stale complete-file output. After applying a current candidate, it opens a draft PR whose body lists the source feedback URLs or IDs, the landed commit range used as adoption evidence, the originating run, gate results, and any operator edits. Raw adapter prompts and responses remain private, but repository reviewers receive those concrete inputs so they can judge whether each proposed rule follows from adopted human feedback.
|
||||
|
||||
### Where the mechanism lives
|
||||
|
||||
The tool source, adapter binaries, provider credentials, and intended daily scheduler are kept private to the maintainer's machine rather than committed to this repository. This document specifies the protocol; the reference implementation is private infrastructure. The mechanism serves a single skill maintained by a single operator, so the ongoing cost of vetting mechanism edits through repository review outweighs any provenance benefit. If the mechanism is ever handed off to a second maintainer, that handoff is a follow-up Agent Note that revises this decision — the operator doc at [docs/cookbook/maintaining-dsh-code-review.md](../../../../docs/cookbook/maintaining-dsh-code-review.md) is the entry point for anyone taking over.
|
||||
The tool source, adapter binaries, provider credentials, and intended daily scheduler are kept private to the maintainer's machine rather than committed to this repository. This document specifies the protocol; the reference implementation is private infrastructure. The mechanism serves a single skill maintained by a single operator, so the ongoing cost of vetting mechanism edits through repository review outweighs the benefit of committing the tool and its history. If the mechanism is ever handed off to a second maintainer, that handoff is a follow-up Agent Note that revises this decision — the operator doc at [docs/cookbook/maintaining-dsh-code-review.md](../../../../docs/cookbook/maintaining-dsh-code-review.md) is the entry point for anyone taking over.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
- **Ship the tool inside this repository.** Rejected for a single-maintainer scope: repository maintenance overhead (typecheck, lint, coverage, cross-cutting refactors) would exceed the value of committed provenance. Retained option for a later handoff.
|
||||
- **Ship the tool inside this repository.** Rejected for a single-maintainer scope: repository maintenance overhead (typecheck, lint, coverage, cross-cutting refactors) would exceed the value of committed source and review history. Retained option for a later handoff.
|
||||
- **Record every feedback-time PR head** — rejected: it improves causal isolation but requires a continuously running observer, durable event state, retries, and force-push reconciliation. Periodic maintenance uses reviewed-commit evidence where available and fails closed on broader whole-PR evidence.
|
||||
- **Persist a processed-PR cursor** — rejected: an overlapping time-window scan is cheap and naturally idempotent against the current skill, while cursor state creates recovery and missed-event problems.
|
||||
- **Run on every new comment** — rejected: review waves produce many related comments and lack the final artifact needed to judge adoption.
|
||||
- **Treat merge or thread resolution as adoption** — rejected: a PR can merge with rejected, superseded, or intentionally unresolved feedback.
|
||||
- **Create or merge repository changes automatically** — rejected: the tool first needs a track record of useful periodic output. The maintainer inspects and promotes the local diff through normal repository review.
|
||||
- **Learn from bot findings that were fixed** — rejected: the source contract is human review feedback. Actor type is filtered before analysis, and human accounts forwarding automated findings are excluded by provenance review.
|
||||
- **Learn from bot findings that were fixed** — rejected: the source contract is human review feedback. Author type is filtered before analysis, and human accounts forwarding automated findings are excluded by the author check.
|
||||
- **Use one reviewer as author and final judge** — rejected: independent verdicts expose unsupported generalization before it reaches the skill.
|
||||
|
||||
## Acceptance criteria
|
||||
@@ -73,7 +73,7 @@ Promotion from `proposed/` to `implemented/` requires all of the following to be
|
||||
- Both reviewer adapters are independently configured (distinct providers or models) and complete an analyze / adopt / review pass without user intervention. **Observed on 2026-07-15:** distinct primary/secondary adapters completed adoption + analysis in ~8 minutes; batch fail-closed handled one adapter id-hallucination without aborting the run.
|
||||
- A scheduler triggers the tool without an interactive terminal, and a candidate diff (or a "no candidate" record) reaches the operator through a durable notification channel.
|
||||
- A controlled acquisition case advances the target branch with a feedback-matching change after the feedback baseline; the reviewer evidence excludes that target-only change while retaining a later PR-owned change.
|
||||
- The promote helper rejects a candidate after the source skill changes, and a current candidate opens a draft PR with the provenance summary defined above.
|
||||
- The promote helper rejects a candidate after the source skill changes, and a current candidate opens a draft PR with the source feedback IDs, adopted commit range, originating run, checks, and operator edits defined above.
|
||||
- At least one candidate diff produced by this workflow is inspected by the operator and promoted to `master` through a normal repository PR review. That PR is the evidence that the workflow can turn adopted feedback into shipped skill guidance.
|
||||
|
||||
## Risks
|
||||
|
||||
@@ -10,13 +10,13 @@ Status: proposed
|
||||
|
||||
## 提案
|
||||
|
||||
在仓库外定期维护。一项保存在 skill 维护者机器上、而不提交到本仓库的私有工具,会针对刷新至 `origin/master` 的干净完整历史 checkout 运行。预期的调度器每天运行,并使用两天的 UTC 重叠窗口;手动运行可以通过另一个 `--since` 时长或重复的 `--pr` 参数指定显式集合。扫描相对于当前 skill 是幂等的,不存储仓库游标。推广时唯一会变更的仓库文件是 [.agents/skills/dsh-code-review/SKILL.md](../../../skills/dsh-code-review/SKILL.md);draft PR(Pull Request)携带来源概述,因此评审人无需私有适配器日志,也能审计源反馈与采纳证据。
|
||||
在仓库外定期维护。一项保存在 skill 维护者机器上、而不提交到本仓库的私有工具,会针对刷新至 `origin/master` 的干净完整历史 checkout 运行。预期的调度器每天运行,并使用两天的 UTC 重叠窗口;手动运行可以通过另一个 `--since` 时长或重复的 `--pr` 参数指定显式集合。扫描相对于当前 skill 是幂等的,不存储仓库游标。推广时唯一会变更的仓库文件是 [.agents/skills/dsh-code-review/SKILL.md](../../../skills/dsh-code-review/SKILL.md);draft PR(Pull Request)列出源反馈 URL 或 ID 和采纳证据,不会公开私有适配器日志。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["Maintainer or scheduler runs the tool on origin/master"] --> B["List PRs merged in the overlap window"]
|
||||
B --> C["Collect pre-merge User feedback and final PR evidence"]
|
||||
C --> D["Two reviewers verify provenance and adoption"]
|
||||
C --> D["Two reviewers verify the author and adoption"]
|
||||
D --> E{"Both confirm human-authored and adopted?"}
|
||||
E -- "No" --> F["Exclude or retain as unresolved"]
|
||||
E -- "Yes" --> G["Two reviewers classify against the current skill"]
|
||||
@@ -38,7 +38,7 @@ flowchart TD
|
||||
|
||||
### 双评审人分类与起草
|
||||
|
||||
两个独立配置的评审适配器,会从来源(`human-authored`、`forwarded-automation` 或 `unclear`)和采纳情况(`adopted`、`rejected` 或 `unclear`)两个维度,对每个符合条件的条目进行分类。只有两个适配器都判定为 `human-authored` 加 `adopted` 的条目才会继续。采纳集合随后会针对当前 skill 接受第二次独立分类:候选项、已经覆盖、实现专用或并非反馈。单个条目即可符合要求,不要求重复出现。意见分歧会得到一次有界的重新评估;如果仍未解决,则继续保留在运行产物中。单个批次的适配器输出如果未通过 schema 或 id 校验,系统会在批次层按不采纳处理:其中的每条反馈都标记为 unclear 并路由到 `excluded`,而不是中止整次运行;有问题的原始输出会保存在该次运行的私有产物中,供调试使用。如果任一适配器在某项操作的任何非空批次中都没有返回有效结果,运行会以非零状态退出并发出失败记录,而不会报告「没有候选项」。
|
||||
两个独立配置的评审适配器,会对每个符合条件的条目分类:谁编写了它(`human-authored`、`forwarded-automation` 或 `unclear`),以及变更是否采纳了它(`adopted`、`rejected` 或 `unclear`)。只有两个适配器都判定为 `human-authored` 加 `adopted` 的条目才会继续。采纳集合随后会针对当前 skill 接受第二次独立分类:候选项、已经覆盖、实现专用或并非反馈。单个条目即可符合要求,不要求重复出现。意见分歧会得到一次有界的重新评估;如果仍未解决,则继续保留在运行产物中。单个批次的适配器输出如果未通过 schema 或 id 校验,系统会在批次层按不采纳处理:其中的每条反馈都标记为 unclear 并路由到 `excluded`,而不是中止整次运行;有问题的原始输出会保存在该次运行的私有产物中,供调试使用。如果任一适配器在某项操作的任何非空批次中都没有返回有效结果,运行会以非零状态退出并发出失败记录,而不会报告「没有候选项」。
|
||||
|
||||
主适配器只根据结构化的共同指引起草,绝不接收原始评审文本。根据适配器作者的约定,它保持无工具且只读:返回完整的候选文件内容,由工具校验后写入唯一目标。两个适配器随后评审同一份完整 skill diff;阻塞性问题会进入有界修订循环,而且两者必须批准同一版修订。工具会在运行文档和 lint 检查前,以及报告成功前,再次拒绝暂存改动和目标 skill 之外的编辑,因此检查或并发进程无法通过添加其他路径混入。失败时,工具使用尽力而为的比较并交换回滚自身写入,以免覆盖维护者的并发编辑。成功时,它保存一份候选资料包,其中包含源 `origin/master` commit、源 skill blob ID、已评审 diff、完整候选文件、源反馈 ID 与 URL、落地证据范围、适配器判定和检查结果;它绝不提交、推送、打开或合并 PR。
|
||||
|
||||
@@ -48,21 +48,21 @@ flowchart TD
|
||||
|
||||
### 推广约定
|
||||
|
||||
推广辅助工具从刷新至 `origin/master` 的干净 checkout 开始;当前 skill blob 与资料包中记录的源 blob 不同时,它拒绝应用候选项。运维方随后重新运行维护分析,或手动把 diff 变基后重新评审候选项;辅助工具绝不会用陈旧的完整文件输出替换较新的 `SKILL.md`。应用仍然有效的候选项后,它会打开 draft PR,其正文列出源反馈 URL 或 ID、用作采纳证据的落地 commit 范围、来源运行、检查结果和任何运维方编辑。原始适配器提示词与响应保持私有,但仓库评审人会获得足够的来源信息,以判断每条提议规则是否确实来自已采纳的人类反馈。
|
||||
推广辅助工具从刷新至 `origin/master` 的干净 checkout 开始;当前 skill blob 与资料包中记录的源 blob 不同时,它拒绝应用候选项。运维方随后重新运行维护分析,或手动把 diff 变基后重新评审候选项;辅助工具绝不会用陈旧的完整文件输出替换较新的 `SKILL.md`。应用仍然有效的候选项后,它会打开 draft PR,其正文列出源反馈 URL 或 ID、用作采纳证据的落地 commit 范围、发起该候选项的运行、检查结果和任何运维方编辑。原始适配器提示词与响应保持私有,但仓库评审人会获得这些具体输入,从而判断每条提议规则是否确实来自已采纳的人类反馈。
|
||||
|
||||
### 机制所在位置
|
||||
|
||||
工具源码、适配器二进制文件、提供方凭据和预期的每日调度器保存在维护者机器上,不会提交到本仓库。本文规定协议,参考实现属于私有基础设施。该机制只服务于由单个运维方维护的一项 skill,因此,持续通过仓库评审审查机制改动的成本高于来源可追溯性的收益。如果该机制将来移交给第二位维护者,移交工作需要一篇后续 Agent Note 来修订本决策;任何接手者都应从运维文档 [docs/cookbook/maintaining-dsh-code-review.md](../../../../docs/cookbook/maintaining-dsh-code-review.md) 入手。
|
||||
工具源码、适配器二进制文件、提供方凭据和预期的每日调度器保存在维护者机器上,不会提交到本仓库。本文规定协议,参考实现属于私有基础设施。该机制只服务于由单个运维方维护的一项 skill,因此,持续通过仓库评审审查机制改动的成本高于提交工具及其历史的收益。如果该机制将来移交给第二位维护者,移交工作需要一篇后续 Agent Note 来修订本决策;任何接手者都应从运维文档 [docs/cookbook/maintaining-dsh-code-review.md](../../../../docs/cookbook/maintaining-dsh-code-review.md) 入手。
|
||||
|
||||
## 考虑过的替代方案
|
||||
|
||||
- **把工具放入本仓库。** 对单维护者作用域不予采纳:仓库维护开销(类型检查、lint、覆盖率与横切重构)会超过已提交来源信息的价值。未来移交时仍可重新考虑。
|
||||
- **把工具放入本仓库。** 对单维护者作用域不予采纳:仓库维护开销(类型检查、lint、覆盖率与横切重构)会超过已提交源码和评审历史的价值。未来移交时仍可重新考虑。
|
||||
- **记录每条反馈产生时的 PR head**:不予采纳,因为这需要持续运行的观察器、持久事件状态、重试和强制推送协调。定期维护会在可用时使用经过评审的 commit 证据,并在整 PR 证据范围过宽、无法确认时直接排除。
|
||||
- **持久化已处理 PR 游标**:不予采纳,因为带重叠的时间窗口扫描成本低廉,并且相对于当前 skill 天然幂等;游标状态反而带来恢复和漏事件问题。
|
||||
- **每次新评论都运行**:不予采纳,因为一轮评审会产生许多相关评论,并且缺少判断采纳情况所需的最终产物。
|
||||
- **把合并或讨论串解决视为采纳**:不予采纳,因为 PR 可能在反馈被拒绝、被取代或刻意不解决的情况下合并。
|
||||
- **自动创建或合并仓库改动**:不予采纳,因为工具首先需要通过有用的定期输出积累可信记录。维护者检查并通过普通仓库评审推广本地 diff。
|
||||
- **从已经修复的 bot 问题中学习**:不予采纳,因为来源约定限定为人类评审反馈。系统会在分析前按 actor 类型过滤,并通过来源评审排除转发自动化问题的人类账号。
|
||||
- **从已经修复的 bot 问题中学习**:不予采纳,因为来源约定限定为人类评审反馈。系统会在分析前按作者类型过滤,并通过作者检查排除转发自动化问题的人类账号。
|
||||
- **让同一个评审人既当作者又作最终裁决**:不予采纳,因为独立判定能在不受支持的概括进入 skill 之前暴露问题。
|
||||
|
||||
## 验收标准
|
||||
@@ -73,7 +73,7 @@ flowchart TD
|
||||
- 两个评审适配器独立配置(不同的提供方或模型),无需用户干预即可完成 analyze/adopt/review 流程。**2026-07-15 已观察:** 不同的主/次适配器约用 8 分钟完成采纳与分析;一次适配器 id 幻觉由批次级保守失败机制处理,没有中止整次运行。
|
||||
- 调度器在没有交互式终端的情况下触发工具,并通过持久通知通道把候选 diff(或「没有候选项」记录)送达运维方。
|
||||
- 一个受控采集场景会在反馈基线之后,向目标分支加入与反馈匹配的变更;评审证据排除该目标分支专有变更,同时保留后续由 PR 自身加入的变更。
|
||||
- 源 skill 改变后,推广辅助工具会拒绝候选项;仍然有效的候选项会按照上文定义的来源概述打开 draft PR。
|
||||
- 源 skill 改变后,推广辅助工具会拒绝候选项;仍然有效的候选项会打开 draft PR,其中包含上文定义的源反馈 ID、已采纳 commit 范围、发起该候选项的运行、检查和运维方编辑。
|
||||
- 该工作流生成的至少一个候选 diff 会由运维方检查,并通过普通仓库 PR 评审推广到 `master`。该 PR 用以证明工作流能够把已采纳反馈转化为已交付的 skill 指引。
|
||||
|
||||
## 风险
|
||||
|
||||
Reference in New Issue
Block a user