Conversation
…category Add `featureGated` boolean to models.json so established models (haiku-4-5, opus-4-5, defaults) are always available without needing Unleash flags, while newer models require explicit flag enablement. The model discovery script sets featureGated=true for newly discovered models so they're disabled by default. Group and alphabetically sort feature flags in the workspace UI by their prefix category (Models, Runners, Frameworks, etc.) with section headers and counts for better organization. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…esponse Add CleanupStaleFlags to archive Unleash feature flags for models that have been marked featureGated=false in models.json. Runs after flag sync at both server startup and via the sync-model-flags CLI. Cleanup failures are non-fatal to avoid blocking startup. Sort the /models API response alphabetically by label for consistent ordering in the frontend dropdown. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
Flag names are API identifiers built from model IDs, not user input. Wrapping them in sanitizeLogString could cause name mismatches between FlagsFromManifest (creation) and StaleFlagsFromManifest (cleanup) if a model ID ever contained characters the function strips. Keep sanitizeLogString only on the Description field which is user-facing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
Add http.StatusNoContent to archiveFlag success cases to handle proxy layers that normalize Unleash's 202 response to 204. Add inline comment explaining why new models default to featureGated=true in the discovery script. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Claude Code ReviewSummaryPR 808 adds a featureGated field to ModelEntry, wires stale-flag cleanup into the Unleash sync pipeline, sorts the /models API response alphabetically, and groups feature flags by category in the UI. Well-structured with solid test coverage. No blocking or critical issues found. Issues by SeverityBlocker Issues: None Critical Issues: None Major Issues: None Minor Issues: M1. StaleFlagsFromManifest includes unavailable models that never had flags The function iterates all non-gated models regardless of Available. Models with available=false were filtered out by the old FlagsFromManifest so no Unleash flag was ever created for them. Cleanup handles this gracefully (existence check before DELETE), but it produces unnecessary API round-trips. Fix: add the Available filter to the skip condition to mirror FlagsFromManifest. M2. respBody is read unconditionally in archiveFlag on success paths io.ReadAll is called before the switch statement, but respBody is only used in the default error branch. On 200/202/204 paths the buffer is allocated and discarded. Minor IO waste; not a correctness issue. M3. sort.Slice is not stable Current model labels are unique so instability will not manifest in practice, but sort.SliceStable would be semantically cleaner for a deterministic API response. M4. Cleanup-only-after-successful-sync behaviour is undocumented If SyncFlags fails on every retry (e.g. Unleash unreachable at startup), CleanupStaleFlags is never called. Intentional design trade-off, but not captured in the SyncAndCleanupAsync godoc. A one-line comment would help future readers. Positive Highlights
Recommendations
|
Merge Readiness — Blockers Found
|
Summary
featureGated: falseinmodels.json/modelsAPI response alphabetically by label for consistent frontend dropdown orderingChanges
Stale flag cleanup (
sync_flags.go,main.go)StaleFlagsFromManifest()— identifies flag names for non-gated models that should be removed from UnleashCleanupStaleFlags()— checks if each flag exists in Unleash and archives it via the Admin API DELETE endpoint; silently skips flags that don't exist (idempotent)archiveFlag()— callsDELETE /api/admin/projects/{project}/features/{name}, treats 404 as successSyncAndCleanupAsync()— runs sync then cleanup in a background goroutine with retries; cleanup failure is non-fatal (logged but doesn't trigger retries or block startup)SyncModelFlagsFromFile(CLI subcommand) and server startup inmain.goSorted models response (
models.go)ListModelsForProjectnow sorts the filtered model list byLabelbefore returning, so the frontend dropdown is always alphabetically ordered regardless of manifest order or flag stateTests (
sync_flags_test.go)TestStaleFlagsFromManifest_ReturnsNonGatedModels— verifies non-gated models produce stale flag namesTestStaleFlagsFromManifest_EmptyWhenAllGated— empty result when all models are gatedTestCleanupStaleFlags_ArchivesExistingFlags— mocks Unleash, verifies DELETE called with correct pathTestCleanupStaleFlags_SkipsNonExistentFlags— 404 from GET → no DELETETestCleanupStaleFlags_SkipsWhenEnvNotSet— graceful no-op when Unleash not configuredTestCleanupStaleFlags_EmptyList— early return for nil inputTest plan
cd components/backend && go vet ./... && go test -tags test ./cmd/UNLEASH_ADMIN_URLandUNLEASH_ADMIN_TOKENare setsync-model-flagsCLI subcommand archives stale flags after sync🤖 Generated with Claude Code