Skip to content

Engine start budgets, status counters and owner-mode command updates - #9

Merged
Kurcide merged 52 commits into
mainfrom
update/engines-and-owner-mode
Nov 13, 2026
Merged

Kurcide merged 52 commits into
mainfrom
update/engines-and-owner-mode

Conversation

@Kurcide

@Kurcide Kurcide commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Change

Engine and owner-mode changes since 1.2.0, with the READMEs brought in line with the code. CHANGELOG.md and the version are not changed here; they belong to the release.

Engines

  1. Managed engine preparation records kit and explicit startup budgets for every engine kind for deployments prepared with this release. Kit manifests use startup_timeout instead of the unused startup_timeout_seconds spelling; previously prepared deployments retain their old budget until prepared again.
  2. Setup now checks startup_timeout for vLLM, SGLang and llama.cpp engines as it already did for native Docker engines: it must be an integer from 60 to 7200 seconds, or setup stops with Engine startup_timeout must be an integer from 60 to 7200 seconds (native Docker setups previously reported Native Docker startup_timeout …). Earlier releases accepted any value for these engines, so a plan with, for example, null, 1800.0, 30 or 10000 now stops setup until the value is corrected.
  3. The benchmark guide installs the checkout before Python commands that import its packages.
  4. Profiles in the startup configuration that were never activated, for example because they were added after the first start, are now activated at the next start; earlier releases did this only on the first start. A configured profile that cannot be staged or activated stops the start. Profiles deactivated with the profile admin commands stay deactivated.
  5. When a configured profile fails at start before its activation is committed, the start now removes the copy it staged, so repeated failed starts no longer fill the generation inventory. The original error is still reported, also when this cleanup fails. If the rollback itself fails, or the process is killed before the commit, the staged copy is kept; retire it with the profile admin commands.
  6. Native startup failures identify the failed readiness step and available cause; failed helper commands report their exit status and standard error.
  7. Benchmark and profile-evaluation errors identify the input option and validation failure without echoing private input contents. Their standard-error wording changes, so scripts matching the previous wording will see different messages.
  8. Every engine kit that exposes runtime status adds output_tokens_total, ttft_seconds_sum and ttft_seconds_count, with null for unavailable measurements, integer counts and a floating-point seconds sum. The engine contract now documents the status schema and tells clients to treat missing counter fields as unavailable.
  9. The text output of status, doctor and dashboard now shows graph mode, generation, expected, installed and exercised sites, active requests and GPU memory, and no longer shows the EXECUTION line; numerical_attestation remains in status payloads and --json output. Output rate and mean first-token time have values for engines that report the new counters.

Owner mode

  1. Channel selections saved with flashalign channels take effect without a restart on Hermes installs set up by this version; an existing allowed_channels setting still limits the plugin until it is removed or setup is rerun.
  2. Requests changed after ticket issuance explain their stock-mode fallback with request_changed, without reusing the ticket's identity metadata.
  3. Plugin managers in one process share the first registration's policy, settings and proxy until the last unload; later registrations' settings are ignored, and after an in-process upgrade, a new registration leaves the previous release's registration running and registers nothing.
  4. Unexpected ingress and request-middleware failures, mismatched loopback proxy routes and mismatched serving arguments write fixed warnings and decision entries; routine rejected messages and unrelated provider calls stay quiet.
  5. flashalign why shows recent decision reasons across Hermes, OpenClaw and direct gateways without message content, and retains readable rows when a log contains invalid bytes or a line nested too deep to parse, or cannot be read.
  6. Setup writes config.yaml as YAML with key order kept (comments, quoting, layout and anchor names are not kept; a string that a YAML 1.2 reader would take for a number, such as 1e3 or 08, is quoted), and changes only the properties it owns in the harness's JSON and JSON5 files; CRLF becomes LF, the files setup patches are read and written as UTF-8, and a harness configuration file that is not valid UTF-8 is refused and left unchanged. FlashAlign's own files (openclaw-bridge.json, setup-result.json and the client configuration) are written whole as strict JSON, as in earlier releases.
  7. flashalign pause turns owner mode off (stock replies; no turn counts as the owner's) and flashalign resume turns it back on, without changing saved contacts, channels, mode or tool settings.
  8. Access approval, revocation, mode, channel and tool commands are available from flashalign; one that the store refuses, such as an unknown channel or an empty contact, prints one line that starts with Access command stopped:, exits with status 1 and leaves the store unchanged.
  9. Provider gateways reuse their upstream HTTP client without imposing a connection cap and close it on shutdown, which ends replies still streaming.
  10. Every installed entry point in flashalign.engine_adapters, flashalign.model_adapters or flashalign.profile_adapters is loaded when a registry is first used, and again on each use until it loads; one that fails to load or collides with a built-in stops setup, profile validation and requests on routes with a legacy request-compatibility name until it is corrected or removed; setup and profile validation name its entry point and distribution, or its group, name and value when the entry point cannot be listed (an invalid name, the same name twice, or missing or invalid distribution metadata); the affected requests answer HTTP 502 provider wrapper unavailable without naming it, and the gateway log gets one OWNER_MODE_EXTENSION warning for each such request, naming the route and the extension, with nothing from the request and not the failure's own text; a profile adapter that collides or fails with an OSError or ValueError instead makes setup list every local profile as skipped, with that error, and continue to profile selection.
  11. The OpenClaw bridge and direct gateway append decisions to owner-mode.log beside their approval store by default, so these files grow as decisions are recorded; readiness polling does not add false failure rows.
  12. Setup writes the audit_log and auditLog settings into bridge and OpenClaw plugin configuration so both use the same decision log.
  13. Bridge error responses include a fixed reason field; the OpenClaw adapter records a fixed rejection code, outside readiness polls, when an HTTP error body is not JSON and returns the fixed control-failure message; its other control errors read Owner Mode control request failed: <reason>, and a connection failure reports control_unavailable instead of the connection error and, outside readiness polls, records it.
  14. A config.yaml that an older setup wrote as JSON is rewritten as YAML when setup saves it.
  15. Newly configured plugins report channels disabled in the live store as channel_disabled instead of channel_not_allowed.
  16. Command-line processes whose first argument matches the first serve_argv argument warn with serving_process_mismatch when later configured arguments differ, including one-shot commands such as gateway status with serve_argv: [gateway, run]; other one-shot commands remain silent.

Smaller changes without a line of their own above

Engines:

  1. The status and doctor text output changed (covered by Engines line 9).
  2. A killed start leaves a staged copy (covered by Engines line 5).
  3. The 1800-second budget now takes effect for the two SGLang kits, and an explicit plan value is now honoured on the non-automation activation path (implied by Engines line 1).
  4. The native Docker error text changed, and non-Docker values that were tolerated are now refused (covered by Engines line 2).
  5. Deployments prepared earlier keep 900 seconds until prepared again (Engines line 1 says so).

Owner mode:

  1. Setup no longer rewrites openclaw.json as strict JSON: comments, single quotes, unquoted keys and trailing commas stay in the file, so a tool that reads it as strict JSON must accept JSON5. FlashAlign's native terminal does.
  2. A byte order mark at the start of a harness JSON file that setup changes, such as openclaw.json, is kept; earlier releases removed it.
  3. A selected channel plugin that fails to load is reported with its entry point and distribution. Code that catches the error now sees RuntimeError, OSError or ValueError instead of the plugin's own error such as ImportError, and two messages about listing installed adapters no longer contain the word "channel".
  4. Setup keeps config.yaml values that JSON cannot hold, such as dates, sets and binary data; earlier releases stopped with an error on them.
  5. The bridge's decision log also records control requests that fail authentication or validation; its model-call rows carry the decision and identity reason instead of no_middleware_context; the Hermes plugin creates its log directory in every process that loads it, not only the serving one.
  6. The OpenClaw native terminal starts when openclaw.json holds comments, trailing commas, single quotes, unquoted keys or a byte order mark, and the file is not changed.
  7. An openclaw.json that is neither JSON nor JSON5 stops flashalign terminal before a session is granted, with an error that names the file and shows nothing from it.
  8. An OpenClaw terminal runner started without the launcher's parsed configuration reads the file as strict JSON, and otherwise ends with one line that names the file.
  9. Setup's detection step skips an openclaw-bridge.json it cannot read (empty, cut short or not UTF-8) instead of stopping, and setup then replaces the file.
  10. The bridge reads its configuration file as UTF-8 under any locale.
  11. flashalign terminal for OpenClaw reads openclaw.json itself as JSON or JSON5 and stops before a session is granted when the file is missing, not UTF-8, not a JSON or JSON5 object, or holds NaN/Infinity.
  12. A broken pipe on the receipt is now caught for both harnesses, so the launcher returns the runner's status at any receipt size.
  13. An OpenClaw terminal runner whose session receipt is cut short, empty or not JSON now ends with one fixed line on standard error and exit status 1, instead of the runtime's own error output, which quoted the start of the receipt; nothing of the receipt, which holds the parsed configuration, is written to standard output or standard error.

READMEs

  1. hermes-owner-mode/README.md now names the OWNER_MODE_EXTENSION warning that the provider proxy logs for each request it answers with HTTP 502 because an installed model adapter could not be loaded or registered, says that after an in-process upgrade a new registration leaves the previous release's registration running and registers nothing, and shows the owner_turn default as tool_name="".
  2. openclaw-owner-mode/README.md now names control_unavailable, the code the extension records for a control connection failure.

Validation

  • Python 3.12: 1,191 core tests passed, and all sixteen offline checks passed (contribution check, core tests, asset and sync checks, packaging, the shared engine, vLLM, SGLang and native engine suites, evidence, shell and Node syntax, wheel build).
  • Python 3.10 was run locally only with libraries borrowed from a 3.12 environment. In that arrangement five tests do not pass: three fail the same way on main, and two tests added here need numpy and httpx built for 3.10. This pull request's CI is the 3.10 check.
  • The checks listed here run offline: they start no engine and load no model.

Contributor rights

Submitted on behalf of Aevonix Inc. No third-party code is added.

  • I agree to the FlashAlign contribution terms version 1.0 for this contribution and have authority to grant the rights described there.
  • Third-party code, data and notices are identified in this pull request.
  • No credentials, private conversation content or private legal details are included.

The encoding tests asserted the subprocess locale through
locale.getencoding(), which exists only from Python 3.11, so all three
failed under Python 3.10. locale.getpreferredencoding(False) gives the
same answer under -X utf8=0 on every supported version.
A direct message from a sender ID that the channel's adapter does not
accept, such as an SMS short code, made the approval lookup raise. Ingress
observation then wrote an ingress_observation_exception warning and decision
row for every such message. Check the sender ID with handle_fits before the
lookup and reject the message like any other unapproved contact: no warning,
no row and nothing pending. The ingress key already holds the adapter's
canonical ID when the adapter accepts the sender, so every sender that was
approved before is still approved.
Errors from installed engine, model, profile and channel extensions are
re-raised with their entry point and distribution in the message. Every
error that was not a ValueError became a RuntimeError, so an extension
whose factory raised, for example, PermissionError ended setup with a
traceback instead of the ACTION NEEDED line setup prints for OSError.
Re-raise such errors as OSError, still naming the extension and chaining
the original error. Other error types are unchanged.
The access command tests call the main CLI in process. Its first access
command imports manage.py, whose standalone bootstrap puts a new owner_mode
package object into sys.modules without the attributes of the submodules
already imported. Python 3.10's mock.patch walks dotted targets through
those attributes, so a later test patching owner_mode.automation failed
when the whole core step ran. Restore the suite's package and its
submodule bindings after each command, as support.load_cli does.
The owner-mode README now says that a command line whose first argument
matches the first serve_argv argument warns when later configured arguments
differ, so a one-shot command such as gateway status does warn. The
extension guide names which errors identify the entry point and its
distribution: load errors and collisions do, errors found while entry points
are listed do not. The setup guide says that the files setup patches, not
every configuration file, are read and written as UTF-8.
Setup keeps the text of openclaw.json, so the file can hold comments,
trailing commas, single quotes, unquoted keys or a byte order mark, which
the terminal's strict reader refused.

The launcher now reads the file as JSON or JSON5 and hands the parsed
configuration to the runner in the receipt it already writes to the pipe.
The terminal uses that instead of parsing the file, and still writes only
its private strict copy. The configuration is never placed in an argument,
an environment variable or an error text.

A runner started without a parsed configuration reads the file as strict
JSON and otherwise ends with one fixed message that names the file. The
launcher refuses a file that is not a JSON or JSON5 object before it
creates the session grant, and returns the runner's exit status when the
runner ends before reading the receipt.
Setup patched every existing JSON file in place, including the files it
owns: openclaw-bridge.json, setup-result.json and the client
configuration. One of those left empty, cut short or not UTF-8 then
stopped every later setup with a parser message that named no file, and
JSON5 text added to them survived although their readers are strict.

Those files are written whole as strict JSON again. Only the harness
configuration the user keeps is patched, and YAML stays YAML. Detection
skips a bridge file it cannot read instead of stopping, so setup reaches
the step that replaces it.
A gateway loads the model adapter group when a request arrives on a
route saved with the legacy request-compatibility name. When an
installed entry point failed to load or collided there, the request was
answered with the fixed 502 text and nothing said which extension was
the cause.

The loader now records the entry point and distribution on the error it
raises, and the request handler logs one fixed warning with those names
and the route. The reply text is unchanged. The warning carries nothing
from the request and not the failure's own text, and requests that do
not meet the failure log nothing.
An installed entry point in the engine, model or profile group that
could not be listed (an invalid name, the same name twice, or missing
or invalid distribution metadata) raised an error that named nothing,
so it did not say which installed package to correct.

These listing errors now name the group and the entry point's name and
value, and the gateway warning for a failing extension names them the
same way. Channel plugin listing keeps its messages.
The access commands of the main command passed a refusal from the
approval store on as an uncaught error, so an unknown channel or an
empty contact ended in a traceback.

The main command's adapter now prints the refusal's fixed text on one
line of standard error and returns exit status 1. The store is not
changed, and accepted commands print what they printed before.
Four small cases, each with its own test:

- `flashalign why` skips a log line nested too deep to parse, like the
  other unreadable lines, instead of ending in a RecursionError.
- A failing control reply whose JSON body is null gives the OpenClaw
  extension's fixed error with the control_request_rejected reason,
  like any reply without a usable reason code, instead of a TypeError.
- Setup quotes a YAML string that a YAML 1.2 reader would take for a
  number, such as 1e3, 08 or 0o17. The library resolves YAML 1.1
  numbers only and wrote those as plain text.
- The bridge reads its configuration file as UTF-8, whatever the
  locale.

The control error tests of the extension remove the temporary
directories they make.
The runner parsed the session receipt outside any error handling. When
the launcher was stopped while it wrote a receipt larger than a pipe
buffer, the runner read a cut-short receipt and the runtime's own error
output quoted its start, which holds the parsed configuration.

A receipt that is cut short, empty or not JSON now ends the runner with
one fixed line on standard error and exit status 1. Nothing of the
receipt is written to standard output or standard error.
The Hermes README now names the `OWNER_MODE_EXTENSION` warning the
provider proxy logs when it answers a request with HTTP 502 because an
installed model adapter could not be loaded or registered, says what a
new registration does after an in-process upgrade, and shows the
`owner_turn` default for `tool_name` as the code has it.

The OpenClaw README now names the `control_unavailable` code the
extension records for a control connection failure.
@chatgpt-codex-connector

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ❌ Failed 2026-11-12T22:40:51.999614Z
We couldn’t complete this review. Comment @codex review to try again.
940f1c3 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@Kurcide
Kurcide merged commit f7bbb1b into main Nov 13, 2026
5 checks passed
@Kurcide
Kurcide deleted the update/engines-and-owner-mode branch November 13, 2026 03:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant