From 83fec7252fbc8996e2e28a253cd0271029a95ea1 Mon Sep 17 00:00:00 2001 From: Dawson Toth Date: Thu, 17 Sep 2026 11:13:58 -0400 Subject: [PATCH 1/4] Correct the deploy response and document the restart it does not do MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two things salvaged from #599, whose two-phase/revert content documents harper#1849 and harper#2301 — both closed without merging. The deploy_component response example still shows "Component deployed successfully". That string is not in core. The example requests a rolling restart, so the real response also carries restartJobId, and the message names the component. Deploying without a restart can flag a restart as needed, which nothing in reference/ said. A component that had no directory before the deploy has never been loaded, so its routes cannot serve until Harper restarts (v5.2.0); a redeploy whose package metadata changed invalidates loaded code that no plugin glob watches (v5.2.1). get_status reports it, per node. The route-miss 404 that names the component is super_user-only, because the difference between it and the generic 404 reports which component directories exist on disk. Co-Authored-By: Claude Opus 5 --- reference/operations-api/operations.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/reference/operations-api/operations.md b/reference/operations-api/operations.md index 256d42ac..2bf4f46a 100644 --- a/reference/operations-api/operations.md +++ b/reference/operations-api/operations.md @@ -999,10 +999,13 @@ Response: ```json { "deployment_id": "a3f8c2d1...", - "message": "Component deployed successfully" + "restartJobId": "b7d41e09...", + "message": "Successfully deployed: my-app, restarting Harper" } ``` +`restartJobId` is present only for `"restart": "rolling"`, which is the one path that hands the restart to a separate job. An inline `"restart": true` returns the same message without it, and a deploy that does not restart returns `Successfully deployed: my-app`. + #### Restarting (`restart`) @@ -1015,6 +1018,23 @@ The wait follows the restart's own progress rather than a fixed timeout, so a wi `drop_component` accepts `"restart": true` and waits for the restart the same way (v5.3.0). +#### Deploying without a restart + + + +A deploy that does not restart (`"restart": false`, or omitting `restart`) flags a restart as needed when it changed something the running process cannot pick up on its own. `get_status`, called with no `id`, then reports `restartRequired: true`. + +Two kinds of deploy set it: + +- A component that had no directory before this deploy. It has never been loaded, so its routes cannot be live until Harper restarts. +- A redeploy whose package metadata changed — a dependency or module-entry change invalidates loaded code, and package metadata sits outside most plugin file globs, so the component's own watcher does not see it. + +An ordinary redeploy sets nothing: the component's watched files are handled by its file watcher, which requests a restart only when the update needs one. + +The flag is evaluated per node. A peer applying the replicated deploy checks its own directory state, since whether the component was already active can differ from node to node. + +Until the restart happens, a request to a route of a never-loaded component returns a 404 naming the component and saying a restart may be needed, instead of the generic 404. That fuller message is returned only to an authenticated `super_user` — the difference between the two responses would otherwise report which component directories exist on disk. + ### Deployment Operations Harper records every `deploy_component` call in the `system.hdb_deployment` table, capturing the full lifecycle of a deployment including phase transitions (prepare → load → replicate → restart → success/failed), per-node outcomes, and a bounded event log of install output. From c068763d0d4201eb348894c96581d95a71956e39 Mon Sep 17 00:00:00 2001 From: Dawson Toth Date: Thu, 17 Sep 2026 11:24:05 -0400 Subject: [PATCH 2/4] Match the page's version convention, and let the super_user gate stand alone A mid-sentence VersionBadge reads as an interruption; the plain (v5.2.1) is what this page already uses for a version noted inside running text. The reason the fuller 404 is super_user-only is a security claim, not an aside on the sentence that precedes it. --- reference/operations-api/operations.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/operations-api/operations.md b/reference/operations-api/operations.md index 2bf4f46a..29643b97 100644 --- a/reference/operations-api/operations.md +++ b/reference/operations-api/operations.md @@ -1027,13 +1027,13 @@ A deploy that does not restart (`"restart": false`, or omitting `restart`) flags Two kinds of deploy set it: - A component that had no directory before this deploy. It has never been loaded, so its routes cannot be live until Harper restarts. -- A redeploy whose package metadata changed — a dependency or module-entry change invalidates loaded code, and package metadata sits outside most plugin file globs, so the component's own watcher does not see it. +- A redeploy whose package metadata changed (v5.2.1) — a dependency or module-entry change invalidates loaded code, and package metadata sits outside most plugin file globs, so the component's own watcher does not see it. An ordinary redeploy sets nothing: the component's watched files are handled by its file watcher, which requests a restart only when the update needs one. The flag is evaluated per node. A peer applying the replicated deploy checks its own directory state, since whether the component was already active can differ from node to node. -Until the restart happens, a request to a route of a never-loaded component returns a 404 naming the component and saying a restart may be needed, instead of the generic 404. That fuller message is returned only to an authenticated `super_user` — the difference between the two responses would otherwise report which component directories exist on disk. +Until the restart happens, a request to a route of a never-loaded component returns a 404 naming the component and saying a restart may be needed, instead of the generic 404. That fuller message is returned only to an authenticated `super_user`. The difference between the two responses would otherwise report which component directories exist on disk. ### Deployment Operations From f50aa5aa8ae2c04087c2a028da3a582bdb6d1edc Mon Sep 17 00:00:00 2001 From: Dawson Toth Date: Fri, 18 Sep 2026 11:21:32 -0400 Subject: [PATCH 3/4] Make the other two pages agree about the deploy response and get_status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both from @kriszyp's review. The 5.1 release note carried the same invented message this PR removed from the reference. `Component deployed successfully` was never emitted at v5.1.0 either — `git log -S` over components/operations.js finds the string in no commit on any branch — so this is not a historical record of an older response, and the note now shows what v5.1.0 actually returned. get_status was documented only as the status-value store, which left the restartRequired flag this PR points readers at undiscoverable. The no-id form returns an instance summary instead of a status value: systemStatus, componentStatus, restartRequired, and middlewareChains when the request asks for it (v5.2.0). Co-Authored-By: Claude Opus 5 --- reference/operations-api/operations.md | 25 ++++++++++++++++++++++++- release-notes/v5-lincoln/5.1.md | 2 +- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/reference/operations-api/operations.md b/reference/operations-api/operations.md index 29643b97..b8511c2e 100644 --- a/reference/operations-api/operations.md +++ b/reference/operations-api/operations.md @@ -1423,7 +1423,7 @@ Operations for restarting Harper and managing system state. | `restart_service` | Restarts a specific Harper service | super_user | | `system_information` | Returns detailed host system metrics | super_user | | `set_status` | Sets an application-specific status value (in-memory) | super_user | -| `get_status` | Returns a previously set status value | super_user | +| `get_status` | Returns one status value, or the instance summary | super_user | | `clear_status` | Removes a status entry | super_user | ### `restart` @@ -1458,6 +1458,29 @@ Manage in-memory application status values. Status types: `primary`, `maintenanc { "operation": "set_status", "id": "primary", "status": "active" } ``` +`get_status` has two forms, and the one you get depends on whether you pass an `id`. + +With an `id`, it returns that one status record: + +```json +{ "operation": "get_status", "id": "primary" } +``` + +**Without an `id`, it returns a summary of the instance** rather than a status value: + +```json +{ "operation": "get_status" } +``` + +| Field | Description | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `systemStatus` | Every status record set with `set_status` | +| `componentStatus` | Per-component health, aggregated across threads: `name` plus a `status` of `healthy`, `warning`, `error`, `loading`, or `unknown` | +| `restartRequired` | Whether a restart is pending on this node — set by a deploy that did not restart (see [Deploying without a restart](#deploying-without-a-restart)) and cleared on restart | +| `middlewareChains` | The resolved HTTP, upgrade, and WebSocket middleware order. Present only when the request passes `middleware: true` | + +`restartRequired` is per node: it reports the node that served the request, not the cluster. + --- ## Agent diff --git a/release-notes/v5-lincoln/5.1.md b/release-notes/v5-lincoln/5.1.md index fe8a2a9a..6452ceea 100644 --- a/release-notes/v5-lincoln/5.1.md +++ b/release-notes/v5-lincoln/5.1.md @@ -152,7 +152,7 @@ The response from `deploy_component` now includes a `deployment_id`: ```json { "deployment_id": "a3f8c2...", - "message": "Component deployed successfully" + "message": "Successfully deployed: my-app" } ``` From 3807a63b09d099f8b18917c1c32ce09f4977bdfb Mon Sep 17 00:00:00 2001 From: Dawson Toth Date: Fri, 18 Sep 2026 11:25:33 -0400 Subject: [PATCH 4/4] Keep the version out of the badge in the get_status table Every other table on this page notes a version as plain (v5.x.y) in the cell; the middlewareChains row I added reached for the badge instead, so one table rendered both ways. --- reference/operations-api/operations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/operations-api/operations.md b/reference/operations-api/operations.md index b8511c2e..8f85c924 100644 --- a/reference/operations-api/operations.md +++ b/reference/operations-api/operations.md @@ -1477,7 +1477,7 @@ With an `id`, it returns that one status record: | `systemStatus` | Every status record set with `set_status` | | `componentStatus` | Per-component health, aggregated across threads: `name` plus a `status` of `healthy`, `warning`, `error`, `loading`, or `unknown` | | `restartRequired` | Whether a restart is pending on this node — set by a deploy that did not restart (see [Deploying without a restart](#deploying-without-a-restart)) and cleared on restart | -| `middlewareChains` | The resolved HTTP, upgrade, and WebSocket middleware order. Present only when the request passes `middleware: true` | +| `middlewareChains` | The resolved HTTP, upgrade, and WebSocket middleware order (v5.2.0). Present only when the request passes `middleware: true` | `restartRequired` is per node: it reports the node that served the request, not the cluster.