refactor(compaction): remove the archive path no fold has written

Compaction receipts carried an Archive field, the wire carried it, and both
frontends rendered it — the CLI as "archived <path>", the desktop card as
",原件留在 …". Nothing has assigned it since summary checkpoints replaced
archiving: canonical keeps the originals, so there is no second copy to name.
Every reader was reading the empty string.

Four tests asserted it stays empty. They passed against a field that could
not be anything else, which is the shape a guard takes once what it guarded
is gone.
This commit is contained in:
esengine committed 2026-08-15 01:04:38 -07:00
1 parent ab9c3f5eb7
commit 99ef4b2f0d
14 files changed
+9 -35

No files matched your search

@@ -237,7 +237,6 @@ export const SCRIPT: Beat[] = [
trigger: "auto",
messages: 34,
summary: "401 已证实是网关瞬时态(curl A/B,A 组 7 次 B 组 0 次)。处置是退避重试,不删 key。",
archive: "~/.reasonix/projects/F--Reasonix/archive/2026-08-13.jsonl",
// A fold that dropped one of its own changes: the case the card exists
// for, since the summary above reads just as finished either way.
sourceTokens: 128_400,
-1
View File
@@ -160,7 +160,6 @@ export interface Compaction {
trigger?: string;
messages?: number;
summary?: string;
archive?: string;
// What the fold cost, and what the digest kept of it. coverageRequired counts
// the changes and failures the folded work produced; coverageMissing is how
// many the digest did not carry.
@@ -104,7 +104,6 @@ export function CompactionCard({ c, done }: { c: Compaction; done: boolean }) {
<b>{tokenLabel(before)}</b> → <b>{tokenLabel(after)}</b>
</>
)}
{c.archive && <>,原件留在 {c.archive}</>}
</div>
<Coverage c={c} />
{c.summary && (
-2
View File
@@ -45,7 +45,6 @@ export interface WireCompaction {
trigger?: string; // "auto" | "manual"
messages?: number; // done: how many messages were folded into the summary
summary?: string; // done: the briefing (empty on an aborted pass)
archive?: string; // done: archive path, if any
}
export interface WireProfile {
model?: string;
@@ -645,7 +644,6 @@ export interface HistoryMessage {
trigger?: string;
messages?: number;
summary?: string;
archive?: string;
decisionReceipt?: WireDecisionReceipt;
}
+2 -2
View File
@@ -220,7 +220,7 @@ func (a *Agent) compressVisibleRange(
inputHash := providerVisibleFingerprint(provider.ModelMessages(snap.visible))
outputHash := providerVisibleFingerprint(projection)
state, err := a.commitSummaryProjection(summaryProjectionCommit{
_, err = a.commitSummaryProjection(summaryProjectionCommit{
canonical: snap.canonical, fold: prepared.fold, projected: projection, result: res,
transcriptVersion: snap.transcriptVersion, projectionVersion: snap.projectionVersion, generation: snap.generation,
activeTurn: a.activeTurnCreatedAt.Load(), trigger: trigger, summary: summary,
@@ -236,7 +236,7 @@ func (a *Agent) compressVisibleRange(
}
a.emitCompactionTelemetry(tele)
a.svc.sink.Emit(event.Event{Kind: event.CompactionDone, Compaction: event.Compaction{
Trigger: trigger, Messages: len(plan.fold), Summary: summary, Archive: state.LastReceipt.Archive,
Trigger: trigger, Messages: len(plan.fold), Summary: summary,
}})
result.Status = "ok"
result.Reason = ""
-4
View File
@@ -67,10 +67,6 @@ func TestCompressContextBeforePreservesCanonicalAndTail(t *testing.T) {
state.LastReceipt.Trigger != CompactionTriggerTool {
t.Fatalf("range compression receipt = %+v", state.LastReceipt)
}
// New summary checkpoints do not create archives; full originals stay in canonical.
if state.LastReceipt.Archive != "" {
t.Fatalf("summary checkpoint should not create archive, got %q", state.LastReceipt.Archive)
}
}
func TestCompressContextAfterExcludesActiveTurnAndAppendsToolResult(t *testing.T) {
@@ -132,7 +132,4 @@ func assertLocalOnlyAbsentFromSummary(t *testing.T, prov *fakeProvider, a *Agent
t.Fatalf("local-only output entered projection: %+v", m)
}
}
if a.sess.compactionState.LastReceipt != nil && a.sess.compactionState.LastReceipt.Archive != "" {
t.Fatalf("checkpoint must not create archives, got %q", a.sess.compactionState.LastReceipt.Archive)
}
}
-1
View File
@@ -90,7 +90,6 @@ type ContextMaintenanceReceipt struct {
SavedTokens int `json:"saved_tokens,omitempty"`
AffectedToolResults int `json:"affected_tool_results,omitempty"`
SummaryHash string `json:"summary_hash,omitempty"`
Archive string `json:"archive,omitempty"`
CacheBreak bool `json:"cache_break,omitempty"`
Reason string `json:"reason,omitempty"`
BlockedInputHash string `json:"blocked_input_hash,omitempty"`
-3
View File
@@ -346,9 +346,6 @@ func TestArchiveDirIgnoredOnCheckpointInstall(t *testing.T) {
if len(a.sess.compactionState.Projection.Messages) == 0 {
t.Fatal("expected projection despite unusable ArchiveDir")
}
if a.sess.compactionState.LastReceipt != nil && a.sess.compactionState.LastReceipt.Archive != "" {
t.Fatalf("checkpoint must not create archives, got %q", a.sess.compactionState.LastReceipt.Archive)
}
}
func writeFile(path string, b []byte) error {
-3
View File
@@ -30,9 +30,6 @@ func compactionCardLines(c event.Compaction) []string {
for ln := range strings.SplitSeq(strings.TrimRight(c.Summary, "\n"), "\n") {
lines = append(lines, dim(" │ "+ln))
}
if c.Archive != "" {
lines = append(lines, dim(" │ archived "+c.Archive))
}
return lines
}
+2 -7
View File
@@ -14,7 +14,6 @@ func TestCompactionCardLines(t *testing.T) {
Trigger: "auto",
Messages: 12,
Summary: "## Goal\n- do X\n## Files & code\n- a.go edited",
Archive: "/tmp/arch/20260531.jsonl",
})
joined := strings.Join(lines, "\n")
@@ -27,7 +26,7 @@ func TestCompactionCardLines(t *testing.T) {
}
}
// Every summary line (and the archive line) sits under the "│" gutter.
for _, want := range []string{"│ ## Goal", "│ - do X", "│ - a.go edited", "│ archived /tmp/arch/20260531.jsonl"} {
for _, want := range []string{"│ ## Goal", "│ - do X", "│ - a.go edited"} {
if !strings.Contains(joined, want) {
t.Errorf("card missing gutter line %q in:\n%s", want, joined)
}
@@ -62,12 +61,8 @@ func TestCompactionCardOmitsQualityWithoutCoverage(t *testing.T) {
}
}
// TestCompactionCardLinesNoArchive omits the archive line when none was written.
func TestCompactionCardLinesNoArchive(t *testing.T) {
func TestCompactionCardLinesManualTrigger(t *testing.T) {
lines := compactionCardLines(event.Compaction{Trigger: "manual", Messages: 3, Summary: "- brief"})
if strings.Contains(strings.Join(lines, "\n"), "archived") {
t.Errorf("no archive path should mean no archive line: %v", lines)
}
if !strings.Contains(lines[0], "manual") {
t.Errorf("header should reflect the manual trigger: %q", lines[0])
}
+2 -3
View File
@@ -66,7 +66,7 @@ const (
// summarizer runs; CompactionDone replaces it. Mirrors ToolDispatch/ToolResult.
CompactionStarted
// CompactionDone reports a finished compaction pass (Compaction payload:
// Trigger/Messages/Summary/Archive). An aborted pass emits this with an empty
// Trigger/Messages/Summary). An aborted pass emits this with an empty
// Summary so the placeholder still resolves. Replaces the older plain Notice
// so a sink can render a distinct, expandable card.
CompactionDone
@@ -449,14 +449,13 @@ type ExtensionNotificationView struct {
// Compaction carries a context-compaction pass for the CompactionStarted /
// CompactionDone events. On CompactionStarted only Trigger is set. On
// CompactionDone, Messages/Summary/Archive are filled in (an aborted pass leaves
// CompactionDone, Messages/Summary are filled in (an aborted pass leaves
// Summary empty). Trigger is "auto" (the prompt reached the window threshold) or
// "manual" (the user ran /compact).
type Compaction struct {
Trigger string // "auto" | "manual"
Messages int // Done: how many messages were folded into the summary
Summary string // Done: the briefing the agent keeps relying on
Archive string // Done: path the dropped originals were archived to ("" if none)
// Done: what the fold cost, and what the digest kept of it. A lossy fold is
// otherwise indistinguishable from a clean one without reading the digest.
SourceTokens int
+1 -2
View File
@@ -329,7 +329,6 @@ type Compaction struct {
Trigger string `json:"trigger,omitempty"`
Messages int `json:"messages,omitempty"`
Summary string `json:"summary,omitempty" externalizable:"true"`
Archive string `json:"archive,omitempty" externalizable:"true"`
// What the fold cost, and what the digest kept of it.
SourceTokens int `json:"sourceTokens,omitempty"`
ProjectionTokens int `json:"projectionTokens,omitempty"`
@@ -341,7 +340,7 @@ type Compaction struct {
func toWireCompaction(c event.Compaction) *Compaction {
return &Compaction{
Trigger: c.Trigger, Messages: c.Messages,
Summary: c.Summary, Archive: c.Archive,
Summary: c.Summary,
SourceTokens: c.SourceTokens, ProjectionTokens: c.ProjectionTokens,
CoverageRequired: c.CoverageRequired, CoverageMissing: c.CoverageMissing,
CoverageRepaired: c.CoverageRepaired,
+2 -2
View File
@@ -440,9 +440,9 @@ func TestToWireInteractionAndLifecyclePayloads(t *testing.T) {
{
name: "compaction",
in: event.Event{Kind: event.CompactionDone, Compaction: event.Compaction{
Trigger: "manual", Messages: 7, Summary: "brief", Archive: "/tmp/archive.jsonl",
Trigger: "manual", Messages: 7, Summary: "brief",
}},
want: []string{`"kind":"compaction_done"`, `"trigger":"manual"`, `"messages":7`, `"summary":"brief"`, `"archive":"/tmp/archive.jsonl"`},
want: []string{`"kind":"compaction_done"`, `"trigger":"manual"`, `"messages":7`, `"summary":"brief"`},
},
{
name: "turn done error",