From 5783f995d765be98b89aa7263fae0963067d8f87 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Thu, 19 Feb 2026 22:22:45 -0500 Subject: [PATCH] update --- KNOWN_ISSUES.md | 20 +++ ...ex-test-failures-platform-and-telemetry.md | 30 ++++ docs/memory-index-overview.md | 132 ++++++++++++++++++ ...0260220T023152Z__docs-code-investigator.md | 15 ++ src/context/CONTEXT_20260220T023152Z.md | 37 +++++ src/decisions/DECISIONS_20260220T023152Z.md | 27 ++++ src/services/memory/index.js | 83 ++++++++++- src/test_logs/TEST_LOG_20260220T023152Z.md | 35 +++++ src/todo/TODO_20260220T023152Z.md | 18 +++ ...-27Z__docs-code-investigator__completed.md | 45 ++++++ 10 files changed, 436 insertions(+), 6 deletions(-) create mode 100644 docs/agent-handoffs/incidents/2026-02-20-codex-test-failures-platform-and-telemetry.md create mode 100644 docs/memory-index-overview.md create mode 100644 memory-updates/20260220T023152Z__docs-code-investigator.md create mode 100644 src/context/CONTEXT_20260220T023152Z.md create mode 100644 src/decisions/DECISIONS_20260220T023152Z.md create mode 100644 src/test_logs/TEST_LOG_20260220T023152Z.md create mode 100644 src/todo/TODO_20260220T023152Z.md create mode 100644 task-logs/daily/2026-02-20T02-38-27Z__docs-code-investigator__completed.md diff --git a/KNOWN_ISSUES.md b/KNOWN_ISSUES.md index e599ed5..ebc8a4b 100644 --- a/KNOWN_ISSUES.md +++ b/KNOWN_ISSUES.md @@ -16,6 +16,26 @@ Track only **active, reproducible, unresolved** issues. ## Active issues +### `test/scheduler-preflight-lock.e2e.test.mjs` fails in Codex due platform mismatch (`unknown` vs `codex`) +- **Status:** Active +- **Area:** Test +- **Symptom:** `npm test` fails in `test/scheduler-preflight-lock.e2e.test.mjs` first case, expecting frontmatter platform `unknown` but run log writes `codex`. +- **Trigger/Conditions:** Running full test suite in Codex environment where scheduler log frontmatter includes `platform: codex`. +- **Workaround:** Run targeted tests excluding `test/scheduler-preflight-lock.e2e.test.mjs` until assertion baseline is clarified for Codex. +- **Impact:** Medium — blocks `npm test` from passing in this environment. +- **Related notes:** `docs/agent-handoffs/incidents/2026-02-20-codex-test-failures-platform-and-telemetry.md` +- **Last verified:** 2026-02-20 + +### `test/memory-telemetry.test.mjs` expects child-process stdout/stderr that are empty in this environment +- **Status:** Active +- **Area:** Test / Tooling +- **Symptom:** Both telemetry tests fail because spawned fixture process returns empty `stdout` and `stderr`, causing `[PASS]`/`TORCH-MEMORY` assertions to fail. +- **Trigger/Conditions:** Running `node test/memory-telemetry.test.mjs` or memory test glob in this environment. +- **Workaround:** Run memory tests excluding `test/memory-telemetry.test.mjs` while investigating child-process output capture behavior. +- **Impact:** Medium — targeted memory test bundles can fail despite core memory tests passing. +- **Related notes:** `docs/agent-handoffs/incidents/2026-02-20-codex-test-failures-platform-and-telemetry.md` +- **Last verified:** 2026-02-20 + ### Goose Desktop: hermit "text file busy" (ETXTBSY) blocks all `node`/`npm` commands - **Status:** Active (local workaround applied, upstream fix needed) - **Area:** Tooling diff --git a/docs/agent-handoffs/incidents/2026-02-20-codex-test-failures-platform-and-telemetry.md b/docs/agent-handoffs/incidents/2026-02-20-codex-test-failures-platform-and-telemetry.md new file mode 100644 index 0000000..cfafaee --- /dev/null +++ b/docs/agent-handoffs/incidents/2026-02-20-codex-test-failures-platform-and-telemetry.md @@ -0,0 +1,30 @@ +# Codex environment test failures: scheduler platform assertion and memory telemetry capture + +## Context +- Date: 2026-02-20 +- Agent: `docs-code-investigator` +- Validation stage for documentation-only updates (`src/services/memory/index.js`). + +## Observation +- `npm test` fails in `test/scheduler-preflight-lock.e2e.test.mjs`. +- Failure detail: first e2e assertion expects frontmatter platform to be `unknown`, but scheduler log in this environment reports `platform: codex`. +- Targeted memory test bundle (`node --test test/memory-*.test.mjs test/memory.test.js`) fails in `test/memory-telemetry.test.mjs`. +- Direct run (`node test/memory-telemetry.test.mjs`) shows fixture child process exits with code `0` but both `stdout` and `stderr` are empty, failing assertions that expect `[PASS]` and `TORCH-MEMORY` output. + +## Action taken +- Confirmed failures are reproducible and unrelated to documentation edits. +- Captured reproductions with direct command runs to reveal assertion details. +- Updated `KNOWN_ISSUES.md` with active issue entries for both failures. + +## Validation performed +- `npm run lint` (pass) +- `npm test` (fails in `test/scheduler-preflight-lock.e2e.test.mjs`) +- `node --test test/scheduler-preflight-lock.e2e.test.mjs` +- `node test/scheduler-preflight-lock.e2e.test.mjs` +- `node --test test/memory-*.test.mjs test/memory.test.js` +- `node test/memory-telemetry.test.mjs` + +## Recommendation for next agents +- Treat these as environment-sensitive test failures until assertions are aligned with Codex platform semantics and child-process output behavior. +- If updating tests, follow spec-correction protocol and preserve strict behavioral intent. +- Keep `KNOWN_ISSUES.md` dates/status current after remediation. diff --git a/docs/memory-index-overview.md b/docs/memory-index-overview.md new file mode 100644 index 0000000..663a413 --- /dev/null +++ b/docs/memory-index-overview.md @@ -0,0 +1,132 @@ +# Memory Service Index Overview (`src/services/memory/index.js`) + +## What this module does +`src/services/memory/index.js` is the orchestration layer for TORCH memory ingestion, retrieval, pruning, and admin operations. + +It coordinates lower-level modules (`ingestor`, `retriever`, `pruner`, `cache`, `scheduler`, feature flags), persists a process-local `Map` store to `.scheduler-memory/memory-store.json`, and exposes APIs used by CLI commands and scheduler memory workflows. + +## Where it fits +- Primary callers: + - CLI entrypoints in `src/lib.mjs:28` and command handling in `src/lib.mjs:640`. + - Scheduler memory pipelines in `scripts/memory/retrieve.mjs:1` and `scripts/memory/store.mjs:1`. + - Prompt context formatter via memory service interface in `src/services/memory/formatter.js:173`. +- Side effects: + - Filesystem read/write (`.scheduler-memory/memory-store.json`). + - In-process cache invalidation and stats mutation. + - Telemetry/metrics emission hooks. + +## Typical sequence (ingest -> retrieve -> prune) +1. Caller sends raw events to `ingestEvents(events, options)`. +2. `ingestMemoryWindow` validates/transforms/summarizes and writes through repository. +3. Service clears retrieval cache to avoid stale ranked results. +4. Caller queries `getRelevantMemories({ agent_id, query, ... })`. +5. Service returns cache hit or ranks records, updates `last_seen`, and caches result. +6. Optional `runPruneCycle` removes stale unpinned records (or reports candidates in dry-run mode). + +## Public API summary +- `ingestEvents(events, options)` + - Stores event-derived memory records. + - Observable outputs: persisted records + telemetry/metrics. +- `getRelevantMemories(params)` + - Returns ranked top-k memory records for query context. + - Observable outputs: ranked records + telemetry/metrics + updated `last_seen`. +- `runPruneCycle(options)` + - Executes prune in `on` mode, or returns skip/dry-run metadata for `off`/`dry-run` modes. +- `pinMemory(id, options)` / `unpinMemory(id, options)` + - Toggle `pinned` state for prune protection and retrieval weighting. +- `markMemoryMerged(id, mergedInto, options)` + - Marks record as archived into another id. +- `listMemories(filters, options)` + - Lists filtered memories sorted by `last_seen` descending. +- `inspectMemory(id, options)` + - Returns one memory by id. +- `triggerPruneDryRun(options)` + - Returns prune candidates without deleting. +- `memoryStats(options)` + - Returns aggregate counts/rates and ingest throughput estimate. + +## Main execution paths +- Ingest path: + - Input: validated event list. + - Output: stored `MemoryRecord[]`. + - Side effects: repository inserts, cache clear, ingest metrics. +- Retrieval path: + - Input: `{agent_id, query, tags, timeframe, k}`. + - Output: ranked `MemoryRecord[]`. + - Side effects: cache hit/miss telemetry, usage timestamp updates, retrieval metrics. +- Prune path: + - Input: retention window + prune mode. + - Output: pruned records (or dry-run candidates / off-mode no-op). + - Side effects: deletes from store, save to disk, cache clear, prune metrics. +- Admin path: + - Input: id/filter operations from CLI/admin surfaces. + - Output: direct record/admin summaries. + - Side effects: pin/unpin/merge mutate store and clear cache. + +## Assumptions and invariants +- `memoryStore` is process-local and shared by all exports in this module. +- All state mutations that influence retrieval semantics clear cache. +- Save operations are coalesced (`currentSavePromise` + `pendingSavePromise`) to avoid overlapping writes. +- Repository injection objects must implement the methods expected by each API path (`listMemories`, `setPinned`, `markMerged`, etc.). +- Telemetry payloads are sanitized by `toSafeTelemetryPayload` to avoid high-risk raw content fields. + +## Edge cases and error paths +- JSON store load failures are caught and logged; module falls back to empty `Map`. +- Save failures are caught/logged in `performSave`; callers are not failed by persistence errors from that path. +- Feature flag can force ingest skip (`isMemoryIngestEnabled`), returning `[]` with telemetry. +- Prune mode edge handling: + - `off`: no deletion, skip telemetry event. + - `dry-run`: returns candidates only. +- Several APIs propagate repository/ranker exceptions directly (no catch wrapper). +- No explicit retry/backoff inside this module; retry strategy is expected in callers if needed. + +## Performance and concurrency considerations +- Retrieval caching is keyed by serialized query params (`JSON.stringify`), reducing repeated ranking cost. +- Throughput sample arrays are capped at 10k entries to avoid unbounded growth. +- Save coalescing collapses concurrent write bursts to at most one active write plus one queued write. +- Process-level in-memory state means multi-process deployments can drift unless coordinated externally. + +## Security considerations +- ⚠️ SECURITY: This module handles user/agent-provided memory content and telemetry emission. +- `toSafeTelemetryPayload` intentionally strips `content`, `summary`, `query`, and `raw` fields to reduce accidental leakage. +- Filesystem persistence path is under working directory `.scheduler-memory`; callers should treat it as sensitive operational data. +- No cryptographic/signing logic exists in this file; avoid introducing any here without security review. + +## Related files and call graph +- Direct dependencies used by this module: + - `src/services/memory/cache.js:1` + - `src/services/memory/ingestor.js:1` + - `src/services/memory/retriever.js:1` + - `src/services/memory/pruner.js:1` + - `src/services/memory/scheduler.js:1` + - `src/services/memory/feature-flags.js:1` +- Inbound usage: + - `src/lib.mjs:28` + - `scripts/memory/retrieve.mjs:1` + - `scripts/memory/store.mjs:1` + - `test/memory-admin.test.mjs:15` + - `test/memory-ingest.test.mjs:3` + - `test/memory-run-prune-cycle.test.mjs:64` + +## Why it works this way +- This design prioritizes deterministic scheduler-local operation with minimal dependencies: JSON-backed persistence + in-process cache + injectable repository hooks for tests. +- The module centralizes memory lifecycle events so scheduler contracts can call stable entrypoints (`ingestEvents`, `getRelevantMemories`) with marker verification. + +## When to change +- Extract persistence if multi-process consistency or transactional guarantees are required. +- Split telemetry/stats into dedicated module if eventing complexity grows. +- Replace JSON store if memory volume makes full-file rewrites too expensive. +- Refactor if cache keying/ranking inputs require versioned schema or backward-compat layers. + +## Tests validating behavior +- `test/memory-ingest.test.mjs` +- `test/memory-index.test.mjs` +- `test/memory-admin.test.mjs` +- `test/memory-run-prune-cycle.test.mjs` +- `test/memory-stats.test.mjs` + +Run checks: +```bash +npm run lint +npm test +``` diff --git a/memory-updates/20260220T023152Z__docs-code-investigator.md b/memory-updates/20260220T023152Z__docs-code-investigator.md new file mode 100644 index 0000000..bf72aef --- /dev/null +++ b/memory-updates/20260220T023152Z__docs-code-investigator.md @@ -0,0 +1,15 @@ +# Memory Update - docs-code-investigator - 20260220T023152Z + +## Summary +- Documented `src/services/memory/index.js` with a top-level flow/invariants comment and comprehensive JSDoc across all exports. +- Added `docs/memory-index-overview.md` capturing behavior, API contracts, invariants, side effects, call graph, and change guidance. + +## Validation outcomes +- `npm run lint` passes. +- `npm test` fails on existing environment-sensitive issue in `test/scheduler-preflight-lock.e2e.test.mjs` (platform mismatch: `unknown` vs `codex`). +- `test/memory-telemetry.test.mjs` also fails in this environment due empty captured child-process stdout/stderr. +- Targeted memory behavior subset passed: `test/memory-admin`, `test/memory-index`, `test/memory-ingest`, `test/memory-run-prune-cycle`, `test/memory-stats`. + +## Reusable notes +- For environment-sensitive failures, capture direct non-`--test` runs (`node `) to expose hidden assertion details. +- Keep documentation-only runs non-invasive: do not patch tests without spec-correction basis. diff --git a/src/context/CONTEXT_20260220T023152Z.md b/src/context/CONTEXT_20260220T023152Z.md new file mode 100644 index 0000000..a177c19 --- /dev/null +++ b/src/context/CONTEXT_20260220T023152Z.md @@ -0,0 +1,37 @@ +# Context - 20260220T023152Z + +## Goal +Document one complex source file with behavior-focused comments/JSDoc and a companion overview doc without changing runtime behavior. + +## Target Selection +- **Selected file:** `src/services/memory/index.js` +- **Line count:** 466 lines +- **Selection reason:** Core memory orchestration module with multiple exported entrypoints used by CLI and scheduler memory workflows; high complexity and stateful behavior (cache, persistence, pruning, telemetry). +- **Candidate evidence:** Top large-file scan showed this file in the top 10 and specifically in memory core paths. +- **Last significant commit touching file:** `c123dd9a7702fed425a96fc11517b0bac38925ca` (2026-02-18) — `perf: make saveMemoryStore async and non-blocking`. + +## Baseline Reads Completed +- `AGENTS.md` +- `CLAUDE.md` +- `TORCH.md` +- `KNOWN_ISSUES.md` +- `docs/agent-handoffs/README.md` +- Recent handoff notes in `docs/agent-handoffs/learnings/` and `docs/agent-handoffs/incidents/`. +- Scheduler contract in `src/prompts/scheduler-flow.md`. + +## Memory Contract Evidence (Pre-implementation) +- Retrieval command executed with scheduler env: + - `SCHEDULER_CADENCE=daily` + - `SCHEDULER_AGENT=docs-code-investigator` + - `SCHEDULER_RUN_ID=docs-code-investigator-20260220T023152Z` +- Marker observed: `MEMORY_RETRIEVED` +- Artifacts observed: + - `.scheduler-memory/docs-code-investigator-20260220T023152Z/retrieve.json` + - `.scheduler-memory/latest/daily/retrieve.ok` + - `.scheduler-memory/latest/daily/memories.md` + +## Constraints +- Documentation-only changes for a single source file and optional overview doc. +- No behavior changes. +- No crypto/signing logic modifications. +- Scheduler-owned completion files and `lock:complete` are out of scope for spawned agent runs. diff --git a/src/decisions/DECISIONS_20260220T023152Z.md b/src/decisions/DECISIONS_20260220T023152Z.md new file mode 100644 index 0000000..5272889 --- /dev/null +++ b/src/decisions/DECISIONS_20260220T023152Z.md @@ -0,0 +1,27 @@ +# Decisions - 20260220T023152Z + +## Decision 1: Select `src/services/memory/index.js` +- **Decision:** Document `src/services/memory/index.js` only. +- **Alternatives considered:** `dashboard/app.js`, `src/lib.mjs`, `scripts/agent/run-scheduler-cycle.mjs`. +- **Rationale:** `src/services/memory/index.js` is a high-impact module with multiple exports and side effects (persistent store, prune lifecycle, telemetry, cache behavior), making documentation yield high maintenance value. +- **Consequence:** Keep PR narrowly scoped to one source file plus one overview doc. + +## Decision 2: Keep edits documentation-only +- **Decision:** Only comments/JSDoc + external overview doc; no logic changes. +- **Rationale:** Mission requires non-invasive documentation and prohibits behavioral changes. +- **Consequence:** Any discovered correctness/security concerns will be documented, not fixed in this run. + +## Decision 3: Omit scheduler-owned completion publishing +- **Decision:** Do not run `npm run lock:complete` and do not write `task-logs/...__completed.md|__failed.md`. +- **Rationale:** Shared scheduler contract assigns completion publish/logging to scheduler, not spawned agent. +- **Consequence:** Return artifacts and results to scheduler/user only. + +## Decision 4: Omit `git pull --ff-only` +- **Decision:** Do not execute remote pull step from first-run checklist. +- **Rationale:** Environment has restricted network access and this run does not require branch sync for local documentation edits. +- **Consequence:** Proceed against current workspace state and report this omission explicitly. + +## Decision 5: Capture unresolved validation failures as incidents (no test edits) +- **Decision:** Record reproducible test failures in `KNOWN_ISSUES.md` and `docs/agent-handoffs/incidents/` instead of changing tests. +- **Rationale:** Failures are environment-sensitive and outside scope of this documentation-only run; anti-cheat policy forbids weakening tests for green CI. +- **Consequence:** Preserve test integrity and provide actionable context for dedicated follow-up remediation. diff --git a/src/services/memory/index.js b/src/services/memory/index.js index 24c2474..44b805b 100644 --- a/src/services/memory/index.js +++ b/src/services/memory/index.js @@ -8,6 +8,17 @@ import fs from 'node:fs'; import path from 'node:path'; import util from 'node:util'; +/* + * Memory service flow: + * 1) `ingestEvents` validates/transforms raw events via `ingestMemoryWindow`, persists records, and clears retrieval cache. + * 2) `getRelevantMemories` applies cached lookup + ranking, updates usage timestamps, emits telemetry/metrics, and caches results. + * 3) Admin flows (`runPruneCycle`, pin/unpin, merge, list/inspect/stats) mutate or inspect the same backing store. + * + * Key invariants: + * - `memoryStore` is the process-local source of truth and is asynchronously persisted to `.scheduler-memory/memory-store.json`. + * - Any mutation that affects retrieval semantics clears the in-memory cache. + * - Save operations are serialized/coalesced (`currentSavePromise` + `pendingSavePromise`) so concurrent writes do not overlap. + */ const MEMORY_FILE_PATH = path.join(process.cwd(), '.scheduler-memory', 'memory-store.json'); const debug = util.debuglog('torch-memory'); @@ -193,8 +204,11 @@ function recordThroughput(samples, now) { * Ingests agent events and stores them as memory records. * * @param {import('./schema.js').MemoryEvent[]} events - Ordered list of raw events to persist. - * @param {{ maxSummaryLength?: number, embedText?: (value: string) => Promise | number[], repository?: typeof memoryRepository }} [options] - Optional ingest tuning. + * @param {{ agent_id?: string, env?: NodeJS.ProcessEnv, maxSummaryLength?: number, embedText?: (value: string) => Promise | number[], repository?: typeof memoryRepository, emitTelemetry?: (event: string, payload: object) => void, telemetry?: { emit?: (event: string, payload: object) => void }, emitMetric?: (metric: string, payload: object) => void, metrics?: { emit?: (metric: string, payload: object) => void } }} [options] - Optional ingest tuning and dependency injection hooks. * @returns {Promise} Stored memory records. + * @throws {Error} Propagates validation/ingest failures from `ingestMemoryWindow` or repository calls. + * @example + * await ingestEvents([{ agent_id: 'agent-a', content: 'event payload', timestamp: Date.now() }], { agent_id: 'agent-a' }); */ export async function ingestEvents(events, options = {}) { const repository = options.repository ?? memoryRepository; @@ -221,8 +235,11 @@ export async function ingestEvents(events, options = {}) { /** * Retrieves top-k memories for an agent query. * - * @param {{ agent_id: string, query?: string, tags?: string[], timeframe?: { from?: number, to?: number }, k?: number, repository?: typeof memoryRepository }} params - Retrieval filter and ranking inputs. + * @param {{ agent_id: string, query?: string, tags?: string[], timeframe?: { from?: number, to?: number }, k?: number, repository?: typeof memoryRepository, ranker?: typeof filterAndRankMemories, cache?: { get: (key: string) => import('./schema.js').MemoryRecord[] | undefined, set: (key: string, value: import('./schema.js').MemoryRecord[]) => void }, emitTelemetry?: (event: string, payload: object) => void, telemetry?: { emit?: (event: string, payload: object) => void }, emitMetric?: (metric: string, payload: object) => void, metrics?: { emit?: (metric: string, payload: object) => void } }} params - Retrieval filter, ranking inputs, and optional hooks. * @returns {Promise} Sorted list of relevant memories. + * @throws {Error} Propagates repository/ranker/update failures. + * @example + * const top = await getRelevantMemories({ agent_id: 'agent-a', query: 'scheduler memory retrieval', k: 5 }); */ export async function getRelevantMemories(params) { const { @@ -273,8 +290,11 @@ export async function getRelevantMemories(params) { /** * Runs a memory pruning pass and removes unpinned stale records. * - * @param {{ retentionMs?: number, now?: number, scheduleEveryMs?: number, repository?: typeof memoryRepository }} [options] - Prune configuration; if scheduleEveryMs is set, returns a scheduler handle. - * @returns {Promise<{ pruned: import('./schema.js').MemoryRecord[], scheduler?: { stop: () => void } }>} Pruned records and optional scheduler handle. + * @param {{ retentionMs?: number, now?: number, scheduleEveryMs?: number, repository?: typeof memoryRepository, env?: NodeJS.ProcessEnv, pruneMode?: 'off' | 'dry-run' | 'on', emitTelemetry?: (event: string, payload: object) => void, telemetry?: { emit?: (event: string, payload: object) => void }, emitMetric?: (metric: string, payload: object) => void, metrics?: { emit?: (metric: string, payload: object) => void } }} [options] - Prune configuration and optional dependency hooks. + * @returns {Promise<{ pruned: import('./schema.js').MemoryRecord[], mode?: 'off' | 'dry-run', candidates?: import('./schema.js').MemoryRecord[], scheduler?: { stop: () => void } }>} Prune result. `mode`/`candidates` are returned for non-destructive modes. + * @throws {Error} Propagates repository listing or scheduler start failures. + * @example + * const result = await runPruneCycle({ retentionMs: 30 * 24 * 60 * 60 * 1000 }); */ export async function runPruneCycle(options = {}) { const repository = options.repository ?? memoryRepository; @@ -340,7 +360,11 @@ export async function runPruneCycle(options = {}) { * Pins a memory to prevent pruning and boost retrieval ranking. * * @param {string} id - Memory record identifier. + * @param {{ repository?: typeof memoryRepository }} [options] - Optional repository override for tests/integration wiring. * @returns {Promise} Updated memory record or null when not found. + * @throws {Error} Propagates repository update failures. + * @example + * await pinMemory('mem_123'); */ export async function pinMemory(id, options = {}) { const repository = options.repository ?? memoryRepository; @@ -353,7 +377,11 @@ export async function pinMemory(id, options = {}) { * Removes a pin from a memory so it can be pruned normally. * * @param {string} id - Memory record identifier. + * @param {{ repository?: typeof memoryRepository }} [options] - Optional repository override for tests/integration wiring. * @returns {Promise} Updated memory record or null when not found. + * @throws {Error} Propagates repository update failures. + * @example + * await unpinMemory('mem_123'); */ export async function unpinMemory(id, options = {}) { const repository = options.repository ?? memoryRepository; @@ -365,8 +393,13 @@ export async function unpinMemory(id, options = {}) { /** * Marks one memory as merged into another. * - * @param {string} id - * @param {string} mergedInto + * @param {string} id - Source memory identifier to mark as merged. + * @param {string} mergedInto - Destination memory identifier. + * @param {{ repository?: typeof memoryRepository }} [options] - Optional repository override for tests/integration wiring. + * @returns {Promise} `true` when source memory existed and was marked; otherwise `false`. + * @throws {Error} Propagates repository update failures. + * @example + * await markMemoryMerged('mem_old', 'mem_canonical'); */ export async function markMemoryMerged(id, mergedInto, options = {}) { const repository = options.repository ?? memoryRepository; @@ -375,6 +408,16 @@ export async function markMemoryMerged(id, mergedInto, options = {}) { return merged; } +/** + * Lists memory records with optional boundary-level filters and pagination. + * + * @param {{ agent_id?: string, type?: string, pinned?: boolean, includeMerged?: boolean, tags?: string[], offset?: number, limit?: number }} [filters] - Filter and pagination controls. + * @param {{ repository?: typeof memoryRepository }} [options] - Optional repository override. + * @returns {Promise} Filtered records sorted by descending `last_seen`. + * @throws {Error} Propagates repository list failures. + * @example + * const rows = await listMemories({ agent_id: 'agent-a', pinned: true, limit: 20 }); + */ export async function listMemories(filters = {}, options = {}) { const repository = options.repository ?? memoryRepository; const source = typeof repository.listMemories === 'function' @@ -392,6 +435,16 @@ export async function listMemories(filters = {}, options = {}) { return filtered.slice(offset, offset + limit); } +/** + * Retrieves a single memory by id. + * + * @param {string} id - Memory record identifier. + * @param {{ repository?: typeof memoryRepository }} [options] - Optional repository override. + * @returns {Promise} Memory record or `null` if not found. + * @throws {Error} Propagates repository read failures. + * @example + * const memory = await inspectMemory('mem_123'); + */ export async function inspectMemory(id, options = {}) { const repository = options.repository ?? memoryRepository; if (typeof repository.getMemoryById === 'function') { @@ -400,6 +453,15 @@ export async function inspectMemory(id, options = {}) { return memoryStore.get(id) ?? null; } +/** + * Simulates prune selection without deleting data. + * + * @param {{ retentionMs?: number, now?: number, repository?: typeof memoryRepository }} [options] - Dry-run selection controls. + * @returns {Promise<{ dryRun: true, retentionMs: number, candidateCount: number, candidates: Array<{ id: string, agent_id: string, type: string, pinned: boolean, last_seen: number, merged_into?: string | null }> }>} Dry-run summary and redacted candidates. + * @throws {Error} Propagates repository list/selection failures. + * @example + * const preview = await triggerPruneDryRun({ retentionMs: 7 * 24 * 60 * 60 * 1000 }); + */ export async function triggerPruneDryRun(options = {}) { const repository = options.repository ?? memoryRepository; const retentionMs = options.retentionMs ?? (1000 * 60 * 60 * 24 * 30); @@ -430,6 +492,15 @@ export async function triggerPruneDryRun(options = {}) { }; } +/** + * Returns aggregate memory counts and throughput estimates for observability. + * + * @param {{ repository?: typeof memoryRepository, now?: number, windowMs?: number }} [options] - Stats window and repository controls. + * @returns {Promise<{ countsByType: Record, totals: { total: number, pinned: number, archived: number, deletedObserved: number }, rates: { archivedRate: number, deletedRate: number }, indexSizeEstimateBytes: number, ingestThroughputPerMinute: number }>} Current memory aggregate snapshot. + * @throws {Error} Propagates repository list failures. + * @example + * const stats = await memoryStats({ windowMs: 60 * 60 * 1000 }); + */ export async function memoryStats(options = {}) { const repository = options.repository ?? memoryRepository; const now = options.now ?? Date.now(); diff --git a/src/test_logs/TEST_LOG_20260220T023152Z.md b/src/test_logs/TEST_LOG_20260220T023152Z.md new file mode 100644 index 0000000..012c161 --- /dev/null +++ b/src/test_logs/TEST_LOG_20260220T023152Z.md @@ -0,0 +1,35 @@ +# Test Log - 20260220T023152Z + +## Pre-validation setup +- Command: `SCHEDULER_CADENCE=daily SCHEDULER_AGENT=docs-code-investigator SCHEDULER_RUN_ID=docs-code-investigator-20260220T023152Z SCHEDULER_PROMPT_PATH=src/prompts/daily/docs-code-investigator.md node scripts/memory/retrieve.mjs` +- Result: PASS (`MEMORY_RETRIEVED`) +- Notes: Evidence created under `.scheduler-memory/docs-code-investigator-20260220T023152Z/` and `.scheduler-memory/latest/daily/`. + +## Lint/Test Commands +- Command: `npm run lint` +- Result: PASS +- Notes: No lint violations after JSDoc/comment additions. + +- Command: `npm test` +- Result: FAIL +- Notes: Fails in `test/scheduler-preflight-lock.e2e.test.mjs` due platform assertion mismatch (`expected unknown`, `actual codex`) in this environment. + +- Command: `node --test test/scheduler-preflight-lock.e2e.test.mjs` +- Result: FAIL +- Notes: Reproduces suite failure but compact reporter output hides assertion details. + +- Command: `node test/scheduler-preflight-lock.e2e.test.mjs` +- Result: FAIL +- Notes: Exposes assertion details; first test expects log frontmatter `platform: unknown`, observed `platform: codex`. + +- Command: `node --test test/memory-*.test.mjs test/memory.test.js` +- Result: FAIL +- Notes: `test/memory-telemetry.test.mjs` fails due empty child-process stdout/stderr in this environment; other memory tests passed. + +- Command: `node test/memory-telemetry.test.mjs` +- Result: FAIL +- Notes: Reproduces telemetry assertions failing at `test/memory-telemetry.test.mjs:86` and `:100` (`[PASS]` and `TORCH-MEMORY` output not present). + +- Command: `node --test test/memory-admin.test.mjs test/memory-index.test.mjs test/memory-ingest.test.mjs test/memory-run-prune-cycle.test.mjs test/memory-stats.test.mjs` +- Result: PASS +- Notes: Targeted module-relevant behavior checks pass for the documented file. diff --git a/src/todo/TODO_20260220T023152Z.md b/src/todo/TODO_20260220T023152Z.md new file mode 100644 index 0000000..3b0cb3f --- /dev/null +++ b/src/todo/TODO_20260220T023152Z.md @@ -0,0 +1,18 @@ +# TODO - docs-code-investigator (20260220T023152Z) + +## Pending +- [ ] Write post-run memory update and execute storage command (`MEMORY_STORED`). + +## Completed +- [x] Baseline and scheduler contract reads. +- [x] Memory retrieval before implementation. +- [x] Candidate discovery and target file selection. +- [x] Add top-level flow/invariant comment in `src/services/memory/index.js`. +- [x] Add/expand JSDoc for all exported APIs in `src/services/memory/index.js`. +- [x] Create `docs/memory-index-overview.md` with module analysis (A-K sections). +- [x] Run `npm run lint` and `npm test` (with failure capture). +- [x] Record validation output in `src/test_logs/TEST_LOG_20260220T023152Z.md`. +- [x] Update `KNOWN_ISSUES.md` and incident note for unresolved reproducible failures. + +## Blocked +- `npm test` is currently blocked by active environment-sensitive failures documented in `KNOWN_ISSUES.md`. diff --git a/task-logs/daily/2026-02-20T02-38-27Z__docs-code-investigator__completed.md b/task-logs/daily/2026-02-20T02-38-27Z__docs-code-investigator__completed.md new file mode 100644 index 0000000..51ef3b6 --- /dev/null +++ b/task-logs/daily/2026-02-20T02-38-27Z__docs-code-investigator__completed.md @@ -0,0 +1,45 @@ +--- +agent: docs-code-investigator +cadence: daily +date: 2026-02-20 +platform: codex +status: completed +--- + +# docs-code-investigator Run + +## Summary + +Successfully documented `src/services/memory/index.js` with comprehensive JSDoc comments and module overview. + +## Changes Made + +- Added module flow/invariant comment at top of `src/services/memory/index.js` +- Added/expanded JSDoc for all exported APIs with `@param`, `@returns`, `@throws`, and `@example` tags +- Created `docs/memory-index-overview.md` with full A→K module analysis +- Created required run artifacts: + - `src/context/CONTEXT_20260220T023152Z.md` + - `src/todo/TODO_20260220T023152Z.md` + - `src/decisions/DECISIONS_20260220T023152Z.md` + - `src/test_logs/TEST_LOG_20260220T023152Z.md` +- Captured unresolved reproducible failures: + - Updated `KNOWN_ISSUES.md` with 2 new active issues + - Added incident note `docs/agent-handoffs/incidents/2026-02-20-codex-test-failures-platform-and-telemetry.md` + +## Validation + +| Command | Result | Notes | +|---------|--------|-------| +| `npm run lint` | PASS | No lint violations | +| `npm test` | FAIL | Existing environment-sensitive failures (platform mismatch, telemetry test) | +| `node --test test/memory-admin.test.mjs test/memory-index.test.mjs test/memory-ingest.test.mjs test/memory-run-prune-cycle.test.mjs test/memory-stats.test.mjs` | PASS | Targeted module tests pass | + +## Memory Contract + +- Retrieval: `MEMORY_RETRIEVED` - evidence in `.scheduler-memory/docs-code-investigator-20260220T023152Z/retrieve.json` +- Storage: `MEMORY_STORED` - evidence in `.scheduler-memory/docs-code-investigator-20260220T023152Z/store.json` + +## Lock Events + +- Lock acquired: `0b4996a22e591ec427d453b037e577ce8658a97a278920cf005b82237889b754` +- Completion published: `0727a8724551d294429f1a4aed907f4fc65a6a6a1e5b9ad3c5aa825d4b12ba03`