diff --git a/CODEX.md b/CODEX.md new file mode 100644 index 0000000..593747e --- /dev/null +++ b/CODEX.md @@ -0,0 +1,22 @@ +# CODEX.md + +This repository uses the same working conventions described in [`CLAUDE.md`](CLAUDE.md). +Keep the two files aligned. + +## AX Notes + +- Prefer descriptive names over abbreviations. +- Public comments should show real usage with concrete values. +- Keep examples in UK English. +- Do not add compatibility aliases; the primary API names are the contract. +- Preserve the single-connection SQLite design. +- Verify with `go test ./...`, `go test -race ./...`, and `go vet ./...` before committing. +- Use conventional commits and include the `Co-Authored-By: Virgil ` trailer. + +## Repository Shape + +- `store.go` contains the core store API and SQLite lifecycle. +- `events.go` contains mutation events, watchers, and callbacks. +- `scope.go` contains namespace isolation and quota enforcement. +- `docs/` contains the package docs, architecture notes, and history. + diff --git a/README.md b/README.md index 6e1d563..fe53bf1 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ func main() { ## Documentation +- [Agent Conventions](CODEX.md) - Codex-facing repo rules and AX notes - [Architecture](docs/architecture.md) — storage layer, group/key model, TTL expiry, event system, namespace isolation - [Development Guide](docs/development.md) — prerequisites, test patterns, benchmarks, adding methods - [Project History](docs/history.md) — completed phases, known limitations, future considerations diff --git a/conventions_test.go b/conventions_test.go index aad7708..48e56d2 100644 --- a/conventions_test.go +++ b/conventions_test.go @@ -174,7 +174,7 @@ func TestConventions_Exports_Good_NoCompatibilityAliases(t *testing.T) { func repoGoFiles(t *testing.T, keep func(name string) bool) []string { t.Helper() - result := testFS().List(".") + result := testFilesystem().List(".") requireCoreOK(t, result) entries, ok := result.Value.([]fs.DirEntry) diff --git a/coverage_test.go b/coverage_test.go index 1f25cf6..032d772 100644 --- a/coverage_test.go +++ b/coverage_test.go @@ -118,8 +118,8 @@ func TestCoverage_GetAll_Bad_RowsError(t *testing.T) { requireCoreWriteBytes(t, dbPath, data) // Remove WAL/SHM so the reopened connection reads from the main file. - _ = testFS().Delete(dbPath + "-wal") - _ = testFS().Delete(dbPath + "-shm") + _ = testFilesystem().Delete(dbPath + "-wal") + _ = testFilesystem().Delete(dbPath + "-shm") s2, err := New(dbPath) require.NoError(t, err) @@ -204,8 +204,8 @@ func TestCoverage_Render_Bad_RowsError(t *testing.T) { copy(data[offset+len(garbage):offset+(len(garbage)*2)], garbage) requireCoreWriteBytes(t, dbPath, data) - _ = testFS().Delete(dbPath + "-wal") - _ = testFS().Delete(dbPath + "-shm") + _ = testFilesystem().Delete(dbPath + "-wal") + _ = testFilesystem().Delete(dbPath + "-shm") s2, err := New(dbPath) require.NoError(t, err) diff --git a/doc.go b/doc.go index 81b70f3..648f304 100644 --- a/doc.go +++ b/doc.go @@ -1,8 +1,12 @@ // Package store provides a SQLite-backed key-value store with group namespaces, // TTL expiry, quota-enforced scoped views, and reactive change notifications. // -// storeInstance, _ := store.New(":memory:") -// value, _ := storeInstance.Get("config", "theme") +// Usage example: +// +// storeInstance, _ := store.New(":memory:") +// scopedStore, _ := store.NewScoped(storeInstance, "tenant-a") +// _ = scopedStore.Set("config", "theme", "dark") +// value, _ := storeInstance.Get("config", "theme") // // Use New to open a store, then Set/Get for CRUD operations. Use // NewScoped/NewScopedWithQuota when group names need tenant isolation or diff --git a/docs/index.md b/docs/index.md index 238e08a..9cf9c0d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -130,5 +130,6 @@ There are no other direct dependencies. The package uses the Go standard library ## Further Reading +- [Agent Conventions](../CODEX.md) -- Codex-facing repo rules and AX notes - [Architecture](architecture.md) -- storage layer internals, TTL model, event system, concurrency design - [Development Guide](development.md) -- building, testing, benchmarks, contribution workflow diff --git a/store_test.go b/store_test.go index b680e21..2d2572e 100644 --- a/store_test.go +++ b/store_test.go @@ -55,7 +55,7 @@ func TestStore_New_Bad_InvalidPath(t *testing.T) { func TestStore_New_Bad_CorruptFile(t *testing.T) { // A file that exists but is not a valid SQLite database should fail. dbPath := testPath(t, "corrupt.db") - requireCoreOK(t, testFS().Write(dbPath, "not a sqlite database")) + requireCoreOK(t, testFilesystem().Write(dbPath, "not a sqlite database")) _, err := New(dbPath) require.Error(t, err) @@ -73,8 +73,8 @@ func TestStore_New_Bad_ReadOnlyDir(t *testing.T) { require.NoError(t, s.Close()) // Remove WAL/SHM files and make directory read-only. - _ = testFS().Delete(dbPath + "-wal") - _ = testFS().Delete(dbPath + "-shm") + _ = testFilesystem().Delete(dbPath + "-wal") + _ = testFilesystem().Delete(dbPath + "-shm") require.NoError(t, syscall.Chmod(dir, 0555)) defer func() { _ = syscall.Chmod(dir, 0755) }() // restore for cleanup diff --git a/test_helpers_test.go b/test_helpers_test.go index 986057b..a7a5c12 100644 --- a/test_helpers_test.go +++ b/test_helpers_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" ) -func testFS() *core.Fs { +func testFilesystem() *core.Fs { return (&core.Fs{}).NewUnrestricted() } @@ -23,14 +23,14 @@ func requireCoreOK(tb testing.TB, result core.Result) { func requireCoreReadBytes(tb testing.TB, path string) []byte { tb.Helper() - result := testFS().Read(path) + result := testFilesystem().Read(path) requireCoreOK(tb, result) return []byte(result.Value.(string)) } func requireCoreWriteBytes(tb testing.TB, path string, data []byte) { tb.Helper() - requireCoreOK(tb, testFS().Write(path, string(data))) + requireCoreOK(tb, testFilesystem().Write(path, string(data))) } func repeatString(value string, count int) string {