docs(ax): add Codex conventions bridge
All checks were successful
Security Scan / security (push) Successful in 9s
Test / test (push) Successful in 1m36s

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-03-30 15:16:16 +00:00
parent 2c55d220fa
commit adc463ba75
8 changed files with 41 additions and 13 deletions

22
CODEX.md Normal file
View file

@ -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 <virgil@lethean.io>` 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.

View file

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

View file

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

View file

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

8
doc.go
View file

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

View file

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

View file

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

View file

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