Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ chart's `appVersion`; the image and chart are released together under it.
- The chart can install a writable catalog — the swiss chart's catalog-server, swiss 0.7.0+; named in the site profile, it lets the Model Library add models even when the site's own catalog is a read-only static index (#90).

### Changed
- Deploy and upgrade share one configuration draft between structured controls and YAML, with read-only baseline/effective panes, current-revision comparison and a visible **Edit YAML** action in the top toolbar. Saving uses the existing form/YAML API and preserves saved form settings omitted from YAML; no deployment-service upgrade is required.
- The swiss subchart is 0.7.0 (was 0.6.3). 0.6.3 predates catalog schema v2 and the site profile's `schemaVersion`/`writable`, so with a bundled swiss the Model Library could not read a v2 catalog or save one (#90).

### Fixed
- Editing deployment configuration preserves unrelated values, keeps form/YAML changes synchronized, and invalidates a review when its inputs or running revision change. Final previews include later system layers.
- Overlay panels keep their edge. The site-wide "no focus ring" rule zeroed the `ring-1` that draws the border of menus, popovers, selects, comboboxes and dialogs, so an open white panel on the white page showed only a faint shadow — the top-bar avatar menu read as a line of text floating under the header.
- The top-bar avatar menu names the signed-in user — avatar, name, role and, when console has one to read, the email — instead of a single `name · role` line. With `server.auth.disabled` the user button itself turns amber and the avatar carries a dot, so the state shows without opening anything and the bar gains no element; the menu carries 登录已关闭,当前为管理员身份 (*Sign-in off — acting as the administrator*) in place of change-password and sign-out, which that mode cannot honour.

Expand Down
40 changes: 33 additions & 7 deletions docs/console-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ DeploySheet -> GET /api/llm/route-options[?route=<existing>]
The deploy and upgrade forms expose the charts' existing `continuationGateway` values (console #63).

```text
form -> recovery values -> adaptive compose -> optional timeout reset -> validate -> diff -> apply
form <-> user values <-> YAML -> compose -> validate -> diff -> apply
nginx -> continuation gateway -> CART -> engine
```

Expand All @@ -351,10 +351,36 @@ nginx -> continuation gateway -> CART -> engine
| Controls | Enable gateway, actual model identity, idle timeout, continuation execution and tool-call buffering |
| Upgrade state | Seed from the stored plan once; query refreshes preserve edits |
| Validation | Check all recorded plan layers, chart compatibility, CART, ModelRoute, actual model, timeout and engine |
| Advanced YAML | Preserve precedence; stop when its effective settings differ from the recovery controls |
| Timeout reset | Clearing removes a retained form override by recomposing the validated form without `fromRelease`, pinned to the resolved source and chart |
| Integrity | Recovery and adaptive cleanup share source pinning and normalized plan comparison; reject unrelated changes |
| Ownership | Existing plan API and chart values; copied Swiss sources remain unchanged |
| Configuration draft | Structured controls and YAML share one document; validate recovery against the complete server composition |
| Timeout reset | Keep the existing guarded cleanup for an explicit form reset; omitted YAML alone retains saved form settings |
| Integrity | Keep `fromRelease` validation and later system layers; verify the running revision before and after planning and before apply |
| Ownership | Existing chart values, form/edit layers and plan/diff/apply API; no backend change |

### Unified deployment configuration

Deploy and upgrade use one shared editing model; structured controls patch their owned paths and YAML edits project back into those controls.

| Surface | Source |
|---|---|
| Deployment baseline | Chart defaults plus non-user target layers, composed by the deployment service |
| User configuration | YAML draft over retained form settings; unknown values and comments survive form edits |
| Effective configuration | The deployment service's complete layer order; read-only |
| Current configuration | The running revision's actual Helm values; independent of target defaults |

```text
form <-> user document <-> YAML
|
overrides + editsYAML + fromRelease -> compose -> diff -> apply
^ |
+---------- re-preview <---------+ (revision moved)
```

- Open the editor through **Edit YAML** in the deployment form's top toolbar; the YAML summary field also names its format explicitly.
- Use existing `overrides` and `editsYAML` requests. Upgrades merge form values and replace the YAML override layer; omitted YAML fields preserve saved form settings. No backend capability is required.
- Invalid YAML remains editable and blocks structured changes and planning. Preview failures retain the draft and clear the effective display.
- Disabling a feature retains its settings unless an existing explicit cleanup action removes dependent fields. Removing a YAML-only override reveals the underlying form or target value.
- System layers that change a user value appear with the configured value, effective value and responsible layer.
- Design and local checks: `docs/plans/2026-11-07-deployment-configuration.md` and `2026-11-07-deployment-configuration-checks.md`.

### Unpublished Monitor integration

Expand All @@ -377,8 +403,8 @@ The master switch and every `needsAdaptive` field share one section (console #75
| Groups | Gateway `needsAdaptive` metadata decides membership; known `adaptive_cc_*` keys are recognized without a live catalog |
| Off | Hide dependent common/advanced inputs, clear their entered values, and prevent adding adaptive custom keys while off |
| Capacity | `default_max` remains in Capacity & failover; it governs limits even with adaptive control off |
| Upgrade removal | Swiss `fromRelease` recursively retains omitted map keys. Compose normally first for its model-move/chart validation; if stale adaptive form keys survive, recompose the full validated form with those keys removed, pinned to the just-resolved model/version/chart |
| Integrity | Preserve unrelated form values and explicit advanced YAML; reject source/chart identity or other layer changes between the two compositions |
| Upgrade removal | Keep the existing guarded recomposition for explicit dependent-parameter cleanup; effective preview follows the same final request |
| Integrity | Preserve unrelated user values; normal upgrade composition retains source/chart validation and later system layers |
| Application | Only the cleaned plan enters the existing diff/revision/apply flow; composition performs no workload write |

### Workload reads (`/api/k8s/...`)
Expand Down
100 changes: 100 additions & 0 deletions docs/plans/2026-11-07-deployment-configuration-checks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Deployment configuration check log

This records the current Console-only implementation, verification evidence and review history for [PR #81](https://github.com/modelsphere/console/pull/81), related to [issue #66](https://github.com/modelsphere/console/issues/66).

## Scope after review — 2026-11-08

| Concern | Current decision |
|---|---|
| Backend | Use the existing form/edit API; withdraw the complete-user-values proposal in [Swiss PR #52](https://github.com/modelsphere/swiss/pull/52) |
| Shared editing | Keep the approved three-pane UI and bidirectional form/YAML updates |
| Saving partial YAML | Preserve omitted saved form settings; YAML remains an override layer |
| Explicit cleanup | Retain the existing guarded timeout/adaptive cleanup flows; preview reuses their final request |
| System layers | Show the actual server result; no new canary lifecycle or autoscaling runtime behavior |
| Identity | Keep the actual service identity locked; reject conflicting YAML before composition |
| Compatibility | No new request field, capability or backend release dependency |

- Design: [deployment configuration](2026-11-07-deployment-configuration.md).
- Request semantics: [existing API contract](2026-11-07-deployment-values-contract.md).
- Browser scenarios: [fixture guide](../../web/test/README.md).
- Release notes: `CHANGELOG.md`.

```text
form <-> shared YAML draft
|
existing overrides + editsYAML -> compose -> diff -> apply
|
same final request -> effective preview
```

## Regression checks

| Behavior | Evidence |
|---|---|
| Partial YAML | Missing replica/image/form-only keys retain the saved form; only supplied YAML keys override them |
| YAML-only clear | A form submission with empty edit YAML clears the prior edit layer while retaining saved form settings |
| Bare upgrade | Existing requests without form overrides retain their previous edit layer |
| Structured changes | Owned paths update the YAML; unknown keys and comments survive |
| Timeout/adaptive reset | Combined cleanup preserves unrelated values; dry-run uses the final pinned request and does not resurrect removed fields |
| GPU clearing | Distinguish omission from an explicit selector clear; remove the whole required rule when no constraints remain |
| GPU automatic selection | Read target defaults/catalog/site/derived constraints and the supported server-resolved resource; do not revive a saved selector/resource |
| Older GPU charts | Continue selecting products when the chart intentionally omits the default GPU resource field |
| GPU constraints | Preserve unrelated zones, matchFields, preferred affinity and selector grouping |
| Revision checks | Check the live revision around snapshot/planning and before apply; keep drafts after stale-result rejection |
| Identity | Reject a changed or null YAML serviceId while retaining the locked actual identity |

## Current automated verification

| Check | Result |
|---|---|
| Frontend suite | 65 files / 605 tests passed (`pnpm --dir web test`) |
| Both TypeScript configurations | Passed (`pnpm --dir web run typecheck`) |
| Console production build | Passed (`pnpm --dir web run build`) |
| Standalone frontend build | Passed (`pnpm --dir web run build:swiss`) |
| Console Go checks | `go vet ./...` and `go test ./...` passed |
| Review | React, TypeScript and legacy API-contract review completed; reported regressions fixed and rechecked |
| Whitespace | `git diff --check` passed |

Both builds retain the existing chunk-size advisories. No chart or backend source was changed.

## Browser verification — existing API fixture

- All scenarios omit the new capability field and use `overrides` plus `editsYAML`.
- Upgrade baseline/effective panes load through the existing plan/dry-run endpoints.
- Pasting only `image.tag` leaves the form's stored replica count at 2.
- Changing the form replica count to 3 inserts `replicaCount: 3` into that partial YAML and preserves the image tag.
- Changing YAML to `replicaCount: 4` updates the form to 4 and reaches deployment review.
- Clearing the saved H100 selection resolves to the target default H100/H800 set and preserves preferred affinity.
- Autoscale shows the configured count 2 alongside the server-effective count 4.
- The 390px layout has no document overflow; desktop and mobile layouts were inspected.
- The fixture blocks live install/apply and unexpected network access.

Browser checks use fixture API data; no live model deployment or crash-recovery validation was performed.

## Production integration

| Entry | Shared implementation |
|---|---|
| Model library deployment | `components/DeploySheet.tsx` |
| Model detail deployment | `components/DeploySheet.tsx` |
| Service list upgrade | `components/DeploySheet.tsx` |
| Service detail upgrade | `components/DeploySheet.tsx` |

```text
production page -> DeploySheet -> shared draft / three-pane editor
|
/api/deploy/plans -> authenticated Console proxy -> existing deployment API
```

The production app enters through `web/index.html` and `src/main.tsx`; the fixture is isolated under `web/test`.

## Review history

- Console baseline: `bac3654b249cc67f3ed03e3807ff0bc51de9f8a6`.
- The original paired backend commit `9a0cd9e` introduced complete replacement and a capability requirement. Its local/CI tests passed, but review identified an ownership/compatibility design blocker. That implementation is withdrawn and its tests are not evidence for the current Console-only solution.
- Review corrections restore existing persistence semantics, retain explicit cleanup, and cover stored GPU affinity/resource and service identity at the Console boundary.

## Repository artifacts

- Verification screenshots are kept outside the repository; the PR contains text verification records only.
- Binary files must not be committed to this repository.
47 changes: 47 additions & 0 deletions docs/plans/2026-11-07-deployment-configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Unified deployment configuration

The approved prototype uses one user draft for structured controls and YAML. The implementation decisions and verification are recorded in this document and its check log.

| Surface | Data |
|---|---|
| Target baseline, read-only | Chart values and non-user configuration for the selected target |
| User configuration, editable | Shared YAML draft projected over retained form settings; invalid text remains editable |
| Effective configuration, read-only | Swiss's complete composition including system layers |
| Current deployment comparison | The current Helm revision's actual values, independent of target defaults |

```text
form <-> user draft <-> YAML
|
Swiss compose -> diff -> apply
^ |
+--- re-preview <--+ (revision changed)
```

## Data and compatibility

- Reuse the existing form serializer/deserializer to project structured controls; preserve unknown YAML keys.
- Keep release identity and apply flags separate from chart values.
- Seed upgrades from explicit form/edit layers; never seed user overrides from Helm's merged defaults.
- Present stored form/edit settings in one draft, then submit the existing `overrides` and `editsYAML` fields. A partial YAML document retains omitted form settings.
- Keep the existing guarded timeout/adaptive cleanup paths for explicit form actions; reuse their final request for the effective preview.
- Use the same composition path for the editor's effective values and deploy review. The UI never appends user YAML after system layers.
- Read and verify the current Helm revision before composing/applying an upgrade. On a mismatch, retain the draft and allow an explicit refresh and new preview.
- Reuse authenticated plan, dry-run Helm values, status and revision-values endpoints. No backend API or capability change is required. See [existing API contract](2026-11-07-deployment-values-contract.md).
- Invalid YAML disables structured changes and composition; source/read failures never become empty successful previews.

## Delivery

1. Test the shared draft and version/compose boundaries.
2. Replace the multi-tab editor with read-only baseline, editable user YAML and read-only effective panes.
3. Integrate the draft, current-revision comparison and preflight checks into deploy/upgrade.
4. Record validation in `2026-11-07-deployment-configuration-checks.md` and user-visible changes in CHANGELOG.

## Interaction decisions

- Structured controls and YAML share one editing model; persisted form and YAML layers retain their existing ownership.
- Project fields from YAML over retained form settings and the selected target baseline. YAML omission preserves the saved form value.
- Patch only the paths owned by changed controls; retain unknown keys and comments.
- Disabling a feature preserves its configuration for re-enabling. Enabling a scaler removes the conflicting fixed replica override.
- Resolve GPU product/resource changes through the deployment service before committing its generated terms to the document. Preserve other required/preferred affinity and original selector groups.
- Bind model paths/resources to their YAML paths; keep release identity and apply flags separate.
- Keep the baseline and final panes read-only; obtain the final configuration through the deployment composition path.
29 changes: 29 additions & 0 deletions docs/plans/2026-11-07-deployment-values-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Deployment configuration on the existing API

Console synchronizes form controls and YAML while retaining the deployment service's existing form/edit ownership.

| Input | Existing behavior |
|---|---|
| `overrides` | Structured form values; upgrades merge these into the saved form layer |
| `editsYAML` | YAML override layer; a form submission replaces the previous edit layer |
| Omitted YAML field | The form or target baseline remains effective; omission does not erase saved form settings |
| Explicit YAML `null` | Existing Helm deletion semantics |
| `fromRelease` | Validate the release/source and carry the settings and system state supported by the existing service |

```text
stored form + target baseline -> form projection <-> YAML draft
|
overrides + editsYAML + fromRelease
|
compose -> diff -> apply
```

- The editor initially presents the stored form and edit values together. Structured edits patch only their owned paths and preserve other YAML and comments.
- Form projection includes retained saved form values beneath the draft, so pasting partial YAML does not reset the omitted controls.
- Keep the existing guarded recovery-timeout and adaptive-parameter cleanup flows for explicit form actions. Their source/layer checks still reject an unsafe recomposition.
- Effective preview reuses the final request selected by composition, including whether an existing cleanup flow removed `fromRelease`. It uses the same resolved target/chart and form/edit payload.
- Compose the read-only baseline separately against that resolved target without user layers. Obtain effective values through the server's full layer order.
- GPU changes resolve against the validated target, preserve unrelated required/preferred affinity, and use an explicit deletion when clearing a retained selector. Empty automatic choices use the target's resolved selector rather than restoring the saved selection. Where the chart exposes a GPU resource, write the actual resolved resource back to the shared document; older charts may legitimately omit that key.
- There is no new request field, capability, backend upgrade requirement or autoscaling runtime change.

The earlier complete-`userValues` proposal was withdrawn after review. [Swiss PR #52](https://github.com/modelsphere/swiss/pull/52) is no longer a dependency of [Console PR #81](https://github.com/modelsphere/console/pull/81).
11 changes: 11 additions & 0 deletions web/src/modules/inferences/components/ConfigurationOverrides.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Alert, AlertDescription } from "@modelsphere/ui";
import { useT } from "../i18n";
import type { ConfigurationOverride } from "../configuration-overrides";

const display = (value: unknown) => value === undefined ? "—" : JSON.stringify(value);

export function ConfigurationOverrides({ items }: { items: ConfigurationOverride[] }) {
const t = useT();
if (!items.length) return null;
return <Alert variant="warning"><AlertDescription><ul className="space-y-1">{items.map((item) => <li key={item.path}>{t("deploy.draft.managed", { field: item.path, requested: display(item.requested), actual: display(item.actual), source: item.source })}</li>)}</ul></AlertDescription></Alert>;
}
Loading
Loading