[agent/claude:opus] DX audit and fix. 1) Review CLAUDE.md — update any outdate... #2

Closed
Virgil wants to merge 1 commit from agent/dx-audit-and-fix--1--review-claude-md into main
3 changed files with 41 additions and 3 deletions

View file

@ -27,7 +27,7 @@ See `docs/architecture.md` for full detail. Summary:
- **Responsive**: Multi-variant breakpoint wrapper (`data-variant` attributes), renders all variants in insertion order
- **Pipeline**: Render → StripTags → go-i18n/reversal Tokenise → GrammarImprint (server-side only)
- **Codegen**: Web Component classes with closed Shadow DOM, generated at build time by `cmd/codegen/`
- **WASM**: `cmd/wasm/` exports `renderToString()` only — size gate: < 3 MB raw, < 1 MB gzip
- **WASM**: `cmd/wasm/` exports `renderToString()` only — size gate: < 3.5 MB raw, < 1 MB gzip
## Server/Client Split
@ -40,9 +40,10 @@ Files guarded with `//go:build !js` are excluded from WASM:
## Dependencies
- `forge.lthn.ai/core/go-i18n` (replace directive → `../go-i18n`)
- `forge.lthn.ai/core/go-i18n` — internationalisation, text reversal pipeline
- `forge.lthn.ai/core/go-io` — file I/O abstraction (`coreio.Local`)
- `forge.lthn.ai/core/go-log` — structured logging and error wrapping (`log.E()`)
- `forge.lthn.ai/core/go-inference` (indirect, via go-i18n)
- Both `go-i18n` and `go-inference` must be cloned alongside this repo for builds
- Go 1.26+ required (uses `range` over integers, `iter.Seq`, `maps.Keys`, `slices.Collect`)
## Coding Standards
@ -53,6 +54,8 @@ Files guarded with `//go:build !js` are excluded from WASM:
- Licence: EUPL-1.2 — add `// SPDX-Licence-Identifier: EUPL-1.2` to new files
- Safe-by-default: HTML escaping via `html.EscapeString()` on Text nodes and attribute values, void element handling, entitlement deny-by-default
- Deterministic output: sorted attributes on El nodes, reproducible block ID paths
- Error handling: use `log.E(scope, message, err)` from `go-log`, never `fmt.Errorf`
- File I/O: use `coreio.Local` from `go-io`, never `os.ReadFile`/`os.WriteFile`
- Commits: conventional commits + `Co-Authored-By: Virgil <virgil@lethean.io>`
## Test Conventions

View file

@ -2,6 +2,7 @@ package main
import (
"bytes"
"errors"
"strings"
"testing"
@ -9,6 +10,12 @@ import (
"github.com/stretchr/testify/require"
)
type errReader struct{}
func (errReader) Read([]byte) (int, error) {
return 0, errors.New("read failed")
}
func TestRun_Good(t *testing.T) {
input := strings.NewReader(`{"H":"nav-bar","C":"main-content"}`)
var output bytes.Buffer
@ -49,3 +56,11 @@ func TestRun_Good_Empty(t *testing.T) {
require.NoError(t, err)
assert.Empty(t, output.String())
}
func TestRun_Bad_ReadError(t *testing.T) {
var output bytes.Buffer
err := run(errReader{}, &output)
assert.Error(t, err)
assert.Contains(t, err.Error(), "reading stdin")
}

View file

@ -52,3 +52,23 @@ func TestGenerateBundle_Good(t *testing.T) {
assert.Contains(t, js, "MainContent")
assert.Equal(t, 2, strings.Count(js, "extends HTMLElement"))
}
func TestGenerateBundle_Good_DeduplicatesTags(t *testing.T) {
slots := map[string]string{
"H": "nav-bar",
"F": "nav-bar",
}
js, err := GenerateBundle(slots)
require.NoError(t, err)
assert.Equal(t, 1, strings.Count(js, "extends HTMLElement"),
"duplicate tag should produce only one class definition")
}
func TestGenerateBundle_Bad_InvalidTag(t *testing.T) {
slots := map[string]string{
"H": "notag",
}
_, err := GenerateBundle(slots)
assert.Error(t, err)
assert.Contains(t, err.Error(), "hyphen")
}