feat(bundle): give the bundle an evidence-only view for downstream writers - #84
Conversation
…iters A bundle has two readers with opposite needs. An auditor cites the session and needs every source byte. A writer must reach its own conclusion and therefore must not be able to read the conclusion the session already reached, which the transcript holds verbatim: on one measured report, 42 of 80 substantive lines were recoverable from the transcript of the session that wrote it, including the shell call that authored it. A check for the earlier report FILE passes while its CONTENT is right there. `traces bundle-view <bundle-dir> --view evidence-only --out <dir>` projects an assembled bundle instead of policing it. The projection is an artifact-to-artifact command, like `inspect` and `export`, so the writer's copy is derivable from the auditor's copy and carries its manifest hash; `--view` on `bundle` is refused so nobody can ask for a projection and receive the full record. The view carries an explicit allow-list: the session index, the policy evidence, and the structured ledger records. Every other path is excluded by name in `manifest.excluded` with its SHA-256 and one of four rules, and an unrecognised path is denied by default, so the view can narrow by accident but never widen. Before anything is written, each candidate is compared against each excluded file for shared eight-word runs of prose, with identifiers and this package's own constants scrubbed from both sides and JSON compared by value rather than by serialized form. A repo ledger file that repeats one is dropped and recorded; a traces-derived artifact that repeats one is a defect in the derivation and no view is written. `manifest.schemaVersion` moves to 2 and every manifest now names its `view`, so a reader can never mistake one copy for the other.
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — 2a6ce7b3
This PR was opened by the trusted drewstone account.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.
tangletools · auto-approval · reason: drewstone_author · 2026-08-10T02:30:41Z
|
| State | Detail |
|---|---|
| Interrupted | webhook restarted |
No review verdict was produced for this run. Trigger a fresh review on the current PR head if the PR is still open.
tangletools · #84 · model: kimi-for-coding · updated 2026-08-10T02:57:06Z
tangletools
left a comment
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — 2a6ce7b3
This PR was opened by the trusted drewstone account.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.
tangletools · auto-approval · reason: drewstone_author · 2026-08-10T03:07:13Z
tangletools
left a comment
There was a problem hiding this comment.
⚪ Value Audit — audit-incomplete
| Verdict | audit-incomplete |
| Concerns | 1 (1 low) |
| Heuristic | 0.0s |
| Duplication | 0.0s |
| Interrogation | 90.0s (2 bridge agents) |
| Total | 90.0s |
💰 Value — error
value agent produced no parseable value-audit JSON.
- Model: opencode/deepseek/deepseek-v4-pro
- Bridge attempts: 3
- Bridge error: opencode/kimi-for-coding/k2p7: Bridge returned 503: {"error":{"message":"cli-bridge admission timed out after 30000ms","type":"admission_rejected","reason":"queue_timeout","admission":{"active":20,"queued":7,"maxActive":20,"maxQueue":48}}}; opencode/zai-coding-plan/glm-5.2: Bridge returned 503: {"error":{"message":"cli-bridge admission timed out after 30000ms","type":"admission_rejected","reason":
🎯 Usefulness — error
usefulness agent produced no parseable value-audit JSON.
- Model: opencode/deepseek/deepseek-v4-pro
- Bridge attempts: 3
- Bridge error: opencode/zai-coding-plan/glm-5.2: Bridge returned 503: {"error":{"message":"cli-bridge admission timed out after 30000ms","type":"admission_rejected","reason":"queue_timeout","admission":{"active":20,"queued":6,"maxActive":20,"maxQueue":48}}}; opencode/kimi-for-coding/k2p7: Bridge returned 503: {"error":{"message":"cli-bridge admission timed out after 30000ms","type":"admission_rejected","reason":
🔎 Heuristic Signals
🟡 Cruft: console debug added src/cli.ts
- console.log(
What this audit checks
It judges the change on its merits — not whether it was tasked out in an issue. Unticketed, fast-moving work is fine; the question is whether the change is good and whether a better or existing approach should be used instead.
| Pass | What it asks |
|---|---|
| Heuristic | Vague title? Whitespace-only or cruft-bearing diff? (content signals only) |
| Duplication | Do added function/class names already exist elsewhere in the repo? |
| Value Audit | What does it do? What goal does it achieve? Is it good? Better architecture or already-exists? |
| Usefulness Audit | Does it integrate and fit? Will it hold up in real use and actually get used? |
Findings are concerns, not blocks — the human reviewer decides what to do with them.
|
A bundle has two readers who need opposite things
An auditor cites the session and needs every source byte. A writer must reach its own conclusion about the session, which means it must not be able to read the conclusion that session already reached.
The full bundle cannot serve the writer, because the transcript holds every word the session wrote. On one measured report, 42 of 80 substantive lines were recoverable from the transcript of the session that wrote it — including the shell call that authored it. A check that looks for the earlier report file passes while its content sits right there in the transcript.
Projecting is the fix, not grepping
bundle-viewis artifact-to-artifact, likeinspectandexport. The writer's copy is derivable from the auditor's copy and carries the full bundle's manifest hash, so an auditor can prove which record it came from.--viewonbundleis refused, so nobody can ask for a projection and receive the full record. Projecting a view of a view is refused.The allow-list is the structure. Three things are carried: the session index, the policy evidence, and the structured ledger records. Every other path is excluded by name in
manifest.excludedwith its SHA-256 and one of four rules:session-sourcesession/— the transcript and every subagent transcriptsession-text-derivedderived/report.md(quotes prompt lines and evidence excerpts),derived/trace.otlp.jsonl(spans carry full prompt and response text)authored-proseledger/progress.md,handoff-*.md,reflections/,experiments.jsonlfree text,repo/git-log.txtnot-allow-listedtracesaddsUnrecognised paths are denied by default, so the view can narrow by accident but never widen.
A content check proves the allow-list is right. Before anything is written, each candidate is compared against each excluded file for shared eight-word runs of prose — with identifiers (paths, URLs, hashes) and this package's own constants scrubbed from both sides, and JSON compared by value rather than by serialized form. A repo ledger file that repeats a run is dropped and recorded (
rule: "content-signature"). Atraces-derived artifact that repeats a run is a defect in the derivation, and no view is written at all.manifest.projection.leakCheckrecords the width, the sources compared, and the result — alwaysmatches: 0, because a match means no view exists.manifest.schemaVersionmoves to 2 and every manifest now names itsview("full"or"evidence-only"), so a reader can never mistake one copy for the other.Checks — re-run on this branch at 2a6ce7b, full CI sequence
Merges cleanly into
origin/main. README gains a "Two views, two consumers" section and theinspect-agent-tracesskill learns the command.