From a6ffc376e3642086d408933f8316bdfa56b7f357 Mon Sep 17 00:00:00 2001 From: kurihada Date: Fri, 20 Mar 2026 15:42:35 +0800 Subject: [PATCH] Add repo-memory CLI test docs --- docs/skill-workspace-monorepo.md | 27 +- docs/tests/repo-memory-skill/README.md | 16 +- .../search-and-add-through-bundled-cli.md | 10 +- docs/tests/repo-memory/README.md | 83 +++++ docs/tests/repo-memory/ROADMAP.md | 300 ++++++++++++++++++ docs/tests/repo-memory/_shared/README.md | 137 ++++++++ docs/tests/repo-memory/add/README.md | 9 + ...-failed-validation-still-registers-repo.md | 32 ++ .../add/add-registers-repo-and-entry.md | 31 ++ ...tes-existing-entry-on-same-kind-and-key.md | 35 ++ docs/tests/repo-memory/events/README.md | 9 + .../events/events-reads-history-by-id.md | 28 ++ .../events-rejects-missing-entry-selector.md | 25 ++ .../events-resolves-entry-by-repo-kind-key.md | 27 ++ docs/tests/repo-memory/ingest/README.md | 9 + .../ingest/ingest-imports-docs-ai-markdown.md | 45 +++ ...ts-headingless-markdown-as-single-entry.md | 38 +++ .../ingest-rejects-when-no-markdown-found.md | 27 ++ docs/tests/repo-memory/init/README.md | 8 + .../init/init-creates-schema-on-empty-db.md | 25 ++ .../init/init-is-idempotent-on-existing-db.md | 26 ++ docs/tests/repo-memory/link/README.md | 9 + .../link-creates-relation-between-entries.md | 28 ++ .../link/link-rejects-missing-relation.md | 26 ++ .../link-rejects-when-entry-id-missing.md | 26 ++ docs/tests/repo-memory/list/README.md | 8 + .../list/list-filters-by-kind-and-status.md | 34 ++ .../list-returns-no-entries-when-empty.md | 25 ++ docs/tests/repo-memory/repos/README.md | 8 + .../repos/repos-lists-tracked-repositories.md | 28 ++ .../repos/repos-prints-no-repos-when-empty.md | 25 ++ docs/tests/repo-memory/search/README.md | 10 + .../search-matches-alias-with-repo-filter.md | 34 ++ .../search/search-rejects-missing-query.md | 25 ++ .../search-returns-matching-entry-snippet.md | 31 ++ .../search-returns-no-results-when-empty.md | 25 ++ docs/tests/repo-memory/verify/README.md | 11 + ...rify-downgrades-changed-file-dependency.md | 36 +++ ...grades-entry-missing-verified-on-commit.md | 37 +++ ...ify-marks-missing-hard-dependency-stale.md | 36 +++ .../verify-prints-no-repos-when-empty.md | 25 ++ ...fy-skips-explicit-repo-without-git-head.md | 28 ++ docs/tests/repo-memory/workflows/README.md | 138 ++++++++ 43 files changed, 1583 insertions(+), 17 deletions(-) create mode 100644 docs/tests/repo-memory/README.md create mode 100644 docs/tests/repo-memory/ROADMAP.md create mode 100644 docs/tests/repo-memory/_shared/README.md create mode 100644 docs/tests/repo-memory/add/README.md create mode 100644 docs/tests/repo-memory/add/add-failed-validation-still-registers-repo.md create mode 100644 docs/tests/repo-memory/add/add-registers-repo-and-entry.md create mode 100644 docs/tests/repo-memory/add/add-updates-existing-entry-on-same-kind-and-key.md create mode 100644 docs/tests/repo-memory/events/README.md create mode 100644 docs/tests/repo-memory/events/events-reads-history-by-id.md create mode 100644 docs/tests/repo-memory/events/events-rejects-missing-entry-selector.md create mode 100644 docs/tests/repo-memory/events/events-resolves-entry-by-repo-kind-key.md create mode 100644 docs/tests/repo-memory/ingest/README.md create mode 100644 docs/tests/repo-memory/ingest/ingest-imports-docs-ai-markdown.md create mode 100644 docs/tests/repo-memory/ingest/ingest-imports-headingless-markdown-as-single-entry.md create mode 100644 docs/tests/repo-memory/ingest/ingest-rejects-when-no-markdown-found.md create mode 100644 docs/tests/repo-memory/init/README.md create mode 100644 docs/tests/repo-memory/init/init-creates-schema-on-empty-db.md create mode 100644 docs/tests/repo-memory/init/init-is-idempotent-on-existing-db.md create mode 100644 docs/tests/repo-memory/link/README.md create mode 100644 docs/tests/repo-memory/link/link-creates-relation-between-entries.md create mode 100644 docs/tests/repo-memory/link/link-rejects-missing-relation.md create mode 100644 docs/tests/repo-memory/link/link-rejects-when-entry-id-missing.md create mode 100644 docs/tests/repo-memory/list/README.md create mode 100644 docs/tests/repo-memory/list/list-filters-by-kind-and-status.md create mode 100644 docs/tests/repo-memory/list/list-returns-no-entries-when-empty.md create mode 100644 docs/tests/repo-memory/repos/README.md create mode 100644 docs/tests/repo-memory/repos/repos-lists-tracked-repositories.md create mode 100644 docs/tests/repo-memory/repos/repos-prints-no-repos-when-empty.md create mode 100644 docs/tests/repo-memory/search/README.md create mode 100644 docs/tests/repo-memory/search/search-matches-alias-with-repo-filter.md create mode 100644 docs/tests/repo-memory/search/search-rejects-missing-query.md create mode 100644 docs/tests/repo-memory/search/search-returns-matching-entry-snippet.md create mode 100644 docs/tests/repo-memory/search/search-returns-no-results-when-empty.md create mode 100644 docs/tests/repo-memory/verify/README.md create mode 100644 docs/tests/repo-memory/verify/verify-downgrades-changed-file-dependency.md create mode 100644 docs/tests/repo-memory/verify/verify-downgrades-entry-missing-verified-on-commit.md create mode 100644 docs/tests/repo-memory/verify/verify-marks-missing-hard-dependency-stale.md create mode 100644 docs/tests/repo-memory/verify/verify-prints-no-repos-when-empty.md create mode 100644 docs/tests/repo-memory/verify/verify-skips-explicit-repo-without-git-head.md create mode 100644 docs/tests/repo-memory/workflows/README.md diff --git a/docs/skill-workspace-monorepo.md b/docs/skill-workspace-monorepo.md index ea2136b..5f4cae0 100644 --- a/docs/skill-workspace-monorepo.md +++ b/docs/skill-workspace-monorepo.md @@ -83,7 +83,7 @@ Examples: │ ├─ inbox-runtime/ # inbox CLI runtime │ ├─ orch-runtime/ # orch CLI runtime │ ├─ operator-api/ # operator HTTP + query/web backend runtime -│ ├─ repo-memory-runtime/ # briefdb / repo-memory runtime +│ ├─ repo-memory-runtime/ # repo-memory runtime │ └─ ... # future skill runtimes ├─ skills/ │ ├─ inbox/ @@ -97,6 +97,9 @@ Examples: │ ├─ skill-bundles.json │ └─ ... └─ docs/tests/ + ├─ inbox/ + ├─ orch/ + ├─ repo-memory/ ├─ inbox-skill/ ├─ orch-skill/ ├─ council-review-skill/ @@ -182,7 +185,7 @@ This package owns the repo-memory implementation. It should contain: -- `cmd/briefdb/main.go` +- `cmd/repo-memory/main.go` - markdown ingest/parser logic - knowledge store and verification logic - its own schema and runtime tests @@ -290,8 +293,8 @@ Example mapping: { "skill": "repo-memory", "type": "go-binary", - "package": "./packages/repo-memory-runtime/cmd/briefdb", - "output": "skills/repo-memory/assets/briefdb" + "package": "./packages/repo-memory-runtime/cmd/repo-memory", + "output": "skills/repo-memory/assets/repo-memory" } ] } @@ -310,6 +313,17 @@ Each runtime package owns: - integration tests - package-local fixtures +### CLI Markdown Test Plans + +Standalone CLIs with user-facing contracts should also keep a Markdown test-plan +set under `docs/tests//`. + +Examples: + +- `docs/tests/inbox/` +- `docs/tests/orch/` +- `docs/tests/repo-memory/` + ### Skill Forward Tests `docs/tests/*-skill/` remains skill-oriented. @@ -320,7 +334,7 @@ Examples: - `docs/tests/inbox-skill/` - `docs/tests/orch-skill/` - `docs/tests/council-review-skill/` -- future `docs/tests/repo-memory-skill/` +- `docs/tests/repo-memory-skill/` ### Cross-Package Validation @@ -406,9 +420,10 @@ Exit criteria: Changes: -- move the exploratory `tmp/briefdb` runtime into `packages/repo-memory-runtime` +- move the exploratory repo-memory runtime into `packages/repo-memory-runtime` - normalize module pathing, tests, and packaging - add `skills/repo-memory` +- add `docs/tests/repo-memory/` - add `docs/tests/repo-memory-skill/` Exit criteria: diff --git a/docs/tests/repo-memory-skill/README.md b/docs/tests/repo-memory-skill/README.md index f20af35..98e5c0f 100644 --- a/docs/tests/repo-memory-skill/README.md +++ b/docs/tests/repo-memory-skill/README.md @@ -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` diff --git a/docs/tests/repo-memory-skill/search-and-add-through-bundled-cli.md b/docs/tests/repo-memory-skill/search-and-add-through-bundled-cli.md index 402a051..025bc87 100644 --- a/docs/tests/repo-memory-skill/search-and-add-through-bundled-cli.md +++ b/docs/tests/repo-memory-skill/search-and-add-through-bundled-cli.md @@ -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 diff --git a/docs/tests/repo-memory/README.md b/docs/tests/repo-memory/README.md new file mode 100644 index 0000000..3f351f9 --- /dev/null +++ b/docs/tests/repo-memory/README.md @@ -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 +.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 diff --git a/docs/tests/repo-memory/ROADMAP.md b/docs/tests/repo-memory/ROADMAP.md new file mode 100644 index 0000000..1315f1b --- /dev/null +++ b/docs/tests/repo-memory/ROADMAP.md @@ -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 +.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 `.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 + .md + add/ + README.md + .md + ingest/ + README.md + .md + search/ + README.md + .md + list/ + README.md + .md + events/ + README.md + .md + link/ + README.md + .md + verify/ + README.md + .md + repos/ + README.md + .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 `.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 diff --git a/docs/tests/repo-memory/_shared/README.md b/docs/tests/repo-memory/_shared/README.md new file mode 100644 index 0000000..8308ec1 --- /dev/null +++ b/docs/tests/repo-memory/_shared/README.md @@ -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. diff --git a/docs/tests/repo-memory/add/README.md b/docs/tests/repo-memory/add/README.md new file mode 100644 index 0000000..2037c07 --- /dev/null +++ b/docs/tests/repo-memory/add/README.md @@ -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` | diff --git a/docs/tests/repo-memory/add/add-failed-validation-still-registers-repo.md b/docs/tests/repo-memory/add/add-failed-validation-still-registers-repo.md new file mode 100644 index 0000000..d35f045 --- /dev/null +++ b/docs/tests/repo-memory/add/add-failed-validation-still-registers-repo.md @@ -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 记录 +- 后续测试或调用方如果依赖“失败无副作用”,必须显式考虑这个例外 diff --git a/docs/tests/repo-memory/add/add-registers-repo-and-entry.md b/docs/tests/repo-memory/add/add-registers-repo-and-entry.md new file mode 100644 index 0000000..f9e4648 --- /dev/null +++ b/docs/tests/repo-memory/add/add-registers-repo-and-entry.md @@ -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` 读取 +- 证据路径、别名、依赖等增强字段不会阻止主写入流程 diff --git a/docs/tests/repo-memory/add/add-updates-existing-entry-on-same-kind-and-key.md b/docs/tests/repo-memory/add/add-updates-existing-entry-on-same-kind-and-key.md new file mode 100644 index 0000000..f6545db --- /dev/null +++ b/docs/tests/repo-memory/add/add-updates-existing-entry-on-same-kind-and-key.md @@ -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,同时追加历史事件 +- 最新摘要、状态、别名会覆盖旧值而不是与旧值并存 diff --git a/docs/tests/repo-memory/events/README.md b/docs/tests/repo-memory/events/README.md new file mode 100644 index 0000000..e676b84 --- /dev/null +++ b/docs/tests/repo-memory/events/README.md @@ -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` | diff --git a/docs/tests/repo-memory/events/events-reads-history-by-id.md b/docs/tests/repo-memory/events/events-reads-history-by-id.md new file mode 100644 index 0000000..9da0dc7 --- /dev/null +++ b/docs/tests/repo-memory/events/events-reads-history-by-id.md @@ -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` 不只显示当前状态,也保留状态演进轨迹 +- 输出顺序是最新事件优先,便于人工快速读到最近变化 diff --git a/docs/tests/repo-memory/events/events-rejects-missing-entry-selector.md b/docs/tests/repo-memory/events/events-rejects-missing-entry-selector.md new file mode 100644 index 0000000..c968ea8 --- /dev/null +++ b/docs/tests/repo-memory/events/events-rejects-missing-entry-selector.md @@ -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,才会进入历史读取路径 +- 两种定位方式是互补关系,但至少要提供其中一种 diff --git a/docs/tests/repo-memory/events/events-resolves-entry-by-repo-kind-key.md b/docs/tests/repo-memory/events/events-resolves-entry-by-repo-kind-key.md new file mode 100644 index 0000000..ae28219 --- /dev/null +++ b/docs/tests/repo-memory/events/events-resolves-entry-by-repo-kind-key.md @@ -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 diff --git a/docs/tests/repo-memory/ingest/README.md b/docs/tests/repo-memory/ingest/README.md new file mode 100644 index 0000000..f82a8ec --- /dev/null +++ b/docs/tests/repo-memory/ingest/README.md @@ -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 | diff --git a/docs/tests/repo-memory/ingest/ingest-imports-docs-ai-markdown.md b/docs/tests/repo-memory/ingest/ingest-imports-docs-ai-markdown.md new file mode 100644 index 0000000..8be25c4 --- /dev/null +++ b/docs/tests/repo-memory/ingest/ingest-imports-docs-ai-markdown.md @@ -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 diff --git a/docs/tests/repo-memory/ingest/ingest-imports-headingless-markdown-as-single-entry.md b/docs/tests/repo-memory/ingest/ingest-imports-headingless-markdown-as-single-entry.md new file mode 100644 index 0000000..d4a2f3c --- /dev/null +++ b/docs/tests/repo-memory/ingest/ingest-imports-headingless-markdown-as-single-entry.md @@ -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` 正常消费 diff --git a/docs/tests/repo-memory/ingest/ingest-rejects-when-no-markdown-found.md b/docs/tests/repo-memory/ingest/ingest-rejects-when-no-markdown-found.md new file mode 100644 index 0000000..c4cc4e7 --- /dev/null +++ b/docs/tests/repo-memory/ingest/ingest-rejects-when-no-markdown-found.md @@ -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 路径本身仍然是合法的 diff --git a/docs/tests/repo-memory/init/README.md b/docs/tests/repo-memory/init/README.md new file mode 100644 index 0000000..9075b57 --- /dev/null +++ b/docs/tests/repo-memory/init/README.md @@ -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 | diff --git a/docs/tests/repo-memory/init/init-creates-schema-on-empty-db.md b/docs/tests/repo-memory/init/init-creates-schema-on-empty-db.md new file mode 100644 index 0000000..7bf0fbe --- /dev/null +++ b/docs/tests/repo-memory/init/init-creates-schema-on-empty-db.md @@ -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` 等只读命令使用同一数据库 diff --git a/docs/tests/repo-memory/init/init-is-idempotent-on-existing-db.md b/docs/tests/repo-memory/init/init-is-idempotent-on-existing-db.md new file mode 100644 index 0000000..8485dcf --- /dev/null +++ b/docs/tests/repo-memory/init/init-is-idempotent-on-existing-db.md @@ -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` 是幂等操作 +- 测试夹具或调用脚本可以安全重复执行初始化而不破坏已有数据 diff --git a/docs/tests/repo-memory/link/README.md b/docs/tests/repo-memory/link/README.md new file mode 100644 index 0000000..b00571d --- /dev/null +++ b/docs/tests/repo-memory/link/README.md @@ -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` | diff --git a/docs/tests/repo-memory/link/link-creates-relation-between-entries.md b/docs/tests/repo-memory/link/link-creates-relation-between-entries.md new file mode 100644 index 0000000..1b2e794 --- /dev/null +++ b/docs/tests/repo-memory/link/link-creates-relation-between-entries.md @@ -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` 决定 diff --git a/docs/tests/repo-memory/link/link-rejects-missing-relation.md b/docs/tests/repo-memory/link/link-rejects-missing-relation.md new file mode 100644 index 0000000..77349b0 --- /dev/null +++ b/docs/tests/repo-memory/link/link-rejects-missing-relation.md @@ -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 记录 diff --git a/docs/tests/repo-memory/link/link-rejects-when-entry-id-missing.md b/docs/tests/repo-memory/link/link-rejects-when-entry-id-missing.md new file mode 100644 index 0000000..a331a31 --- /dev/null +++ b/docs/tests/repo-memory/link/link-rejects-when-entry-id-missing.md @@ -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 记录 diff --git a/docs/tests/repo-memory/list/README.md b/docs/tests/repo-memory/list/README.md new file mode 100644 index 0000000..4fa710c --- /dev/null +++ b/docs/tests/repo-memory/list/README.md @@ -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 | diff --git a/docs/tests/repo-memory/list/list-filters-by-kind-and-status.md b/docs/tests/repo-memory/list/list-filters-by-kind-and-status.md new file mode 100644 index 0000000..63457c4 --- /dev/null +++ b/docs/tests/repo-memory/list/list-filters-by-kind-and-status.md @@ -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 过滤可以叠加使用 diff --git a/docs/tests/repo-memory/list/list-returns-no-entries-when-empty.md b/docs/tests/repo-memory/list/list-returns-no-entries-when-empty.md new file mode 100644 index 0000000..4e83e3e --- /dev/null +++ b/docs/tests/repo-memory/list/list-returns-no-entries-when-empty.md @@ -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` + +## 断言结论 + +- 空列表属于正常读取路径,不应被当作错误 +- 调用方可以通过固定文本判断当前过滤条件下无匹配项 diff --git a/docs/tests/repo-memory/repos/README.md b/docs/tests/repo-memory/repos/README.md new file mode 100644 index 0000000..14a19a3 --- /dev/null +++ b/docs/tests/repo-memory/repos/README.md @@ -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 | diff --git a/docs/tests/repo-memory/repos/repos-lists-tracked-repositories.md b/docs/tests/repo-memory/repos/repos-lists-tracked-repositories.md new file mode 100644 index 0000000..c32a06f --- /dev/null +++ b/docs/tests/repo-memory/repos/repos-lists-tracked-repositories.md @@ -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 统计,而不是瞬时搜索结果 diff --git a/docs/tests/repo-memory/repos/repos-prints-no-repos-when-empty.md b/docs/tests/repo-memory/repos/repos-prints-no-repos-when-empty.md new file mode 100644 index 0000000..214a4cb --- /dev/null +++ b/docs/tests/repo-memory/repos/repos-prints-no-repos-when-empty.md @@ -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” 的快速探针 diff --git a/docs/tests/repo-memory/search/README.md b/docs/tests/repo-memory/search/README.md new file mode 100644 index 0000000..2cf5ab0 --- /dev/null +++ b/docs/tests/repo-memory/search/README.md @@ -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 | diff --git a/docs/tests/repo-memory/search/search-matches-alias-with-repo-filter.md b/docs/tests/repo-memory/search/search-matches-alias-with-repo-filter.md new file mode 100644 index 0000000..f5d5e3f --- /dev/null +++ b/docs/tests/repo-memory/search/search-matches-alias-with-repo-filter.md @@ -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 命中能力 diff --git a/docs/tests/repo-memory/search/search-rejects-missing-query.md b/docs/tests/repo-memory/search/search-rejects-missing-query.md new file mode 100644 index 0000000..65e3d44 --- /dev/null +++ b/docs/tests/repo-memory/search/search-rejects-missing-query.md @@ -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` 不支持“列出全部”式空查询 +- 缺失查询词属于输入错误,而不是空结果 diff --git a/docs/tests/repo-memory/search/search-returns-matching-entry-snippet.md b/docs/tests/repo-memory/search/search-returns-matching-entry-snippet.md new file mode 100644 index 0000000..ed7fa25 --- /dev/null +++ b/docs/tests/repo-memory/search/search-returns-matching-entry-snippet.md @@ -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` diff --git a/docs/tests/repo-memory/search/search-returns-no-results-when-empty.md b/docs/tests/repo-memory/search/search-returns-no-results-when-empty.md new file mode 100644 index 0000000..249bd16 --- /dev/null +++ b/docs/tests/repo-memory/search/search-returns-no-results-when-empty.md @@ -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` 区分“没命中”和“命令失败” diff --git a/docs/tests/repo-memory/verify/README.md b/docs/tests/repo-memory/verify/README.md new file mode 100644 index 0000000..7661c2d --- /dev/null +++ b/docs/tests/repo-memory/verify/README.md @@ -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` | diff --git a/docs/tests/repo-memory/verify/verify-downgrades-changed-file-dependency.md b/docs/tests/repo-memory/verify/verify-downgrades-changed-file-dependency.md new file mode 100644 index 0000000..1c3bded --- /dev/null +++ b/docs/tests/repo-memory/verify/verify-downgrades-changed-file-dependency.md @@ -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` 会同时更新当前状态与历史事件 diff --git a/docs/tests/repo-memory/verify/verify-downgrades-entry-missing-verified-on-commit.md b/docs/tests/repo-memory/verify/verify-downgrades-entry-missing-verified-on-commit.md new file mode 100644 index 0000000..3862df1 --- /dev/null +++ b/docs/tests/repo-memory/verify/verify-downgrades-entry-missing-verified-on-commit.md @@ -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 历史”的仓库演进阶段 diff --git a/docs/tests/repo-memory/verify/verify-marks-missing-hard-dependency-stale.md b/docs/tests/repo-memory/verify/verify-marks-missing-hard-dependency-stale.md new file mode 100644 index 0000000..f151b5c --- /dev/null +++ b/docs/tests/repo-memory/verify/verify-marks-missing-hard-dependency-stale.md @@ -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 结果 diff --git a/docs/tests/repo-memory/verify/verify-prints-no-repos-when-empty.md b/docs/tests/repo-memory/verify/verify-prints-no-repos-when-empty.md new file mode 100644 index 0000000..2838222 --- /dev/null +++ b/docs/tests/repo-memory/verify/verify-prints-no-repos-when-empty.md @@ -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` diff --git a/docs/tests/repo-memory/verify/verify-skips-explicit-repo-without-git-head.md b/docs/tests/repo-memory/verify/verify-skips-explicit-repo-without-git-head.md new file mode 100644 index 0000000..f1f4acb --- /dev/null +++ b/docs/tests/repo-memory/verify/verify-skips-explicit-repo-without-git-head.md @@ -0,0 +1,28 @@ +# Case: `verify-skips-explicit-repo-without-git-head` + +## 用例意义 + +验证 `verify --repo ` 在目标目录不是 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 记录 diff --git a/docs/tests/repo-memory/workflows/README.md b/docs/tests/repo-memory/workflows/README.md new file mode 100644 index 0000000..8e92014 --- /dev/null +++ b/docs/tests/repo-memory/workflows/README.md @@ -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,也会追加历史事件供后续审计