Commit Graph

64 Commits

Author SHA1 Message Date
Jesse Merhi 0e8faacd71 fix(scripts): build heap ignores its systemd memory budget and takes the full default (#123979)
* fix(scripts): size the tsdown heap from the build's own cgroup budget

The build heap probe only read the cgroup root (/sys/fs/cgroup/memory.max and
the v1 equivalent). Those files exist only when the process runs in a
namespaced container cgroup; under systemd the budget lives on the process's
own slice, and the v2 root carries no limit at all. So every systemd-managed
build found no limit, fell back to /proc/meminfo MemTotal, and took the full
12288 MB default heap regardless of its actual budget.

Observed on a 15.4 GiB host: openclaw-main-update.service ran tsdown with
NODE_OPTIONS=--max-old-space-size=12288 while its user@999.service slice was
bounded at 5 GiB, reaching 3.2 GB RSS and 6.25 GB peak before the host began
OOM-killing unrelated services.

Resolve the limit from /proc/self/cgroup and walk that chain instead, reading
memory.high alongside memory.max (memory.high throttles reclaim rather than
failing allocation, so a heap above it stalls the build instead of OOM-ing),
and take the tightest bound found. Root paths stay as the container fallback,
and an explicitly injected path list still disables detection.

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>

* fix(scripts): resolve the build heap budget from the v1 memory controller too

The slice walk only accepted the unified 0:: record, so a legacy or hybrid
systemd host fell back to the root probe and kept taking host memory. One
resolver now walks both hierarchies leaf-to-root, which makes the static root
list its own depth-0 case and removes it.

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>

* fix(scripts): read cgroup controller mounts instead of assuming their paths

v1 controllers can be co-mounted at the cgroup root, where memory.limit_in_bytes
sits under the slice with no per-controller directory, so the hardcoded
/sys/fs/cgroup/memory probe missed the budget and the build took the full
12288MB default. Mount points now come from mountinfo.

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>

* fix(scripts): translate cgroup records through the mount root

mountinfo field 4 is the subtree a cgroupfs mount exposes. Under a container
mount the /proc/self/cgroup record stays host-absolute, so walking it verbatim
probed paths below the visible mount and the build fell back to host memory.
Records now translate through the mount root before the walk.

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>

* fix(scripts): skip cgroup mounts that cannot represent this process

Falling back to the mount root for a record outside the mount's subtree sized
the build from an unrelated cgroup: an inherited namespace clamped the heap to
the 2048MB floor from a foreign 1GiB limit. Non-representable mounts are now
skipped, and the blind root probe only runs when no memory record exists.

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>

* fix(scripts): keep every cgroup mount view, not just the last one seen

One hierarchy can be visible through several mounts and only some expose a
subtree containing this process. Retaining only the last view dropped the
budget whenever a non-representable bind view came later, sending the build
back to host MemTotal.

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>

* fix(scripts): decode octal-escaped mountinfo paths before matching cgroups

ClawSweeper P2 on 7e64ad61f7: the cgroup resolver compared mountinfo's mount
root and mount point verbatim. The kernel escapes space, tab, newline, and
backslash in those two fields, so any cgroup mounted under such a path never
matched, the bounded slice was missed, and heap sizing silently fell back to
host memory.

Decode both fields before matching. The decoder lives in scripts/lib beside the
other shared script helpers rather than inline, so the scripts program has one
copy rather than a new ad hoc one.

Regression test fails pre-fix: a v2 mount at "/sys/fs/cgroup\040dir" with a
5 GiB memory.high yields --max-old-space-size=12288 (host fallback) before the
fix and 4352 after.

Follow-up, deliberately not bundled here: src/infra/sqlite-wal.ts,
src/commands/doctor-state-integrity.ts, and src/plugins/bundled-source-overlays.ts
each carry their own private copy of this same decoder. Consolidating all four
into @openclaw/normalization-core is the right end state, but it touches a
shared package plus three core modules and belongs in its own reviewable change.

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>

* fix(scripts): resolve cgroup-namespace-relative records to their mount

ClawSweeper P1 on d6fe49dd3f: inside a cgroup namespace /proc/self/cgroup
reports the namespace root ("0::/") while mountinfo field 4 stays the host
subtree the cgroupfs was mounted from ("/docker/<id>"). relativeCgroupPath then
found no prefix match and returned null; because a memory record had already
been seen, the root probe was skipped and the build fell back to host MemTotal.
A constrained container therefore missed its own budget entirely.

That namespace root is exactly what the mount exposes at its mount point, so it
resolves to "/" rather than failing closed.

Regression test fails pre-fix: a "0::/" record against a /docker/2f1a9c mount
root with a 5 GiB memory.max yields --max-old-space-size=12288 before the fix
and 4352 after.

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>

* fix(scripts): reject inherited cgroup mount views instead of guessing

ClawSweeper P1 on b4d200c5d2: the previous commit resolved a namespace-relative
record against any mount root, including the inherited views cgroup_namespaces(7)
documents, whose field-4 root reads "/..". Which cgroup such a view exposes is not
derivable from mountinfo, so probing it can size the build from an unrelated
cgroup's limit.

Reject non-canonical mount roots outright. An undecidable view now falls back to
host sizing, which is current main's behavior, rather than silently adopting the
wrong budget.

Regression test covers the "/.." inherited mount: it must yield host MemTotal
sizing, not the 5 GiB limit sitting behind that mount.

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>

* fix(scripts): fail closed on namespace-root records against non-root mounts

ClawSweeper P1 on 731d3bbc8e: a "0::/" record does not prove that a mount
rooted at some other subtree exposes this process's cgroup. Resolving that pair
could cap the build heap from an unrelated cgroup's limit.

Return no mapping for it. An undecidable pair now falls back to host sizing,
which is current main's behavior, so the failure mode is a missed optimisation
rather than a wrong budget. The "/.." inherited-mount rejection stays; this
covers the broader ambiguous mapping it did not.

The namespace-relative test is repointed accordingly: an unrelated mounted
subtree must yield host sizing, not that subtree's limit.

Net production change: none (4 lines swapped).

Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>

* fix(build): cap tsdown heap to the real budget and refuse hosts that cannot build

The 2048MB floor was applied on top of a discovered cgroup limit, so a small
container was handed a heap larger than it could honour. Measured in real
cgroups, that does not OOM-kill, it thrashes: a 1500MiB container sat pinned at
its ceiling for 10 minutes with oom_kill at 0, never finished the second of
eleven invocations, and starved every other process on the host.

Cap to the discovered budget, then refuse up front when that budget cannot hold
the build. The threshold is the whole-build peak, not a single pass: a full
eleven-invocation build peaks at 4730MiB, so a 5GiB slice completes while 4GiB
and 2816MiB slices are both killed partway through the third invocation.

The refusal runs before any output is cleaned, so a host that cannot rebuild
does not also lose the build it has.

* fix(build): harden tsdown heap admission

* fix(build): guard the default tsdown plan

* fix(build): preserve runtime-only Docker builds

* fix(build): admit only declaration cache misses

* fix(build): scope heap admission to real budgets

* fix(build): guard direct unified declarations

* fix(build): guard the canonical tsdown config

* fix(build): satisfy cache planning lint

* fix(gateway): release empty orphan leases

* fix(build): cap cgroup budget by host memory

* fix(build): serialize the canonical tsdown config

* test(build): freeze host memory fixtures

* fix(build): honor cgroup v1 soft limits

* fix(build): respect cgroup v1 hierarchy mode

* fix(build): admit unified runtime plans

* fix(build): admit every unified runtime path

* fix(build): collect repeated tsdown filters

* fix(build): ignore cgroup v1 soft limits

* fix(build): use explicit heap override as opt-in

* refactor(build): simplify memory admission

* fix(build): harden constrained build recovery

* fix(ci): prebuild runtime before real CLI shards

* fix(build): honor runtime-only runner environment

* fix(ci): satisfy tooling shard lint
2026-08-24 14:18:48 +10:00
Ayaan Zaidi 2eecf3d3f2 perf(mantis): build proof lanes runtime-only (#128007)
The proof gateways execute runtime JS only; declarations forced a ~177s
unified rebuild per lane because the declaration cache key is an
aggregate source hash. OPENCLAW_RUN_NODE_SKIP_DTS_BUILD=1 on profile
full now selects the runtime artifact surface via the uncached generic
tsdown graph, both Mantis lanes pass it through, and the baseline
archive moves to an isolated mantis-runtime-v1 namespace. Measured
candidate build: 177.1s -> 33.05s.
2026-08-23 00:15:24 +05:30
Josh Avant a042125170 fix(memory): preserve provenance across dreaming (#126489)
* fix(memory): preserve provenance across dreaming

* fix(build): preserve bundled hook metadata

* refactor(build): remove obsolete directory helper

* test(memory): align provenance fixtures

* test(memory): type consolidation run options

* test(memory): register write provenance siblings

* fix(memory): preserve legacy provenance registration

* fix(memory): make provenance provider-independent

* fix(memory): canonicalize provenance workspace keys

* fix(memory): keep provenance mutation host-private

* fix(build): track runtime postbuild implementations

* fix(build): verify bundled hook metadata outputs
2026-08-20 17:58:31 -07:00
Peter Steinberger f92e9367e8 fix(build): rebuild incomplete managed-update cache hits (#125954)
* fix(build): invalidate incomplete cache hits

* test(qa): align empty completion lifecycle
2026-08-18 23:25:04 -07:00
Peter Steinberger eeffa53b20 improve(plugins): compile externalized plugins in source builds (#124639)
* build(plugins): compile externalized plugins into local dist

* test(plugins): assert native external plugin loading

* chore(plugins): keep source runner asset scan unchanged

* refactor(plugins): isolate external local dist builds

* test(plugins): codify external artifact precedence

* test(plugins): preserve contract path boundary
2026-08-16 08:21:17 -07:00
Peter Steinberger c98ae0f99c test(scripts): remove duplicate parser facades (#124167) 2026-08-15 05:37:04 -07:00
Peter Steinberger 93f5e0f1f6 fix(build): restore exact cache output snapshots (#122837) 2026-08-12 15:20:11 -07:00
Vincent Koc 8d3f3377da fix(ci): make Control UI artifact validation consistent (#122086) 2026-08-12 00:11:22 +08:00
Peter Steinberger c70aee247e refactor(scripts): migrate JavaScript tools to TypeScript (#121005)
* refactor(scripts): migrate JavaScript tools to TypeScript

* fix(ci): keep changed-scope preflight zero-install

* fix(ci): preserve zero-install script owners

* fix(ci): complete script migration follow-through

* fix(release): keep stable closeout zero-install

* fix(scripts): preserve standalone execution boundaries

* fix(scripts): repair standalone loader boundaries

* fix(scripts): normalize gateway observation ids

* fix(scripts): keep Docker packager standalone

* test(scripts): preserve rebase cleanup helpers

* test(sessions): use tracked temp directory
2026-08-09 07:21:35 -07:00
Peter Steinberger 8b501c1c13 fix(build): reject incomplete Plugin SDK declaration caches (#120961)
Require the unified declaration cache to contain every production Plugin SDK declaration before accepting or stamping it. Matching partial v4 stamps are now stale and rebuild instead of failing later in the canonical declaration writer.
2026-08-09 03:38:37 -07:00
Vincent Koc e4aab26d01 fix(cli): avoid repeated migration scans during local agent turns (#119051)
* fix(cli): avoid repeated state migration scans

* fix(build): preserve source runtime provenance

* fix(cli): persist state checkpoint before plugin convergence

* fix(cli): invalidate migration checkpoints on input changes

* fix(plugins): refresh changed doctor contracts

* fix(plugins): preserve warm Doctor contract indexes

* test(plugins): align manifest registry fixtures

* test(cli): isolate ACP process state

* fix(doctor): persist refreshed plugin indexes

* fix(doctor): verify persisted plugin index from disk

* fix(doctor): fence plugin index persistence

* fix(doctor): retain validated migration lease

* fix(plugins): canonicalize persisted build metadata

* fix(plugins): preserve config policy during install repair
2026-08-04 20:28:16 +08:00
Peter Steinberger 8a36e0470c Build export HTML vendor assets from pinned dependencies (#117583)
* build: generate export html vendor assets

* build: declare marked generator contract

* fix(build): preserve export asset working root

* fix(build): preserve postbuild root ownership

* test(build): update Docker TypeScript step count
2026-08-01 15:03:35 -07:00
Peter Steinberger e7950d968b refactor(state): inline canonical database schemas at build (#117433) 2026-08-01 08:39:42 -07:00
Peter Steinberger 137050cedd perf(update): reuse dev preflight build cache (#117246) 2026-07-31 22:59:44 -07:00
Peter Steinberger c7e7ac2728 refactor: remove expired plugin compatibility surfaces (#111451)
* docs(secrets): remove retired web credential paths

* refactor(web): remove retired provider compatibility paths

* refactor(providers): delete retired compatibility routes

* refactor(secrets): remove retired credential aliases

* refactor(plugin-sdk): delete retired compatibility surfaces

* docs(plugin-sdk): remove retired migration guidance

* chore(plugin-sdk): refresh rebased surface budgets

* chore(plugin-sdk): refresh API removal baseline

* refactor(compat): migrate retired internal callers

* chore(plugin-sdk): refresh current-main baselines

* test(config): migrate plugin-owned secret assertions

* test(gateway): narrow plugin secret refs

* fix(plugin-sdk): preserve private boundary type identity

* chore(compat): remove stale sweep references

* chore(lint): lower max-lines budget

* refactor(secrets): remove unused web helper

* build(plugin-sdk): drop removed compat entries

* chore(plugin-sdk): refresh rebased API baseline

* chore(plugin-sdk): use Linux API baseline hash

* fix(plugin-sdk): preserve private bundled build entries

* fix(plugin-sdk): package private runtime facades

* fix(plugins): preserve external credential contracts
2026-07-19 11:04:48 -07:00
Peter Steinberger 5024c100a3 perf(ci): reuse CLI startup metadata cache (#109863) 2026-07-17 10:25:26 +01:00
Peter Steinberger d78396124e perf(build): reuse tsdown declaration groups (#109737) 2026-07-17 00:03:41 -07:00
Peter Steinberger e7c389b97a perf(ci): cache declarations and remove test import tail (#109593) 2026-07-16 21:51:06 -07:00
Peter Steinberger 1d5479520f perf(ci): skip global declaration emission in the CI artifacts build (#108949)
* perf(ci): skip global declaration emission in the CI artifacts build

Declaration emission is ~95% of the tsdown wall clock (measured 132.5s
with dts vs 6.0s without on the main graph; 224.7s in CI). PR CI's dist
consumers only execute runtime JS, so the ciArtifacts profile now skips
global dts and the plugin-sdk export gate validates self-built scoped
declarations (write-plugin-sdk-entry-dts non-canonical mode, 45s local).
The step cache is dropped in self-build mode because its outputs depend
on the SDK source graph the canonical cache inputs do not cover.
Release and docker packaging builds keep canonical declarations.
Local end-to-end: build:ci-artifacts 92s with all gates green.

* fix(ci): pin gateway suites to the proven 2-worker Vitest budget

gateway-core and gateway-methods flaked at 6 workers (hook timeouts,
mock-state res.setHeader TypeError, waitForAssertion misses) on the
first run after the worker-budget raise while passing on two prior
validation runs — the same intermittent contention class media-ui
showed. Pin both like the other timing-sensitive groups.
2026-07-16 04:54:34 -07:00
Peter Steinberger adf6b08ab4 refactor: consolidate duration parsing and formatting (#105988)
* refactor: consolidate duration handling

* docs: leave release notes to release workflow

* fix: preserve build timing precision

* ci: align plugin sdk surface budgets
2026-07-12 23:38:22 -07:00
Peter Steinberger e0f45bfbf0 feat(tooling): enforce indexed access checks in root tests (#105223)
* feat(tooling): enforce indexed access checks in root tests

* style(tooling): clarify scoped package guard
2026-07-12 10:42:07 +01:00
Peter Steinberger 8fe6ac7fb9 refactor: remove pre-2026.4 compatibility shims and legacy migrations (#104650)
* refactor(matrix): retire pre-2026.4 legacy crypto and flat-storage migrations

* refactor(cli): drop pre-tsdown daemon-cli dist compat shim from the build

* refactor(diffs): remove deprecated image*/format tool params and output aliases

* refactor(ui): drop pre-gateway-scoped localStorage readers and legacy theme map

* refactor: remove assorted pre-2026.4 compat shims and deprecated aliases

* fix(discord): map legacy thread-binding fields in the doctor JSON import

* fix(msteams): keep bot read fallback for legacy imported conversation rows

* test(msteams): cover legacy bot-only imported conversation references

* fix(ui): keep channel-prefixed session key display fallback

* chore: refresh native i18n inventory and build-docker step count

* chore(matrix): drop now-unused migration-config module

* chore: re-pin plugin SDK public export budget after compat removals

* chore: refresh native i18n inventory after rebase

* chore: re-pin plugin SDK callable budget and refresh i18n inventory after rebase
2026-07-11 13:22:27 -07:00
Vincent Koc 6013e78f5a perf(build): add source performance profile 2026-07-11 19:13:52 +08:00
Peter Steinberger 1e660ac7b2 fix: preserve runtime plugin assets after build (#104229) 2026-07-11 00:07:59 -07:00
Peter Steinberger 7fe004d852 feat: show build identity in About screens (#103595)
* feat: show build identity in About screens

* chore: leave root changelog to release automation

* fix: translate Control UI About build details
2026-07-10 10:42:36 +01:00
Glen - I am an OpenClaw+Codex bot 23998a148f fix(build): fall back to tsx for build TypeScript scripts (#91262)
* fix(build): fall back to tsx for build TypeScript scripts

* fix(build): use tsx across TypeScript build scripts

---------

Co-authored-by: Steffen Moeller <moeller@debian.org>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
2026-07-06 06:55:20 +00:00
Vincent Koc c22270a917 fix(build): restore package artifact declarations (#100249)
* fix(build): restore package artifact declarations

* fix(build): stage plugin sdk strict smoke artifacts

* test(exec): accept resolved safe-bin paths

* test(qa): type missing delivery metadata regression

* fix(build): restore llm runtime tsdown root

* fix(build): drop removed llm runtime tsdown root
2026-07-05 02:22:11 -07:00
Vincent Koc f53fdb688d fix(qa): restore package docker gates 2026-07-04 01:56:21 +02:00
Dallin Romney d32c4cf300 perf(build): canonicalize plugin SDK declarations (#98758) 2026-07-02 00:21:41 -07:00
zenglingbiao 09d6479681 fix(build): ship export session html assets
Align the export-session template asset copy step and build-all cache output with the runtime lookup path so published packages include the HTML export assets at `dist/export-html`.

Adds a focused build-all regression assertion for the output path contract.

Fixes #90843
2026-06-06 09:14:12 -07:00
Peter Steinberger 58c663920d docs: document script tests 2026-06-04 20:49:50 -04:00
Vincent Koc 55e9194a4c perf(scripts): avoid duplicate build cache input hashing 2026-06-02 03:50:19 +02:00
Peter Steinberger a4196a4445 fix(ci): cache plugin sdk declarations safely 2026-06-01 04:09:07 -04:00
Vincent Koc ef9e9bf6b9 fix(build): preserve fresh startup metadata across rebuilds 2026-05-31 07:16:13 +02:00
Vincent Koc ee2b90b4e2 perf(scripts): prebuild qa runtime assets 2026-05-31 00:17:39 +02:00
Vincent Koc ada22739be perf(build): skip dts for runtime build profiles 2026-05-30 23:06:25 +02:00
Vincent Koc 37058ad75a fix(scripts): quiet minimal runtime asset copies
Stop minimal cliStartup and gatewayWatch builds from copying generated plugin static assets they intentionally do not build.\n\nVerified with focused Vitest, autoreview, AWS Crabbox startup-memory proof, and AWS Crabbox changed gate run_bd9ea01e6a12 plus rebased changed gate run_bd9ea01e6a12.
2026-05-30 20:38:19 +01:00
Vincent Koc a06daab97e fix(test): guard build runner help 2026-05-30 13:00:32 +02:00
Peter Steinberger 69550a9d3d ci: satisfy build profile lint 2026-05-30 00:05:40 +01:00
Peter Steinberger 0e6937cc1b ci: skip bundled dts in artifact build 2026-05-29 23:56:31 +01:00
Peter Steinberger 1c8de09ba9 ci: stabilize main checks 2026-05-29 22:49:06 +01:00
Peter Steinberger 99b24a80fb build(plugins): externalize copilot runtime 2026-05-29 20:14:38 +01:00
Ramrajprabu f3cfd752d3 feat(copilot): add GitHub Copilot agent runtime
Adds the opt-in bundled GitHub Copilot agent runtime, pinned SDK install path, docs/inventory, SDK/tool/sandbox/auth wiring, and replay/tool-safety fixes.

Verification:
- Local: git diff --check; fnm exec --using 24.15.0 pnpm tsgo:extensions; fnm exec --using 24.15.0 pnpm check:test-types; fnm exec --using 24.15.0 pnpm build.
- Autoreview local: clean for the replay-safety fix; branch autoreview engine returned empty output twice, so local autoreview plus local/Crabbox/CI proof was used.
- Crabbox focused Copilot: run_2c0db9f48a4a, 19 files / 485 tests passed.
- Crabbox additional boundary shard: run_26a246a1aa24, prompt snapshots and plugin SDK boundary/export checks passed.
- Crabbox live Copilot: run_d128e4048b4e, real gpt-4.1 turn with live_echo phase-1-green and clean session-file check.
- GitHub checks: green on head 7cc8657e0d, including Dependency Guard after exact-head approval.

Co-authored-by: Ramraj Balasubramanian <ramrajba@microsoft.com>
2026-05-29 05:15:22 +01:00
Vincent Koc dc5671edae fix(install): harden Windows git installs 2026-05-28 11:47:05 +02:00
Dallin Romney 53704b26e8 perf(ci): instrument build artifacts phases (#87514) 2026-05-27 22:31:32 -07:00
xin zhuang 6704d0ab27 fix(scripts): include ui:build in build-all full and ciArtifacts profiles (#86010)
* fix(scripts): include ui:build in build-all full and ciArtifacts profiles

Closes #85206.

scripts/build-all.mjs only ran ui:build via a separate `pnpm ui:build`
command. Because `pnpm build` invokes tsdown which removes `dist/`,
a backend rebuild silently deletes any previously generated
dist/control-ui assets, leaving the gateway to serve the
"Control UI assets not found" message at startup. Documentation and
startup auto-repair masked the bug at the worst possible time
(LaunchAgent readiness / remote recovery) instead of guaranteeing the
build artifact contract.

This change adds ui:build as a build-all step after
copy-export-html-templates and before write-build-info, and includes
it in the full and ciArtifacts profiles. Minimal backend dev profiles
(gatewayWatch, cliStartup) keep their existing fast-loop step lists
and do not run ui:build.

Regression coverage:
- ciArtifacts step list assertion updated to match the new ordering.
- Three new resolveBuildAllSteps assertions: ui:build is in full and
  ciArtifacts and runs after tsdown/runtime-postbuild-stamp and before
  write-build-info; ui:build is excluded from gatewayWatch/cliStartup;
  ui:build cache outputs declare dist/control-ui.

* fix(scripts): leave ui:build uncached so dist/control-ui never restores stale build IDs

ClawSweeper review on #86010 flagged that the original ui:build cache only
hashed ui/, scripts/ui.js, and scripts/lib/copy-assets.ts, but
ui/vite.config.ts also reads package.json plus git HEAD and the
OPENCLAW_CONTROL_UI_BUILD_ID/OPENCLAW_VERSION env vars to embed a build ID
into the app and service worker. A file-input cache signature cannot
exactly invalidate those metadata sources, so a warm build-all hit could
restore a previously generated dist/control-ui after tsdown clears dist
and ship stale service-worker/app cache metadata.

Leaving the step uncached keeps the contract simple: every pnpm build
re-runs Vite, which is fast for the Control UI bundle and matches the
existing behavior of every other un-cached build-all step. Backend-only
profiles (gatewayWatch, cliStartup) are still unchanged.

Tests:
- Updated the ui:build cache assertion to require step.cache to be
  undefined and explain the metadata-input reason.
- Existing presence/order/exclusion assertions for ui:build are unchanged
  and still cover the full and ciArtifacts profile contract.

* fix(scripts): keep ui build fallback pnpm-free

---------

Co-authored-by: 1052326311 <1052326311@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-05-25 08:08:52 +01:00
Peter Steinberger 7b1fbe1c37 ci(release): harden docker package build 2026-05-22 14:15:46 +01:00
Peter Steinberger 333f65fc8a fix: tighten release tooling checks 2026-05-15 21:21:17 +01:00
Vincent Koc 97283f0a2e test(cli): add response-time contract for CLI surfaces 2026-05-10 23:06:28 +08:00
Peter Steinberger 62bdf5d5eb test: tighten build all cache assertions 2026-05-09 10:01:38 +01:00