diff --git a/.squad/agents/scribe/charter.md b/.squad/agents/scribe/charter.md index 0e45c24a6..0dbe6e3ad 100644 --- a/.squad/agents/scribe/charter.md +++ b/.squad/agents/scribe/charter.md @@ -23,6 +23,9 @@ After substantial work: 1. Log session to `.squad/log/{timestamp}-{topic}.md` (who, what, outcomes) 2. Merge `.squad/decisions/inbox/` → `.squad/decisions.md`, delete inbox files + - **IMPORTANT — Date Format Mandate:** All merged entries MUST use the format `### YYYY-MM-DD: Topic` for decision headings. + - If an inbox file is missing a date, add today's date (`YYYY-MM-DD`). + - If an entry cannot be dated (missing context, ambiguous age), log a warning, skip it, and report. 3. Deduplicate decisions.md by `### ` blocks (exact duplicates, overlapping topics) 4. Propagate: append `📌 Team update` to affected agents' history.md 5. Commit: cd to team root, `git add .squad/`, temp file, `git commit -F` (Windows: no `-C`, no `-m` newlines) diff --git a/.squad/templates/scribe-charter.md b/.squad/templates/scribe-charter.md index 9082faa45..743443b04 100644 --- a/.squad/templates/scribe-charter.md +++ b/.squad/templates/scribe-charter.md @@ -32,6 +32,9 @@ After every substantial work session: 2. **Merge the decision inbox:** - Read all files in `.squad/decisions/inbox/` - APPEND each decision's contents to `.squad/decisions.md` + - **IMPORTANT — Date Format Mandate:** All merged entries MUST use the format `### YYYY-MM-DD: Topic` for decision headings. + - If an inbox file is missing a date, add today's date (`YYYY-MM-DD`). + - If an entry cannot be dated (missing context, ambiguous age), log a warning, skip it, and report. - Delete each inbox file after merging 3. **Deduplicate and consolidate decisions.md:** diff --git a/packages/squad-cli/src/cli/core/nap.ts b/packages/squad-cli/src/cli/core/nap.ts index 6466879a9..5a33c2a5e 100644 --- a/packages/squad-cli/src/cli/core/nap.ts +++ b/packages/squad-cli/src/cli/core/nap.ts @@ -308,6 +308,33 @@ function cleanInbox(squadDir: string, dryRun: boolean): NapAction[] { // ─── Decision archival ────────────────────────────────────────────────── +/** + * Archive stale decision entries from `decisions.md` to `decisions-archive.md`. + * + * **Entry format:** Each entry starts with `### YYYY-MM-DD: Topic`. Entries + * without a parseable date are treated as undated and always preserved (they + * are typically foundational directives). + * + * **Invariant:** `entries_before === entries_kept + entries_archived` — no + * decision data is ever silently dropped. + * + * **Threshold:** The file must exceed {@link DECISION_THRESHOLD} (default + * 20 KB) before any archival is attempted. This constant is overridable via + * config in future iterations. + * + * **Archival strategy:** + * 1. *Age-based* — entries older than {@link DECISION_MAX_AGE_DAYS} are + * archived first. + * 2. *Count-based fallback* — when no entries exceed the age limit but the + * file still exceeds the threshold, the oldest dated entries are archived + * until the remaining content fits within the budget. + * + * @param squadDir - Absolute path to the `.squad` directory. + * @param dryRun - When `true`, calculates the action without writing to disk. + * @returns `null` when the file is under threshold, doesn't exist, or nothing + * was archivable (e.g. only undated entries remain). Otherwise a + * {@link NapAction} describing the archive operation and bytes saved. + */ function archiveDecisions(squadDir: string, dryRun: boolean): NapAction | null { const decisionsFile = path.join(squadDir, 'decisions.md'); if (!fs.existsSync(decisionsFile)) return null;