Replace internal task tracking (TODO.md, FINDINGS.md) with structured documentation in docs/. Trim CLAUDE.md to agent instructions only. Co-Authored-By: Virgil <virgil@lethean.io>
166 lines
5.1 KiB
Markdown
166 lines
5.1 KiB
Markdown
# Development Guide
|
|
|
|
## Prerequisites
|
|
|
|
- Go 1.25 or later (the benchmark suite uses `b.Loop()`, introduced in Go 1.25).
|
|
- `github.com/stretchr/testify` — test-only dependency, fetched automatically by `go test`.
|
|
- `vhs` (`github.com/charmbracelet/vhs`) — optional, required only for `RenderMP4`. Install with `go install github.com/charmbracelet/vhs@latest`.
|
|
|
|
## Build and Test
|
|
|
|
```bash
|
|
# Run all tests
|
|
go test ./...
|
|
|
|
# Run a single test by name
|
|
go test -v -run TestParseTranscript_ToolCalls_Good
|
|
|
|
# Run with race detector
|
|
go test -race ./...
|
|
|
|
# Run benchmarks
|
|
go test -bench=. -benchmem ./...
|
|
|
|
# Vet the package
|
|
go vet ./...
|
|
|
|
# Check test coverage
|
|
go test -coverprofile=coverage.out ./...
|
|
go tool cover -html=coverage.out
|
|
```
|
|
|
|
The benchmark suite generates synthetic JSONL files of varying sizes:
|
|
|
|
| Benchmark | File size | Tool pairs |
|
|
|-----------|-----------|------------|
|
|
| `BenchmarkParseTranscript` | ~2.2 MB | 5 000 |
|
|
| `BenchmarkParseTranscript_Large` | ~11 MB | 25 000 |
|
|
| `BenchmarkListSessions` | 20 files, 100 pairs each | — |
|
|
| `BenchmarkSearch` | 10 files, 500 pairs each | — |
|
|
|
|
## Test Patterns
|
|
|
|
All tests are in the `session` package (white-box). Test files are co-located with source files.
|
|
|
|
### Test Naming Convention
|
|
|
|
Tests use a `_Good`, `_Bad`, `_Ugly` suffix:
|
|
|
|
- `_Good`: happy path; valid inputs, expected successful output.
|
|
- `_Bad`: expected error conditions or graceful degradation (malformed input, missing optional data).
|
|
- `_Ugly`: panic-inducing or extreme edge cases (missing files, nil input, path errors).
|
|
|
|
### Test Helpers
|
|
|
|
`parser_test.go` defines a set of helpers for building synthetic JSONL content:
|
|
|
|
```go
|
|
// Fixed epoch: 2026-02-20 10:00:00 UTC, offset by seconds
|
|
ts(offsetSec int) string
|
|
|
|
// Marshal arbitrary map to a single JSONL line
|
|
jsonlLine(m map[string]interface{}) string
|
|
|
|
// Convenience builders
|
|
userTextEntry(timestamp, text string) string
|
|
assistantTextEntry(timestamp, text string) string
|
|
toolUseEntry(timestamp, toolName, toolID string, input map[string]interface{}) string
|
|
toolResultEntry(timestamp, toolUseID string, content interface{}, isError bool) string
|
|
|
|
// Write lines to a temp .jsonl file, return path
|
|
writeJSONL(t *testing.T, dir string, name string, lines ...string) string
|
|
```
|
|
|
|
Use `t.TempDir()` for all test output; Go cleans it up automatically after each test.
|
|
|
|
### Coverage Targets
|
|
|
|
The current statement coverage is 90.9%. New contributions should maintain or improve this figure. When adding a function, add corresponding tests covering at minimum:
|
|
- The success path.
|
|
- Nil or zero-value inputs where applicable.
|
|
- At least one error path.
|
|
|
|
## Coding Standards
|
|
|
|
### Language
|
|
|
|
UK English throughout all source code comments, documentation, and commit messages. Examples: `colour`, `organisation`, `licence`, `initialise`.
|
|
|
|
### Formatting and Lint
|
|
|
|
Code must be formatted with `gofmt` (or `goimports`). `go vet ./...` must be clean before committing.
|
|
|
|
### Types and Declarations
|
|
|
|
- Use explicit types on struct fields and function signatures.
|
|
- Avoid `interface{}` in public APIs; use typed parameters where possible.
|
|
- Handle all errors explicitly; do not use blank `_` for error returns in non-test code.
|
|
|
|
### File Headers
|
|
|
|
Source files that are part of the main package should carry the SPDX licence identifier:
|
|
|
|
```go
|
|
// SPDX-Licence-Identifier: EUPL-1.2
|
|
package session
|
|
```
|
|
|
|
### Licence
|
|
|
|
EUPL-1.2. All new source files must include the SPDX header.
|
|
|
|
## Commit Guidelines
|
|
|
|
Use conventional commits:
|
|
|
|
```
|
|
type(scope): description
|
|
```
|
|
|
|
Common types: `feat`, `fix`, `test`, `refactor`, `docs`, `chore`.
|
|
|
|
Examples:
|
|
|
|
```
|
|
feat(parser): add ParseStats orphan detection
|
|
fix(html): escape data-text attribute value
|
|
test(analytics): add latency calculation edge cases
|
|
```
|
|
|
|
All commits must include the co-author trailer:
|
|
|
|
```
|
|
Co-Authored-By: Virgil <virgil@lethean.io>
|
|
```
|
|
|
|
`go test ./...` must pass before committing. The repository does not use a CI gate at present, so this is a manual requirement.
|
|
|
|
## Adding a New Tool Type
|
|
|
|
1. Define an input struct in `parser.go`:
|
|
```go
|
|
type myToolInput struct {
|
|
SomeField string `json:"some_field"`
|
|
}
|
|
```
|
|
|
|
2. Add a `case "MyTool":` branch in `extractToolInput` that unmarshals the struct and returns a human-readable string.
|
|
|
|
3. Add a corresponding case in `html.go`'s input label logic if the label should differ from the default `"Command"`.
|
|
|
|
4. Add a case in `video.go`'s `generateTape` switch if the tool should appear in the VHS tape.
|
|
|
|
5. Add tests in `parser_test.go` for `extractToolInput` covering the new tool name, and an integration test using `toolUseEntry` + `toolResultEntry` to exercise the full parse path.
|
|
|
|
## Adding Analytics Fields
|
|
|
|
`analytics.go` is a pure computation layer. To add a new metric:
|
|
|
|
1. Add the field to `SessionAnalytics`.
|
|
2. Populate it in the `Analyse` function's event iteration loop.
|
|
3. Add a row to `FormatAnalytics` if it should appear in CLI output.
|
|
4. Add a test case in `analytics_test.go`.
|
|
|
|
## Module Path and Go Workspace
|
|
|
|
The module path is `forge.lthn.ai/core/go-session`. If this package is used within the Go workspace at `forge.lthn.ai/core/go`, add it to `go.work` with `go work use ./go-session` and run `go work sync`.
|