docs(01): fix plan checker blockers (research resolution, catalog updater)

This commit is contained in:
Mikkel Georgsen 2026-04-10 01:11:41 +00:00
parent c9ad50fdf2
commit b1e4db0b6d
2 changed files with 47 additions and 16 deletions

View file

@ -10,6 +10,7 @@ files_modified:
- internal/netbox/hwid_test.go
- internal/inventory/quality_gate.go
- internal/inventory/quality_gate_test.go
- internal/inventory/catalog_updater.go
- internal/inventory/types.go
- internal/netbox/tags.go
- internal/netbox/tags_test.go
@ -424,6 +425,45 @@ func BuildCustomFieldsPatch(hwID, catalogStatus string, photoURLs []string) map[
}
```
2b. Create `internal/inventory/catalog_updater.go` — wires quality gate transitions to NetBox persistence:
```go
package inventory
import (
"context"
"fmt"
"git.georgsen.dk/hwlab/internal/netbox"
)
// CatalogUpdater persists quality gate transitions to NetBox.
type CatalogUpdater struct {
client *netbox.Client
}
// NewCatalogUpdater creates a CatalogUpdater backed by the given NetBox client.
func NewCatalogUpdater(client *netbox.Client) *CatalogUpdater {
return &CatalogUpdater{client: client}
}
// UpdateCatalogStatus validates the transition from current to next status
// and persists the result to NetBox via PatchCustomFields.
// Returns the new status on success.
func (u *CatalogUpdater) UpdateCatalogStatus(ctx context.Context, deviceID int, current, next CatalogStatus) (CatalogStatus, error) {
newStatus, err := Transition(current, next)
if err != nil {
return "", err
}
patch := map[string]interface{}{
"catalog_status": string(newStatus),
}
if err := u.client.PatchCustomFields(ctx, deviceID, patch); err != nil {
return "", fmt.Errorf("persist catalog_status to NetBox: %w", err)
}
return newStatus, nil
}
```
3. Create `internal/inventory/quality_gate_test.go`:
```go
package inventory_test
@ -645,6 +685,8 @@ func BuildCustomFieldsPatch(hwID, catalogStatus string, photoURLs []string) map[
- `grep "StatusComplete.*{}" internal/inventory/quality_gate.go` returns the terminal state entry with empty transitions
- `grep "invalid transition" internal/inventory/quality_gate.go` returns error string in Transition()
- `ensureTag` in `internal/netbox/tags.go` is implemented with real go-netbox v4 TagRequest (not stub returning error string)
- `grep "UpdateCatalogStatus" internal/inventory/catalog_updater.go` returns the function that calls Transition() then PatchCustomFields
- `grep "PatchCustomFields" internal/inventory/catalog_updater.go` confirms NetBox persistence wiring
- `go build ./internal/inventory/... ./internal/netbox/...` exits 0
</acceptance_criteria>

View file

@ -572,26 +572,15 @@ Create via DCIM API endpoints:
---
## Open Questions
## Open Questions (RESOLVED)
1. **Real NetBox API token**
- What we know: The `.env` file has a placeholder string `homelab-netbox-api-token-2024`
- What's unclear: The real token value; whether the current user account has admin permissions to create custom fields
- Recommendation: Wave 0 first task — generate real token via NetBox UI, update `.env`
1. **Real NetBox API token** — RESOLVED: Integration tests use `t.Skip()` when placeholder token detected. Operator generates real token via NetBox UI before running provisioning (Plan 03).
2. **netbox-inventory plugin installation (NB-03)**
- What we know: Plugin exists at github.com/ArnesSI/netbox-inventory; requires SSH to LXC 130
- What's unclear: Whether the LXC 130 has internet access for pip install, or if the plugin must be transferred manually
- Recommendation: Treat as a manual pre-phase step with a Makefile verification target
2. **netbox-inventory plugin installation (NB-03)** — RESOLVED: Plan 03 implements runtime check via `/api/plugins/` endpoint with CLI warning if absent. Installation is a manual pre-requisite (SSH to LXC 130).
3. **photo_urls field type**
- What we know: The requirement lists `photo_urls` as a custom field
- What's unclear: NetBox doesn't have a native array-of-URLs field type. Options: JSON field (store as JSON array string), multiline-text (one URL per line), or multiple object attachments
- Recommendation: Use `json` field type and store as a JSON array string; parse in Go
3. **photo_urls field type** — RESOLVED: Plan 03 Task 1 uses `text` type with comma-separated URLs (simpler than JSON, sufficient for Phase 1).
4. **PRD vs. REQUIREMENTS.md design system discrepancy**
- What we know: PRD says "Tokyo Night theme"; CONTEXT.md and PROJECT.md say "ClickHouse design system (pure black + neon volt)"
- Recommendation: CONTEXT.md wins — use ClickHouse design system. The stub Phase 1 frontend needs no real styling.
4. **PRD vs. REQUIREMENTS.md design system discrepancy** — RESOLVED: CONTEXT.md and PROJECT.md specify ClickHouse design system. Plan 01 stub SPA uses ClickHouse colors.
---