Commit graph

15 commits

Author SHA1 Message Date
73eab561cf feat(02-02): WAQ real NetBox op handler replacing NoOpHandler
- NewNetBoxOpHandler routes create_device → CreateDevice, patch_custom_fields → PatchCustomFields
- NetBoxOpsClient interface enables test injection without importing netbox package
- Unknown op types return error (re-queued by worker, not silently dropped — T-02-08)
- JSON payloads decoded into typed structs (T-02-07 tampering mitigation)
- 6 handler tests all passing (TDD green); NoOpHandler untouched in worker.go
2026-04-10 05:48:30 +00:00
799acd26ef feat(02-02): three-tier orchestrator with confidence routing and research stub
- Orchestrator.Analyze: tier1 → confidence check → tier2 escalation if < threshold
- CatalogStatus mapped from confidence: >= threshold → StatusIndexed, else StatusNeedsResearch
- Both tiers fail gracefully: returns zero-value IntakeResult + StatusNeedsResearch, err nil
- ResearchClient interface + NoOpResearchClient stub for Phase 7 SearXNG
- 5 TestOrchestrator* tests all passing (TDD green)
2026-04-10 05:47:41 +00:00
8c03780230 feat(02-01): AI package foundation — types, interface, mock, prompts, config extension
- internal/ai/types.go: IntakeRequest, IntakeResult, TierConfig, AIConfig domain types
- internal/ai/client.go: AIClient interface + TierClient (go-openai, BaseURL tier-routing)
- internal/ai/mock.go: MockAIClient test double with HighConfidenceResult/LowConfidenceResult fixtures
- internal/ai/prompts/intake.go: BuildIntakePrompt() JSON-extraction prompt template
- internal/config/config.go: Config.AI AIConfig field, tier defaults, env bindings, ai_config.json merge
- ai_config.json: template config with placeholder Tier2 API key
- .gitignore: add ai_config.local.json pattern for real keys (T-02-01 mitigation)
- All tests pass: TestMockAIClient, TestMockAIClientError, TestTierClientConstruction, TestAIConfigDefaults
2026-04-10 05:45:13 +00:00
6040ecc3cc feat(02-01): install go-openai and add CreateDevice to NetBox client
- go get github.com/sashabaranov/go-openai v1.41.2
- Add CreateDevice(ctx, name, assetTag, deviceTypeID, roleID, siteID) → (int64, error)
- Add DeleteDevice(ctx, id) for test cleanup
- Use Int32As* oneOf helpers for go-netbox v4 FK fields
- TestCreateDeviceValidation PASS; TestCreateDeviceLive SKIP (no live token)
2026-04-10 05:42:51 +00:00
28e2f5a879 Merge branch 'worktree-agent-a86e8ac9' 2026-04-10 05:23:48 +00:00
1f9621fcaa feat(01-04): quality gate state machine, tag sync, catalog updater
- CatalogStatus type with forward-only state machine (draft→indexed→…→complete)
- Transition() enforces valid transitions, returns error with 'invalid transition' message
- ParseCatalogStatus() validates known status strings
- HardwareRecord domain type composing netbox.Device with quality gate state
- CatalogUpdater.UpdateCatalogStatus() validates transition then PatchCustomFields
- SyncTags() normalizes tags (slug form) and ensures they exist in NetBox
- normalizeTags deduplicates across case/whitespace/space-vs-hyphen variants
- ensureTag uses go-netbox v4 NewTagRequest(name, slug) / ExtrasTagsCreate
- All 12 state machine table-driven tests pass
2026-04-10 05:22:22 +00:00
d1192c3380 feat(01-05): WAQ retry worker and graceful shutdown wiring
- Add RunWorker: BLPOP loop with context cancellation and retryInterval backoff
- Add NoOpHandler: Phase 1 placeholder that drains ops with a log line
- Drop ops after maxAttempts with warning log (T-05-03 mitigation)
- Update main.go: non-fatal WAQ init, graceful HTTP shutdown on SIGINT/SIGTERM
2026-04-10 05:22:10 +00:00
e07ad922eb feat(01-05): write-ahead queue core (Enqueue, Dequeue, Len)
- Add PendingOp struct with UUID, type, payload, created_at, attempts
- Add WAQ type backed by DragonFlyDB via go-redis v9
- Implement Enqueue (RPUSH), Dequeue (BLPOP), Len (LLEN)
- Custom URL parser handles passwords with forward slashes
- Unit tests pass; integration test passes against DragonFlyDB at 10.5.0.10:6379
2026-04-10 05:21:28 +00:00
9b4cc9a661 feat(01-03): implement custom field provisioning with go-netbox v4
- Define hwlabCustomFields slice with all 8 HWLab custom field specs
- Implement ProvisionCustomFields with idempotent check-before-create
- Implement createCustomField using WritableCustomFieldRequest
- Implement customFieldSpec lookup for testing
2026-04-10 05:21:23 +00:00
e1cee31620 feat(01-04): HW-XXXXX sequential ID allocation
- formatHWID/parseHWID with HW-NNNNN regex validation
- AllocateNextHWID with optimistic-lock retry (3 attempts)
- getHighestHWIDNumber scans all devices for highest existing asset_tag
- hwIDExists checks specific asset_tag via DcimDevicesList filter
- Unit tests for format/parse covering valid and invalid cases
2026-04-10 05:20:41 +00:00
07130d2ceb test(01-03): add failing tests for custom field spec and provisioning 2026-04-10 05:20:37 +00:00
17a2eb6f9f feat(01-02): custom field read/write wrappers (NB-02)
- Add ParseCustomFields: safe type-assertion mapping from map[string]interface{}
- Add BuildCustomFieldsPatch: selective flat patch map (avoids clearing unset fields)
- Add BuildFullCustomFieldsPatch: full custom fields patch for initial record creation
- Add PatchCustomFields method on Client using PatchedWritableDeviceWithConfigContextRequest
- Add custom_fields_test.go with 5 unit tests and 1 skippable integration round-trip test
2026-04-10 05:17:11 +00:00
9f3ed9fddc feat(01-02): NetBox client wrapper with device CRUD (NB-01)
- Add internal/netbox/types.go with Device and CustomFields domain types
- Add internal/netbox/client.go with NewClient, Ping, ListDevices, GetDevice
- Add client_test.go with validation unit tests and skippable integration tests
- go-netbox v4.3.0 dependency added
2026-04-10 05:16:17 +00:00
6595e345a2 feat(01-foundation-01): viper config loader and SPA fallback fix
- Add internal/config/config.go with viper-backed Config struct
- Explicit BindEnv calls for reliable env var -> config mapping (mapstructure v2 compat)
- Config loads from config.json + .env, env vars take precedence
- Add config.json with non-secret defaults (port, timeouts, URLs)
- Fix SPA fallback: spaHandler serves index.html for unknown paths (client-side routing)
- All 5 tests pass: TestHealth, TestLoadDefaults, TestLoadEnvOverride, TestLoadNetBoxURL
- Add Makefile with build/dev/test/clean targets
2026-04-10 01:27:54 +00:00
77e5a78d5a feat(01-foundation-01): Go module init, chi server, go:embed SPA scaffold
- Initialize module git.georgsen.dk/hwlab with Go 1.23
- Install chi v5.2.5, go-redis v9.18.0, viper v1.21.0, godotenv v1.5.1, uuid v1.6.0, go-netbox v4.3.0
- Create health handler GET /api/health returning {status:ok, version:0.1.0}
- Create chi router with Logger/Recoverer/RealIP middleware and SPA fallback
- Embed web/dist via assets.go at module root (go:embed cannot use .. paths)
- Create stub web/dist/index.html with ClickHouse dark theme
- TestHealth passes
2026-04-10 01:17:03 +00:00