Skip to content

feat(core+db+git): memory CRUD/read, soft delete, git wrapper, validation - #6

Merged
goofmint merged 4 commits into
mainfrom
feature/git-wrapper
Jun 14, 2026
Merged

feat(core+db+git): memory CRUD/read, soft delete, git wrapper, validation#6
goofmint merged 4 commits into
mainfrom
feature/git-wrapper

Conversation

@goofmint

@goofmint goofmint commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Summary

v0.1 のライト経路を構成する 4 つの層を同時に積みました:

Git wrapper (T8.1)

  • isomorphic-git@1.38.4 を追加
  • gitAdd / gitCommit / gitRemove:vault 相対パス正規化、user.name/user.email が未設定なら dennoh / dennoh@localhost にフォールバック
  • gitAdd は削除済みファイルを stage できないため gitRemove を別関数として用意

DB ソフトデリート (T4 拡張)

  • migration v2: ALTER TABLE notes ADD COLUMN deleted_at TEXT
  • getNoteById / getAllNotesWHERE deleted_at IS NULL フィルタ
  • softDeleteNotedeleted_at を関数内で生成(frontmatter updated_at と分離)。hard deleteNote はテスト/真の purge 用に保持

Config

  • Config.maxFileSizeBytes?: number、デフォルト 100 MiB
  • readConfig で正の整数バリデーション + デフォルト埋め込み

Validation

  • ContentValidationErrorcode: \"validate.content.binary\" | \"validate.content.too_large\" で i18n 連携想定)
  • validateContent:NULL byte → サイズ上限の順で検査、Buffer.byteLength(content, \"utf8\") で UTF-8 バイト長を計測

Memory CRUD + read (T5)

  • saveMemory / updateMemory / deleteMemory:file → DB → git の順次実行。v0.1 は atomicity を犠牲にし、scanAndSync が起動時に file vs DB を整合
  • updateMemory は DB に保存された既存 path に直接 writeFileAtomic + serializeFrontmatter で書き込み(writeNotebuildNotePath 経由だと createdAt の local-TZ 解釈で path が flip するリスク)
  • deleteMemorygitRemovegitAdd では deletion を stage できない)
  • getNote / listRecent:読み取り系。listRecent はデフォルト 10、deleted_at IS NULL フィルタ済み

スコープ外の必須修正(main の lint/typecheck blocker 復旧)

  • sync.tserrors 宣言を for-await ループより前に移動(TS2448)
  • sync.ts / reindex.tslet entrieslet entries: fs.Dirent[](biome noImplicitAnyLet
  • reindex.test.tsdates[i]! 非 null 断言を const-tuple + pairs.entries() に置換(biome noNonNullAssertion

CodeRabbit

公開 API 追記

  • @/dbsoftDeleteNote 追加
  • @/corevalidateContent / ContentValidationError / saveMemory / updateMemory / deleteMemory / getNote / listRecent 追加
  • 内部実装(mapper, getAllNotes, getCurrentVersion, getNoteById)は直接モジュール参照のみ可

設計判断(タスク文言からの意図的な逸脱)

  1. deleteMemory の git ステップ:仕様は gitAdd + gitCommit だが、isomorphic-git は削除済みファイルに対する add 不可。gitRemove + gitCommit に変更し、src/git/commit.tsgitRemove ヘルパーを追加。
  2. updateMemory の書き込み:仕様は writeNote(...) だが、buildNotePath が createdAt を local-TZ Date getter で YYYY/MM/DD に再分解するため、TZ 差異で path が flip するリスクあり。DB の既存 path に直接 writeFileAtomic + serializeFrontmatter で書き込む実装に変更。
  3. updateMemorydeleted_at != NULL 例外getNoteById のフィルタで到達不能。タスク文言自身が補足しているとおり省略(CLAUDE.md の「起き得ないシナリオの validation を書かない」とも整合)。
  4. maxFileSizeBytes === undefined ガードreadConfig が DEFAULT_CONFIG から埋め込むため実際には起き得ないが、型ナローイング目的で残置(実害なし、内部エラーで失敗)。

Test plan

  • bun test(230 pass / 17 files / 461 expects)
  • bun run lint(Biome clean)
  • bun run typecheck(tsc --noEmit clean)
  • CodeRabbit のレビュー確認

🤖 Generated with Claude Code

Summary by CodeRabbit

リリースノート

  • New Features
    • 設定でノートの最大サイズ上限(デフォルト100MB)を指定可能にし、UTF-8バイト長とNULLバイトを保存/更新時に検証
    • ノートをソフトデリート(論理削除)対応に拡張し、最近の一覧・メモリCRUD・Git操作を公開APIとして追加
  • Tests
    • コンテンツ検証、メモリCRUD、ソフトデリート、Git連携(コミット作成/差分反映)の統合テストを追加

…wrapper, validation

Layers landed together because they compose into the v0.1 write path:

git wrapper (T8.1)
- isomorphic-git@1.38.4 added; gitAdd / gitCommit / gitRemove with
  vault-relative path normalization and config-driven author fallback
  (dennoh / dennoh@localhost) when user.name / user.email is unset

DB soft delete (extends T4)
- migration v2: ALTER TABLE notes ADD COLUMN deleted_at TEXT
- getNoteById / getAllNotes now filter `deleted_at IS NULL`
- softDeleteNote stamps deleted_at internally (separate from frontmatter
  updated_at); hard deleteNote retained for tests / true purge

Config
- Config.maxFileSizeBytes?: number, default 100 MiB (104_857_600)
- readConfig validates positive-integer + fills in default

Validation
- ContentValidationError carries a stable `code`
  (validate.content.binary / validate.content.too_large) for the future
  i18n layer; validateContent rejects NULL bytes then size-cap in that
  order, measuring Buffer.byteLength(content, "utf8")

Memory CRUD + read (T5)
- saveMemory / updateMemory / deleteMemory run file → DB → git
  sequentially; v0.1 trades atomicity for simplicity, scanAndSync
  reconciles file vs DB at next startup
- saveMemory uses writeNote, deleteMemory uses gitRemove (gitAdd cannot
  stage a deletion in isomorphic-git)
- updateMemory writes directly to the stored `path` via
  writeFileAtomic + serializeFrontmatter to avoid buildNotePath's
  local-TZ round-trip on createdAt
- getNote / listRecent are read-side helpers; listRecent defaults to 10
  and excludes soft-deleted via the repository filter

Drive-by lint/typecheck fixes on already-merged code
- sync.ts: moved `errors` declaration above first use (TS2448)
- sync.ts / reindex.ts: `let entries` → `let entries: fs.Dirent[]`
- reindex.test.ts: replaced `dates[i]!` non-null assertion with a
  const-tuple `pairs.entries()` loop

Public APIs updated: @/db adds softDeleteNote; @/core adds
validateContent + ContentValidationError + saveMemory/updateMemory/
deleteMemory/getNote/listRecent. Internal helpers (mapper, getAllNotes,
getCurrentVersion, getNoteById) stay reachable via direct module paths
for tests.

230 pass, lint + typecheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 14, 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3d82b91e-b01a-4ca8-ad94-f1a3dcdd70ac

📥 Commits

Reviewing files that changed from the base of the PR and between c1762cc and 0a7872c.

📒 Files selected for processing (2)
  • src/git/commit.ts
  • tests/git/commit.test.ts

📝 Walkthrough

Walkthrough

isomorphic-git を追加して gitAdd/gitRemove/gitCommit ヘルパーを実装。DBスキーマにバージョン2移行(deleted_at列)と softDeleteNote を追加。コンテンツバリデーター(NULLバイト・サイズ上限)を新設。Configに maxFileSizeBytes を追加。これらを組み合わせたコア層のメモCRUD(saveMemory/updateMemory/deleteMemory/getNote/listRecent)を実装した。

Changes

メモCRUD・Git連携・soft delete基盤

Layer / File(s) Summary
Config に maxFileSizeBytes を追加
src/config/index.ts, tests/config.test.ts, tests/cli/config.test.ts
Config/DEFAULT_CONFIGmaxFileSizeBytes(100MiB)を追加し、readConfig() で正の整数バリデーションを行い戻り値へ含める。テストは省略時のデフォルト補完・明示値保持・不正値例外を検証するよう更新。
コンテンツバリデーター実装
src/core/validate.ts, tests/core/validate.test.ts
ContentValidationCode/ContentValidationError を新設し validateContent でNULLバイト検出とUTF-8バイト長上限チェックを実装。NULLバイト検出がサイズ判定より優先されることも検証。
DB soft deleteスキーマとリポジトリ拡張
src/db/schema.ts, src/db/repository.ts, src/db/index.ts, src/db/reindex.ts, src/db/sync.ts, tests/db/connection.test.ts, tests/db/repository.test.ts, tests/db/reindex.test.ts, tests/db/sync.test.ts
マイグレーション v2 で notes.deleted_at 列を追加。getNoteById/getAllNotesdeleted_at IS NULL フィルタに変更し softDeleteNote を追加。DB・reindex・syncのマイナー型注釈修正も含む。全リポジトリ・マイグレーション・reindex・sync各テストを更新。
isomorphic-git ヘルパー実装
package.json, src/git/commit.ts, src/git/index.ts, tests/git/commit.test.ts
gitAdd/gitRemove/gitCommitisomorphic-git で実装。toRelative() でパスを正規化し、resolveAuthor() でgit config読み取りとデフォルトフォールバックを行う。src/git/index.ts で再エクスポート。統合テスト新規追加。
コアメモCRUD実装
src/core/memory.ts, src/core/index.ts, tests/core/memory.test.ts
saveMemory/updateMemory/deleteMemory/getNote/listRecent を新規実装。ファイル→DB→Gitの順で逐次実行し補償トランザクションは持たない。src/core/index.ts でバリデーターとCRUDを再エクスポート。全操作の統合テスト新規追加。

Sequence Diagram(s)

sequenceDiagram
    rect rgba(70, 130, 180, 0.5)
        Note over caller,git: saveMemory
    end
    participant caller as 呼び出し元
    participant memory as memory.ts
    participant validate as validateContent
    participant fs as ファイルシステム
    participant db as SQLite DB
    participant git as isomorphic-git

    caller->>memory: saveMemory(db, vaultPath, content)
    memory->>validate: validateContent(content, maxSizeBytes)
    validate-->>memory: OK or ContentValidationError
    memory->>fs: writeNote(YYYY/MM/DD/<id>.md)
    memory->>db: insertNote(row)
    memory->>git: gitAdd(vaultPath, filePath)
    memory->>git: gitCommit(vaultPath, "add <id>")
    git-->>memory: sha
    memory-->>caller: id

    rect rgba(180, 70, 70, 0.5)
        Note over caller,git: deleteMemory
    end
    caller->>memory: deleteMemory(db, vaultPath, id)
    memory->>db: getNoteById(id)
    db-->>memory: row (deleted_at IS NULL)
    memory->>fs: rmSync(filePath)
    memory->>db: softDeleteNote(db, id)
    memory->>git: gitRemove(vaultPath, filePath)
    memory->>git: gitCommit(vaultPath, "delete <id>")
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • goofmint/dennoh#2: src/config/index.tsConfig / readConfig() の初期実装PR。本PRはその拡張として maxFileSizeBytes バリデーションを追加している。
  • goofmint/dennoh#5: src/db/repository.ts / src/db/schema.ts の元となるSQLiteリポジトリ基盤PR。本PRはその上にsoft delete(deleted_at列・softDeleteNote)を追加している。
  • goofmint/dennoh#3: src/core/index.ts の再エクスポート拡張PR。本PRは同ファイルにバリデーターとメモCRUD機能の再エクスポートを追加している。

Poem

🐇 ウサギのコード詩

ファイルに書いて、DBに刻み、
Gitにそっとコミットする。
NULLバイトは門前払い、
サイズ超過も許さない。
soft deleteで足跡残して、
今日もメモは安全に眠る。 🌙

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed タイトル「feat(core+db+git): memory CRUD/read, soft delete, git wrapper, validation」は、プルリクエストの主要な変更内容(メモリCRUD/読み取り操作、ソフトデリート、Gitラッパー、バリデーション)を明確に要約しており、変更セット全体と完全に関連している。
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/git-wrapper

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

@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: 9

🤖 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/core/memory.ts`:
- Around line 134-135: The listRecent function accepts a limit parameter without
validation, allowing invalid values like zero, negative numbers, or non-integers
to be passed through to the slice operation, resulting in incorrect behavior.
Add input validation at the beginning of the listRecent function to ensure limit
is a positive integer before using it. Throw an appropriate error if the limit
value is invalid (zero, negative, or not an integer), as this is a public API
boundary that should enforce strict input requirements per the coding guidelines
for input validation.
- Around line 149-150: The fs.rmSync(filePath) call will throw an exception if
the file has already been deleted, preventing the subsequent softDeleteNote(db,
id) from executing. Modify the fs.rmSync call to use the force option set to
true (fs.rmSync(filePath, { force: true })) so that the deletion succeeds
silently even if the file is missing, allowing the soft delete database
operation to continue executing reliably.

In `@src/core/validate.ts`:
- Line 33: The validateContent function lacks input validation for the
maxSizeBytes parameter, which should be a positive integer. Add explicit
validation at the start of the validateContent function to check that
maxSizeBytes is a positive integer, throwing a descriptive error if the value is
zero, negative, or non-integer. This ensures invalid inputs are caught early at
the entry point rather than producing ambiguous errors downstream.

In `@src/git/commit.ts`:
- Around line 33-40: The code currently falls back to DEFAULT_AUTHOR_NAME and
DEFAULT_AUTHOR_EMAIL using the nullish coalescing operator (??), which can lead
to commits with incorrect author information when git configuration is missing.
Instead of using the ?? fallback, check if both configuredName and
configuredEmail are properly set and throw an explicit error if either is
missing or null/undefined. Only return the configured values when both are
successfully retrieved, ensuring the function fails explicitly when git user
configuration is not properly set up.
- Around line 12-14: The toRelative function currently accepts any filePath
without validating whether the result escapes the vault directory. Add explicit
validation to reject paths containing `..` in the result of path.relative().
After computing the relative path, check if it includes `..` (which indicates an
attempt to escape the vault), and throw an error if detected. This provides
defensive validation at the function level rather than relying solely on
upstream checks like assertSafeNoteId, preventing future callers from
accidentally using unsafe paths. Apply this validation logic at the toRelative
function definition (the anchor site) and ensure consistent error handling
across all callers at the sibling sites as well.

In `@tests/core/memory.test.ts`:
- Around line 117-118: The test at tests/core/memory.test.ts lines 117-118 uses
optional chaining and nullish coalescing (afterRow?.path ?? "") to hide
precondition failures instead of explicitly asserting preconditions. Replace
this pattern by first adding an explicit assertion
expect(afterRow).not.toBeNull() to verify the precondition, then use
non-optional access with afterRow!.path to test the actual behavior. Apply the
same fix pattern to the other affected locations in the same file at lines
148-149, 160-161, and 169-170 where similar optional chaining and nullish
coalescing patterns are used with row or other variables.

In `@tests/core/validate.test.ts`:
- Line 65: The test assertion at line 65 uses a nullish coalescing operator to
check either `e.details.maxFileSizeBytes` or `e.details.maxSizeBytes`, which
masks contract mismatches and fails to strictly validate the error structure.
Replace this ambiguous check with a direct assertion on the correct key that
matches the actual public error contract. If the error contract specifies
`maxSizeBytes`, change the expect statement to check only
`e.details.maxSizeBytes` without any fallback operator, ensuring the assertion
validates the exact error shape and behavior rather than allowing multiple
possible keys.
- Around line 29-38: The test contains an `if (e instanceof
ContentValidationError)` conditional branch that violates the guideline
prohibiting branching in tests. Remove this if statement from three locations in
the file (lines 29-38, 57-67, and 88-96). At each location, after the
`expect(e).toBeInstanceOf(ContentValidationError);` line, add a type assertion
to cast `e` as `ContentValidationError` and then directly perform the subsequent
assertions on `e.code` and `e.message` without any conditional wrapping. This
eliminates the branching while preserving type safety through explicit
assertion.

In `@tests/git/commit.test.ts`:
- Around line 76-90: The test is using the direct git.remove method call for the
deletion case instead of using the gitRemove wrapper function, which means it is
not verifying the public API contract that includes logic like toRelative
conversion. Replace the git.remove call with gitRemove to ensure the deletion
case is tested through the same public wrapper as the add and update cases,
maintaining consistent verification of the complete API behavior across all
operations.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 80ccc30f-6c09-4111-900e-3d02e0fea1ba

📥 Commits

Reviewing files that changed from the base of the PR and between 2dfc30c and abfe8cc.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock, !bun.lock
📒 Files selected for processing (21)
  • package.json
  • src/config/index.ts
  • src/core/index.ts
  • src/core/memory.ts
  • src/core/validate.ts
  • src/db/index.ts
  • src/db/reindex.ts
  • src/db/repository.ts
  • src/db/schema.ts
  • src/db/sync.ts
  • src/git/commit.ts
  • src/git/index.ts
  • tests/cli/config.test.ts
  • tests/config.test.ts
  • tests/core/memory.test.ts
  • tests/core/validate.test.ts
  • tests/db/connection.test.ts
  • tests/db/reindex.test.ts
  • tests/db/repository.test.ts
  • tests/db/sync.test.ts
  • tests/git/commit.test.ts

Comment thread src/core/memory.ts
Comment thread src/core/memory.ts Outdated
Comment thread src/core/validate.ts
Comment thread src/git/commit.ts
Comment thread src/git/commit.ts Outdated
Comment thread tests/core/memory.test.ts Outdated
Comment thread tests/core/validate.test.ts
Comment thread tests/core/validate.test.ts Outdated
Comment thread tests/git/commit.test.ts
…rigor)

- memory.ts: fs.rmSync({force:true}) so deleteMemory is idempotent when the
  backing file was already removed externally
- git/commit.ts: toRelative rejects paths whose result contains '..' segments
  as defense-in-depth against vault escape
- validate.test.ts: assert e.details.maxSizeBytes directly (no fallback key),
  replace if-instanceof branches with `as` casts after toBeInstanceOf
- memory.test.ts: replace `?.x ?? ""` patterns with early-throw on null so
  precondition failures aren't hidden behind defaults
- git/commit.test.ts: delete case now goes through the gitRemove public
  wrapper instead of calling git.remove directly

Skipped findings: listRecent / validateContent input validation (non-boundary
per CLAUDE.md) and strict-fail on missing git config (explicit product
decision in the prior phase spec).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@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.

♻️ Duplicate comments (2)
src/git/commit.ts (1)

44-53: ⚠️ Potential issue | 🟠 Major

Git author の暗黙フォールバックをやめ、未設定時は明示エラーにしてください。

user.name / user.email 未設定時に既定値へフォールバックすると、誤った author 情報でコミットされる可能性があります。ガイドラインどおり明示的に失敗させるべきです。

🤖 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/git/commit.ts` around lines 44 - 53, The resolveAuthor function currently
silently falls back to DEFAULT_AUTHOR_NAME and DEFAULT_AUTHOR_EMAIL when git
user.name or user.email are not configured. This can lead to commits with
incorrect author information. Instead, modify the function to throw an explicit
error when either configuredName or configuredEmail are not set, ensuring that
commits require proper git author configuration. Remove the nullish coalescing
operators that provide the default fallback values.

Source: Coding guidelines

src/core/memory.ts (1)

134-135: ⚠️ Potential issue | 🟠 Major

listRecentlimit を明示検証してください。

limit0 以下や非整数でもそのまま slice されるため、呼び出し入力によって不正な結果になります。公開API境界で正の整数のみ受け付けるべきです。

🤖 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/core/memory.ts` around lines 134 - 135, The listRecent function accepts a
limit parameter but does not validate that it is a positive integer before
passing it to slice, which can produce incorrect results. Add validation at the
beginning of the listRecent function to ensure that limit is greater than zero
and is an integer value. If the limit is invalid, either throw an error with a
clear message or handle it gracefully by using the DEFAULT_RECENT_LIMIT as a
fallback.

Source: Coding guidelines

🤖 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.

Duplicate comments:
In `@src/core/memory.ts`:
- Around line 134-135: The listRecent function accepts a limit parameter but
does not validate that it is a positive integer before passing it to slice,
which can produce incorrect results. Add validation at the beginning of the
listRecent function to ensure that limit is greater than zero and is an integer
value. If the limit is invalid, either throw an error with a clear message or
handle it gracefully by using the DEFAULT_RECENT_LIMIT as a fallback.

In `@src/git/commit.ts`:
- Around line 44-53: The resolveAuthor function currently silently falls back to
DEFAULT_AUTHOR_NAME and DEFAULT_AUTHOR_EMAIL when git user.name or user.email
are not configured. This can lead to commits with incorrect author information.
Instead, modify the function to throw an explicit error when either
configuredName or configuredEmail are not set, ensuring that commits require
proper git author configuration. Remove the nullish coalescing operators that
provide the default fallback values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3defebd9-016a-4a7e-ab72-b8fdbdf4b6f6

📥 Commits

Reviewing files that changed from the base of the PR and between abfe8cc and 289c439.

📒 Files selected for processing (5)
  • src/core/memory.ts
  • src/git/commit.ts
  • tests/core/memory.test.ts
  • tests/core/validate.test.ts
  • tests/git/commit.test.ts

- git/commit.ts: remove DEFAULT_AUTHOR_NAME/EMAIL and the `??` fallback in
  resolveAuthor; throw an explicit error when user.name or user.email is
  unset (or empty). This aligns with the project's "fallbacks are absolutely
  forbidden" rule that supersedes the prior phase spec's default-author
  wording — silent placeholders for git identity were exactly the kind of
  "とりあえず動く" footgun the rule targets.
- core/memory.ts: listRecent now rejects non-positive-integer limits.
  Earlier reasoning leaned on "TS guarantees number at runtime" — incorrect
  since TS is compile-time only; `slice` silently drops trailing rows on
  negatives and returns empty on NaN, so a bad limit produces a confusing
  result rather than a clear error.
- tests/git/commit.test.ts: split into "configured identity" and "missing
  identity" describes; replaced the obsolete "falls back to defaults" test
  with three failure-path tests (missing name / missing email / both).
- tests/core/memory.test.ts: added listRecent guard test (0, -1, 1.5, NaN
  all throw).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@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: 1

🤖 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/git/commit.ts`:
- Around line 48-57: The validation checks for configuredName and
configuredEmail only verify if length equals zero, which allows whitespace-only
strings (like "   ") to pass through as valid values. Update both validation
conditions to trim the string values first, then check if the trimmed result is
empty. This ensures that strings containing only whitespace are properly
rejected as unconfigured, preventing invalid author information from being used
in commits.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ea5a963a-0d23-41d2-997c-0d47987b7c96

📥 Commits

Reviewing files that changed from the base of the PR and between 289c439 and c1762cc.

📒 Files selected for processing (4)
  • src/core/memory.ts
  • src/git/commit.ts
  • tests/core/memory.test.ts
  • tests/git/commit.test.ts

Comment thread src/git/commit.ts Outdated
`length === 0` only catches explicit empty strings; values like `"   "`
slipped through and produced commits with uninformative author entries.
Switch to `trim().length === 0` so whitespace-only configuration is
rejected with the same "not configured" error. The original (untrimmed)
value is discarded — the contract is "reject if effectively empty", not
"silently normalize".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant