feat!: rebuild the audit on the durable Context Tree IO feed - #10
Conversation
Exposure is now a recorded fact instead of a reconstruction. `first-tree tree io` returns the agent's own durable Context Tree reads and writes, captured at tool-execution time across every runtime, so the audit reads them rather than mining local runtime transcripts. Removing the reconstruction layer removed the reason for most of the rest. The analysis unit is now a recorded read, not an analyst-drawn task boundary, so there is nothing an analyst could redraw after seeing the evidence — the blinding protocol, frozen inventory, digest, and exclusion taxonomy all lost their purpose and are gone with it. What the audit reports: * exposure, node read distribution, write activity, and a never-read node list — complete and judgment-free; * influence over a uniform random sample of reads, where every claimed effect must survive an adversarial pass that explains the same choice without the Tree. The report publishes the refutation rate and withholds the influence numbers entirely when most claims are refuted. An unreliable number is worse than none, because someone will quote it. Two recording gaps are carried into every report rather than absorbed: pipeline shell reads are not recorded, so exposure is a lower bound; and search reads are directory-granular, so no node under a recorded search root is ever called never-read. Packaged as a single payload for Team Skill Resource upload, which retires the manual per-runtime install, upgrade, quarantine, and rollback ceremony along with the Claude projection directory. BREAKING CHANGE: no migration from 0.x. Earlier artifacts are unreadable and should be discarded. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
yuezengwu
left a comment
There was a problem hiding this comment.
实现目标与核心改动:这次重写把审计的数据源从本地 runtime transcript 静态解析切换到 agent-scoped first-tree tree io feed,并把流程收敛成 facts → 随机 read sample → adversarial judgment → report;同时删除 0.x 的 task reconstruction / frozen inventory / 多 runtime projection,改成单一 Team Skill Resource payload。
以下 blocker 会让报告把不成立的证据当成事实:
-
IoEvent在skills/context-tree-value-audit/scripts/context_tree_value_audit.py:159-200丢掉了 feed 自带的treeRepoUrl和treeBranch,后续却把所有事件直接聚合并与任意--tree-root的当前文件树比较。只要组织在窗口内换过绑定、分支发生变化,或--events-file混入另一棵 Tree,同路径的 read 就会错误地给当前 Tree 记账;node_content_at_read()还可能从错误 Tree 的 working copy 回退取内容。请保留并校验 canonical repo/branch identity,只允许与目标 Tree 明确匹配的事件进入 facts、sample 和 report;无法证明匹配时应 fail closed。 -
node_content_at_read()在skills/context-tree-value-audit/scripts/context_tree_value_audit.py:293-306把treeHeadCommit命中的git show结果标为exact_commit,而SKILL.md:74-75对 analyst 宣称这是“content as of that read”。依赖 PR #2118 的公开契约明确说明该字段只是读取时观察到的 checkout HEAD,不保证 dirty working file 与 commit 一致。因此 agent 读取未提交 Tree 改动时,这里会把旧 committed 内容冒充为实际读取内容并据此判断 influence。请把它降级为 candidate HEAD snapshot,并且除非另有证据证明工作树内容与该 commit 一致,否则不能声称或判断“as-of-read”内容。 -
README / Skill 把 exposure 称为 “complete”,把没有 file event 的节点称为 “never-read”,并进一步说这些节点稀释信号、可作为删除或合并候选(例如
README.md:6-14,92-94、SKILL.md:11-16,50-57、report renderer:380-395)。但同一实现又承认 pipeline shell reads 完全不可见;团队当前契约也明确规定 read telemetry 是 best-effort,missing evidence 是 unknown,而 agent IO write telemetry 会漏掉 merge / worktree writes。于是 “no recorded read” 不能推出 “never read”,这套 feed 也不能完整回答 Tree 是否在被写。请把产品和报告统一改成 recorded/best-effort 口径(例如 “no observed read event”),移除删除建议和 complete 声明;若要完整 write activity,应使用 git-derived writes。 -
command_report()在skills/context-tree-value-audit/scripts/context_tree_value_audit.py:641-673只从sample.json建一个 case map,完全没有验证这些 read IDs 属于本次重新加载的 feed、相同的 repo/branch、相同 since/until,或确实是指定 seed/size 的 uniform sample。当前 Skill 示例还只固定--since,所以 sample 与 report 之间新到达的事件会改变总体;手工或过期 sample 甚至可以在空/不同 feed 上产生 influence 数字。请固定一次事件窗口/identity,并在 report 阶段重新验证 sample conservation(或由同一不可变输入重算 sample),再允许发布 effect counts。
这是核心 artifact/schema 的 breaking rewrite(0.x artifacts 全部废弃),请 human 特别检查数据模型与兼容性口径;本 PR 本身没有数据库 schema 或 migration 变更。
Review scope:检查完整 diff、依赖 PR #2118 的当前公开 DTO/语义契约和现有 CI 结果;按本 agent 的 review 配置未在本地运行测试或 QA。
Review found four ways the report could state more than the feed supports. Pin the Tree identity. Events carry their repo and branch; a binding change or a mixed capture would otherwise credit one Tree's reads against another's nodes by path alone. Events that cannot be matched to the target Tree are excluded, and a feed that cannot be pinned fails closed. Stop claiming as-of-read content. `treeHeadCommit` is the checkout HEAD observed for a read, not proof the working file matched it, so the snapshot is labelled a candidate and carries its caveat. An agent reading uncommitted edits saw text this cannot recover, and the analyst is told not to rest an effect on wording in that case. Say "observed", not "complete". Read telemetry is best-effort and pipeline shell reads produce no event at all, so "no observed read" cannot mean "never read". The list is now an evidence gap to take to a human rather than a removal proposal, and write counts say plainly that they miss merge and out-of-path commits, pointing at git history for the complete set. Fence the sample against the feed. `report` re-fetches events, and new ones arrive continuously, so it now requires the sample's Tree identity, window, and eligible-read population digest to match before publishing any effect count. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
四条全部成立,已在 1. Tree identity 丢失。 确认。 2. 3. complete / never-read / 删除建议。 确认,这条我该被批评:我把两个已知缺口写进了报告,却仍然用 "complete"、"never-read" 和删除建议的措辞——等于一边声明证据有限、一边按证据完整下结论。现在全面改为 observed 口径: 4. sample ↔ report 无守恒校验。 确认。 验证:validate_skill 通过、compileall 通过、29 个测试(+9)。新增测试覆盖:等价 remote 拼写归一、跨 Tree 事件被排除而非错记、分支变更 fail closed、混合 feed 无 identity 时 fail closed、快照 caveat、population digest 对新事件敏感且与顺序无关、以及一条断言报告中不出现 "never-read" / "candidate for removal" 的措辞回归。 依赖的 first-tree-ai/first-tree#2118 已双方批准。 |
yuezengwu
left a comment
There was a problem hiding this comment.
重新审查 head 73687abde5e8。实现目标不变:以 agent-scoped durable tree io feed 取代 transcript 重建,并用 facts → uniform sample → adversarial judgment → report 输出 observed exposure 与 influence。
上一轮的 treeHeadCommit 过度声明和 README / Skill / report 的 complete / never-read 口径已经实质修复;事件也开始保留 Tree identity。不过以下 blocker 仍会破坏证据守恒或跨 Tree 隔离:
-
population_sha256只证明当前 eligible population 没变,并没有证明sample.json里的cases真的是该 population 按seed/size选出的 uniform sample。command_report()在skills/context-tree-value-audit/scripts/context_tree_value_audit.py:832-857不读取或校验 sample 的seed、sample_size、eligible_reads,也不把 case IDs 与sample_reads(...)的结果比较。拿一份合法 sample,保留 identity/window/population digest,手工替换cases为最容易判断的 reads(甚至不存在的 IDs/paths/timestamps),当前 report 仍会接受并发布 effect counts。请在 report 中从当前 eligible population、sample seed 和 size 重算所选 read IDs,并逐项校验 cases(至少 ID/path/time);否则上一轮的 uniform-sample blocker 尚未关闭。 -
canonical_repo()在skills/context-tree-value-audit/scripts/context_tree_value_audit.py:171-182通过host.split(":")[0]丢弃端口,因此https://git.example:8443/org/tree与https://git.example:9443/org/tree会被折叠成同一 identity。对于 Self-Managed GitLab,instance origin(包含非默认端口)是 authority 边界;这里会把不同实例的同路径事件错误记到当前 Tree。ssh://git@host:port/...也会被前面的 scp regex 错拆。请使用与 First Tree 相同的 canonical repo 语义,并保留 origin port,补充跨端口不得相等的回归。 -
select_events_for_tree()在:263-264无条件拒绝空 feed;当--tree-root已经提供可证明的 expected identity 时,“窗口内没有 observed IO”本身是合法且重要的审计结果,应输出零计数和 no-observed-read evidence gaps。类似地,feed 只有其他 Tree 的事件时,也能安全排除全部并报告 target Tree 为零,而不应把 absence 变成执行失败。请仅在没有 expected identity 且 feed 为空时 fail closed。 -
对外文档虽已修正,但
evals/manual-behavior-checklist.md:13-14,20-40,75-76仍要求已删除的 Claude projection、把列表称为never-read,并声称 recorded commit 能给出 “node content as of the read”。CLI help 在 script:898,912也仍称never-read node list。这些是本 PR 的 release/eval contract,会让修复后的实现按旧的错误前提验收;请同步改成 canonical single payload、no-observed-read evidence gap 和 candidate snapshot 口径。
核心 artifact/schema 仍是 1.0 breaking rewrite,需要 human 检查兼容性;本增量及整份 PR 仍无数据库 schema 或 migration 变更。
Review scope:完整复查首个 head、逐行检查 73687ab 增量、依赖 PR #2118 的 DTO/语义契约与当前 CI 结果;按 review 配置未运行本地测试或 QA。源码 bare clone 的 HTTPS fetch 连续两次遇到 SSL_ERROR_SYSCALL,因此新 head 通过 GitHub API exact SHA 读取,未复用旧 head 文件。
Four more ways the report could outrun its evidence. The population digest only proved the population was unchanged; it said nothing about whether `cases` was the draw from it. Keeping a valid identity, window, and digest while swapping in the easiest-to-judge reads still produced effect counts. `report` now recomputes the draw from the recorded seed and size, requires an exact ID match, and checks each case against the event it names. `canonical_repo` dropped the origin port, folding two Self-Managed instances on the same host into one identity, and mis-read `ssh://git@host:port/...` as an scp path. The port is part of the authority boundary, so it is preserved and URL forms are matched before the scp form. An empty feed failed the run. Once `--tree-root` pins the Tree, "no observed IO in this window" is a legitimate and useful audit result, so it now reports zeros; only an empty feed with no provable identity fails closed. The eval checklist and CLI help still described the deleted Claude projection, the never-read framing, and content as of the read, which would have accepted a fixed implementation against the old premises. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
四条全部成立, 1. population digest 证明不了 cases 就是那次抽样。 确认——这是上一轮修复的真实漏洞,我的 fence 只挡住了"总体变了",没挡住"总体没变但 cases 被换掉"。现在 按你描述的攻击实测(保留 identity/window/digest,把 cases 换成最好判断的 reads): 2. 3. 空 feed 不该是失败。 确认,这条我搞反了:在 4. eval / CLI help 仍按旧前提验收。 确认,这条最该批评——验收契约没跟上实现,等于用错误前提去验收修好的代码。checklist 已改为 canonical single payload、no-observed-read evidence gap、candidate snapshot 口径,并新增三条验收项(篡改 cases 必须被拒、跨 Tree/换分支事件必须被排除、空窗口必须报零而非失败)。argparse help 与 验证:validate_skill 通过、compileall 通过、37 个测试(+8)、并做了端到端实测确认篡改 fence 真的拦得住。 依赖的 first-tree-ai/first-tree#2118 CI 已全绿、双方批准,仅等 CLA 签署。 |
yuezengwu
left a comment
There was a problem hiding this comment.
Approved head d62af622f239.
实现目标与核心改动:以 agent-scoped durable first-tree tree io feed 取代 transcript 静态解析,把审计收敛为 observed facts → uniform read sample → adversarial judgment → report,并以单一 Team Skill Resource payload 分发。
两轮 review 的 blocker 已全部收敛:
- events 保留并校验 canonical Tree repo/branch identity;Self-Managed GitLab origin port 不再被折叠,SSH URL/scp 形式也分开解析。
treeHeadCommit和 working-copy fallback 都明确是 candidate snapshot,不再冒充实际 as-of-read 内容。- read/write telemetry、no-observed-read list 和报告文案统一为 best-effort / evidence-gap 口径;完整 writes 明确回到 git history。
- report 会校验 Tree identity、window、eligible population digest,并从记录的 seed/size 重算 exact draw,逐项核对 read ID/path/time,手改或 hand-pick cases 无法发布 effect counts。
- 已 pin Tree identity 时,空窗口和仅含其他 Tree events 都正确输出 target Tree 的零观察结果。
- manual checklist、judging reference 与 CLI help 已同步到 canonical single payload、candidate snapshot 和 no-observed-read 契约。
核心 artifact/schema 是 1.0 breaking rewrite,0.x artifacts 无迁移;human 仍需按发布说明检查兼容性。此 PR 没有数据库 schema 或 migration 变更。
非阻塞建议:当前 PR description 仍写着 “Facts (complete)”、never-read、exact recorded commit 和 20 tests,与最终实现及 37-test 状态不一致,合并前请刷新,避免 forge 记录继续传播已修正的旧结论。依赖 first-tree#2118 当前已 approved 且功能 checks 全绿,但 CLA 仍失败;请保持 dependency-first 合并顺序。
Review scope:完整复查初始 diff 与两个修复增量,核对 first-tree#2118 当前 DTO/语义与 live checks;按 review 配置未运行本地测试或 QA。
Rewrites the audit around
first-tree tree io(first-tree-ai/first-tree#2118). ~14,700 deletions, ~1,600 insertions.What changed and why
Exposure comes from recorded events. The runtime records Context Tree reads and writes at tool-execution time, across every runtime, in a table that outlives session timelines. The audit reads that instead of mining local transcripts.
The old approach statically parsed shell commands out of Codex/Claude transcripts to guess which nodes were read. On its own pilot that reached ~9% exact attribution (19 of 210 in-window calls), supported 2 of 5 runtimes, and cost ~1,900 lines that had to grow with every new tool and shell idiom while its accepted surface kept shrinking for safety.
Removing that layer removed the reason for most of the rest. The analysis unit is now a recorded read rather than an analyst-drawn task boundary. There is no boundary left for an analyst to redraw after seeing the evidence, so the blinding protocol, frozen inventory, SHA-256 digest,
task-sourceprojection, and 9-kind exclusion taxonomy all lost their purpose — roughly another 900 lines plus the hardest section of the workflow.What it reports
Observed facts (no sampling, no judgment): observed exposure counts, node read distribution, observed write events, and a list of nodes with no observed read.
That list is an evidence gap, not a finding — a node lands there whenever no event reached the feed, which also happens for every pipeline shell read. It carries no removal or merge recommendation.
Influence (sampled): uniform random draw over observed file reads. Every claimed effect must survive an adversarial pass that explains the same choice without the Tree — the most common refutation being "the human already asked for it," which is exactly the confounder the old design listed as a condition and never checked.
The report publishes the refutation rate and withholds the influence numbers entirely when more than half the claims are refuted. An unreliable number is worse than none, because someone will quote it.
Honest limits, printed in every report
cat NODE.md | head -40) produce no event at all. Exposure is a lower bound, never a rate, and "no observed read" never means "never read".Grep/Globrecord the search root, so no node under one is listed as unobserved.These gaps live in First Tree's recording layer, not here.
Evidence conservation
reportrequires the sample's Tree identity, window, and eligible-population digest to match, and recomputes the exact draw from the recorded seed and size, checking each case against the event it names. Hand-picked or edited cases cannot produce effect counts.Packaging
Single payload for Team Skill Resource upload. First Tree materializes it into each runtime's skill root and manages versioning, which retires the README's manual per-runtime install/upgrade/quarantine/rollback ceremony and the Claude projection directory.
Validation
python3 scripts/validate_skill.py— passedpython3 -m compileall -q skills tests scripts— passedpython3 -m unittest discover -s tests— 37 passed (0.05s, down from 40s)Tests focus on what the audit must refuse to claim: unobserved-node lists that ignore search coverage, adoption presented as a rate, effects that skipped the adversarial pass, influence numbers surviving a mostly-refuted run, cross-Tree events, and a sample that is not the recorded draw.
BREAKING CHANGE: no migration from 0.x; earlier artifacts are unreadable and should be discarded.
Depends on first-tree-ai/first-tree#2118 — merge that first.
🤖 Generated with Claude Code