Add repo-memory CLI test docs

This commit is contained in:
2026-03-20 15:42:35 +08:00
parent e32c81db12
commit a6ffc376e3
43 changed files with 1583 additions and 17 deletions
+10 -6
View File
@@ -5,13 +5,16 @@
This directory tracks human-readable test plans for the `skills/repo-memory/`
Codex skill bundle.
These documents are not package-level unit tests for `briefdb`.
Those live with the runtime under `packages/repo-memory-runtime/`.
These documents are not direct CLI command-contract specs for `repo-memory`.
That coverage now lives under [../repo-memory/](../repo-memory/).
These documents are also not package-level unit tests for the runtime.
Those live under `packages/repo-memory-runtime/`.
This directory covers a different surface:
- whether an agent can actually use the packaged `repo-memory` skill
- whether the bundled `./assets/briefdb` CLI works inside real skill-guided
- whether the bundled `./assets/repo-memory` CLI works inside real skill-guided
repository work
- whether durable repository knowledge is stored and retrieved correctly
@@ -27,7 +30,7 @@ Use these defaults unless a case file explicitly overrides them:
- run the scenario with one real agent using the bundled `repo-memory` skill
- create an isolated temporary directory, repository fixture, and SQLite DB path
- require the agent to use the bundled `./assets/briefdb` CLI instead of ad hoc
- require the agent to use the bundled `./assets/repo-memory` CLI instead of ad hoc
notes
- validate final database state independently from the main thread after the
agent stops
@@ -59,12 +62,13 @@ Each case file should use this structure:
In scope:
- explicit `$repo-memory` skill invocation
- bundled `./assets/briefdb` CLI usage
- bundled `./assets/repo-memory` CLI usage
- durable knowledge add/search/list/event flows
- package-backed SQLite memory database behavior as surfaced through the skill
Out of scope:
- package-level unit tests for `briefdb`
- direct CLI contract coverage that now belongs under [../repo-memory/](../repo-memory/)
- package-level unit tests for `packages/repo-memory-runtime`
- future auto-export flows such as `repo-brief` generation
- implicit skill triggering without `$repo-memory`
@@ -12,7 +12,7 @@
## Preconditions
- `skills/repo-memory/assets/briefdb` exists and is executable
- `skills/repo-memory/assets/repo-memory` exists and is executable
- the test runner can create a temporary Git repository fixture
- the test runner can create a temporary SQLite DB path
@@ -43,10 +43,10 @@
Run these from the main thread after the agent stops:
```bash
SKILL_PATH/assets/briefdb init --db DB_PATH
SKILL_PATH/assets/briefdb search --db DB_PATH --repo REPO_PATH --query "plan task"
SKILL_PATH/assets/briefdb list --db DB_PATH --repo REPO_PATH --kind term
SKILL_PATH/assets/briefdb events --db DB_PATH --id 1
SKILL_PATH/assets/repo-memory init --db DB_PATH
SKILL_PATH/assets/repo-memory search --db DB_PATH --repo REPO_PATH --query "plan task"
SKILL_PATH/assets/repo-memory list --db DB_PATH --repo REPO_PATH --kind term
SKILL_PATH/assets/repo-memory events --db DB_PATH --id 1
```
## Expected Outcomes
+83
View File
@@ -0,0 +1,83 @@
# Repo Memory Markdown Test Plan
## Purpose
This directory contains the human-readable Markdown test plan for the
`repo-memory` CLI.
It complements package-level Go tests. The goal is to preserve the user-visible
command contract in a form that can be reviewed, extended, and replayed without
re-deriving behavior from implementation code.
## Directory Rules
- one folder per `repo-memory` command or shared area
- each folder keeps a `README.md` entrypoint
- command folders use `README.md` as an index only
- each command test case lives in its own Markdown file named after the case slug
- no numeric test IDs
- each command case is identified by its concrete file path
Case file naming pattern:
```text
<case-slug>.md
```
## Authoring Principles
- focus on externally visible CLI behavior rather than store internals
- prefer stable command sequences that a new agent can replay against a temp repo and SQLite DB
- document both success contracts and failure boundaries
- reuse scenarios from existing Go tests before inventing new cases
- keep terminology consistent with the CLI: repo, entry, alias, dependency, event, verify, stale, and needs_review
## Common Execution Model
Most cases in this directory assume the same baseline:
1. create an isolated temporary directory
2. create a Git repository fixture such as `TMPDIR/repo`
3. choose a database path such as `TMPDIR/repo-memory.db`
4. run `repo-memory init --db TMPDIR/repo-memory.db`
5. run the target command sequence against that database and repository
Unless a case says otherwise:
- assertions should check both exit code and human-readable stdout or stderr
- repo-scoped cases should use an actual Git repo so `verified_on_commit` and repo registration are meaningful
- `add` and `ingest` may bootstrap schema automatically, but most read commands assume `init` already ran
## Folder Map
- `README.md`: global conventions and glossary
- `ROADMAP.md`: document progress, planned case backlog, and authored-case register
- `_shared/README.md`: reusable fixtures, output assertions, exit-code rules, and repo conventions
- `workflows/README.md`: cross-command end-to-end scenarios
- per-command folders: command-specific index `README.md` files plus one case document per test case
## Glossary
- `repo`: one tracked repository root stored in the memory database
- `entry`: one durable knowledge record keyed by repo, kind, key, and optional scope
- `alias`: an alternate search term attached to one entry
- `dependency`: a file, dir, or glob evidence locator used during verification
- `event`: a historical record such as `created`, `updated`, `downgraded`, or `marked_stale`
- `needs_review`: knowledge that may still be useful but should be re-checked
- `stale`: knowledge that no longer has valid hard evidence and should not be treated as current
## Relationship To Automated Tests
The current executable references are:
- [store_test.go](../../../packages/repo-memory-runtime/internal/store/store_test.go) for import, search, alias, dependency, link, and verification-state transitions
- [load_test.go](../../../packages/repo-memory-runtime/internal/documents/load_test.go) for markdown parsing
- [main_test.go](../../../packages/repo-memory-runtime/cmd/repo-memory/main_test.go) for verify downgrade heuristics
These tests do not replace the Markdown plan. They only reduce discovery work.
When this Markdown plan expands:
- prefer matching an existing automated scenario first
- record any additional manual-only CLI contract coverage explicitly in the relevant command case file
- keep [ROADMAP.md](./ROADMAP.md) synchronized with authored files and case slugs
+300
View File
@@ -0,0 +1,300 @@
# Repo Memory Test Documentation Roadmap
## Purpose
This roadmap tracks the human-readable Markdown test plan for `repo-memory`.
It exists so a new agent can immediately answer four questions without
re-reading the whole codebase:
- which test-plan documents already exist
- which cases have already been written down
- which cases are still missing
- what file should be updated next
This roadmap is for the Markdown test-plan set under `docs/tests/repo-memory/`.
It is not a replacement for automated Go tests.
## Current Snapshot
Snapshot date:
- `2026-03-20`
Current state:
- `repo-memory` CLI is implemented for `init`, `add`, `ingest`, `search`, `list`, `events`, `link`, `verify`, and `repos`
- package-local automated Go tests already cover markdown parsing, import/search behavior, alias and dependency persistence, relation writes, and verification-state transitions, but they do not yet provide a dedicated CLI Markdown contract map
- this roadmap now exists under `docs/tests/repo-memory/ROADMAP.md`
- all planned global, shared, workflow, command-index, and command-case Markdown documents in the current `repo-memory` test-plan set have been authored
- each implemented `repo-memory` command folder now uses `README.md` as an index plus one Markdown file per planned case
- `docs/tests/repo-memory-skill/` can now stay focused on skill-forward behavior while `docs/tests/repo-memory/` owns direct CLI contract coverage
- a follow-up edge audit on `2026-03-20` identified seven additional boundary cases, and those cases are now authored in the Markdown plan
Progress summary for planned test-plan documents, excluding `ROADMAP.md`:
- planned document files: `39`
- authored document files: `39`
- planned case slugs in this roadmap: `31`
- authored case slugs in this roadmap: `31`
## Scope
In scope:
- `repo-memory init`
- `repo-memory add`
- `repo-memory ingest`
- `repo-memory search`
- `repo-memory list`
- `repo-memory events`
- `repo-memory link`
- `repo-memory verify`
- `repo-memory repos`
- cross-command workflows
- shared test conventions for text output, exit codes, temp repos, repo fixtures, and read-only DB inspection where the CLI has no inspection surface
Out of scope:
- `skills/repo-memory/` forward execution behavior except as a related reference
- implementation details that are not visible through the `repo-memory` CLI contract
- future commands that are not currently implemented
## Tracking Rules
Directory model:
- one folder per command or shared area
- each folder keeps a `README.md` entrypoint
- command folders use `README.md` as an index only
- each command case lives in its own Markdown file named after the case slug
- cross-command workflow cases remain grouped in `docs/tests/repo-memory/workflows/README.md`
Case identity:
- do not use numeric IDs
- identify each command case by its concrete file path
- identify each workflow case by `path + case slug`
- command case file naming pattern:
```text
<case-slug>.md
```
- workflow case heading pattern:
```md
## case: add-search-events-roundtrip
```
Per-case structure inside the case document:
- `用例意义`
- `前置条件`
- `输入`
- `预期输出`
- `断言结论`
How to update this roadmap when a new case is written:
1. if it is a command case, create or update the target `<case-slug>.md` file under the relevant command folder
2. if it is a command case, add or update the entry in that folder `README.md` index
3. if it is a workflow case, add or update the case inside `docs/tests/repo-memory/workflows/README.md`
4. move the case slug from `Pending Case Backlog` to `Authored Case Register`
5. update the authored counts in `Current Snapshot`
6. if a new Markdown file is created, update `Document Progress`
Allowed status values in this roadmap:
- `pending`
- `in_progress`
- `done`
- `deferred`
## Existing Automated Coverage Reference
The Markdown test-plan set starts from explicit CLI contract docs, but these
automated tests already exist and should be used as source material when
writing the docs:
- [store_test.go](../../../packages/repo-memory-runtime/internal/store/store_test.go#L11) `TestImportDocumentAndSearch`
- [store_test.go](../../../packages/repo-memory-runtime/internal/store/store_test.go#L67) `TestUpsertEntryWithAliasesAndDependencies`
- [store_test.go](../../../packages/repo-memory-runtime/internal/store/store_test.go#L178) `TestApplyVerificationResult`
- [load_test.go](../../../packages/repo-memory-runtime/internal/documents/load_test.go#L10) `TestParseFile`
- [main_test.go](../../../packages/repo-memory-runtime/cmd/repo-memory/main_test.go#L12) `TestVerifyCandidateDetectsFileChange`
- [main_test.go](../../../packages/repo-memory-runtime/cmd/repo-memory/main_test.go#L50) `TestVerifyCandidateMarksMissingDependencyStale`
These tests do not remove the need for the Markdown plan. They only reduce
discovery work.
## Planned Directory Tree
```text
docs/tests/repo-memory/
ROADMAP.md
README.md
_shared/
README.md
workflows/
README.md
init/
README.md
<case-slug>.md
add/
README.md
<case-slug>.md
ingest/
README.md
<case-slug>.md
search/
README.md
<case-slug>.md
list/
README.md
<case-slug>.md
events/
README.md
<case-slug>.md
link/
README.md
<case-slug>.md
verify/
README.md
<case-slug>.md
repos/
README.md
<case-slug>.md
```
## Document Progress
| Path | Purpose | Planned Cases | Authored Cases | Status |
| --- | --- | ---: | ---: | --- |
| `docs/tests/repo-memory/README.md` | Global testing conventions and glossary | 0 | 0 | done |
| `docs/tests/repo-memory/_shared/README.md` | Shared fixtures, output assertions, exit codes, and repo rules | 0 | 0 | done |
| `docs/tests/repo-memory/workflows/README.md` | Cross-command scenarios | 4 | 4 | done |
| `docs/tests/repo-memory/init/README.md` | `init` command case index | 0 | 0 | done |
| `docs/tests/repo-memory/init/init-creates-schema-on-empty-db.md` | `init` command case | 1 | 1 | done |
| `docs/tests/repo-memory/init/init-is-idempotent-on-existing-db.md` | `init` command case | 1 | 1 | done |
| `docs/tests/repo-memory/add/README.md` | `add` command case index | 0 | 0 | done |
| `docs/tests/repo-memory/add/add-registers-repo-and-entry.md` | `add` command case | 1 | 1 | done |
| `docs/tests/repo-memory/add/add-updates-existing-entry-on-same-kind-and-key.md` | `add` command case | 1 | 1 | done |
| `docs/tests/repo-memory/add/add-failed-validation-still-registers-repo.md` | `add` command case | 1 | 1 | done |
| `docs/tests/repo-memory/ingest/README.md` | `ingest` command case index | 0 | 0 | done |
| `docs/tests/repo-memory/ingest/ingest-imports-docs-ai-markdown.md` | `ingest` command case | 1 | 1 | done |
| `docs/tests/repo-memory/ingest/ingest-rejects-when-no-markdown-found.md` | `ingest` command case | 1 | 1 | done |
| `docs/tests/repo-memory/ingest/ingest-imports-headingless-markdown-as-single-entry.md` | `ingest` command case | 1 | 1 | done |
| `docs/tests/repo-memory/search/README.md` | `search` command case index | 0 | 0 | done |
| `docs/tests/repo-memory/search/search-returns-matching-entry-snippet.md` | `search` command case | 1 | 1 | done |
| `docs/tests/repo-memory/search/search-matches-alias-with-repo-filter.md` | `search` command case | 1 | 1 | done |
| `docs/tests/repo-memory/search/search-returns-no-results-when-empty.md` | `search` command case | 1 | 1 | done |
| `docs/tests/repo-memory/search/search-rejects-missing-query.md` | `search` command case | 1 | 1 | done |
| `docs/tests/repo-memory/list/README.md` | `list` command case index | 0 | 0 | done |
| `docs/tests/repo-memory/list/list-filters-by-kind-and-status.md` | `list` command case | 1 | 1 | done |
| `docs/tests/repo-memory/list/list-returns-no-entries-when-empty.md` | `list` command case | 1 | 1 | done |
| `docs/tests/repo-memory/events/README.md` | `events` command case index | 0 | 0 | done |
| `docs/tests/repo-memory/events/events-reads-history-by-id.md` | `events` command case | 1 | 1 | done |
| `docs/tests/repo-memory/events/events-resolves-entry-by-repo-kind-key.md` | `events` command case | 1 | 1 | done |
| `docs/tests/repo-memory/events/events-rejects-missing-entry-selector.md` | `events` command case | 1 | 1 | done |
| `docs/tests/repo-memory/link/README.md` | `link` command case index | 0 | 0 | done |
| `docs/tests/repo-memory/link/link-creates-relation-between-entries.md` | `link` command case | 1 | 1 | done |
| `docs/tests/repo-memory/link/link-rejects-missing-relation.md` | `link` command case | 1 | 1 | done |
| `docs/tests/repo-memory/link/link-rejects-when-entry-id-missing.md` | `link` command case | 1 | 1 | done |
| `docs/tests/repo-memory/verify/README.md` | `verify` command case index | 0 | 0 | done |
| `docs/tests/repo-memory/verify/verify-downgrades-changed-file-dependency.md` | `verify` command case | 1 | 1 | done |
| `docs/tests/repo-memory/verify/verify-marks-missing-hard-dependency-stale.md` | `verify` command case | 1 | 1 | done |
| `docs/tests/repo-memory/verify/verify-prints-no-repos-when-empty.md` | `verify` command case | 1 | 1 | done |
| `docs/tests/repo-memory/verify/verify-skips-explicit-repo-without-git-head.md` | `verify` command case | 1 | 1 | done |
| `docs/tests/repo-memory/verify/verify-downgrades-entry-missing-verified-on-commit.md` | `verify` command case | 1 | 1 | done |
| `docs/tests/repo-memory/repos/README.md` | `repos` command case index | 0 | 0 | done |
| `docs/tests/repo-memory/repos/repos-lists-tracked-repositories.md` | `repos` command case | 1 | 1 | done |
| `docs/tests/repo-memory/repos/repos-prints-no-repos-when-empty.md` | `repos` command case | 1 | 1 | done |
## Authoring Order
Recommended order:
1. `docs/tests/repo-memory/README.md`
2. `docs/tests/repo-memory/_shared/README.md`
3. `docs/tests/repo-memory/workflows/README.md`
4. `docs/tests/repo-memory/add/README.md` plus its linked case files
5. `docs/tests/repo-memory/ingest/README.md` plus its linked case files
6. `docs/tests/repo-memory/search/README.md` plus its linked case files
7. `docs/tests/repo-memory/verify/README.md` plus its linked case files
8. the remaining command indexes and case files
Reason:
- the workflow file captures the highest-value repo-memory lifecycle behavior first
- command documents can then reuse shared conventions and already-fixed terminology
## Edge Audit Notes
Per-command review status after auditing the current CLI source and authored docs:
- `init`: current coverage is sufficient for now; no additional high-value boundary was found beyond ordinary filesystem failure paths
- `add`: now covers both normal upsert flow and the surprising zero-entry repo side effect on failed validation
- `ingest`: now covers both ordinary section import and the headingless fallback-entry parser path
- `search`: now covers both positive lookup behavior and the required `--query` failure contract
- `list`: current coverage is acceptable for now; remaining gaps are mostly lower-priority default-limit behavior and shared uninitialized-schema behavior
- `events`: now covers both selector styles and the missing-selector failure contract
- `link`: now covers both successful relation writes and missing-input rejection for ids and relation
- `verify`: now covers changed-file downgrade, missing-hard-dependency stale, empty-repo set, explicit skip without Git HEAD, and missing `verified_on_commit`
- `repos`: current coverage is acceptable for now; the zero-entry repo side effect is intentionally documented from the `add` boundary case
## Authored Case Register
| Path | Case Slug | Coverage Note | Status |
| --- | --- | --- | --- |
| `docs/tests/repo-memory/workflows/README.md` | `add-search-events-roundtrip` | end-to-end write, search, and history roundtrip for one durable entry | done |
| `docs/tests/repo-memory/workflows/README.md` | `ingest-search-list-across-sections` | markdown ingest surfaces multiple imported entries through search and list | done |
| `docs/tests/repo-memory/workflows/README.md` | `add-link-and-resolve-related-entry` | two entries are linked and the relation is persisted | done |
| `docs/tests/repo-memory/workflows/README.md` | `verify-downgrades-after-repo-change` | repo changes propagate into downgraded or stale durable knowledge | done |
| `docs/tests/repo-memory/init/init-creates-schema-on-empty-db.md` | `init-creates-schema-on-empty-db` | initializes an empty database path and prints the initialized path | done |
| `docs/tests/repo-memory/init/init-is-idempotent-on-existing-db.md` | `init-is-idempotent-on-existing-db` | repeated init succeeds on the same database path | done |
| `docs/tests/repo-memory/add/add-registers-repo-and-entry.md` | `add-registers-repo-and-entry` | auto-bootstraps schema, registers the repo, and creates one durable entry | done |
| `docs/tests/repo-memory/add/add-updates-existing-entry-on-same-kind-and-key.md` | `add-updates-existing-entry-on-same-kind-and-key` | repeated upsert reuses the same entry id and records an update event | done |
| `docs/tests/repo-memory/add/add-failed-validation-still-registers-repo.md` | `add-failed-validation-still-registers-repo` | failed validation still leaves a zero-entry repo row visible through `repos` | done |
| `docs/tests/repo-memory/ingest/ingest-imports-docs-ai-markdown.md` | `ingest-imports-docs-ai-markdown` | imports markdown sections under `docs/ai` as confirmed knowledge entries | done |
| `docs/tests/repo-memory/ingest/ingest-rejects-when-no-markdown-found.md` | `ingest-rejects-when-no-markdown-found` | rejects an empty scan tree with a stable error message | done |
| `docs/tests/repo-memory/ingest/ingest-imports-headingless-markdown-as-single-entry.md` | `ingest-imports-headingless-markdown-as-single-entry` | headingless markdown falls back to one imported entry instead of being skipped | done |
| `docs/tests/repo-memory/search/search-returns-matching-entry-snippet.md` | `search-returns-matching-entry-snippet` | returns a ranked text result with status and snippet lines | done |
| `docs/tests/repo-memory/search/search-matches-alias-with-repo-filter.md` | `search-matches-alias-with-repo-filter` | matches alias terms while narrowing by repo substring | done |
| `docs/tests/repo-memory/search/search-returns-no-results-when-empty.md` | `search-returns-no-results-when-empty` | prints `no results` for an empty search result set | done |
| `docs/tests/repo-memory/search/search-rejects-missing-query.md` | `search-rejects-missing-query` | rejects empty search invocation without `--query` | done |
| `docs/tests/repo-memory/list/list-filters-by-kind-and-status.md` | `list-filters-by-kind-and-status` | narrows entries by repo substring, kind, and status | done |
| `docs/tests/repo-memory/list/list-returns-no-entries-when-empty.md` | `list-returns-no-entries-when-empty` | prints `no entries` when the filtered result set is empty | done |
| `docs/tests/repo-memory/events/events-reads-history-by-id.md` | `events-reads-history-by-id` | prints newest-first history for one entry id | done |
| `docs/tests/repo-memory/events/events-resolves-entry-by-repo-kind-key.md` | `events-resolves-entry-by-repo-kind-key` | resolves an entry without `--id` when repo, kind, and key are provided | done |
| `docs/tests/repo-memory/events/events-rejects-missing-entry-selector.md` | `events-rejects-missing-entry-selector` | rejects calls that omit both `--id` and `--repo+--kind+--key` | done |
| `docs/tests/repo-memory/link/link-creates-relation-between-entries.md` | `link-creates-relation-between-entries` | persists one directed relation between two existing entries | done |
| `docs/tests/repo-memory/link/link-rejects-missing-relation.md` | `link-rejects-missing-relation` | rejects empty relation input before write | done |
| `docs/tests/repo-memory/link/link-rejects-when-entry-id-missing.md` | `link-rejects-when-entry-id-missing` | rejects link requests without both entry ids | done |
| `docs/tests/repo-memory/verify/verify-downgrades-changed-file-dependency.md` | `verify-downgrades-changed-file-dependency` | downgrades a confirmed entry to `needs_review` when a tracked file changed | done |
| `docs/tests/repo-memory/verify/verify-marks-missing-hard-dependency-stale.md` | `verify-marks-missing-hard-dependency-stale` | marks a confirmed entry `stale` when a hard dependency disappears | done |
| `docs/tests/repo-memory/verify/verify-prints-no-repos-when-empty.md` | `verify-prints-no-repos-when-empty` | prints `no repos` when the initialized DB has no tracked repositories | done |
| `docs/tests/repo-memory/verify/verify-skips-explicit-repo-without-git-head.md` | `verify-skips-explicit-repo-without-git-head` | explicit repo verification reports a skip when the repo is not a Git repo or has no HEAD | done |
| `docs/tests/repo-memory/verify/verify-downgrades-entry-missing-verified-on-commit.md` | `verify-downgrades-entry-missing-verified-on-commit` | entries created without `verified_on_commit` downgrade to `needs_review` once the repo becomes verifiable | done |
| `docs/tests/repo-memory/repos/repos-lists-tracked-repositories.md` | `repos-lists-tracked-repositories` | lists every tracked repository with entry counts and update timestamps | done |
| `docs/tests/repo-memory/repos/repos-prints-no-repos-when-empty.md` | `repos-prints-no-repos-when-empty` | prints `no repos` for an initialized but unused database | done |
## Pending Case Backlog
No pending case slugs remain in the current plan.
When a new CLI contract or workflow needs coverage:
1. if it is a command case, create a new `<case-slug>.md` file under the relevant command folder and add it to that folder `README.md` index
2. if it is a workflow case, add it to `docs/tests/repo-memory/workflows/README.md`
3. add the new slug to `Authored Case Register`
4. update `Current Snapshot` and `Document Progress`
## Definition Of Done
This roadmap is complete only when all of the following are true:
- every implemented `repo-memory` command has a corresponding document folder
- each planned command index and case document exists
- each pending case slug has been either authored or explicitly deferred
- the authored-case register matches the actual Markdown files on disk
- a new agent can pick any pending case and know exactly where it should be written
+137
View File
@@ -0,0 +1,137 @@
# Repo Memory Shared Test Conventions
## Purpose
This document captures shared assumptions used by multiple `repo-memory`
test-plan documents so command and workflow files can stay focused on behavior
instead of repeating setup boilerplate.
## Recommended Fixture Shape
Use an isolated temp workspace per case:
- database path: `TMPDIR/repo-memory.db`
- repository path: `TMPDIR/repo`
- optional second repository path: `TMPDIR/repo-b`
- default ingest path: `TMPDIR/repo/docs/ai`
- optional evidence file: `TMPDIR/repo/path/to/file`
Recommended bootstrap command:
```bash
repo-memory init --db TMPDIR/repo-memory.db
```
Recommended repo bootstrap for Git-aware cases:
```bash
git -C TMPDIR/repo init
git -C TMPDIR/repo config user.email test@example.com
git -C TMPDIR/repo config user.name Tester
git -C TMPDIR/repo add .
git -C TMPDIR/repo commit -m "init"
```
## Flag Model
`repo-memory` uses one subcommand-specific flag set per command. There is no
root `--json` mode and no shared global flag parser.
Common flags across multiple commands:
- `--db`: SQLite database path
- `--repo`: repository root or repo-path substring filter depending on command
- `--limit`: result limit on read commands
Case files should call out whether `--repo` is:
- a required absolute repo root for `add` and `ingest`
- an optional substring filter for `search` and `list`
- an optional absolute repo root selector for `verify`
## Text Output Contract
Successful output is plain text written to stdout.
Shared assertion guidance:
- assert stable prefixes or phrases, not timestamp values
- prefer checking identifiers, kinds, keys, statuses, and count summaries
- when output contains absolute repo paths, compare against the concrete fixture path used by the case
Representative success phrases:
- `initialized TMPDIR/repo-memory.db`
- `upserted entry 1 (term:AITask)`
- `ingested 1 docs from ABS_REPO`
- `linked #1 -[related_to]-> #2`
- `ABS_REPO: verified 1 entries, 1 downgraded, 0 stale`
- `no results`
- `no entries`
- `no repos`
## Exit Code Contract
The current CLI contract uses these exit codes:
| Exit Code | Meaning | Typical Trigger |
| --- | --- | --- |
| `0` | success | command completed normally, including empty-result text such as `no results` |
| `1` | command failure | invalid flags, missing required values, missing repo docs, unresolved entry, or store/runtime error |
| `2` | top-level usage failure | missing subcommand or unknown subcommand |
When a case expects failure, assert both the non-zero exit code and the human-readable stderr message.
## Schema Bootstrap Rules
Current command behavior is intentionally uneven and should be documented:
- `init` creates schema explicitly
- `add` and `ingest` call `Init` internally and can succeed on a fresh DB path
- `search`, `list`, `events`, `link`, `verify`, and `repos` assume schema already exists
If a case relies on automatic schema bootstrap in `add` or `ingest`, state that explicitly in `前置条件` and `断言结论`.
## Repo Fixture Rules
Cases covering `add`, `ingest`, or `verify` should state:
- whether the target repo is a real Git repo
- whether a HEAD commit already exists
- which file path is being used as evidence or dependency
`verify` behavior depends on Git state:
- if a repo has a readable HEAD commit, verification updates repo metadata and evaluates dependencies
- if a repo is missing Git state or has no HEAD, the command prints `skipped (not a git repo or no HEAD)` for that repo
## Markdown Ingest Rules
`ingest` scans markdown recursively under `docs/ai` by default.
Shared assertions for ingest cases:
- `.md` files are discovered recursively
- file base name influences imported key prefixes
- heading text influences imported `kind` classification and key slug
- an empty `docs/ai` tree fails with `no markdown files found under ...`
## Direct DB Inspection
Most cases should stay at the CLI contract level.
One exception is `link`: the CLI currently writes the relation but does not have
an inspection command for links. Link cases may use a read-only `sqlite3` query
to confirm persistence after the CLI call.
Typical example:
```bash
sqlite3 TMPDIR/repo-memory.db "SELECT relation FROM knowledge_links WHERE from_entry_id = 1 AND to_entry_id = 2;"
```
## Workflow Authoring Rule
If a case spans multiple commands, place the end-to-end narrative in
`workflows/README.md` first, then add narrower command-level cases only when
they are easier to reason about in isolation.
+9
View File
@@ -0,0 +1,9 @@
# Repo Memory `add` Test Plan Index
## Case Files
| Case Slug | File | Coverage Note |
| --- | --- | --- |
| `add-registers-repo-and-entry` | [add-registers-repo-and-entry.md](./add-registers-repo-and-entry.md) | auto-bootstraps schema, registers the repo, and creates one durable entry |
| `add-updates-existing-entry-on-same-kind-and-key` | [add-updates-existing-entry-on-same-kind-and-key.md](./add-updates-existing-entry-on-same-kind-and-key.md) | reuses the same entry id and records an update event on repeated upsert |
| `add-failed-validation-still-registers-repo` | [add-failed-validation-still-registers-repo.md](./add-failed-validation-still-registers-repo.md) | failed validation still leaves a zero-entry repo row visible through `repos` |
@@ -0,0 +1,32 @@
# Case: `add-failed-validation-still-registers-repo`
## 用例意义
验证 `add` 即使因为 entry 校验失败退出,仍会留下 repo 注册副作用,这个行为需要被明确记录。
## 前置条件
- `TMPDIR/repo` 是一个已提交初始 commit 的 Git 仓库
- `TMPDIR/repo-memory.db` 尚不存在
## 输入
```bash
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/repo --summary "missing kind"
repo-memory repos --db TMPDIR/repo-memory.db
repo-memory list --db TMPDIR/repo-memory.db --repo repo
```
## 预期输出
- `add` 退出码为 `1`
- `add` 的 stderr 包含 `kind is required`
- `repos` 退出码为 `0`
- `repos` 输出包含 `TMPDIR/repo (0 entries, updated `
- `list` 输出 `no entries`
## 断言结论
- `add` 会先初始化数据库并注册 repo,再进入 entry 级校验
- 失败的 `add` 不会创建 entry,但会留下可见的零条目 repo 记录
- 后续测试或调用方如果依赖“失败无副作用”,必须显式考虑这个例外
@@ -0,0 +1,31 @@
# Case: `add-registers-repo-and-entry`
## 用例意义
验证 `add` 可以在新数据库路径上自动初始化 schema、注册 repo,并写入一条可枚举的 durable knowledge entry。
## 前置条件
- `TMPDIR/repo` 是一个已提交初始 commit 的 Git 仓库
- 证据文件 `TMPDIR/repo/app/app/src/main/java/foo/AITask.java` 已存在
- `TMPDIR/repo-memory.db` 尚不存在
## 输入
```bash
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/repo --kind term --key AITask --summary "Plan 内嵌任务结构,不是独立表" --status confirmed --source-path TMPDIR/repo/app/app/src/main/java/foo/AITask.java --source-line 42 --alias "AI Task" --dep file:TMPDIR/repo/app/app/src/main/java/foo/AITask.java:hard
repo-memory list --db TMPDIR/repo-memory.db --repo repo --kind term --status confirmed
```
## 预期输出
- `add` 退出码为 `0`
- `add` 输出 `upserted entry 1 (term:AITask)`
- `list` 输出包含 `#1 [repo] term:AITask [confirmed]`
- `list` 输出包含摘要 `Plan 内嵌任务结构,不是独立表`
## 断言结论
- `add` 会自动完成 schema bootstrap 与 repo 注册,不要求先单独跑 `init`
- 新增 entry 立即可被 `list` 读取
- 证据路径、别名、依赖等增强字段不会阻止主写入流程
@@ -0,0 +1,35 @@
# Case: `add-updates-existing-entry-on-same-kind-and-key`
## 用例意义
验证同一 repo 下相同 `kind + key + scope` 再次执行 `add` 时会更新既有 entry,而不是生成重复记录。
## 前置条件
- `TMPDIR/repo` 是一个已提交初始 commit 的 Git 仓库
- 空数据库已完成 `init`
- 已执行过一次:
```bash
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/repo --kind term --key AITask --summary "初版摘要" --status draft
```
## 输入
```bash
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/repo --kind term --key AITask --summary "修订后的摘要" --status confirmed --alias "AI Task"
repo-memory events --db TMPDIR/repo-memory.db --id 1
repo-memory list --db TMPDIR/repo-memory.db --repo repo --kind term
```
## 预期输出
- 第二次 `add` 仍输出 `upserted entry 1 (term:AITask)`
- `events` 中同时包含 `updated (draft -> confirmed)` 与更早的 `created (- -> draft)`
- `list` 中该 entry 的摘要为 `修订后的摘要`
## 断言结论
- `add` 的核心语义是 upsert,而不是 append-only create
- 更新会保留同一 entry id,同时追加历史事件
- 最新摘要、状态、别名会覆盖旧值而不是与旧值并存
+9
View File
@@ -0,0 +1,9 @@
# Repo Memory `events` Test Plan Index
## Case Files
| Case Slug | File | Coverage Note |
| --- | --- | --- |
| `events-reads-history-by-id` | [events-reads-history-by-id.md](./events-reads-history-by-id.md) | prints newest-first history for one entry id |
| `events-resolves-entry-by-repo-kind-key` | [events-resolves-entry-by-repo-kind-key.md](./events-resolves-entry-by-repo-kind-key.md) | resolves an entry without `--id` when repo, kind, and key are provided |
| `events-rejects-missing-entry-selector` | [events-rejects-missing-entry-selector.md](./events-rejects-missing-entry-selector.md) | rejects calls that provide neither `--id` nor `--repo + --kind + --key` |
@@ -0,0 +1,28 @@
# Case: `events-reads-history-by-id`
## 用例意义
验证 `events --id` 会返回某个 entry 的历史记录,并按新到旧排序。
## 前置条件
- 空数据库已完成 `init`
- `TMPDIR/repo` 下已经执行过两次同 key 的 `add`,第二次把状态从 `draft` 更新为 `confirmed`
## 输入
```bash
repo-memory events --db TMPDIR/repo-memory.db --id 1
```
## 预期输出
- 命令退出码为 `0`
- 第一行包含 `term:AITask [confirmed] #1`
- 事件列表包含 `updated (draft -> confirmed)`
- 较早事件包含 `created (- -> draft)`
## 断言结论
- `events` 不只显示当前状态,也保留状态演进轨迹
- 输出顺序是最新事件优先,便于人工快速读到最近变化
@@ -0,0 +1,25 @@
# Case: `events-rejects-missing-entry-selector`
## 用例意义
验证 `events` 在既没有 `--id`,也没有完整 `--repo + --kind + --key` 选择器时,会返回稳定错误。
## 前置条件
- 空数据库已完成 `init`
## 输入
```bash
repo-memory events --db TMPDIR/repo-memory.db
```
## 预期输出
- 命令退出码为 `1`
- stderr 包含 `either --id or --repo+--kind+--key is required`
## 断言结论
- `events` 必须先能唯一定位 entry,才会进入历史读取路径
- 两种定位方式是互补关系,但至少要提供其中一种
@@ -0,0 +1,27 @@
# Case: `events-resolves-entry-by-repo-kind-key`
## 用例意义
验证 `events` 在没有 `--id` 时,仍可通过 `repo + kind + key` 解析目标 entry。
## 前置条件
- 空数据库已完成 `init`
- `TMPDIR/repo` 下已存在 `term:AITask` 一条 entry
## 输入
```bash
repo-memory events --db TMPDIR/repo-memory.db --repo TMPDIR/repo --kind term --key AITask
```
## 预期输出
- 命令退出码为 `0`
- 第一行包含 `term:AITask`
- 事件列表至少包含一条 `created`
## 断言结论
- `events` 支持两种定位方式:`--id``--repo + --kind + --key`
- 对调用方来说,repo-scoped natural key 足以定位单条 durable knowledge
+9
View File
@@ -0,0 +1,9 @@
# Repo Memory `ingest` Test Plan Index
## Case Files
| Case Slug | File | Coverage Note |
| --- | --- | --- |
| `ingest-imports-docs-ai-markdown` | [ingest-imports-docs-ai-markdown.md](./ingest-imports-docs-ai-markdown.md) | imports markdown sections under `docs/ai` as confirmed knowledge entries |
| `ingest-rejects-when-no-markdown-found` | [ingest-rejects-when-no-markdown-found.md](./ingest-rejects-when-no-markdown-found.md) | rejects an empty scan tree with a stable error message |
| `ingest-imports-headingless-markdown-as-single-entry` | [ingest-imports-headingless-markdown-as-single-entry.md](./ingest-imports-headingless-markdown-as-single-entry.md) | imports headingless markdown as one fallback `Overview` entry |
@@ -0,0 +1,45 @@
# Case: `ingest-imports-docs-ai-markdown`
## 用例意义
验证 `ingest` 会扫描 `docs/ai` 下的 Markdown,并把 section 导入为可检索的 durable knowledge entry。
## 前置条件
- `TMPDIR/repo` 是一个已提交初始 commit 的 Git 仓库
- `TMPDIR/repo/docs/ai/repo-memory.md` 内容至少包含:
```md
# Repo Memory
## Module Map
- gateway
- app/app
## Danger Zones
- shared libs first
```
- `TMPDIR/repo-memory.db` 尚不存在
## 输入
```bash
repo-memory ingest --db TMPDIR/repo-memory.db --repo TMPDIR/repo
repo-memory list --db TMPDIR/repo-memory.db --repo repo
```
## 预期输出
- `ingest` 退出码为 `0`
- `ingest` 输出 `ingested 1 docs from ABS_REPO`
- `list` 输出包含 `module:repo-memory:module-map [confirmed]`
- `list` 输出包含 `danger:repo-memory:danger-zones [confirmed]`
## 断言结论
- 一个 Markdown 文件中的多个 section 会被拆成多条知识 entry
- `ingest` 会自动初始化数据库并注册 repo
-`repo-memory.md` 导入的 `Module Map``Danger Zones` 会被分类为不同 kind
@@ -0,0 +1,38 @@
# Case: `ingest-imports-headingless-markdown-as-single-entry`
## 用例意义
验证 `ingest` 遇到没有任何 Markdown heading 的文档时,不会跳过,而是回退为单条导入 entry。
## 前置条件
- `TMPDIR/repo` 是一个已提交初始 commit 的 Git 仓库
- `TMPDIR/repo/docs/ai/repo-memory.md` 存在,内容只有普通段落,没有任何 `#` heading,例如:
```md
This repository keeps AI memory notes near docs/ai.
Gateway owns ingress and app/app owns orchestration.
```
- 空数据库已完成 `init`
## 输入
```bash
repo-memory ingest --db TMPDIR/repo-memory.db --repo TMPDIR/repo
repo-memory list --db TMPDIR/repo-memory.db --repo repo
repo-memory search --db TMPDIR/repo-memory.db --repo repo --query "Gateway orchestration"
```
## 预期输出
- `ingest` 退出码为 `0`
- `ingest` 输出 `ingested 1 docs from ABS_REPO`
- `list` 输出包含 `decision:repo-memory:overview [confirmed]`
- `search` 输出包含 `decision:repo-memory:overview`
## 断言结论
- headingless markdown 不会被忽略
- 该类文档会以回退 heading `Overview` 导入为单条 entry
- 回退导入的 entry 仍然可以被 `list``search` 正常消费
@@ -0,0 +1,27 @@
# Case: `ingest-rejects-when-no-markdown-found`
## 用例意义
验证 `ingest` 在扫描目录存在但没有 Markdown 文件时,会返回稳定的失败信息而不是静默成功。
## 前置条件
- `TMPDIR/repo` 是一个已提交初始 commit 的 Git 仓库
- `TMPDIR/repo/docs/ai/` 目录存在但为空
- 空数据库已完成 `init`
## 输入
```bash
repo-memory ingest --db TMPDIR/repo-memory.db --repo TMPDIR/repo
```
## 预期输出
- 命令退出码为 `1`
- stderr 包含 `no markdown files found under ABS_REPO/docs/ai`
## 断言结论
- `ingest` 不会把“没有可导入文档”误报为成功
- 错误边界发生在导入阶段,repo 路径本身仍然是合法的
+8
View File
@@ -0,0 +1,8 @@
# Repo Memory `init` Test Plan Index
## Case Files
| Case Slug | File | Coverage Note |
| --- | --- | --- |
| `init-creates-schema-on-empty-db` | [init-creates-schema-on-empty-db.md](./init-creates-schema-on-empty-db.md) | initializes an empty database path and prints the initialized path |
| `init-is-idempotent-on-existing-db` | [init-is-idempotent-on-existing-db.md](./init-is-idempotent-on-existing-db.md) | repeated init succeeds on the same database path |
@@ -0,0 +1,25 @@
# Case: `init-creates-schema-on-empty-db`
## 用例意义
验证在空数据库路径上执行 `init` 会创建可用的 repo-memory schema,并返回稳定的初始化文本。
## 前置条件
- 选择一个尚不存在的数据库路径 `TMPDIR/repo-memory.db`
## 输入
```bash
repo-memory init --db TMPDIR/repo-memory.db
```
## 预期输出
- 命令退出码为 `0`
- stdout 等于 `initialized TMPDIR/repo-memory.db`
## 断言结论
- `init` 在空路径上可以直接完成 schema 初始化
- 初始化结果足以让后续 `search``list``repos` 等只读命令使用同一数据库
@@ -0,0 +1,26 @@
# Case: `init-is-idempotent-on-existing-db`
## 用例意义
验证 `init` 在已初始化数据库上重复执行仍然成功,不要求调用方先判断 schema 是否存在。
## 前置条件
- `TMPDIR/repo-memory.db` 已经执行过一次 `repo-memory init --db TMPDIR/repo-memory.db`
## 输入
```bash
repo-memory init --db TMPDIR/repo-memory.db
repo-memory init --db TMPDIR/repo-memory.db
```
## 预期输出
- 两次命令退出码都为 `0`
- 两次 stdout 都等于 `initialized TMPDIR/repo-memory.db`
## 断言结论
- `init` 是幂等操作
- 测试夹具或调用脚本可以安全重复执行初始化而不破坏已有数据
+9
View File
@@ -0,0 +1,9 @@
# Repo Memory `link` Test Plan Index
## Case Files
| Case Slug | File | Coverage Note |
| --- | --- | --- |
| `link-creates-relation-between-entries` | [link-creates-relation-between-entries.md](./link-creates-relation-between-entries.md) | persists one directed relation between two existing entries |
| `link-rejects-missing-relation` | [link-rejects-missing-relation.md](./link-rejects-missing-relation.md) | rejects empty relation input before write |
| `link-rejects-when-entry-id-missing` | [link-rejects-when-entry-id-missing.md](./link-rejects-when-entry-id-missing.md) | rejects link requests that omit either `--from-id` or `--to-id` |
@@ -0,0 +1,28 @@
# Case: `link-creates-relation-between-entries`
## 用例意义
验证 `link` 可以在两条已存在 entry 之间建立一条可持久化的关系记录。
## 前置条件
- 空数据库已完成 `init`
- 已存在两条 entry`#1 term:AITask``#2 chain:ai-insight.get`
## 输入
```bash
repo-memory link --db TMPDIR/repo-memory.db --from-id 1 --to-id 2 --relation related_to
sqlite3 TMPDIR/repo-memory.db "SELECT relation FROM knowledge_links WHERE from_entry_id = 1 AND to_entry_id = 2;"
```
## 预期输出
- `link` 命令退出码为 `0`
- `link` 输出 `linked #1 -[related_to]-> #2`
- SQL 查询返回一行 `related_to`
## 断言结论
- `link` 的副作用已落库,而不是只打印成功提示
- 关系是定向的,方向由 `from-id``to-id` 决定
@@ -0,0 +1,26 @@
# Case: `link-rejects-missing-relation`
## 用例意义
验证 `link` 对空 relation 输入给出稳定错误,而不是写入无意义关系。
## 前置条件
- 空数据库已完成 `init`
- 已存在两条 entry`#1``#2`
## 输入
```bash
repo-memory link --db TMPDIR/repo-memory.db --from-id 1 --to-id 2
```
## 预期输出
- 命令退出码为 `1`
- stderr 包含 `relation is required`
## 断言结论
- `relation` 是必填输入
- 错误发生在写库前,不会产生半有效的 link 记录
@@ -0,0 +1,26 @@
# Case: `link-rejects-when-entry-id-missing`
## 用例意义
验证 `link` 在缺少 `--from-id``--to-id` 时,会在写库前拒绝请求。
## 前置条件
- 空数据库已完成 `init`
- 已存在一条 entry`#1 term:AITask`
## 输入
```bash
repo-memory link --db TMPDIR/repo-memory.db --from-id 1 --relation related_to
```
## 预期输出
- 命令退出码为 `1`
- stderr 包含 `both entry ids are required`
## 断言结论
- `link` 需要完整的双端 entry id,不能只靠单端 id 建立半关系
- 缺失 id 的错误发生在写库前,不会生成不完整 link 记录
+8
View File
@@ -0,0 +1,8 @@
# Repo Memory `list` Test Plan Index
## Case Files
| Case Slug | File | Coverage Note |
| --- | --- | --- |
| `list-filters-by-kind-and-status` | [list-filters-by-kind-and-status.md](./list-filters-by-kind-and-status.md) | narrows entries by repo substring, kind, and status |
| `list-returns-no-entries-when-empty` | [list-returns-no-entries-when-empty.md](./list-returns-no-entries-when-empty.md) | prints `no entries` when the filtered result set is empty |
@@ -0,0 +1,34 @@
# Case: `list-filters-by-kind-and-status`
## 用例意义
验证 `list` 会同时应用 repo、kind、status 过滤条件,而不是只看其中之一。
## 前置条件
- 空数据库已完成 `init`
- 同一 repo 下已存在三条 entry
```bash
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/repo --kind term --key AITask --summary "Plan 内嵌任务结构" --status confirmed
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/repo --kind term --key AIJob --summary "后台任务封装" --status draft
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/repo --kind chain --key ai-insight.get --summary "gateway -> app service -> cache/db" --status confirmed
```
## 输入
```bash
repo-memory list --db TMPDIR/repo-memory.db --repo repo --kind term --status confirmed
```
## 预期输出
- 命令退出码为 `0`
- 输出包含 `term:AITask [confirmed]`
- 输出不包含 `AIJob`
- 输出不包含 `chain:ai-insight.get`
## 断言结论
- `list` 过滤条件是交集语义
- repo 路径过滤、kind 过滤、status 过滤可以叠加使用
@@ -0,0 +1,25 @@
# Case: `list-returns-no-entries-when-empty`
## 用例意义
验证 `list` 在没有任何匹配 entry 时返回稳定空结果文本。
## 前置条件
- 空数据库已完成 `init`
## 输入
```bash
repo-memory list --db TMPDIR/repo-memory.db --repo repo --kind term --status confirmed
```
## 预期输出
- 命令退出码为 `0`
- stdout 等于 `no entries`
## 断言结论
- 空列表属于正常读取路径,不应被当作错误
- 调用方可以通过固定文本判断当前过滤条件下无匹配项
+8
View File
@@ -0,0 +1,8 @@
# Repo Memory `repos` Test Plan Index
## Case Files
| Case Slug | File | Coverage Note |
| --- | --- | --- |
| `repos-lists-tracked-repositories` | [repos-lists-tracked-repositories.md](./repos-lists-tracked-repositories.md) | lists every tracked repository with entry counts and update timestamps |
| `repos-prints-no-repos-when-empty` | [repos-prints-no-repos-when-empty.md](./repos-prints-no-repos-when-empty.md) | prints `no repos` for an initialized but unused database |
@@ -0,0 +1,28 @@
# Case: `repos-lists-tracked-repositories`
## 用例意义
验证 `repos` 会列出当前数据库中所有已注册仓库,并附带 entry 数量。
## 前置条件
- 空数据库已完成 `init`
- 已存在两个 Git 仓库:`TMPDIR/cupid-service``TMPDIR/mars-service`
- 已分别执行一次 `add`,使两个 repo 都被注册到数据库
## 输入
```bash
repo-memory repos --db TMPDIR/repo-memory.db
```
## 预期输出
- 命令退出码为 `0`
- 输出包含 `TMPDIR/cupid-service (1 entries, updated `
- 输出包含 `TMPDIR/mars-service (1 entries, updated `
## 断言结论
- `repos` 以 repo 为聚合维度展示当前内存库覆盖范围
- 输出中的条目数来自持久化 entry 统计,而不是瞬时搜索结果
@@ -0,0 +1,25 @@
# Case: `repos-prints-no-repos-when-empty`
## 用例意义
验证 `repos` 在数据库已初始化但没有任何 repo 记录时返回稳定空结果文本。
## 前置条件
- 空数据库已完成 `init`
## 输入
```bash
repo-memory repos --db TMPDIR/repo-memory.db
```
## 预期输出
- 命令退出码为 `0`
- stdout 等于 `no repos`
## 断言结论
- `repos` 的空结果是正常状态,而不是错误
- 该命令可作为“数据库里是否已经有任何 repo memory” 的快速探针
+10
View File
@@ -0,0 +1,10 @@
# Repo Memory `search` Test Plan Index
## Case Files
| Case Slug | File | Coverage Note |
| --- | --- | --- |
| `search-returns-matching-entry-snippet` | [search-returns-matching-entry-snippet.md](./search-returns-matching-entry-snippet.md) | returns a ranked text result with status and snippet lines |
| `search-matches-alias-with-repo-filter` | [search-matches-alias-with-repo-filter.md](./search-matches-alias-with-repo-filter.md) | matches alias terms while narrowing by repo substring |
| `search-returns-no-results-when-empty` | [search-returns-no-results-when-empty.md](./search-returns-no-results-when-empty.md) | prints `no results` for an empty search result set |
| `search-rejects-missing-query` | [search-rejects-missing-query.md](./search-rejects-missing-query.md) | rejects invocations that omit the required `--query` flag |
@@ -0,0 +1,34 @@
# Case: `search-matches-alias-with-repo-filter`
## 用例意义
验证 `search` 会命中 alias,同时 `--repo` 作为路径子串过滤器只返回目标仓库的结果。
## 前置条件
- 空数据库已完成 `init`
- 已存在两个 Git 仓库:`TMPDIR/cupid-service``TMPDIR/mars-service`
- 已分别执行:
```bash
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/cupid-service --kind term --key AITask --summary "Plan 内嵌任务结构" --status confirmed --alias "plan task"
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/mars-service --kind term --key DeployPlan --summary "发布计划" --status confirmed --alias "release plan"
```
## 输入
```bash
repo-memory search --db TMPDIR/repo-memory.db --repo cupid --query "plan task"
```
## 预期输出
- 命令退出码为 `0`
- 输出包含 `[cupid-service] term:AITask [confirmed]`
- 输出不包含 `[mars-service]`
## 断言结论
- alias 会进入搜索面
- `--repo` 是 repo path substring filter,而不是必须传完整绝对路径
- 过滤发生在结果集层面,不影响 alias 命中能力
@@ -0,0 +1,25 @@
# Case: `search-rejects-missing-query`
## 用例意义
验证 `search` 对缺失 `--query` 的调用给出稳定失败契约。
## 前置条件
- 空数据库已完成 `init`
## 输入
```bash
repo-memory search --db TMPDIR/repo-memory.db
```
## 预期输出
- 命令退出码为 `1`
- stderr 包含 `--query is required`
## 断言结论
- `search` 不支持“列出全部”式空查询
- 缺失查询词属于输入错误,而不是空结果
@@ -0,0 +1,31 @@
# Case: `search-returns-matching-entry-snippet`
## 用例意义
验证 `search` 返回的文本结果既包含 entry 身份信息,也包含便于人工判断的 snippet。
## 前置条件
- 空数据库已完成 `init`
- `TMPDIR/repo` 下已有一条 `confirmed` entry
```bash
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/repo --kind chain --key ai-insight.get --summary "gateway -> app service -> cache/db" --detail "The AI insight read path goes through gateway before app service reaches cache and database." --status confirmed
```
## 输入
```bash
repo-memory search --db TMPDIR/repo-memory.db --repo repo --query "insight gateway"
```
## 预期输出
- 命令退出码为 `0`
- 第一行包含 `1. [repo] chain:ai-insight.get [confirmed]`
- 后续文本包含 `gateway` 的 snippet 片段
## 断言结论
- `search` 的核心输出不是纯 id 列表,而是可直接消费的人工排查文本
- 查询会同时命中 `key``summary``detail`
@@ -0,0 +1,25 @@
# Case: `search-returns-no-results-when-empty`
## 用例意义
验证 `search` 在没有命中项时返回稳定空结果文本,而不是异常退出。
## 前置条件
- 空数据库已完成 `init`
## 输入
```bash
repo-memory search --db TMPDIR/repo-memory.db --query "missing term"
```
## 预期输出
- 命令退出码为 `0`
- stdout 等于 `no results`
## 断言结论
- 空搜索结果被视为正常控制流
- 调用方可以用退出码 `0` + 文本 `no results` 区分“没命中”和“命令失败”
+11
View File
@@ -0,0 +1,11 @@
# Repo Memory `verify` Test Plan Index
## Case Files
| Case Slug | File | Coverage Note |
| --- | --- | --- |
| `verify-downgrades-changed-file-dependency` | [verify-downgrades-changed-file-dependency.md](./verify-downgrades-changed-file-dependency.md) | downgrades a confirmed entry to `needs_review` when a tracked file changed |
| `verify-marks-missing-hard-dependency-stale` | [verify-marks-missing-hard-dependency-stale.md](./verify-marks-missing-hard-dependency-stale.md) | marks a confirmed entry `stale` when a hard dependency disappears |
| `verify-prints-no-repos-when-empty` | [verify-prints-no-repos-when-empty.md](./verify-prints-no-repos-when-empty.md) | prints `no repos` when the initialized DB has no tracked repositories |
| `verify-skips-explicit-repo-without-git-head` | [verify-skips-explicit-repo-without-git-head.md](./verify-skips-explicit-repo-without-git-head.md) | prints a skip line when the explicit repo is not a Git repo or has no HEAD |
| `verify-downgrades-entry-missing-verified-on-commit` | [verify-downgrades-entry-missing-verified-on-commit.md](./verify-downgrades-entry-missing-verified-on-commit.md) | downgrades an entry to `needs_review` once the repo becomes verifiable but the entry lacks `verified_on_commit` |
@@ -0,0 +1,36 @@
# Case: `verify-downgrades-changed-file-dependency`
## 用例意义
验证 `verify` 在硬依赖文件内容发生变更时,会把 `confirmed` entry 降级为 `needs_review`
## 前置条件
- 空数据库已完成 `init`
- `TMPDIR/repo` 是一个已提交初始 commit 的 Git 仓库
- 已执行:
```bash
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/repo --kind term --key AITask --summary "Plan 内嵌任务结构" --status confirmed --dep file:TMPDIR/repo/foo.txt:hard
```
- 在执行 `verify` 前,`TMPDIR/repo/foo.txt` 已被修改但尚未重新验证
## 输入
```bash
repo-memory verify --db TMPDIR/repo-memory.db --repo TMPDIR/repo
repo-memory list --db TMPDIR/repo-memory.db --repo repo --status needs_review
repo-memory events --db TMPDIR/repo-memory.db --id 1
```
## 预期输出
- `verify` 输出包含 `verified 1 entries, 1 downgraded, 0 stale`
- `list` 输出包含 `term:AITask [needs_review]`
- `events` 输出包含 `downgraded (confirmed -> needs_review)`
## 断言结论
- 文件变更不会直接删除知识,而是先降级为 `needs_review`
- `verify` 会同时更新当前状态与历史事件
@@ -0,0 +1,37 @@
# Case: `verify-downgrades-entry-missing-verified-on-commit`
## 用例意义
验证 entry 一旦缺少 `verified_on_commit`,在 repo 变得可验证后会被 `verify` 降级到 `needs_review`
## 前置条件
- `TMPDIR/repo` 目录最开始不是 Git repo,但包含证据文件 `foo.txt`
- 已执行:
```bash
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/repo --kind term --key AITask --summary "Recorded before git init" --status confirmed --dep file:TMPDIR/repo/foo.txt:hard
```
- 之后才把 `TMPDIR/repo` 初始化为 Git repo,并完成第一次 commit
## 输入
```bash
repo-memory verify --db TMPDIR/repo-memory.db --repo TMPDIR/repo
repo-memory list --db TMPDIR/repo-memory.db --repo repo --status needs_review
repo-memory events --db TMPDIR/repo-memory.db --id 1
```
## 预期输出
- `verify` 退出码为 `0`
- `verify` 输出包含 `verified 1 entries, 1 downgraded, 0 stale`
- `list` 输出包含 `term:AITask [needs_review]`
- `events` 输出包含 `downgraded (confirmed -> needs_review)`
- `events` 输出包含原因 `missing verified_on_commit`
## 断言结论
- 只要 entry 缺少 `verified_on_commit`,即使依赖文件当前存在,也不能继续保持 `confirmed`
- 这个边界主要出现在“先写 repo-memory,后补 Git 历史”的仓库演进阶段
@@ -0,0 +1,36 @@
# Case: `verify-marks-missing-hard-dependency-stale`
## 用例意义
验证 `verify` 在硬依赖文件已经不存在时,会把 entry 标记为 `stale`
## 前置条件
- 空数据库已完成 `init`
- `TMPDIR/repo` 是一个已提交初始 commit 的 Git 仓库
- 已执行:
```bash
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/repo --kind term --key AITask --summary "Plan 内嵌任务结构" --status confirmed --dep file:TMPDIR/repo/missing.txt:hard
```
- `TMPDIR/repo/missing.txt` 不存在
## 输入
```bash
repo-memory verify --db TMPDIR/repo-memory.db --repo TMPDIR/repo
repo-memory list --db TMPDIR/repo-memory.db --repo repo --status stale
repo-memory events --db TMPDIR/repo-memory.db --id 1
```
## 预期输出
- `verify` 输出包含 `verified 1 entries, 0 downgraded, 1 stale`
- `list` 输出包含 `term:AITask [stale]`
- `events` 输出包含 `marked_stale (confirmed -> stale)`
## 断言结论
- 缺失的硬依赖会让知识条目直接过期,而不是只进入待复核状态
- `stale``needs_review` 是两种不同的 verify 结果
@@ -0,0 +1,25 @@
# Case: `verify-prints-no-repos-when-empty`
## 用例意义
验证 `verify` 在已初始化但尚未注册任何 repo 的数据库上返回稳定空结果文本。
## 前置条件
- 空数据库已完成 `init`
## 输入
```bash
repo-memory verify --db TMPDIR/repo-memory.db
```
## 预期输出
- 命令退出码为 `0`
- stdout 等于 `no repos`
## 断言结论
- 没有 tracked repo 时,`verify` 走正常空结果路径
- 调用方可以先跑 `verify`,再根据 `no repos` 决定是否需要补充 `add``ingest`
@@ -0,0 +1,28 @@
# Case: `verify-skips-explicit-repo-without-git-head`
## 用例意义
验证 `verify --repo <path>` 在目标目录不是 Git repo 或没有 HEAD commit 时,会返回稳定 skip 文本,而不是失败。
## 前置条件
- `TMPDIR/repo` 目录存在,但不是 Git repo,或者已经 `git init` 但还没有第一次 commit
- 空数据库已完成 `init`
## 输入
```bash
repo-memory verify --db TMPDIR/repo-memory.db --repo TMPDIR/repo
repo-memory repos --db TMPDIR/repo-memory.db
```
## 预期输出
- `verify` 退出码为 `0`
- `verify` 输出包含 `TMPDIR/repo: skipped (not a git repo or no HEAD)`
- `repos` 输出 `no repos`
## 断言结论
- 对显式 repo 的 verify,缺失 Git HEAD 被视为可跳过状态,不是命令失败
- skip 发生在 repo 注册之前,因此不会额外写入 repo 记录
+138
View File
@@ -0,0 +1,138 @@
# Repo Memory Workflow Test Plan
## Scope
This document tracks cross-command scenarios where the main value is the
interaction between multiple `repo-memory` subcommands.
All examples assume:
- isolated temp DB and repo fixtures
- assertions follow the shared rules in [../_shared/README.md](../_shared/README.md)
- commands use the concrete fixture paths created for the case
## case: add-search-events-roundtrip
### 用例意义
验证 `add -> search -> events` 的主干链路可用,确保新写入的 durable knowledge 能被立即检索并带有可追溯历史。
### 前置条件
- `TMPDIR/repo` 是一个已提交初始 commit 的 Git 仓库
- 证据文件 `TMPDIR/repo/app/app/src/main/java/foo/AITask.java` 已存在
- 空数据库已完成 `init`
### 输入
```bash
repo-memory add --db TMPDIR/repo-memory.db --repo TMPDIR/repo --kind term --key AITask --summary "Plan 内嵌任务结构,不是独立表" --status confirmed --source-path TMPDIR/repo/app/app/src/main/java/foo/AITask.java --source-line 42 --alias "AI Task" --dep file:TMPDIR/repo/app/app/src/main/java/foo/AITask.java:hard
repo-memory search --db TMPDIR/repo-memory.db --repo repo --query "AI Task"
repo-memory events --db TMPDIR/repo-memory.db --id 1
```
### 预期输出
- `add` 输出 `upserted entry 1 (term:AITask)`
- `search` 返回 `term:AITask [confirmed]`
- `events``term:AITask [confirmed] #1` 开头,并包含 `created`
### 断言结论
- 新增 entry 后无需额外同步即可被搜索到
- alias 可参与搜索命中
- 事件历史足以追溯 durable knowledge 的创建来源
## case: ingest-search-list-across-sections
### 用例意义
验证 `ingest -> search -> list` 可以把 `docs/ai` Markdown 中的多个 section 转成可搜索、可枚举的知识条目。
### 前置条件
- `TMPDIR/repo` 是一个已提交初始 commit 的 Git 仓库
- `TMPDIR/repo/docs/ai/repo-memory.md` 包含 `Module Map``Danger Zones` 等 section
- 目标数据库路径尚未初始化也可,因为该用例验证 `ingest` 的自动 schema bootstrap
### 输入
```bash
repo-memory ingest --db TMPDIR/repo-memory.db --repo TMPDIR/repo
repo-memory search --db TMPDIR/repo-memory.db --repo repo --query "gateway"
repo-memory list --db TMPDIR/repo-memory.db --repo repo
```
### 预期输出
- `ingest` 输出 `ingested 1 docs from ABS_REPO`
- `search` 命中从 `Module Map` 导入的 section
- `list` 至少包含 `module:repo-memory:module-map``danger:repo-memory:danger-zones`
### 断言结论
- 一个 Markdown 文件可以导出多个 durable knowledge entry
- 导入 entry 默认状态为 `confirmed`
- `ingest` 既完成导入,也完成 repo 注册与 schema 初始化
## case: add-link-and-resolve-related-entry
### 用例意义
验证两个 entry 可以通过 `link` 建立关系,同时各自的历史记录仍可独立读取。
### 前置条件
- 空数据库已完成 `init`
- 同一 repo 下已存在 `term:AITask``chain:ai-insight.get` 两条 entry
### 输入
```bash
repo-memory link --db TMPDIR/repo-memory.db --from-id 1 --to-id 2 --relation related_to
sqlite3 TMPDIR/repo-memory.db "SELECT relation FROM knowledge_links WHERE from_entry_id = 1 AND to_entry_id = 2;"
repo-memory events --db TMPDIR/repo-memory.db --id 1
repo-memory events --db TMPDIR/repo-memory.db --id 2
```
### 预期输出
- `link` 输出 `linked #1 -[related_to]-> #2`
- SQL 查询返回一行 `related_to`
- 两个 `events` 调用仍能分别读取各自历史
### 断言结论
- `link` 的副作用被持久化,而不是只回显成功文本
- entry 关系与 entry 历史是两个独立维度
## case: verify-downgrades-after-repo-change
### 用例意义
验证 `add -> verify -> list -> events` 在 repo 内容变更后会把已确认知识降级到需要复核或过期状态。
### 前置条件
- `TMPDIR/repo` 是一个已提交初始 commit 的 Git 仓库
- 已存在一个 `confirmed` entry,硬依赖 `TMPDIR/repo/foo.txt`
-`verify` 前,`foo.txt` 已被修改或删除
### 输入
```bash
repo-memory verify --db TMPDIR/repo-memory.db --repo TMPDIR/repo
repo-memory list --db TMPDIR/repo-memory.db --repo repo
repo-memory events --db TMPDIR/repo-memory.db --id 1
```
### 预期输出
- `verify` 输出包含 `verified 1 entries`
- `list` 中相应 entry 状态变为 `needs_review``stale`
- `events` 中新增 `downgraded``marked_stale` 事件
### 断言结论
- `verify` 会根据 repo 当前状态重新评估 durable knowledge
- 状态变化不仅更新当前 entry,也会追加历史事件供后续审计