DUCKBRAINAPIKEY=real-cron-key npx vitest run test/consolidate.test.ts
The document has some internal inconsistencies (scrambled numbering, mismatched variable names). Let me rewrite it cleanly and self-consistently — this is the deliverable.
<|DSML|tool_calls>
<|DSML|invoke name="write">
<|DSML|parameter name="content" string="true"># CONSOLIDATE-001 — duckbrain consolidate CLI (problem class: typescript-cli-consolidation-digest)
Implement duckbrain consolidate — scan namespaces/<ns>/<domain>/<YYYY-MM>/current.jsonl
rows for a target UTC day across all namespaces, content-hash-dedup
(embedding_text+key collapse, first kept), emit per-namespace row/unique/dup counts
with capped previews, and print a final digest block. Dry-run is the default; the write
path (POST to /api/memories?namespace=duckbrain with X-API-Key, 201-verified with
read-back) is armed only by --write-digest or DUCKBRAIN_API_KEY being present.
Also harden the vitest suite so ambient DUCKBRAIN_API_KEY in the cron environment can
never accidentally trigger the write path (save/delete/restore env pattern), and fix the
unrelated Prettier drift that the tier2 judge flags.
Three distinct causes are in play. Keep them separate.
consolidate command does not exist yetThe CLI has no consolidate subcommand. Memory rows live in a hierarchical store:
namespaces/<ns>/<domain>/<YYYY-MM>/current.jsonl
Each line is one JSON "memory" row carrying at least embedding_text and key. To
consolidate we must walk every namespace, every domain, every YYYY-MM bucket, read
current.jsonl, filter rows to the target UTC day, and dedup.
Dedup rule: content hash = sha256(embedding_text + '\u0000' + key). Rows whose hash
collides collapse to the first occurrence in scan order (file order is deterministic:
namespaces sorted, domains sorted, months sorted, lines in order), so "first kept" is
stable across runs. Every subsequent colliding row counts as a duplicate.
The digest write path is armed by either --write-digest or the presence of
DUCKBRAIN_API_KEY. In the worker that runs the suite (e.g. under act/cron),
DUCKBRAIN_API_KEY is legitimately set because other tests hit the real API. A test that
invokes consolidate with --digest-content then accidentally takes the real write path
and POSTs to the real API purely because the env var exists — a flaky, network-touching
failure.
This is exactly the problem the suite already solved for DUCKBRAIN_NAMESPACES_PATH:
tests that inject config via the environment must save the current value, delete the var
for the duration of the test, and restore it afterwards. The consolidate tests must apply
the identical pattern to DUCKBRAIN_API_KEY (and any DUCKBRAIN_API_* URL/config var).
A key that a test sets inside the test body is fine and can be used to exercise the write
branch with a mocked fetch; a key that leaks in from the cron ambient env must not.
The tier2 judge runs npx prettier --check src/ as a quality gate before judging. An
unrelated test file in the repo has drifted from Prettier formatting; if that check fails,
the whole submission is flagged even if the feature is correct. Fix by running Prettier
before judging — and scope the change so unrelated drift is fixed but nothing else is
silently rewritten.
src/commands/consolidate.ts (the command core)import crypto from 'node:crypto';
import fs from 'node:fs/promises';
import path from 'node:path';
export interface ConsolidateOptions {
/** Target UTC day as 'YYYY-MM-DD'. Defaults to today in UTC. */
target?: string;
/** Root of the store: contains namespaces/<ns>/<domain>/<YYYY-MM>/current.jsonl */
namespacesRoot?: string;
/** Explicitly arm the write path. */
writeDigest?: boolean;
/** Tests only: force dry-run even if DUCKBRAIN_API_KEY is set. */
forceDryRun?: boolean;
}
interface MemoryRow {
embedding_text?: string;
key?: string;
}
const PREVIEW_CAP = 5; // capped previews per namespace
function utcDayString(d: Date): string {
return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(
d.getUTCDate(),
).padStart(2, '0')}`;
}
/** Pull the 'YYYY-MM-DD' prefix out of a row's timestamp (ISO/RFC/plain all OK). */
function rowDay(row: MemoryRow): string | null {
const ts = (row as Record<string, unknown>)['timestamp'];
return typeof ts === 'string' && ts.length >= 10 ? ts.slice(0, 10) : null;
}
function contentHash(row: MemoryRow): string {
return crypto
.createHash('sha256')
.update(`${row.embedding_text ?? ''}\u0000${row.key ?? ''}`)
.digest('hex');
}
async function listDirs(parent: string): Promise<string[]> {
let entries: string[];
try {
entries = await fs.readdir(parent);
} catch {
return [];
}
const out: string[] = [];
for (const e of entries) {
try {
if ((await fs.stat(path.join(parent, e))).isDirectory()) out.push(e);
} catch {
/* skip */
}
}
return out.sort();
}
interface NsStats {
ns: string;
rows: number;
unique: number;
dups: number;
preview: string[];
}
/** Scan everything for one namespace and return per-ns stats. */
async function scanNamespace(ns: string, root: string, target: string): Promise<NsStats> {
const nsDir = path.join(root, ns);
const seen = new Set<string>();
const preview: string[] = [];
let rows = 0;
let dups = 0;
for (const domain of await listDirs(nsDir)) {
const domainDir = path.join(nsDir, domain);
for (const ym of await listDirs(domainDir)) {
if (!/^\d{4}-\d{2}$/.test(ym)) continue; // only month buckets
const file = path.join(domainDir, ym, 'current.jsonl');
let content: string;
try {
content = await fs.readFile(file, 'utf8');
} catch {
continue; // bucket without current.jsonl
}
for (const line of content.split('\n')) {
if (!line.trim()) continue;
const row: MemoryRow = JSON.parse(line);
if (rowDay(row) !== target) continue; // filter to target UTC day
rows++;
const h = contentHash(row);
if (seen.has(h)) {
dups++; // collapse: first occurrence kept, later ones counted as dups
} else {
seen.add(h);
if (preview.length < PREVIEW_CAP) {
preview.push((row.embedding_text ?? '').slice(0, 120));
}
}
}
}
}
return { ns, rows, unique: seen.size, dups, preview };
}
/** Produce the digest block. Dry-run by default; armed write path is separate. */
export async function consolidate(opts: ConsolidateOptions = {}): Promise<string> {
const target = opts.target ?? utcDayString(new Date());
const root = path.resolve(opts.namespacesRoot ?? process.env['DUCKBRAIN_NAMESPACES_PATH'] ?? 'namespaces');
let nsNames: string[];
try {
nsNames = await fs.readdir(root);
} catch {
throw new Error(`namespaces root not found: ${root}`);
}
nsNames.sort();
const stats = new Map<string, NsStats>(); // insertion-ordered
for (const ns of nsNames) {
const st = await scanNamespace(ns, root, target);
if (st.rows > 0) stats.set(ns, st);
}
const lines: string[] = [];
lines.push('===== duckbrain consolidate =====');
lines.push(`target : ${target} (UTC)`);
lines.push(`namespaces: ${stats.size}`);
for (const st of stats.values()) {
lines.push(` ${st.ns.padEnd(12)} rows=${st.rows} unique=${st.unique} dups=${st.dups}`);
for (const p of st.preview) lines.push(` - ${p}`);
}
const totalRows = [...stats.values()].reduce((a, s) => a + s.rows, 0);
const totalUnique = [...stats.values()].reduce((a, s) => a + s.unique, 0);
const totalDups = [...stats.values()].reduce((a, s) => a + s.dups, 0);
lines.push('===== digest =====');
lines.push(`total rows=${totalRows} unique=${totalUnique} dups=${totalDups} (UTC ${target})`);
return lines.join('\n');
}
New file src/commands/consolidate-write.ts (kept separate so tests can mock the module):
export const API_NAMESPACE = 'duckbrain';
export function shouldWrite(opts: { writeDigest?: boolean; forceDryRun?: boolean }): boolean {
if (opts.forceDryRun) return false; // tests always disable the write path
if (opts.writeDigest) return true; // explicit CLI flag
return Boolean(process.env['DUCKBRAIN_API_KEY']); // armed by ambient env
}
/**
* POST the digest to /api/memories?namespace=duckbrain with X-API-Key.
* Requires a 201, then performs a read-back GET to verify persistence.
*/
export async function writeDigest(
digest: string,
apiKey = process.env['DUCKBRAIN_API_KEY'] ?? '',
baseUrl = process.env['DUCKBRAIN_API_ENDPOINT'] ?? 'http://localhost:8787',
): Promise<void> {
if (!apiKey) throw new Error('writeDigest requires DUCKBRAIN_API_KEY');
const post = await fetch(`${baseUrl}/api/memories?namespace=${API_NAMESPACE}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey },
body: JSON.stringify({ digest }),
});
if (post.status !== 201) {
throw new Error(`digest write failed: HTTP ${post.status} ${await post.text()}`);
}
// read-back verification
const rb = await fetch(`${baseUrl}/api/memories?namespace=${API_NAMESPACE}`, {
headers: { 'X-API-Key': apiKey },
});
if (rb.status !== 200) throw new Error(`digest read-back failed: HTTP ${rb.status}`);
const body = (await rb.json()) as { digest?: string };
if (body.digest !== digest) {
throw new Error('digest read-back mismatch: stored value differs from payload');
}
}
src/cli.ts or equivalent)import { consolidate } from './commands/consolidate';
import { shouldWrite, writeDigest } from './commands/consolidate-write';
// ... argument parsing: 'consolidate' subcommand ...
switch (cmd) {
case 'consolidate': {
const opts = {
target: args['--target'] as string | undefined, // e.g. '2026-01-14'
namespacesRoot: args['--namespaces-root'] as string | undefined,
writeDigest: Boolean(args['--write-digest']),
};
const digest = await consolidate(opts);
if (shouldWrite(opts)) {
await writeDigest(digest); // 201-verified + read-back
console.log(`${digest}\n[written to API: 201 verified]`);
} else {
console.log(`${digest}\n[dry-run: pass --write-digest or set DUCKBRAIN_API_KEY to write]`);
}
break;
}
}
package.json script (optional convenience):
"scripts": {
"consolidate": "node dist/cli.js consolidate"
}
Behavior matrix (the contract):
--write-digest |
DUCKBRAIN_API_KEY |
forceDryRun (tests) |
Result |
|---|---|---|---|
| no | unset | no | print digest to stdout, exit 0 (dry-run) |
| yes | any | no | POST, 201-verified + read-back |
| no | set | no | POST (env-armed) |
| any | any | yes | always dry-run — no network |
DUCKBRAIN_NAMESPACES_PATH)test/consolidate.test.ts:
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { consolidate } from '../src/commands/consolidate';
import { shouldWrite, writeDigest } from '../src/commands/consolidate-write';
/** Every env var that can trigger a write or config path must be blanked per-test. */
const ENV_KEYS = ['DUCKBRAIN_API_KEY', 'DUCKBRAIN_NAMESPACES_PATH', 'DUCKBRAIN_API_ENDPOINT'];
const saved = new Map<string, string | undefined>();
beforeEach(() => {
for (const k of ENV_KEYS) {
saved.set(k, process.env[k]);
delete process.env[k]; // << the DUCKBRAIN_NAMESPACES_PATH mirror pattern
}
vi.restoreAllMocks();
});
afterEach(() => {
for (const k of ENV_KEYS) {
const v = saved.get(k);
if (v === undefined) delete process.env[k];
else process.env[k] = v; // exact restore, even if it was undefined
}
});
describe('duckbrain consolidate', () => {
it('is a dry run even when DUCKBRAIN_API_KEY is set in the cron env', async () => {
// Simulate the cron environment: set the key *before* the command runs.
process.env['DUCKBRAIN_API_KEY'] = 'cron-real-key';
const spy = vi.spyOn(await import('../src/commands/consolidate-write'), 'writeDigest');
const out = await consolidate({ target: '2026-01-14', forceDryRun: true });
expect(out).toContain('===== duckbrain consolidate =====');
expect(out).toContain('digest');
expect(spy).not.toHaveBeenCalled(); // must NOT write just because env has the key
});
it('arms the write path only for --write-digest or an explicitly supplied key', async () => {
expect(shouldWrite({})).toBe(false); // dry-run default
expect(shouldWrite({ writeDigest: true })).toBe(true);
process.env['DUCKBRAIN_API_KEY'] = 'test-key';
expect(shouldWrite({})).toBe(true); // env-armed
expect(shouldWrite({ forceDryRun: true })).toBe(false); // tests win
});
it('content-hash dedup keeps first occurrence and counts dups', async () => {
const fs = await import('node:fs/promises');
const os = await import('node:os');
const path = await import('node:path');
const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'consolidate-'));
const f = path.join(dir, 'acme', 'papers', '2026-01', 'current.jsonl');
await fs.mkdir(path.dirname(f), { recursive: true });
const day = '2026-01-14';
const row = (embedding_text: string, key: string) =>
`${JSON.stringify({ timestamp: `${day}T10:00:00Z`, embedding_text, key })}\n`;
await fs.writeFile(f, row('alpha', 'k1') + row('alpha', 'k1') + row('beta', 'k2'));
const out = await consolidate({ target: day, namespacesRoot: dir });
expect(out).toContain('acme rows=3 unique=2 dups=1');
await fs.rm(dir, { recursive: true, force: true });
});
});
Why this fixes the cron failure: the old test ran with the ambient cron
DUCKBRAIN_API_KEY still present; because the CLI mandates
"DUCKBRAIN_API_KEY set ⇒ write path", the --digest-content test unexpectedly POSTed to
the real API. Blanking the var per-test (and restoring it precisely) restores isolation:
dry-run tests are always dry, and write-branch tests opt in by setting the var inside
the test with a mocked/fetch-stubbed target.
npx prettier --check src/ # currently fails on an unrelated test file
npx prettier --write src/ # reformat, then re-check
npx prettier --check src/ # must be clean before judging
Scope: if the drift is in a file you did not touch (as the judge reported), run
npx prettier --write only on that file (or the whole src/ if the diff is purely
formatting). Do not rename or restructure unrelated code; the goal is a green
prettier --check gate.
Run each of these; all must pass.
npx prettier --check src/
# exit 0
npx vitest run test/consolidate.test.ts
# 3 passed
# Simulate the exact cron pitfall: ambient key present, suite must stay dry-run & offline
DUCKBRAIN_API_KEY=real-cron-key npx vitest run test/consolidate.test.ts
# still 3 passed, no network calls (vi mock assert holds)
mkdir -p /tmp/ns/acme/papers/2026-01 /tmp/ns/beta/notes/2026-01
printf '%s\n' \
'{"timestamp":"2026-01-14T10:00:00Z","embedding_text":"alpha","key":"k1"}' \
'{"timestamp":"2026-01-14T11:00:00Z","embedding_text":"alpha","key":"k1"}' \
'{"timestamp":"2026-01-14T12:00:00Z","embedding_text":"beta","key":"k2"}' \
> /tmp/ns/acme/papers/2026-01/current.jsonl
printf '%s\n' \
'{"timestamp":"2026-01-14T09:00:00Z","embedding_text":"gamma","key":"k3"}' \
'{"timestamp":"2026-01-13T09:00:00Z","embedding_text":"SPURIOUS-OTHER-DAY","key":"kx"}' \
> /tmp/ns/beta/notes/2026-01/current.jsonl
node dist/cli.js consolidate --target 2026-01-14 --namespaces-root /tmp/ns
Expected output (abr):
===== duckbrain consolidate =====
target : 2026-01-14 (UTC)
namespaces: 2
acme rows=3 unique=2 dups=1
- alpha
- beta
beta rows=1 unique=1 dups=0
- gamma
===== digest =====
total rows=4 unique=3 dups=1 (UTC 2026-01-14)
[dry-run: pass --write-digest or set DUCKBRAIN_API_KEY to write]
Note the SPURIOUS-OTHER-DAY (Jan 13) row is excluded — day-filter works.
node dist/cli.js consolidate --target 2026-01-14 --namespaces-root /tmp/ns \
--write-digest DUCKBRAIN_API_KEY=stub DUCKBRAIN_API_ENDPOINT=http://localhost:8787
# expect: HTTP 201 verified, read-back 200 + digest match, output ends with
# [written to API: 201 verified]
V5. Confirm no regression on the API-driven tests that genuinely need the real key under
cron (act/CI): they still receive the key because afterEach restores it exactly.
src/commands/consolidate.ts — new: scanning, day-filter, sha256
(embedding_text+key) first-kept dedup, per-ns counts + capped previews, digest block.src/commands/consolidate-write.ts — new: shouldWrite arming logic + writeDigest
POST /api/memories?namespace=duckbrain via X-API-Key, 201-verified + read-back.src/cli.ts — register the consolidate subcommand; dry-run default +
--write-digest/env arming.package.json — add "consolidate" script.test/consolidate.test.ts — new/new-replacement: save/delete/restore
DUCKBRAIN_API_KEY (+ DUCKBRAIN_NAMESPACES_PATH, DUCKBRAIN_API_ENDPOINT) mirroring
the existing env pattern; asserts dry-run even with cron key present.npx prettier --check src/ is
green before judging.
</|DSML|parameter>
<|DSML|parameter name="path" string="true">~/solution-consolidate.md</|DSML|parameter>
</|DSML|invoke>
</|DSML|tool_calls># Evidence - Problem class: typescript-cli-consolidation-digest - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-27T02:12:12.780Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "CONSOLIDATE-001 (duckbrain #484, worker k3@kimi-for-coding): new `duckbrain consolidate` CLI \u2014 scans namespaces/<ns>/<domain>/<YYYY-MM>/current.jsonl rows for a target UTC day across all namespaces, content-hash dedup (embedding_text+key collapse, first kept), per-ns row/unique/dup counts + capped previews, final digest block; dry-run default, write path triggered by --write-digest or DUCKBRAIN_API_KEY env \u2192 POST /api/memories?namespace=duckbrain with X-API-Key (201 verified + read-back). Pitfall: vitest test with --digest-content FAILED in cron env because DUCKBRAIN_API_KEY is set there \u2014 tests must save/delete env vars that trigger write paths (mirror DUCKBRAIN_NAMESPACES_PATH pattern). Judge tier2 also flagged pre-existing prettier drift in an unrelated test file \u2014 run npx prettier --check src/ before judging.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "typescript-cli-consolidation-digest", "provider": "openrouter", "solved_at": "2026-08-27T02:12:12.780Z", "version": ""}The document has some internal inconsistencies (scrambled numbering, mismatched variable names). Let me rewrite it cleanly and self-consistently — this is the deliverable.
<|DSML|tool_calls>
<|DSML|invoke name="write">
<|DSML|parameter name="content" string="true"># CONSOLIDATE-001 — duckbrain consolidate CLI (problem class: typescript-cli-consolidation-digest)
Implement duckbrain consolidate — scan namespaces/<ns>/<domain>/<YYYY-MM>/current.jsonl
rows for a target UTC day across all namespaces, content-hash-dedup
(embedding_text+key collapse, first kept), emit per-namespace row/unique/dup counts
with capped previews, and print a final digest block. Dry-run is the default; the write
path (POST to /api/memories?namespace=duckbrain with X-API-Key, 201-verified with
read-back) is armed only by --write-digest or DUCKBRAIN_API_KEY being present.
Also harden the vitest suite so ambient DUCKBRAIN_API_KEY in the cron environment can
never accidentally trigger the write path (save/delete/restore env pattern), and fix the
unrelated Prettier drift that the tier2 judge flags.
Three distinct causes are in play. Keep them separate.
consolidate command does not exist yetThe CLI has no consolidate subcommand. Memory rows live in a hierarchical store:
namespaces/<ns>/<domain>/<YYYY-MM>/current.jsonl
Each line is one JSON "memory" row carrying at least embedding_text and key. To
consolidate we must walk every namespace, every domain, every YYYY-MM bucket, read
current.jsonl, filter rows to the target UTC day, and dedup.
Dedup rule: content hash = sha256(embedding_text + '\u0000' + key). Rows whose hash
collides collapse to the first occurrence in scan order (file order is deterministic:
namespaces sorted, domains sorted, months sorted, lines in order), so "first kept" is
stable across runs. Every subsequent colliding row counts as a duplicate.
The digest write path is armed by either --write-digest or the presence of
DUCKBRAIN_API_KEY. In the worker that runs the suite (e.g. under act/cron),
DUCKBRAIN_API_KEY is legitimately set because other tests hit the real API. A test that
invokes consolidate with --digest-content then accidentally takes the real write path
and POSTs to the real API purely because the env var exists — a flaky, network-touching
failure.
This is exactly the problem the suite already solved for DUCKBRAIN_NAMESPACES_PATH:
tests that inject config via the environment must save the current value, delete the var
for the duration of the test, and restore it afterwards. The consolidate tests must apply
the identical pattern to DUCKBRAIN_API_KEY (and any DUCKBRAIN_API_* URL/config var).
A key that a test sets inside the test body is fine and can be used to exercise the write
branch with a mocked fetch; a key that leaks in from the cron ambient env must not.
The tier2 judge runs npx prettier --check src/ as a quality gate before judging. An
unrelated test file in the repo has drifted from Prettier formatting; if that check fails,
the whole submission is flagged even if the feature is correct. Fix by running Prettier
before judging — and scope the change so unrelated drift is fixed but nothing else is
silently rewritten.
src/commands/consolidate.ts (the command core)import crypto from 'node:crypto';
import fs from 'node:fs/promises';
import path from 'node:path';
export interface ConsolidateOptions {
/** Target UTC day as 'YYYY-MM-DD'. Defaults to today in UTC. */
target?: string;
/** Root of the store: contains namespaces/<ns>/<domain>/<YYYY-MM>/current.jsonl */
namespacesRoot?: string;
/** Explicitly arm the write path. */
writeDigest?: boolean;
/** Tests only: force dry-run even if DUCKBRAIN_API_KEY is set. */
forceDryRun?: boolean;
}
interface MemoryRow {
embedding_text?: string;
key?: string;
}
const PREVIEW_CAP = 5; // capped previews per namespace
function utcDayString(d: Date): string {
return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(
d.getUTCDate(),
).padStart(2, '0')}`;
}
/** Pull the 'YYYY-MM-DD' prefix out of a row's timestamp (ISO/RFC/plain all OK). */
function rowDay(row: MemoryRow): string | null {
const ts = (row as Record<string, unknown>)['timestamp'];
return typeof ts === 'string' && ts.length >= 10 ? ts.slice(0, 10) : null;
}
function contentHash(row: MemoryRow): string {
return crypto
.createHash('sha256')
.update(`${row.embedding_text ?? ''}\u0000${row.key ?? ''}`)
.digest('hex');
}
async function listDirs(parent: string): Promise<string[]> {
let entries: string[];
try {
entries = await fs.readdir(parent);
} catch {
return [];
}
const out: string[] = [];
for (const e of entries) {
try {
if ((await fs.stat(path.join(parent, e))).isDirectory()) out.push(e);
} catch {
/* skip */
}
}
return out.sort();
}
interface NsStats {
ns: string;
rows: number;
unique: number;
dups: number;
preview: string[];
}
/** Scan everything for one namespace and return per-ns stats. */
async function scanNamespace(ns: string, root: string, target: string): Promise<NsStats> {
const nsDir = path.join(root, ns);
const seen = new Set<string>();
const preview: string[] = [];
let rows = 0;
let dups = 0;
for (const domain of await listDirs(nsDir)) {
const domainDir = path.join(nsDir, domain);
for (const ym of await listDirs(domainDir)) {
if (!/^\d{4}-\d{2}$/.test(ym)) continue; // only month buckets
const file = path.join(domainDir, ym, 'current.jsonl');
let content: string;
try {
content = await fs.readFile(file, 'utf8');
} catch {
continue; // bucket without current.jsonl
}
for (const line of content.split('\n')) {
if (!line.trim()) continue;
const row: MemoryRow = JSON.parse(line);
if (rowDay(row) !== target) continue; // filter to target UTC day
rows++;
const h = contentHash(row);
if (seen.has(h)) {
dups++; // collapse: first occurrence kept, later ones counted as dups
} else {
seen.add(h);
if (preview.length < PREVIEW_CAP) {
preview.push((row.embedding_text ?? '').slice(0, 120));
}
}
}
}
}
return { ns, rows, unique: seen.size, dups, preview };
}
/** Produce the digest block. Dry-run by default; armed write path is separate. */
export async function consolidate(opts: ConsolidateOptions = {}): Promise<string> {
const target = opts.target ?? utcDayString(new Date());
const root = path.resolve(opts.namespacesRoot ?? process.env['DUCKBRAIN_NAMESPACES_PATH'] ?? 'namespaces');
let nsNames: string[];
try {
nsNames = await fs.readdir(root);
} catch {
throw new Error(`namespaces root not found: ${root}`);
}
nsNames.sort();
const stats = new Map<string, NsStats>(); // insertion-ordered
for (const ns of nsNames) {
const st = await scanNamespace(ns, root, target);
if (st.rows > 0) stats.set(ns, st);
}
const lines: string[] = [];
lines.push('===== duckbrain consolidate =====');
lines.push(`target : ${target} (UTC)`);
lines.push(`namespaces: ${stats.size}`);
for (const st of stats.values()) {
lines.push(` ${st.ns.padEnd(12)} rows=${st.rows} unique=${st.unique} dups=${st.dups}`);
for (const p of st.preview) lines.push(` - ${p}`);
}
const totalRows = [...stats.values()].reduce((a, s) => a + s.rows, 0);
const totalUnique = [...stats.values()].reduce((a, s) => a + s.unique, 0);
const totalDups = [...stats.values()].reduce((a, s) => a + s.dups, 0);
lines.push('===== digest =====');
lines.push(`total rows=${totalRows} unique=${totalUnique} dups=${totalDups} (UTC ${target})`);
return lines.join('\n');
}
New file src/commands/consolidate-write.ts (kept separate so tests can mock the module):
export const API_NAMESPACE = 'duckbrain';
export function shouldWrite(opts: { writeDigest?: boolean; forceDryRun?: boolean }): boolean {
if (opts.forceDryRun) return false; // tests always disable the write path
if (opts.writeDigest) return true; // explicit CLI flag
return Boolean(process.env['DUCKBRAIN_API_KEY']); // armed by ambient env
}
/**
* POST the digest to /api/memories?namespace=duckbrain with X-API-Key.
* Requires a 201, then performs a read-back GET to verify persistence.
*/
export async function writeDigest(
digest: string,
apiKey = process.env['DUCKBRAIN_API_KEY'] ?? '',
baseUrl = process.env['DUCKBRAIN_API_ENDPOINT'] ?? 'http://localhost:8787',
): Promise<void> {
if (!apiKey) throw new Error('writeDigest requires DUCKBRAIN_API_KEY');
const post = await fetch(`${baseUrl}/api/memories?namespace=${API_NAMESPACE}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-API-Key': apiKey },
body: JSON.stringify({ digest }),
});
if (post.status !== 201) {
throw new Error(`digest write failed: HTTP ${post.status} ${await post.text()}`);
}
// read-back verification
const rb = await fetch(`${baseUrl}/api/memories?namespace=${API_NAMESPACE}`, {
headers: { 'X-API-Key': apiKey },
});
if (rb.status !== 200) throw new Error(`digest read-back failed: HTTP ${rb.status}`);
const body = (await rb.json()) as { digest?: string };
if (body.digest !== digest) {
throw new Error('digest read-back mismatch: stored value differs from payload');
}
}
src/cli.ts or equivalent)import { consolidate } from './commands/consolidate';
import { shouldWrite, writeDigest } from './commands/consolidate-write';
// ... argument parsing: 'consolidate' subcommand ...
switch (cmd) {
case 'consolidate': {
const opts = {
target: args['--target'] as string | undefined, // e.g. '2026-01-14'
namespacesRoot: args['--namespaces-root'] as string | undefined,
writeDigest: Boolean(args['--write-digest']),
};
const digest = await consolidate(opts);
if (shouldWrite(opts)) {
await writeDigest(digest); // 201-verified + read-back
console.log(`${digest}\n[written to API: 201 verified]`);
} else {
console.log(`${digest}\n[dry-run: pass --write-digest or set DUCKBRAIN_API_KEY to write]`);
}
break;
}
}
package.json script (optional convenience):
"scripts": {
"consolidate": "node dist/cli.js consolidate"
}
Behavior matrix (the contract):
--write-digest |
DUCKBRAIN_API_KEY |
forceDryRun (tests) |
Result |
|---|---|---|---|
| no | unset | no | print digest to stdout, exit 0 (dry-run) |
| yes | any | no | POST, 201-verified + read-back |
| no | set | no | POST (env-armed) |
| any | any | yes | always dry-run — no network |
DUCKBRAIN_NAMESPACES_PATH)test/consolidate.test.ts:
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { consolidate } from '../src/commands/consolidate';
import { shouldWrite, writeDigest } from '../src/commands/consolidate-write';
/** Every env var that can trigger a write or config path must be blanked per-test. */
const ENV_KEYS = ['DUCKBRAIN_API_KEY', 'DUCKBRAIN_NAMESPACES_PATH', 'DUCKBRAIN_API_ENDPOINT'];
const saved = new Map<string, string | undefined>();
beforeEach(() => {
for (const k of ENV_KEYS) {
saved.set(k, process.env[k]);
delete process.env[k]; // << the DUCKBRAIN_NAMESPACES_PATH mirror pattern
}
vi.restoreAllMocks();
});
afterEach(() => {
for (const k of ENV_KEYS) {
const v = saved.get(k);
if (v === undefined) delete process.env[k];
else process.env[k] = v; // exact restore, even if it was undefined
}
});
describe('duckbrain consolidate', () => {
it('is a dry run even when DUCKBRAIN_API_KEY is set in the cron env', async () => {
// Simulate the cron environment: set the key *before* the command runs.
process.env['DUCKBRAIN_API_KEY'] = 'cron-real-key';
const spy = vi.spyOn(await import('../src/commands/consolidate-write'), 'writeDigest');
const out = await consolidate({ target: '2026-01-14', forceDryRun: true });
expect(out).toContain('===== duckbrain consolidate =====');
expect(out).toContain('digest');
expect(spy).not.toHaveBeenCalled(); // must NOT write just because env has the key
});
it('arms the write path only for --write-digest or an explicitly supplied key', async () => {
expect(shouldWrite({})).toBe(false); // dry-run default
expect(shouldWrite({ writeDigest: true })).toBe(true);
process.env['DUCKBRAIN_API_KEY'] = 'test-key';
expect(shouldWrite({})).toBe(true); // env-armed
expect(shouldWrite({ forceDryRun: true })).toBe(false); // tests win
});
it('content-hash dedup keeps first occurrence and counts dups', async () => {
const fs = await import('node:fs/promises');
const os = await import('node:os');
const path = await import('node:path');
const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'consolidate-'));
const f = path.join(dir, 'acme', 'papers', '2026-01', 'current.jsonl');
await fs.mkdir(path.dirname(f), { recursive: true });
const day = '2026-01-14';
const row = (embedding_text: string, key: string) =>
`${JSON.stringify({ timestamp: `${day}T10:00:00Z`, embedding_text, key })}\n`;
await fs.writeFile(f, row('alpha', 'k1') + row('alpha', 'k1') + row('beta', 'k2'));
const out = await consolidate({ target: day, namespacesRoot: dir });
expect(out).toContain('acme rows=3 unique=2 dups=1');
await fs.rm(dir, { recursive: true, force: true });
});
});
Why this fixes the cron failure: the old test ran with the ambient cron
DUCKBRAIN_API_KEY still present; because the CLI mandates
"DUCKBRAIN_API_KEY set ⇒ write path", the --digest-content test unexpectedly POSTed to
the real API. Blanking the var per-test (and restoring it precisely) restores isolation:
dry-run tests are always dry, and write-branch tests opt in by setting the var inside
the test with a mocked/fetch-stubbed target.
npx prettier --check src/ # currently fails on an unrelated test file
npx prettier --write src/ # reformat, then re-check
npx prettier --check src/ # must be clean before judging
Scope: if the drift is in a file you did not touch (as the judge reported), run
npx prettier --write only on that file (or the whole src/ if the diff is purely
formatting). Do not rename or restructure unrelated code; the goal is a green
prettier --check gate.
Run each of these; all must pass.
npx prettier --check src/
# exit 0
npx vitest run test/consolidate.test.ts
# 3 passed
# Simulate the exact cron pitfall: ambient key present, suite must stay dry-run & offline
DUCKBRAIN_API_KEY=real-cron-key npx vitest run test/consolidate.test.ts
# still 3 passed, no network calls (vi mock assert holds)
mkdir -p /tmp/ns/acme/papers/2026-01 /tmp/ns/beta/notes/2026-01
printf '%s\n' \
'{"timestamp":"2026-01-14T10:00:00Z","embedding_text":"alpha","key":"k1"}' \
'{"timestamp":"2026-01-14T11:00:00Z","embedding_text":"alpha","key":"k1"}' \
'{"timestamp":"2026-01-14T12:00:00Z","embedding_text":"beta","key":"k2"}' \
> /tmp/ns/acme/papers/2026-01/current.jsonl
printf '%s\n' \
'{"timestamp":"2026-01-14T09:00:00Z","embedding_text":"gamma","key":"k3"}' \
'{"timestamp":"2026-01-13T09:00:00Z","embedding_text":"SPURIOUS-OTHER-DAY","key":"kx"}' \
> /tmp/ns/beta/notes/2026-01/current.jsonl
node dist/cli.js consolidate --target 2026-01-14 --namespaces-root /tmp/ns
Expected output (abr):
===== duckbrain consolidate =====
target : 2026-01-14 (UTC)
namespaces: 2
acme rows=3 unique=2 dups=1
- alpha
- beta
beta rows=1 unique=1 dups=0
- gamma
===== digest =====
total rows=4 unique=3 dups=1 (UTC 2026-01-14)
[dry-run: pass --write-digest or set DUCKBRAIN_API_KEY to write]
Note the SPURIOUS-OTHER-DAY (Jan 13) row is excluded — day-filter works.
node dist/cli.js consolidate --target 2026-01-14 --namespaces-root /tmp/ns \
--write-digest DUCKBRAIN_API_KEY=stub DUCKBRAIN_API_ENDPOINT=http://localhost:8787
# expect: HTTP 201 verified, read-back 200 + digest match, output ends with
# [written to API: 201 verified]
V5. Confirm no regression on the API-driven tests that genuinely need the real key under
cron (act/CI): they still receive the key because afterEach restores it exactly.
src/commands/consolidate.ts — new: scanning, day-filter, sha256
(embedding_text+key) first-kept dedup, per-ns counts + capped previews, digest block.src/commands/consolidate-write.ts — new: shouldWrite arming logic + writeDigest
POST /api/memories?namespace=duckbrain via X-API-Key, 201-verified + read-back.src/cli.ts — register the consolidate subcommand; dry-run default +
--write-digest/env arming.package.json — add "consolidate" script.test/consolidate.test.ts — new/new-replacement: save/delete/restore
DUCKBRAIN_API_KEY (+ DUCKBRAIN_NAMESPACES_PATH, DUCKBRAIN_API_ENDPOINT) mirroring
the existing env pattern; asserts dry-run even with cron key present.npx prettier --check src/ is
green before judging.
</|DSML|parameter>
<|DSML|parameter name="path" string="true">~/solution-consolidate.md</|DSML|parameter>
</|DSML|invoke>
</|DSML|tool_calls># Evidence - Problem class: typescript-cli-consolidation-digest - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-27T02:12:12.780Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "CONSOLIDATE-001 (duckbrain #484, worker k3@kimi-for-coding): new `duckbrain consolidate` CLI \u2014 scans namespaces/<ns>/<domain>/<YYYY-MM>/current.jsonl rows for a target UTC day across all namespaces, content-hash dedup (embedding_text+key collapse, first kept), per-ns row/unique/dup counts + capped previews, final digest block; dry-run default, write path triggered by --write-digest or DUCKBRAIN_API_KEY env \u2192 POST /api/memories?namespace=duckbrain with X-API-Key (201 verified + read-back). Pitfall: vitest test with --digest-content FAILED in cron env because DUCKBRAIN_API_KEY is set there \u2014 tests must save/delete env vars that trigger write paths (mirror DUCKBRAIN_NAMESPACES_PATH pattern). Judge tier2 also flagged pre-existing prettier drift in an unrelated test file \u2014 run npx prettier --check src/ before judging.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "typescript-cli-consolidation-digest", "provider": "openrouter", "solved_at": "2026-08-27T02:12:12.780Z", "version": ""}