Skip to content
Merged
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
34 changes: 34 additions & 0 deletions devlog/_plan/260912_operations/000_plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Operations delivery roadmap

Operators need accurate startup failures, safe update retry cleanup, readable usage, and actionable connected-client guidance. This unit carries the remaining reviewed contributions and repairs their current callers. The original stop-refusal implementation is already present on dev; it is not applied twice.

Loop: satisfy-spec HOTL, triggered by the operations lane assignment. Goal: reviewable PRs with final-tip hosted evidence and a durable handoff. Non-goals: merging, closing originals, releases, live service/config changes, local product suites/build/typecheck/install. Scope: this managed worktree and explicitly authorized GitHub PR writes; existing credentials only. No user token/time/agent-count cap. Stop only after every disposition, acceptance row and final-tip result is recorded, or an actual unavailable external gate is documented. Memory artifact: this unit and ignored .tmp/operations/handoff.md. Escalation: real tool/access denial or scope beyond assigned issues; main owns code and decisions. Native architect role is unavailable; supported inherited design reviews plus separate A audits follow explicit user direction.

## Work-phase map

| ID | Document | Outcome | Dependency |
| --- | --- | --- | --- |
| roadmap | 000 + all decade docs | Docs-only source-grounded roadmap | none |
| update | 010_update.md | Retire observed exited pinned children (#4185) | roadmap |
| listeners | 020_listeners.md | Name auxiliary bind failures and malformed edits (#4236 residual) | roadmap |
| totals | 030_totals.md | Keep readable usage and disclose omissions (#4111) | roadmap |
| client-usage | 040_client_usage.md | Hub usage scoped to connected client (#4205) | roadmap; preserve totals contract if shared |
| pairing | 050_pairing.md | Hub identity and origin-specific browser authentication (#4206/#4208) | roadmap |
| transport | 060_transport.md | Reviewed local management catalog read (#4315/#4317) | roadmap |
| verification | 070_verification.md | Exact tips, hosted results, credits, handoff | all implementations |

Independent changes use independent branches/PRs from the fetched dev baseline plus the common roadmap checkpoint. Only actual shared-code dependencies become an ordinary manual chain. No native stack registration. Intermediate auto-CI stays enabled; final cumulative tips are the acceptance unit.

## Source disposition

- #4170 OPEN at 4d72ef010363b80cd78f65148a5228d6797a3117, but dev contains 1ada8f5ff1 and further refusalNextStep behavior in src/lib/process-control.ts. No duplicate carry. Missing-message incident and actual scheduler behavior are not proven resolved by wording.
- #4185 OPEN at 2602f3ceca4b93237436911dcd8dffc35b3b5e57; current src/update/job.ts still uses lastChild.pid alone.
- #4111 OPEN at 2f07acb58b3e73f48cea38334f301b430a8634cd. Readable totals differ from connected-client routing.
- #4317 OPEN / CHANGES_REQUESTED at 27f577aa795f3b968c070a50eded48411bd7e985. Independent security review and own caller-complete patch required. Sensitive analysis stays in ignored scratch.
- #4236 latest public comment identifies only auxiliary listener bind diagnosis and malformed edit reporting as outstanding. #4249/#4250/#4251/#4252/#4254/#4255 are already landed and must not be replayed.

## Evidence policy

Local suites of every size, typecheck, builds and install: NOT RUN by explicit user instruction. Regression code goes to GitHub-hosted Cross-platform CI, whose pull_request trigger has no base filter (.github/workflows/ci.yml:3). Docs consistency uses git diff --check and file-map inspection, not claimed test coverage. Source review is not execution. Each final source SHA is paired with its actual run ID/URL/conclusion; skipped/cancelled runs are not passing proof. Every C/D records this limitation and defers behavioral acceptance to final hosted results.

Existing tree conventions: src/cli owns commands, src/server owns listener/management boundaries, src/update owns update retries, gui/src owns React presentation, tests mirrors domains, structure/manifest.json maps owning docs. No new dependencies, service layer, or settings are needed.
7 changes: 7 additions & 0 deletions devlog/_plan/260912_operations/001_roadmap_audit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Roadmap audit outcome

Independent design reviewers accepted the update, listener, usage, pairing and local-catalog designs after reflection. Native architect selection was unavailable; user-directed inherited model review was used without a native-role claim. Two reflection calls initially reported model capacity errors; same-handle retries completed.

Independent A reviewer identified nested managementIngress degradation hidden by schema catch and an incomplete CLI regression path. Both were folded in and re-audited. Final verdict: GO-WITH-FIXES (blockers=0); remaining deps.managementOrigin wording corrected before lock. This audit certifies the plan only, not implementation or test behavior.

The first cycle is docs-only. All eight roadmap files exist, source/test paths were reviewed, and git diff --cached --check exits zero. Product suites/build/typecheck/install NOT RUN by explicit instruction. Next direction: implement the observed-child cleanup slice from 010, then the independent listener slice. Final-tip hosted CI owns behavior acceptance. No retired update architecture or already-carried stop implementation is replayed.
13 changes: 13 additions & 0 deletions devlog/_plan/260912_operations/010_update.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Pinned child retirement

Class C4: process termination boundary. Dependency: roadmap. Reuse the existing RestartIo and restartAfterUpdate retry loop; no new process supervisor.

MODIFY src/update/job.ts: RestartIo gains injectable spawnDetachedStartFn, preparePortForPinnedStartFn, waitForGhostListenClearFn and killProxyFn, matching existing functions. Replace Date.now in the pinned retry window with existing io.now. Replace both lastChild.pid-only kills with one closure accepting the ChildProcess: return when pid absent, exitCode non-null, or signalCode non-null; otherwise existing isAlive then kill. Capture the exact spawned child and attach once(exit) to clear lastChild only when lastChild === child. Keep healthy-probe early return. No persisted schema or serialization changes; these are process-local IO seams consumed in the retry loop only.
Comment thread
lidge-jun marked this conversation as resolved.

MODIFY tests/update/update-job.test.ts: carry #4185 deterministic fake EventEmitter children through actual three retries, using injected clock and no real kill. Cases: successful exit, nonzero exit, signal exit, event retirement, live timeout cleanup, same-PID late old event, healthy last attempt. MODIFY tests/windows/windows-deploy-close-regressions.test.ts: replace obsolete exact PID-expression oracle with reference to behavior regression; keep wrapper ownership assertions. MODIFY structure/runtime.md to state observed-child retirement. Existing process code is otherwise unchanged.

Exact starting patch: public PR #4185 head 2602f3ceca4b93237436911dcd8dffc35b3b5e57, reviewed source diff retained locally in .tmp/operations/pr-4185.diff. Before: numeric PID may remain after child exit. After: recorded exit/signal or matching exit event retires cleanup authority. This does not make all OS signalling atomic against PID reuse.

Planned hosted activation checks (not yet executed): seven tests in update/update-job.test.ts exercise both cleanup sites. Local execution NOT RUN. Source check: both sites use the same child-aware closure; no unrelated test weakened. Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com>.

Follow-up080 extends exact-child retirement to error/close/exit and releases its own handlers; failed spawn error+close without exit is covered separately. Local tests remain NOT RUN.
13 changes: 13 additions & 0 deletions devlog/_plan/260912_operations/020_listeners.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Auxiliary bind diagnosis and malformed edit reporting

Class C3; dependency roadmap. Existing owners: src/server/ports.ts: isAddrInUse, src/server/index.ts: startup transaction, src/cli/index.ts: handleStart retry loop, src/config.ts: loadConfig warnings.

MODIFY src/server/ports.ts: add AuxiliaryListenerBindError carrying listener name (unauthenticatedLoopbackListener or hub.managementIngress), port, hostname and original cause. Its message names the precise config key/address and directs correction of that effective auxiliary address (including a port-less companion). MODIFY src/server/index.ts: keep synchronous rollback of opened listeners, wrap only each auxiliary Bun.serve failure after rollback. MODIFY src/cli/index.ts: reject AuxiliaryListenerBindError before generic isAddrInUse retry logic. Public-listener EADDRINUSE retains soft/hard-pin behavior; auxiliary collisions never re-pick the public port. Fields are transient Error data, created by both auxiliary catches, consumed by CLI; no serialization.

MODIFY src/config.ts: reuse load-time degraded-field warning family. When raw unauthenticatedLoopbackListener is present and validated value disappeared, emit field-specific warning without raw values; keep valid providers/keys and file bytes. The same pure warning is exposed by validFileConfigDiagnostics, so doctor/status also report degradation. Existing write-time loopbackListenerPortError stays strict. Whole-hub malformed blocks already warn, but nested hub.managementIngress can be silently swallowed before that check. Add a raw-versus-validated nested-ingress warning to the same owner and diagnostics. Cover string enabled and invalid port for BOTH listener blocks, preserving providers/file bytes.

MODIFY existing tests/server/ports.test.ts and tests/server/loopback-listener-integration.test.ts : occupied loopback and management ports must report their config key and actual port, preserve cause and release every successful bind; non-EADDRINUSE errors identify bind failure without claiming the port is busy. Public conflict remains classified normally. Extend tests/config/config-load-degrade.test.ts and tests/server/loopback-listener-admission.test.ts with string enabled and out-of-range port: warning present, provider preserved, file unchanged. No local socket or service operation: tests only written, run remotely.

MODIFY directly relevant structure/runtime.md, structure/config.md, structure/ops/service-and-sidecars.md and public hub/loopback guidance; link the canonical contract from other mapped ownership docs only where applicable. Review all conditional activation rows on hosted CI. Source inspection is not runtime proof.

Design OPS-LIST-01..04 accepted with amendments. NEW tests/cli/cli-start-auxiliary-bind.test.ts, registered in both test-layout files, uses isolated CLI subprocess to cover soft and hard-pinned startup: failure names auxiliary key/address, exit nonzero, no public repick/wait branch. Existing management rollback fixture occupies management first then selects distinct public/loopback ports. Warning helper runs on all three load return paths plus read-only diagnostics; controls cover absent and valid-disabled entries and malformed secret-shaped input without echoing raw values.
11 changes: 11 additions & 0 deletions devlog/_plan/260912_operations/030_totals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Readable usage totals with explicit omissions

Class C3; dependency roadmap. Adopt public #4111 final diff (2f07acb58b3e73f48cea38334f301b430a8634cd) after current-base and latest-review audit; preserve luvs01 credit. Source diff and metadata are in ignored .tmp/operations/pr-4111.diff/json, fetched directly from GitHub.

MODIFY src/server/management/usage-aggregate-cache.ts: replace four oversizedRows throws with retained usageIncomplete boolean, set on full scan, OR on append, preserve in resultFrom; cache API-key snapshots with diagnostic. MODIFY api-key-usage.ts: keep readable accumulator output and attach usageIncomplete:true / usageIncompleteReason:oversized_rows instead of throwing. MODIFY logs-usage-routes.ts: serialize diagnostics on filtered and unfiltered summaries. MODIFY usage-summary-cache.ts CachedUsageSummary and oauth-account-routes.ts GET /api/keys to retain/serialize flags. Other IO/mutation errors still fail.

MODIFY src/cli/usage-report.ts: warnings precede totals/no-match branch; incomplete no-match says skipped records may match. MODIFY gui/src/usage-summary-resource.ts shared optional diagnostic type; NEW components/usage-incomplete-notice.tsx; extend consumers Usage, dashboard overview, Models, AddProviderModal, ProviderWorkspaceShell, ApiKeysWorkspace/ListPanel and ApiKeys. Incomplete keys do not claim inactivity; warnings survive consumer caching. Add all locale keys. Full field chain: scanner oversizedRows -> retained aggregate boolean/API key snapshot -> route JSON/cache -> shared GUI/CLI input types -> every totals/ranking/key activity consumer.

MODIFY existing tests/cli/cli-usage-report.test.ts, tests/server/api-usage.test.ts, tests/server/api-key-attribution.test.ts, tests/usage/usage-aggregate-cache.test.ts and GUI usage/custom-range/model-picker/key-workspace tests; NEW gui/tests/usage-incomplete-consumers.test.tsx. Activation: good + oversized + good rows yields readable sums and warning; append oversized sticky flag, full clean rewrite clears it, missing filter matches stays uncertain, loading/stale consumers retain warning. Do not turn IO errors into zero totals.

MODIFY structure/gui-and-management-api.md and relevant mapped contract pointers; public management API, CLI agents and web-dashboard guides in all existing translated paths from original diff. Hosted full CI and dashboard evidence certify final tip; local suites/build/typecheck NOT RUN. This does not implement hub client-scoped CLI usage (#4205).
13 changes: 13 additions & 0 deletions devlog/_plan/260912_operations/040_client_usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Connected client usage

Class C4 for credential scope; dependency roadmap and only shared usage contract if needed. Existing src/cli/observe.ts:155 usage currently calls runtimeRequest('/api/usage'), whose owner src/cli/runtime-api.ts always resolves a local endpoint. Connected machine listener does not expose that route.

MODIFY observe.ts usage dispatch to inspect existing client connection state before choosing the endpoint; standalone keeps runtimeRequest unchanged. Reuse the existing client-to-hub request owner and add a dedicated client-authenticated /v1/usage read, with only the enrolled client credential. Fail closed on invalid/mismatched state. Retain range/surface/provider/model and inclusive custom-window options, JSON versus human output, endpoint error messages and hub key scope. Do not send the local admin token to the hub or expose global management usage. If the existing hub endpoint supports fewer selectors, reject unsupported options explicitly until it is extended with the same authenticated scope.

MODIFY existing client/hub API owner only where the read contract requires it; extend CLI usage and hub admission regression owners. Activation: connected client succeeds with own-key data despite local /api/usage absence; second client data excluded; revoked/bad credentials refuse; standalone still uses local management; custom-window contract preserved. Exact file map: NEW src/server/hub-usage.ts route handler and src/remote/hub-usage.ts shared response contract; MODIFY src/server/index.ts dispatch near /v1/models, src/server/auth-cors.ts configured-key identity resolver, src/client/hub-client.ts authenticated client read, src/cli/observe.ts usage dispatch, src/cli/usage-report.ts source/scope label. The route requires explicit configured-key admission even on loopback, derives apiKeyId from that identity, rejects caller-selected key IDs, uses filtered aggregation and no hub-wide summary cache. It omits private account attribution from the client DTO. Authentication/route enforcement tier: server code; caller-selected IDs cannot override the authenticated key; local admin/host control remains a residual outside client isolation. Final layer: server authorization. No claim of protection against the host owner. No local credential provisioning or running client changes.

MODIFY public connected-client/CLI usage guide and structure/runtime.md / gui-and-management-api.md canonical scope. Any pre-disclosure details stay in scratch. Hosted regressions only; local execution NOT RUN.

Accepted design OPS-USAGE-02/03/04. NEW tests/server/hub-usage.test.ts and tests/clients/hub-usage.test.ts with entries in scripts/test-layout/layout.json explicit and tests/fixtures/test-layout-expected.json; NEW tests/cli/cli-usage-hub.test.ts. Tests use two client keys, loopback and remote admissions, invalid state, custom window, unsupported endpoint, bad response, expired/revoked credentials. Full implementation follows source confirmation before B.

Reflection amendments: getFilteredUsageAggregate in src/server/management/usage-aggregate-cache.ts is the aggregation owner. Client DTO preserves #4111 incomplete flags; CLI suppresses advice to remove filters for account totals because that scope never exports accounts. Public files: docs-site/src/content/docs/guides/remote-hub.md and reference/cli/agents.md. All three new tests register in scripts/test-layout/layout.json and tests/fixtures/test-layout-expected.json.
13 changes: 13 additions & 0 deletions devlog/_plan/260912_operations/050_pairing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Pending browser authentication guidance

Class C3; dependency roadmap. Reuse existing connected-client state and browser-auth components. Target #4206 and #4208 together because both concern the same pending local-dashboard pairing journey.

MODIFY owning dashboard pending-auth component and bootstrap state: distinguish a reachable connected machine awaiting hub browser authentication from a stopped standalone proxy. Show configured hub identity/origin, explain that machine enrollment and browser session are separate, offer the current origin-specific existing pairing/authentication action. Preserve revoked/expired/unreachable states and their existing retry actions; do not suggest ocx start while the local runtime is reachable. Derive the next action from current origin + configured hub instead of a hardcoded localhost URL. No credentials appear in visible copy/URLs.

MODIFY all gui/src/i18n locale dictionaries with meaningful labels. Extend existing pending-auth/dashboard tests for local origin, remote hub origin, pending, authenticated, expired/revoked and unavailable standalone; positive browser auth transitions into connected dashboard. Exact files: gui/src/App.tsx, api.ts, pages/dashboard-core-poll.ts, pages/use-dashboard-data.ts and pages/Dashboard.tsx consume a classified authentication/error state instead of a boolean. Existing connect-pairing.ts and connect-pairing-transport.ts own hub identity and origin-specific action. Define the error classification in api.ts at response ingress; consume in polling and Dashboard; reset on authenticated success and pairing completion. No persistence/serialization for this UI state. Keep cached data with stale labeling when auth fails; do not erase a known hub into standalone offline. Public hub/browser-pairing guidance is updated with the same distinction. No service restart or live auth reconfiguration.

Hosted component suite and screenshot artifact of the rendered pending state required for final delivery; local GUI tests/build NOT RUN. Static source or mockup is not rendered application evidence.

Accepted OPS-PAIR-01/02. Cases include browser session expiry and post-pairing refresh, local and hub origin guidance, code versus API/admin-key explanation, and operator handoff text. Prefer existing component tests; new test files only where needed.

Reflection amendments: reuse existing api.ts SESSION_UNAVAILABLE_EVENT and App sharedSessionReady; subscribe in App, emit on terminal 401 expiry (not aborted requests), reset/read refresh on successful pairing. Do not create duplicate auth state. Poll classification and pairing errors distinguish HTTP auth refusal, transport/network, and invalid responses; aborted work does not show a failure.
Loading
Loading