Skip to content

feat: import foundation layer (compression primitives, envelope, state store) - #1

Merged
yohnark merged 3 commits into
mainfrom
import/pr1-foundation
Aug 3, 2026
Merged

yohnark merged 3 commits into
mainfrom
import/pr1-foundation

Conversation

@yohnark

@yohnark yohnark commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

First of a series of dependency-ordered import PRs from a private predecessor repository. This PR brings in only the foundation layer — files with no dependency on code that hasn't landed yet — so CI (install → typecheck → test → build) stays green at every step.

  • Deterministic compression primitives: ANSI stripping, JSON sampling, line filtering, code-skeleton detection, tool-description compression, known-CLI budget helper
  • Result envelope contract (src/envelope.ts)
  • Request/response logging (src/logging.ts) and opt-in telemetry sink (src/telemetry.ts)
  • TTL-bounded artifact retention store (src/retrieve.ts)
  • Read Governor classification/evidence groundwork (observe-only, no policy wiring yet)
  • OAuth broker helper (src/auth.ts)
  • Cross-platform state directory resolver (src/state/paths.ts) and SQLite migration/store scaffolding

Renames from the predecessor

The predecessor project was named mottainai-nosy-mcp. This PR renames its state-directory name and log-line prefixes to mottainai:

  • src/state/paths.ts: APP_DIR_NAMEmottainai (was mottainai-nosy-mcp)
  • src/logging.ts, src/telemetry.ts, src/adaptive/trace.ts: console.error prefixes updated to match
  • package.json: package name → @yohn-jp/mottainai, repository/homepage/bugs URLs → yohn-jp/mottainai

What's intentionally not here yet

proxy.ts, upstream.ts, config.ts, catalog.ts, adaptive routing, local tools, and the CLI entry point (index.ts) land in follow-up PRs as their prerequisite files arrive. README.md is a minimal placeholder; the full architecture doc lands once the pieces it describes exist in this repo. package.json scripts/bin entries referencing not-yet-present files (mcp, policy, read-governor scripts, mottainai/mtnai bin) are added back once those files land.

Test plan

  • pnpm install
  • pnpm run typecheck — passes
  • pnpm test — 111 passing
  • pnpm run build — passes

…e store basics)

Import from private predecessor, first of a series of dependency-ordered
PRs. Includes deterministic compression primitives (ANSI/JSON/lines/code
skeleton/tool-description/budget), the result envelope contract, request
logging, telemetry sink, TTL-bounded artifact retention, read-governor
classification/evidence groundwork, OAuth broker helper, and the
cross-platform state directory resolver. Renames the project-scoped state
directory and log prefixes from the predecessor's mottainai-nosy-mcp to
mottainai.

Proxy relay, upstream connections, tool catalog, adaptive routing, and the
CLI entry point land in follow-up PRs as their dependencies are satisfied.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e9ad37ba-ce00-43a7-9335-d6f63b3892a9

📥 Commits

Reviewing files that changed from the base of the PR and between 6c7a2f8 and 7734cf8.

📒 Files selected for processing (4)
  • src/envelope.test.ts
  • src/envelope.ts
  • src/retrieve.test.ts
  • src/retrieve.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/retrieve.test.ts
  • src/envelope.test.ts
  • src/envelope.ts
  • src/retrieve.ts

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added tools to compress code, JSON, descriptions, and oversized text while preserving key context.
    • Added artifact retrieval, read-evidence tracking, session state, decision storage, and standardized tool output.
    • Added optional structured logging, telemetry, trace analysis, OAuth credential brokerage, and file classification.
  • Documentation
    • Expanded setup, architecture, development, configuration, and licensing guidance.
  • Tests
    • Added comprehensive automated coverage for compression, persistence, authentication, telemetry, and routing analysis.
  • Chores
    • Added project-wide editor settings, build configuration, ignore rules, and example server configuration.

Walkthrough

Changes

Mottainai gateway foundation

Layer / File(s) Summary
Project foundation and package setup
.editorconfig, .gitignore, LICENSE, README.md, package.json, pnpm-workspace.yaml, mottainai.config.json.example, tsconfig*.json
Adds project metadata, package scripts, MCP server configuration, TypeScript build settings, editor rules, ignore rules, documentation, and the MIT license.
Adaptive taxonomy, traces, and statistics
src/adaptive/*
Adds taxonomy normalization, JSONL trace persistence, schema migration, review records, filtering, and aggregate routing statistics.
Compression and structured output
src/compress/*, src/envelope.ts
Adds ANSI, line, byte-budget, source-code, JSON, static-information, and tool-description compression utilities, plus a structured MCP output envelope.
Authentication, logging, and telemetry
src/auth.ts, src/logging.ts, src/telemetry.ts, related tests
Adds OAuth broker loading and endpoint validation, structured JSONL logging with redaction and rotation, and opt-in persisted telemetry aggregation.
Read governance and artifact retrieval
src/read-governor/*, src/retrieve.ts, related tests
Adds file classification, in-memory read evidence with TTL and eviction, and bounded artifact retrieval and search.
State contracts and SQLite migrations
src/state/*
Adds cross-platform state paths, session/evidence/decision contracts, and transactional SQLite migration infrastructure.

Estimated code review effort: 5 (Critical) | ~120 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.06% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the foundation-layer import and names its primary components.
Description check ✅ Passed The description directly explains the foundation-layer changes, deferred work, renames, and validation results.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch import/pr1-foundation

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 17

🧹 Nitpick comments (4)
src/adaptive/trace.test.ts (1)

1-174: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for file rotation and TTL sweep.

The test suite does not exercise MOTTAINAI_TRACE_MAX_FILE_BYTES rotation or the MOTTAINAI_TRACE_RETENTION_DAYS startup sweep in trace.ts. Both are documented, non-trivial persistence behaviors that other layers will depend on. Add a test that sets a small MOTTAINAI_TRACE_MAX_FILE_BYTES and verifies multiple files get created, and a test that seeds an aged file (via fs.utimesSync) and verifies it is removed on the next store creation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/adaptive/trace.test.ts` around lines 1 - 174, Extend the trace store
tests with coverage for persistence rotation and retention: add a test using
MOTTAINAI_TRACE_MAX_FILE_BYTES with a small limit that records enough data
through createTraceStore to produce multiple JSONL files, and add a test that
ages a trace file with fs.utimesSync, sets MOTTAINAI_TRACE_RETENTION_DAYS, then
creates a new store and verifies the aged file is removed. Anchor both tests
near the existing createTraceStore persistence tests and preserve current
temporary-directory setup.
src/telemetry.ts (2)

166-169: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

snapshot() exposes internal mutable state by reference.

snapshot() spreads state shallowly, so totals, by_provider, and by_capability in the returned object are the same references held internally (Line 44-48). A caller that mutates a returned snapshot would silently corrupt the sink's ongoing aggregation.

Deep-clone the returned counters (e.g. via structuredClone or a manual copy) to make snapshot() safe against caller mutation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/telemetry.ts` around lines 166 - 169, Update the snapshot() method to
deep-clone the mutable totals, by_provider, and by_capability counters before
returning them, ensuring callers cannot mutate the sink’s internal state while
preserving the existing snapshot metadata.

135-165: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider batching telemetry persistence instead of writing on every call.

persist() is invoked on every recordToolCall and recordRetrieval (Line 160, Line 164), each time serializing the entire aggregate state and writing it to disk (Lines 138-140), plus recreating the target directory. Under sustained tool-call volume, this produces one full-state JSON write per call, serialized through a single writeQueue, which can accumulate I/O backlog.

Debounce persistence (e.g. flush on a timer or after N updates) to reduce write amplification while keeping the opt-in telemetry file eventually consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/telemetry.ts` around lines 135 - 165, Batch telemetry persistence in
persist and the recordToolCall/recordRetrieval paths instead of writing the full
snapshot on every update. Add a debounce or update-count threshold so frequent
calls coalesce into fewer directory, serialization, and file-write operations,
while ensuring pending updates are eventually flushed and the existing
writeQueue ordering and error handling remain intact.
src/auth.ts (1)

31-44: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider a more robust marker than a string prefix for validation errors.

resolveBrokerEndpoint distinguishes its own validation error from an arbitrary provider error by checking error.message.startsWith("oauth broker returned invalid endpoint:"). A provider implementation that throws an Error with a message starting with that exact literal string bypasses sanitization and its message reaches the caller unredacted.

Use a dedicated error class or a non-enumerable marker property (e.g. a custom MottainaiBrokerValidationError) instead of string matching, to make the distinction robust regardless of what message text a provider throws.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/auth.ts` around lines 31 - 44, Update resolveBrokerEndpoint to identify
brokerUrl validation failures using a dedicated error type or non-enumerable
marker rather than matching the error message prefix. Ensure only errors created
by the broker validation path are rethrown unchanged, while provider
errors—including ones with the same message prefix—are replaced with the
sanitized resolution error.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@package.json`:
- Around line 6-8: Add a source entry module corresponding to the package's main
entry so the TypeScript build emits dist/index.js, preserving the existing main
and exports declarations; alternatively remove those package entry declarations
until a valid entry module exists.

In `@README.md`:
- Line 18: Update the ASCII diagram’s opening fenced code block in README.md to
specify the text language, changing the untyped fence to a text-labeled fence so
the MD040 requirement is satisfied.

In `@src/adaptive/trace.ts`:
- Around line 412-415: Update the trace store around loadTraces and
recordExecutionReview to maintain an in-memory set of execution IDs recorded
during the current store lifetime. In recordExecutionReview, use that set to
resolve same-store reviews without calling loadTraces; retain the loadTraces
fallback for IDs from other processes or reopened stores, and add each
successfully recorded execution ID to the set.
- Around line 361-390: Update the file-rotation flow in createTraceStore to
invoke sweepExpiredTraces again whenever a new trace file is created or rotated,
using the existing directory and retention-duration calculation from
prepareDirectory. Keep the prepared guard for initial directory setup, and
ensure subsequent rotations perform cleanup without recreating the directory
unnecessarily.

In `@src/compress/budget.ts`:
- Around line 12-38: Update compactToBudget so rawBytes below the envelope
reservation does not force the budget to the fixed 256-byte floor; retain the
target-based budget while applying only a non-negative rawBytes reservation.
Before calculating headBudget and selecting tail lines, reserve the omission
marker’s byte cost from the available budget, using that reduced value for both
head/tail splitting while preserving the existing marker format and output
behavior.

In `@src/compress/json.ts`:
- Around line 83-85: Validate the merged options in compressJsonValue before
calling compressValue, ensuring every numeric compression limit is finite,
non-negative, and an integer; reject invalid values or normalize them
consistently. Preserve the existing defaults and compression behavior for valid
inputs, and add regression coverage for negative maxStringLength, maxArrayItems,
and tailArrayItems.
- Around line 70-75: Update the object-building loop in compressValue to define
each key on out as an own data property, including "__proto__", instead of
assigning through out[key]. Preserve the existing compressed value and default
object prototype while ensuring the JSON key remains an enumerable own property.

In `@src/compress/lines.ts`:
- Around line 89-92: Update the line-retention logic in the compression function
around head, tail, and omitted so headLines is capped at maxTotalLines and
tailLines is capped to the remaining budget after the retained head. Preserve
normal behavior when the requested counts fit within the budget, and add a test
covering headLines + tailLines exceeding maxTotalLines without overlap or
negative omitted counts.

In `@src/compress/tool-description.ts`:
- Line 5: Update PROTECTED_LITERAL’s single-quoted literal branch to require
non-word-character boundaries before the opening apostrophe and after the
closing apostrophe, preventing apostrophes within contractions from forming
protected spans while preserving genuine quoted literals.

In `@src/envelope.ts`:
- Around line 27-30: Update the envelope construction around structuredContent
so details cannot overwrite reserved OUTPUT_SCHEMA fields, including operation,
status, summary, result_id, facts, diagnostics, metrics, and truncated. Validate
typed optional values from details, then remove reserved keys before spreading
only extension fields into the final structuredContent while preserving the
envelope defaults and error flag behavior.

In `@src/logging.ts`:
- Around line 63-77: Make serialization in boundedLogLine failure-tolerant for
both the full record and rawResult fallback hashing. Update the log flow around
boundedLogLine and log so synchronous JSON.stringify errors are caught like
writeQueue failures, recorded as a logging error, and never reject the caller’s
log() promise.

In `@src/read-governor/evidence.ts`:
- Around line 62-66: Validate retention options before assigning them in
InMemoryEvidenceStore’s constructor: require ttlMs to be finite and
non-negative, and maxEntries to be finite and a positive integer, rejecting
invalid values. Apply the same validation in src/retrieve.ts at lines 91-96 for
its constructor/options: ttlMs must be finite and non-negative, maxEntries
finite and positive integer, and the byte limit finite and positive.
- Around line 97-102: Update the read-evidence storage flow around issue() and
get() so the internal entries map retains a private record while both methods
return independent copies, preventing callers from mutating stored evidence
fields. Add a regression test that mutates the object returned by issue() and
verifies get() returns the original evidence values.

In `@src/retrieve.ts`:
- Around line 111-116: Update the artifact retention logic before entries.set so
maxBytes applies to the complete stored artifact, not only artifact.text.
Reserve space for the truncation footer, truncate text on UTF-8 boundaries
within the remaining budget, and bound stdout, stderr, and metadata rather than
retaining them through the object spread. Add tests covering oversized UTF-8
text and oversized stdout or stderr.
- Around line 136-142: Update the context calculation in the retrieval flow
around matchIndex, contextLines, and startLine so preceding context is capped at
maxLines - 1 before computing the window start, ensuring the matched line
remains in selected even when contextLines is large. Add a test covering
contextLines: 20 and maxLines: 1, verifying the returned window includes the
query match.

In `@src/state/migrations.ts`:
- Around line 68-82: Update applyMigrations to serialize discovery and
application: repeatedly start a BEGIN IMMEDIATE transaction before calling
currentVersion, select the next pending migration, and apply and record only
that migration within the transaction. Commit when successful, roll back on
failure, and repeat until no migration remains; preserve the existing migration
ordering and descriptive error behavior.

In `@src/state/paths.ts`:
- Around line 34-36: Update the XDG_STATE_HOME handling in the state-path
construction to accept the environment value only when it is non-empty and
absolute; otherwise fall back to path.join(home, ".local", "state"). Add a test
covering a relative XDG_STATE_HOME and verify the returned path uses the
home-directory fallback.

---

Nitpick comments:
In `@src/adaptive/trace.test.ts`:
- Around line 1-174: Extend the trace store tests with coverage for persistence
rotation and retention: add a test using MOTTAINAI_TRACE_MAX_FILE_BYTES with a
small limit that records enough data through createTraceStore to produce
multiple JSONL files, and add a test that ages a trace file with fs.utimesSync,
sets MOTTAINAI_TRACE_RETENTION_DAYS, then creates a new store and verifies the
aged file is removed. Anchor both tests near the existing createTraceStore
persistence tests and preserve current temporary-directory setup.

In `@src/auth.ts`:
- Around line 31-44: Update resolveBrokerEndpoint to identify brokerUrl
validation failures using a dedicated error type or non-enumerable marker rather
than matching the error message prefix. Ensure only errors created by the broker
validation path are rethrown unchanged, while provider errors—including ones
with the same message prefix—are replaced with the sanitized resolution error.

In `@src/telemetry.ts`:
- Around line 166-169: Update the snapshot() method to deep-clone the mutable
totals, by_provider, and by_capability counters before returning them, ensuring
callers cannot mutate the sink’s internal state while preserving the existing
snapshot metadata.
- Around line 135-165: Batch telemetry persistence in persist and the
recordToolCall/recordRetrieval paths instead of writing the full snapshot on
every update. Add a debounce or update-count threshold so frequent calls
coalesce into fewer directory, serialization, and file-write operations, while
ensuring pending updates are eventually flushed and the existing writeQueue
ordering and error handling remain intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b88263ca-bfe7-4fcd-89ed-bf42199c47f6

📥 Commits

Reviewing files that changed from the base of the PR and between 4512eb8 and 7dd73bd.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (46)
  • .editorconfig
  • .gitignore
  • LICENSE
  • README.md
  • mottainai.config.json.example
  • package.json
  • pnpm-workspace.yaml
  • src/adaptive/stats.test.ts
  • src/adaptive/stats.ts
  • src/adaptive/taxonomy.test.ts
  • src/adaptive/taxonomy.ts
  • src/adaptive/trace.test.ts
  • src/adaptive/trace.ts
  • src/auth.test.ts
  • src/auth.ts
  • src/compress/ansi.test.ts
  • src/compress/ansi.ts
  • src/compress/budget.test.ts
  • src/compress/budget.ts
  • src/compress/code.test.ts
  • src/compress/code.ts
  • src/compress/json.test.ts
  • src/compress/json.ts
  • src/compress/lines.test.ts
  • src/compress/lines.ts
  • src/compress/static-information.test.ts
  • src/compress/static-information.ts
  • src/compress/tool-description.test.ts
  • src/compress/tool-description.ts
  • src/envelope.ts
  • src/logging.test.ts
  • src/logging.ts
  • src/read-governor/classify.test.ts
  • src/read-governor/classify.ts
  • src/read-governor/evidence.test.ts
  • src/read-governor/evidence.ts
  • src/retrieve.test.ts
  • src/retrieve.ts
  • src/state/migrations.ts
  • src/state/paths.test.ts
  • src/state/paths.ts
  • src/state/store.ts
  • src/telemetry.test.ts
  • src/telemetry.ts
  • tsconfig.build.json
  • tsconfig.json

Comment thread package.json
Comment thread README.md Outdated
Comment thread src/adaptive/trace.ts
Comment thread src/adaptive/trace.ts
Comment thread src/compress/budget.ts
Comment thread src/read-governor/evidence.ts Outdated
Comment thread src/retrieve.ts Outdated
Comment thread src/retrieve.ts
Comment thread src/state/migrations.ts
Comment thread src/state/paths.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (8)
src/retrieve.ts (2)

255-265: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Share the retention-limit validation with the evidence store.

src/read-governor/evidence.ts Lines 50-62 define validateTtlMs and validateMaxEntries with the same rules and the same messages. Move both helpers into a shared module and add a maxBytes variant. The two stores then cannot drift apart.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/retrieve.ts` around lines 255 - 265, Extract the retention-limit
validation currently duplicated in the retrieve store and the evidence store’s
validateTtlMs and validateMaxEntries helpers into a shared module, preserving
their existing rules and error messages. Add a shared validateMaxBytes helper
with the same finite-positive-number validation, then update both stores to
reuse all three shared validators instead of maintaining local implementations.

128-149: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared binary-search helper.

fitStringField, fitMetadataString, and fitText implement the same search loop with a different candidate builder. Extract one helper that takes a build(bytes) => T function and a predicate. One implementation then carries the monotonicity assumption and the off-by-one bounds.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/retrieve.ts` around lines 128 - 149, Extract the duplicated binary-search
loop from fitStringField, fitMetadataString, and fitText into one shared helper
accepting a build(bytes) => T function and a predicate that determines whether
the candidate fits. Update each caller, including fitMetadataString, to provide
its candidate builder and fit predicate while preserving the existing UTF-8
prefix behavior, byte limits, monotonic search, and returned best candidate.
src/state/migrations.test.ts (1)

6-26: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a failing-migration test.

applyMigrations rolls back the transaction and wraps the error with the migration version and description. No test covers that path. Add a case where up() throws, then assert the error message and assert that schema_migrations does not record the failed version.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/state/migrations.test.ts` around lines 6 - 26, Add a test alongside the
existing applyMigrations coverage where a migration’s up() throws, assert the
thrown error includes its version and description, and verify schema_migrations
contains no row for the failed version. Ensure the test closes the in-memory
database and preserves the existing ordered-success behavior.
src/read-governor/evidence.test.ts (1)

60-66: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the per-entry ttlMs validation.

issue() also validates input.ttlMs through validateTtlMs. No test exercises that path. Add one assertion so a future change to issue() cannot silently drop the check.

♻️ Proposed additional assertion
   assert.throws(() => new InMemoryEvidenceStore({ maxEntries: 0 }), /maxEntries/);
 });
+
+test("issue() rejects an invalid per-entry ttlMs", () => {
+  const store = new InMemoryEvidenceStore();
+  assert.throws(() => store.issue({ ...baseInput(), ttlMs: Number.POSITIVE_INFINITY }), /ttlMs/);
+  assert.throws(() => store.issue({ ...baseInput(), ttlMs: -1 }), /ttlMs/);
+});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/read-governor/evidence.test.ts` around lines 60 - 66, Add an assertion in
the “constructor rejects invalid retention limits” test or a nearby
issue-validation test that calls InMemoryEvidenceStore.issue() with an invalid
per-entry input.ttlMs and expects the /ttlMs/ validation error, covering the
validateTtlMs path without changing existing constructor coverage.
src/retrieve.test.ts (1)

82-98: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Tighten the stdout and stderr assertions.

Line 97 uses a disjunction. The test passes when only one field is shortened. Assert each field separately so a regression in either bounding path fails the test.

♻️ Proposed assertion change
-  assert.ok(stdout.text.length < 100 || stderr.text.length < 1_000);
+  assert.ok(stdout.text.length < 100);
+  assert.ok(stderr.text.length < 1_000);
+  assert.equal(stdout.text.includes("\uFFFD"), false);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/retrieve.test.ts` around lines 82 - 98, Update the test “artifact store
bounds oversized stdout and stderr fields” to assert truncation independently
for stdout and stderr, replacing the combined disjunction with separate checks
that each retrieved field is shorter than its original input. Keep the existing
byte-length bounds unchanged.
src/read-governor/evidence.ts (1)

112-119: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Document EvidenceStore.get() expiry semantics.

get() intentionally returns expired records. Authorization must compare expiresAt with the current time. Add this behavior to the EvidenceStore.get() contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/read-governor/evidence.ts` around lines 112 - 119, Document the expiry
semantics in the EvidenceStore.get() contract: it intentionally returns records
even when their expiresAt has passed, so callers must compare expiresAt against
the current time for authorization decisions. Keep the existing get() behavior
unchanged.
src/adaptive/trace.test.ts (2)

99-116: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert that fresh traces survive retention cleanup.

Line 115 checks only stale-file removal. Because reopened.beginRequest writes after preparation, a cleanup that deletes every existing JSONL file could still pass. Capture the request ID created by seed and verify that reopened.load({ requestId }) still returns it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/adaptive/trace.test.ts` around lines 99 - 116, Update the trace retention
test around seed and reopened.beginRequest to capture the request ID returned by
seed, then assert reopened.load({ requestId }) still returns that seeded trace
after cleanup. Keep the existing stalePath removal assertion so the test
verifies both fresh-trace preservation and stale-file deletion.

91-97: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Verify that rotation preserves all records.

Line 96 checks only the file count. A faulty rotation can create multiple files while losing or duplicating records. After seed completes, load the trace and assert that the expected request, execution, and review data remains available.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/adaptive/trace.test.ts` around lines 91 - 97, Update the test “trace
store rotates to multiple files at the configured size” to validate record
preservation, not just file count. After seed completes, load the trace using
the existing trace-loading API and assert that the expected request, execution,
and review records are present exactly as expected, while retaining the
multiple-files assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/envelope.ts`:
- Line 17: Update RESERVED_OUTPUT_FIELDS and the extension-copying logic in the
envelope construction flow to reserve isError alongside OUTPUT_SCHEMA fields,
preventing details.isError from being copied into structuredContent while
preserving the default result error flag behavior. Add a regression test
covering details: { isError: true } with the default isError parameter and
verify structuredContent excludes isError while the MCP result reports the
appropriate error state.

In `@src/retrieve.ts`:
- Around line 233-241: The payload-size reduction in the artifact-building flow
must preserve metadata.operation for search(). Update the truncation logic near
the metadata/stderr/stdout deletion loop to truncate text before dropping
metadata, or retain a minimal metadata record containing operation; keep
search() able to read entry.metadata?.operation while still enforcing maxBytes.
- Around line 85-124: Refactor fitStringField and the related fitText bounding
path to compute the payload’s fixed JSON overhead once using an empty target
field, derive the available byte budget arithmetically, and call utf8Prefix only
once per field. Use the resulting prefix directly when JSON escaping does not
consume additional capacity; retain the existing binary-search validation only
as a fallback for escaped characters, avoiding repeated full-payload
serialization and full-value Buffer allocation.

---

Nitpick comments:
In `@src/adaptive/trace.test.ts`:
- Around line 99-116: Update the trace retention test around seed and
reopened.beginRequest to capture the request ID returned by seed, then assert
reopened.load({ requestId }) still returns that seeded trace after cleanup. Keep
the existing stalePath removal assertion so the test verifies both fresh-trace
preservation and stale-file deletion.
- Around line 91-97: Update the test “trace store rotates to multiple files at
the configured size” to validate record preservation, not just file count. After
seed completes, load the trace using the existing trace-loading API and assert
that the expected request, execution, and review records are present exactly as
expected, while retaining the multiple-files assertion.

In `@src/read-governor/evidence.test.ts`:
- Around line 60-66: Add an assertion in the “constructor rejects invalid
retention limits” test or a nearby issue-validation test that calls
InMemoryEvidenceStore.issue() with an invalid per-entry input.ttlMs and expects
the /ttlMs/ validation error, covering the validateTtlMs path without changing
existing constructor coverage.

In `@src/read-governor/evidence.ts`:
- Around line 112-119: Document the expiry semantics in the EvidenceStore.get()
contract: it intentionally returns records even when their expiresAt has passed,
so callers must compare expiresAt against the current time for authorization
decisions. Keep the existing get() behavior unchanged.

In `@src/retrieve.test.ts`:
- Around line 82-98: Update the test “artifact store bounds oversized stdout and
stderr fields” to assert truncation independently for stdout and stderr,
replacing the combined disjunction with separate checks that each retrieved
field is shorter than its original input. Keep the existing byte-length bounds
unchanged.

In `@src/retrieve.ts`:
- Around line 255-265: Extract the retention-limit validation currently
duplicated in the retrieve store and the evidence store’s validateTtlMs and
validateMaxEntries helpers into a shared module, preserving their existing rules
and error messages. Add a shared validateMaxBytes helper with the same
finite-positive-number validation, then update both stores to reuse all three
shared validators instead of maintaining local implementations.
- Around line 128-149: Extract the duplicated binary-search loop from
fitStringField, fitMetadataString, and fitText into one shared helper accepting
a build(bytes) => T function and a predicate that determines whether the
candidate fits. Update each caller, including fitMetadataString, to provide its
candidate builder and fit predicate while preserving the existing UTF-8 prefix
behavior, byte limits, monotonic search, and returned best candidate.

In `@src/state/migrations.test.ts`:
- Around line 6-26: Add a test alongside the existing applyMigrations coverage
where a migration’s up() throws, assert the thrown error includes its version
and description, and verify schema_migrations contains no row for the failed
version. Ensure the test closes the in-memory database and preserves the
existing ordered-success behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0993dd3a-8c6e-4c79-95f9-ae6a6ff421bb

📥 Commits

Reviewing files that changed from the base of the PR and between 7dd73bd and 6c7a2f8.

📒 Files selected for processing (27)
  • README.md
  • src/adaptive/trace.test.ts
  • src/adaptive/trace.ts
  • src/auth.test.ts
  • src/auth.ts
  • src/compress/budget.test.ts
  • src/compress/budget.ts
  • src/compress/json.test.ts
  • src/compress/json.ts
  • src/compress/lines.test.ts
  • src/compress/lines.ts
  • src/compress/tool-description.test.ts
  • src/compress/tool-description.ts
  • src/envelope.test.ts
  • src/envelope.ts
  • src/logging.test.ts
  • src/logging.ts
  • src/read-governor/evidence.test.ts
  • src/read-governor/evidence.ts
  • src/retrieve.test.ts
  • src/retrieve.ts
  • src/state/migrations.test.ts
  • src/state/migrations.ts
  • src/state/paths.test.ts
  • src/state/paths.ts
  • src/telemetry.test.ts
  • src/telemetry.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • src/auth.ts
  • src/compress/budget.ts
  • src/auth.test.ts
  • src/state/paths.test.ts
  • src/state/migrations.ts
  • src/compress/tool-description.test.ts
  • src/compress/tool-description.ts
  • src/telemetry.test.ts
  • src/logging.test.ts
  • README.md
  • src/compress/lines.ts
  • src/state/paths.ts
  • src/logging.ts
  • src/adaptive/trace.ts

Comment thread src/envelope.ts Outdated
Comment thread src/retrieve.ts
Comment thread src/retrieve.ts
- envelope.ts: reserve `isError` alongside OUTPUT_SCHEMA fields so
  details.isError can no longer leak into structuredContent while the
  actual MCP result reports a different error state.
- retrieve.ts: keep a minimal { operation } metadata record alive
  through artifact size bounding, reserving its bytes before text
  truncation, so search() doesn't fall back to "unknown" once an
  oversized text/stdout/stderr forces the rest of metadata out.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Prz9oz69aU1eZoVvcTry89
@yohnark
yohnark merged commit b79645b into main Aug 3, 2026
1 check passed
@yohnark
yohnark deleted the import/pr1-foundation branch August 3, 2026 23:09
yohnark pushed a commit that referenced this pull request Aug 7, 2026
…lidation with CLI

- callWorkflowCommandTool now checks config.workflowTasks before resolving
  defaultWorkflowStore() for task_start/task_status, instead of after. A
  disabled workspace no longer opens/initializes the on-disk SQLite DB
  before rejecting the call; the inner requireWorkflowTasksConfigured()
  checks stay as defense in depth.
- Extracted validateTaskSlug/validateIssueRef from mcp-tools.ts's inline
  checks and reused them in src/cli.ts's `task start`, so the CLI rejects
  the same invalid taskSlug/issueRef values at the same boundary the MCP
  tool does, before any state reservation or git invocation (previously
  the CLI forwarded raw argv values straight into startTask).
- Added a CLI test covering both rejections.

Addresses blocker #1 and medium #3 from the human review on PR #69.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants