Skip to content

arch: archive logic ignores class and loadGuidance — POLICY entries get aged out identically to LOCAL notes #1269

Closed as not planned

Description

@tamirdresher

Summary

Scribe's hard-gated archive logic (squad.agent.md:608) uses time only:

DECISIONS ARCHIVE [HARD GATE]:
  If decisions.md >= 20,480 bytes → archive entries older than 30 days
  If decisions.md >= 51,200 bytes → archive entries older than 7 days

HISTORY SUMMARIZATION [HARD GATE]:
  If any history.md >= 15,360 bytes → summarize now

This ignores metadata the governance pipeline already computes — class (TRANSIENT/LOCAL/DECISION/POLICY) and loadGuidance (ALWAYS/ON-DEMAND/ARCHIVE/NEVER) — both stored in .squad/memory/index.json. Result: a 60-day-old POLICY decision (which loadGuidance: ALWAYS flags as "always load") gets archived identically to a 60-day-old throwaway LOCAL note.

Failure scenarios

"Hot policy gets aged out"

A POLICY like "Always use Zod for input validation" from 40 days ago is referenced in every PR. Scribe hits the 30-day threshold, archives it. New sub-agents spawn, don't see it in decisions.md (archived files aren't pre-loaded), write code using joi instead. The information loss is silent — .squad/decisions-archive.md has the entry, but nothing reads archives at spawn time.

"POLICY treated like LOCAL"

The classifier deliberately tags POLICY entries with loadGuidance: ALWAYS (verified at packages/squad-sdk/src/memory/index.ts:428-440). That field is purely advisory today — no Scribe step honors it.

"Importance is invisible to the archiver"

Scribe's archive logic looks at the heading date in decisions.md (e.g. ### 2026-04-15: Use bcrypt for ...) and a quick scan of content size. It doesn't open memory/index.json to check the entry's class — that metadata is sitting right there but unused.

Proposed: leverage the existing governance metadata

The classifier ALREADY computes everything needed. The fix is plumbing.

Phase 1 — block obvious losses (small, additive)

Before archiving any decision block in decisions.md:

  1. Try to resolve the block back to its entry in memory/index.json (by id slug in the original inbox file, or by title match)
  2. Skip archival if:
    • class == 'POLICY' (always)
    • loadGuidance == 'ALWAYS' (regardless of class)
    • User has explicitly pinned (new field — see Phase 2)
  3. Log preserved-by-policy items in the HEALTH REPORT so you can see what survived

Phase 2 — track usage (data collection)

Add lastReadAt and readCount fields to each entry in memory/index.json. Populate by:

  1. memory.search results update lastReadAt for each returned id
  2. (Future) When the read-side gap is closed and agents call memory.search instead of filesystem grep, every read pre-loads the index update

Phase 3 — score-based archival (using all signals)

Once Phase 2 has data, archive decisions:

score = (
  (now - lastReadAt).days +    // staleness penalty
  -(class.weight) +             // POLICY=∞, DECISION=10, LOCAL=1
  -(readCount * 2)              // popularity bonus
)
if score > THRESHOLD: archive

POLICY entries never archive (weight ∞). Frequently-read LOCAL entries survive. Old unread entries get archived first.

Phase 4 — user pin / explicit retention

Add pinned: true to memory/index.json entries. CLI: squad memory pin <id> / squad memory unpin <id>. Pinned entries never archive regardless of age or score. Useful for legacy decisions that aren't promoted to POLICY but are still load-bearing.

Why this matters more once #1251 ships

PR #1251 (memory MCP bridge) makes memory.write reachable from agents. Adoption will grow → governance metadata accumulates. The archive logic is the first place that metadata gets meaningful — until then, it's just an unused field. Today's loss-by-age policy is acceptable because metadata is sparse; once it isn't, the loss becomes visible.

Related

  • #600 and #595 propose tiered hot/cold history retrieval — orthogonal but compatible. Their tiering is time-based and content-only; this issue would make their tiering importance-aware too.
  • #1037 (closed) — context budget proposal anticipated this kind of refinement
  • Related (filed today): arch: Scribe bypasses the governed memory pipeline — Phase 1 of this proposal lands naturally as part of that issue's fix
  • PR #1251 — prerequisite

Severity

🟡 High — degrades over time as governed memory adoption grows. Pre-#1251 users don't hit this (no metadata to consult); post-#1251 users will hit it within months of heavy use.

Activity

  1. added
    stalled-initiativeWork area that was started but never completed — cut, close, finish, or reprioritize
    on Aug 30, 2026
  2. bradygaster commented on Nov 5, 2026

    @bradygaster
    Collaborator

    Consolidated into #2392 during 2.0 board triage (owner decision). The decision and its validation tests are tracked there; original text remains here for reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stalled-initiativeWork area that was started but never completed — cut, close, finish, or reprioritizetriagedIssue has been triagedwave:2-soonWave 2 — next 2-4 weeks

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions