Skip to content

feat: add generic deployment recovery and engine lifecycle - #100

Open
qinyue0508-cmd wants to merge 75 commits into
developfrom
amd395-win
Open

feat: add generic deployment recovery and engine lifecycle#100
qinyue0508-cmd wants to merge 75 commits into
developfrom
amd395-win

Conversation

@qinyue0508-cmd

Copy link
Copy Markdown

Summary

  • persist deployment desired state and run a bounded AIMA Reconciler
  • recover failed Native inference processes while observing Docker/K3S restart loops
  • add retry limits, backoff, quarantine state, Patrol notification, and redacted audit records
  • add generic Engine inventory, preinstalled version detection, verified install/upgrade, import, activation, and rollback
  • preserve persisted Native ports during recovery
  • keep partner and hardware differences Catalog-driven without partner-specific recovery branches

Validation

  • go test ./... -count=1
  • go test -race ./internal/recovery ./internal/runtime ./internal/engine ./internal/mcp ./internal/cli ./cmd/aima -count=1
  • go vet ./...
  • cross-build: Windows amd64, macOS arm64, Linux amd64, Linux arm64
  • Baiying 395 Windows Native recovery UAT: process recreated, status ready/healthy, response AIMA_RECOVERY_OK

@rjckkkkk please review.

rjckkkkk and others added 30 commits June 9, 2026 17:26
Windows 11 24H2+ removes the legacy wmic CLI, so CPU/RAM detection on
modern Windows returned an empty model and zero RAM. AMD GPUs were also
invisible on Windows: the probe chain only knows nvidia-smi/rocm-smi and
the sysfs fallback is Linux-only, so AMD APU hosts (Ryzen AI Max+ "Strix
Halo") detected no accelerator at all.

Replace wmic with `powershell Get-CimInstance` for CPU, RAM, pagefile and
CPU load, and add a Windows Win32_VideoController GPU fallback wired into
detectGPU through a detectPlatformGPU hook (no-op on non-Windows). AMD
identity (name/gfx/arch/unified) is resolved from the PCI device ID via
the existing amdPCIToInfo, shared with the Linux sysfs path.

CIM cannot report true APU VRAM (Win32 AdapterRAM saturates at 4 GiB) or
GPU utilization, so VRAM falls back to OS-visible RAM via the existing
unified-memory backfill; exact carve-out still needs amd-smi/rocm-smi.

Pure CIM JSON parsers live in cim.go (no build tags) with table-driven
tests in cim_test.go using fixtures captured from a real Strix Halo box.

Verified on AMD Ryzen AI Max+ 395 (Radeon 8060S, gfx1151): hal detect now
reports the GPU (RDNA3.5, driver 32.0.31007.1017), CPU model + 16c/32t,
and 32 GB RAM.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On Strix Halo and similar unified-memory APUs, Windows exposes only a fraction
of physical memory to the OS (e.g. 32 GiB of 128 GiB) — the rest is carved out
for the iGPU. TotalVisibleMemorySize therefore undersold a 128 GiB box as 32 GiB,
which also flowed into the unified-VRAM backfill and the onboarding "统一内存" card.

Query Win32_PhysicalMemory (sum of DIMM capacity) and use it as RAM.TotalMiB when
it exceeds the OS-visible total; recompute AvailableMiB as total - OS-used so it
stays correct for both unified and conventional hosts.

Tests (cim_test.go, build-tag-free): parse the Measure-Object Sum JSON; override
to 128 GiB on a Strix Halo fixture; no-shrink / no-op on conventional hosts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On Strix Halo, Win32 AdapterRAM saturates at 4 GiB and there is no rocm-smi, so
the unified-memory backfill set GPU.VRAMMiB = installed RAM (128 GiB). But the OS
carves that 128 GiB pool — only ~110 GiB is GPU-addressable (dedicated VRAM +
GTT) — so deploy-fit over-stated usable VRAM and could accept a model the iGPU
cannot hold.

When the AMD iGPU's VRAM is unknown, query the ROCm-capable llama.cpp engine's
own `--list-devices` (preferring AIMA_ENGINE_DIR, else PATH) and use its reported
device memory (e.g. "ROCm0: ... (110456 MiB, ...)") as GPU.VRAMMiB. Installed RAM
— and thus the normalized "unified memory" the UI shows — is unchanged; only the
fit-relevant usable VRAM is corrected.

Tests (cim_test.go, build-tag-free): parseLlamaROCmVRAMMiB extracts the device
total and ignores non-device output.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On Windows the model scanner only looked at %USERPROFILE% directories, so
models on other drives (D:\models, D:\lmstudio\models, ...) were never
found and users had to set AIMA_MODEL_DIR by hand. Split GGUF shards were
each registered as a separate model, and mmproj projector files showed up
as standalone models — both break one-click deploy from the Web UI (a user
clicking a single shard would fail to load the model).

Scan discovery:
- enumerate fixed/removable drives and probe conventional model dirs that
  exist (<drive>:\models, <drive>:\lmstudio\models, .ollama, HF hub). This
  stays targeted — it never walks whole drives, so recycle bins and system
  folders are not pulled in.
- AIMA_MODEL_DIR now accepts a list (os.PathListSeparator) for custom dirs.
- honor HF_HOME / OLLAMA_MODELS for relocated caches.
- harden scanner.yaml skip list ($recycle.bin, system volume information,
  node_modules, .git, ...) so even an explicit drive-root scan stays clean.

GGUF grouping:
- collapse "...-00001-of-000NN.gguf" shards into one logical model whose
  Path is the first shard (llama.cpp auto-loads the rest) and whose size is
  the sum of all parts — so deploy targets the whole model, not one piece.
- drop mmproj projector files. The scanner already skips "mmproj" *dirs*
  (scanner.yaml); this covers the file-name form, so projectors no longer
  appear as deployable models.

Pure logic (groupGGUFModels, dedupePaths, DefaultScanPaths multi-path) is
table-driven tested. Verified on an AMD Strix Halo Windows box: a clean
scan now yields 22 grouped models across D:\model, D:\models,
D:\models-gguf and D:\lmstudio (drive auto-probe found the latter two on
its own), with no shards-as-models, no mmproj, and no recycle/tooling junk.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Engine scan only looked in ~/.aima/dist/{os-arch}/ and PATH for native
engine binaries, so engines installed in arbitrary dirs off the system
drive (e.g. Windows D:\tools\llama-b9180-win-hip-radeon-x64\llama-server.exe)
were invisible and `aima engine scan` returned [].

Add ScanOptions.ExtraDirs, fed from a new AIMA_ENGINE_DIR OS-path-list env
var (mirrors AIMA_MODEL_DIR), and extract scanDirForEngineBinaries so
distDir / extra dirs / PATH share one scan path with consistent dedup and
ID semantics. Once discovered, the existing local-engine overlay reinjects
the binary path as a preinstalled probe, so native deploy resolves the
absolute binary with no further changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On the AMD Strix Halo (Radeon 8060S iGPU) rig, scanned on-disk GGUF model
names (e.g. Qwen3.5-9B-Q4_K_M) did not match catalog metadata.name, so
deploy fell back to auto-detect instead of the curated config. Add
metadata.aliases so the local scanner matches, and record llama.cpp b9180
HIP verified decode perf (all 999 layers offloaded, Q4_K_M):

  qwen3.5-9b       33.8 tok/s   (alias only; llamacpp variant already present)
  qwen3.5-27b      11.7 tok/s   (added universal llamacpp variant + GGUF source)
  glm-4.7-flash    58.9 tok/s   (added universal llamacpp variant + GGUF source)
  qwen3.5-35b-a3b  63.0 tok/s   (alias + verified perf; variant already present)

New llamacpp variants use gpu_arch "*" so they apply on any device (GGUF is
the path for low-VRAM hardware). No Go changes — knowledge-only (INV-1/2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AIMA's model scanner lists every weight artifact on disk as an
independently deployable model. Speculative draft heads (DFlash / MTP)
only make sense paired with their parent model for speculative decoding,
yet they showed up as standalone models with a deploy button
(e.g. Qwen3.6-35B-A3B-DFlash, Qwen3.6-35B-A3B-DFlash-Q4_K_M).

The catalog already names each draft via its parent variant's
speculative_config.model, so detection needs no new per-model YAML:

- knowledge.NormalizeModelKey: lowercases a model name and strips
  quantization/precision/layout suffixes (q4_k_m, bf16, ud, unfused, ...)
  while keeping role tokens like "dflash", so all on-disk artifacts of one
  logical draft share a key and stay distinct from the parent.
- Catalog.SpeculativeDraftModelKeys: harvests speculative_config.model
  across all variants into a set of normalized draft keys.
- annotateModelsFromCatalog: a scanned model whose normalized name is a
  draft key gets standalone_deploy=false + ui.role=draft (only when not
  already set); the embedded UI already hides the deploy button on
  standalone_deploy=false.

Knowledge-driven (INV-1/2): no hardcoded model names, derived entirely
from the catalog. Parent models and quantization variants are unaffected,
and DB rows / deploy-by-name paths are untouched (annotation is applied at
model.list time only).

Tests: NormalizeModelKey table cases (incl. "glm-4.7-flash" not stripped),
SpeculativeDraftModelKeys harvest + nil-catalog, and the annotate wiring
(drafts -> non-standalone draft, parent stays deployable).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…services

The external-service scanner probes a fixed port list that includes 8080 —
llama.cpp's default port — which AIMA's own native deployments also bind. So a
model AIMA deployed itself (e.g. Qwen3.6-27B-Q4_K_M on 127.0.0.1:8080) was also
surfaced under "external services" as importable, and importing it would
register a self-referential backend.

Exclude any scanned/persisted service whose host:port matches an AIMA-owned
(non-external) proxy backend:

- normalizeHostPort: reduce a base URL/address to a comparable host:port,
  folding localhost/::1/0.0.0.0 to 127.0.0.1.
- Reconciler.ownDeploymentAddrs: host:port set of non-external proxy backends.
- Scan skips own-deployment addresses (no upsert); List filters them out so a
  previously-recorded self entry disappears too.

Tests: normalizeHostPort table; List excludes the own :8080 deployment while a
genuine external service (ollama :11434) is kept.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A scanned (auto-discovered) external service was upserted when found but never
reconciled away when it disappeared. So after a model was undeployed and its
backend (e.g. native llama.cpp on :8080) stopped, the dead service lingered as a
stale "reachable" row and kept showing under external services.

On each scan, mark previously-discovered scanned (non-imported, non-own) services
that are no longer reachable as unreachable; List now hides scanned, non-imported,
unreachable services. Imported services are untouched (they still show, with their
status, by user intent).

Tests: staleScannedAddrs (skips imported / already-unreachable / own deployments);
List hides a vanished scanned :8080 while keeping a reachable :11434 and an offline
imported :9000.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Prebuilt aima-windows-amd64.exe + serve.bat + handoff README for collaborator
R&D, on the develop + #78-#83 integration (Strix Halo hardware detection, model/
engine scan, draft-head + external-service n_guan, OpenClaw local-model sync).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Halo

On a no-NVIDIA AMD Windows box (Ryzen AI Max+ 395 / Radeon 8060S, RDNA3.5),
the only catalog llama.cpp source for windows/amd64 was the CUDA build, which
runs CPU-only there; the AMD engines (llamacpp-vulkan / llamacpp-rocm-rdna3)
are linux-only. So out-of-the-box auto-download fetched the wrong (CUDA) build
and users had to manually install a ROCm/HIP llama.cpp and point AIMA_ENGINE_DIR
at it.

Add a native engine asset `llamacpp-hip-windows` (gpu_arch RDNA3.5, windows/amd64,
source = official llama.cpp `win-hip-radeon-x64.zip`, version b9330). The native
engine resolver already skips engines whose source has no binary for the host
platform, so on RDNA3.5+Windows this exact-arch, windows-supported asset is
selected over the linux-only vulkan asset and the NVIDIA-only universal CUDA
source — making `aima deploy <model>` auto-download the right ROCm/HIP build
with no AIMA_ENGINE_DIR. Knowledge-only, no Go changes (INV-1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The engine scanner discovers native binaries in AIMA_ENGINE_DIR, but native
deploy resolved the binary only via dist → BinarySource probe/download → PATH.
When a pre-installed engine was registered via AIMA_ENGINE_DIR but not in dist
or PATH, and the catalog probe-path injection didn't reach the resolved engine
asset (e.g. AMD-Windows, where gpu_arch matching picks a linux-only asset), the
launch command fell back to the bare name ("llama-server") and Windows reported
"'llama-server' is not recognized" — so a model that scanned fine could not be
deployed.

Resolve the native binary against AIMA_ENGINE_DIR too — the SAME dirs the engine
scanner reads — so "scanned ⇒ launchable" holds regardless of catalog/overlay
engine selection. Order: dist → AIMA_ENGINE_DIR → auto-download → PATH. No-op when
AIMA_ENGINE_DIR is unset, so other devices/runtimes are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dist exe filename now carries its version string so a new build does NOT
overwrite the previous one in place. Two builds coexist:

  aima-windows-amd64-v0.5-dev-amd-strix-halo-20260610.exe  -> v0.5-dev-amd-strix-halo-20260610
      latest; adds the out-of-box AMD-HIP llama.cpp engine (#85, #86). serve.bat uses this.
  aima-windows-amd64-v0.5-dev-amd-strix-halo.exe           -> v0.5-dev-amd-strix-halo
      restored 2026-06-09 build (#78-#83 only, no HIP auto-download). Kept for rollback.

Both from source commit fc3ef41; filename == the exe's own `aima version` string.

- #85 llamacpp-hip-windows engine asset (go:embed'd into the exe + in source at
  catalog/engines/llamacpp-hip-windows.yaml, pins official b9330 win-hip-radeon-x64):
  a no-NVIDIA Strix Halo box auto-downloads the right ROCm/HIP llama.cpp instead of
  the CPU-only CUDA universal source.
- #86 native runtime resolves the engine binary against AIMA_ENGINE_DIR
  (dist -> AIMA_ENGINE_DIR -> auto-download -> PATH), so a pre-installed llama.cpp
  of ANY version is launchable -- the partner's llama.cpp version is supported
  whether or not it matches the bundled b9330.

Verified the latest build on the 395 rig: `aima version` ->
v0.5-dev-amd-strix-halo-20260610 / fc3ef41; `aima engine info llamacpp-hip-windows`
-> b9330 asset; `aima hal detect` -> RDNA3.5 gfx1151, ~110 GB VRAM.
README + serve.bat updated (build table; AIMA_ENGINE_DIR now optional).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
)

New version-stamped build aima-windows-amd64-v0.5-dev-amd-strix-halo-20260612.exe
(source commit fa35aa4) on top of the HIP-engine build. Adds, vs the 20260610 exe:

  #87 native deploy readiness uses the real runtime name (no false "not ready")
  #88 deploy launcher hidden (no cmd.exe console popup) via VBS launcher
  #89 Qwen2.5-VL-3B-Instruct catalog knowledge (vlm + aliases + verified perf)
  #90 zero-config vision: llama.cpp --mmproj auto-wired for VL gguf models
  #91 openclaw sync preflight-probes :6188 and warns loudly when unreachable

serve.bat now points at the 20260612 exe; older builds kept for rollback.
README build table + fixes list + OpenClaw data-plane guidance updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…text

A high catalog/user ctx_size (e.g. the 128000 default we now want for agent
clients) would OOM llama-server at load on memory-constrained machines — AIMA
previously passed ctx_size through unchanged (estimateVRAM ignores the KV cache;
CheckFit only adjusts vLLM/SGLang gpu_memory_utilization, never llama.cpp ctx).

On deploy, for llama.cpp GGUF models, size the context to the hardware:
- Read the model's real architecture from the GGUF header (new model.ReadKVArch:
  block_count / head_count_kv / head_dim / context_length) and compute exact f16
  KV bytes/token — not a guess.
- Clamp ctx_size down so weights + projector + KV cache fit usable memory (GPU
  VRAM for discrete GPUs, RAM minus an OS reserve for unified/CPU hosts), and cap
  it at the model's trained context. Only ever lowers; never raises.
- Graceful no-op when the GGUF arch can't be read or memory is unknown.

So a high default degrades gracefully: big boxes get the full context, small ones
auto-shrink to what fits instead of failing. Bump Qwen2.5-VL-3B default ctx_size
to 128000 (its trained max) now that it's memory-safe; the agent floor (~9.3K of
MCP tool schemas) always fits where the model fits.

clampContextForMemory / usableMemoryMiB are pure and unit-tested; verified on the
Strix Halo rig (request 200000 → clamped to trained 128000).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…K default

New version-stamped build aima-windows-amd64-v0.5-dev-amd-strix-halo-20260615.exe
(source commit 88ef097) on top of the 20260612 build. Adds:

  - Hardware-aware ctx_size clamping: reads the GGUF arch and fits the context to
    memory (weights + projector + KV) and the trained limit, only lowering it.
  - Qwen2.5-VL-3B default ctx_size 8192 -> 128000, now memory-safe everywhere:
    big boxes get 128K, constrained boxes auto-shrink instead of OOM-ing. Fixes
    OpenClaw agent "context overflow" (its MCP-tool-schema prompt exceeds 8192).

serve.bat points at the 20260615 exe; older builds kept for rollback.
README build table + fixes list + rebuild note updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…en3-Embedding-4B

Set each model's catalog default ctx_size to its full trained context (verified
loading + serving on the Strix Halo iGPU, 2026-06-16):
- glm-4.7-flash llamacpp variant: ctx_size 8192 -> 202752.
- qwen3.6-35b-a3b: add a universal llamacpp GGUF variant (ctx_size 262144) + gguf
  source + scan-name aliases (Qwen3.6-35B-A3B-UD-Q4_K_M, qwen3.6-35b-a3b-q4_k_m);
  it previously had only vLLM/Blackwell variants.
- new qwen3-embedding-4b.yaml: type embedding, llamacpp variant with embedding=true
  (-> llama-server --embedding) + ctx_size 40960; serves /v1/embeddings (2560-dim).
  Deploy-only — embedding models are not written into OpenClaw config by sync.

These large ctx defaults are memory-safe via the deploy-time auto-clamp.

Also fix usableMemoryMiB to prefer GPU VRAM over system RAM: an all-offloaded
llama.cpp model is bounded by GPU memory, and on unified-memory APUs the OS-visible
RAM is under-reported (Strix Halo: ~32GB OS vs ~110GB iGPU). The clamp now uses the
iGPU pool, so it won't wrongly shrink contexts on such APUs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… fix

New aima-windows-amd64-v0.5-dev-amd-strix-halo-20260616.exe (source 80c7216). Adds the
verified catalog context windows (GLM-4.7-Flash 202752, Qwen3.6-35B-A3B 262144 with
a new llama.cpp variant + aliases, new Qwen3-Embedding-4B in --embedding mode), and
the auto-clamp now sizes against the iGPU memory pool instead of under-reported APU
system RAM. serve.bat -> 20260616; older builds kept for rollback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… (env)

Two product-level controls so a partner integrating AIMA owns OpenClaw behavior
without code changes on their side (both honor CLI sync AND the serve auto-sync loop):

- AIMA_OPENCLAW_SET_DEFAULT=false — register the AIMA provider + models but do NOT
  set OpenClaw's primary/default chat model (leave the user's current primary alone).
  Unset = previous behavior (AIMA sets it). Threaded as Deps.SetDefaultModel *bool →
  SyncResult.SkipDefaultModel → mergeChatModelDefault early-returns (preserving prior
  ownership record so toggling back on works).
- AIMA_OPENCLAW_CONFIG=<path>/openclaw.json — write to a custom config dir (e.g. a
  partner using .byClaw instead of .openclaw). Skills, extensions and managed-state
  all follow filepath.Dir(ConfigPath), so the whole set relocates. This is purely
  AIMA-side and independent of the OpenClaw/byClaw product's own layout.

Verified on the Strix Halo rig: SET_DEFAULT=false → provider written, primary empty;
default → primary set; custom config dir → config+skills land under .byClaw.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lt + config dir)

The 2026-06-16 build now also carries AIMA_OPENCLAW_SET_DEFAULT and
AIMA_OPENCLAW_CONFIG (partner-controllable primary-model + custom config dir).
Same version-stamped filename; README rebuild note updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…w sync controls)

Q&A capturing this round's partner requests and how each is handled: the four model
context windows (tested + yaml'd), embedding-not-synced, AIMA_OPENCLAW_SET_DEFAULT,
historical-service-info read paths, and AIMA_OPENCLAW_CONFIG custom dir.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…alog-miss fix)

Committing pre-existing uncommitted work from the 2026-06-18 round on this build
box (issues 4 & 5 of the integration list), verified building + tests passing:

- Issue 4 / B2 — engine image registry via env: AIMA_ENGINE_REGISTRIES /
  AIMA_ENGINE_REGISTRY merged into resolved registries (engineRegistriesWithEnv),
  native binary mirror/registry resolution in internal/engine/binary.go, + tests.
- Issue 5 / A2 — multi-model OpenClaw sync: models absent from the catalog (no
  type) were skipped by sync; now fall back to the backend-reported model type so
  every deployed provider syncs (TestSyncUsesBackendModelTypeWhenCatalogMisses);
  drop the canManageChatModelDefault guard so the synced model is set as default.

Also includes the round's dist artifacts (20260618 exe + P0 assessment doc).
Preserved as-is before layering the 2026-06-22 A-item fixes on top.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ch, A6 undeploy hint

A1 (P0) — deploy canonicalizes the model name (alias "Qwen2.5-VL-3B-Instruct-Q4_K_M"
→ "qwen2.5-vl-3b-instruct"), so undeploy/status/logs with the original alias failed
to match. Add canonicalModelAlt(cat, name) and retry undeploy/status/logs with the
canonical name; surface the original via a requested_model field in deploy results.

A5 — make the serve OpenClaw auto-sync loop switchable: `aima serve --no-openclaw-sync`
or AIMA_OPENCLAW_SYNC=manual|off|false|0|no disables it (sync then only on explicit
`aima openclaw sync`). Default unchanged (auto).

A6 — undeploy now prints a hint that model files are kept and how to free disk
(`aima model remove --delete-files <name>`); undeploy semantics unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New aima-windows-amd64-v0.5-dev-amd-strix-halo-20260623.exe (source 88b83b5) with the
2026-06-22 doc's A-item fixes: A1 undeploy/status/logs by original name, A5
--no-openclaw-sync / AIMA_OPENCLAW_SYNC switch, A6 undeploy disk-cleanup hint.
Adds AIMA集成问题-解决说明-20260623.md (per-item solution guide incl. A3 AIMA_MODEL_DIR
multi-dir, A4 AIMA_ENGINE_DIR, A2/A7 status). serve.bat -> 20260623.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
rjckkkkk and others added 28 commits July 9, 2026 16:32
@qinyue0508-cmd
qinyue0508-cmd requested a review from rjckkkkk August 3, 2026 08:53

@rjckkkkk rjckkkkk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

结论:当前不能合并,请修改后重新请求 Review。

1. 先清理 PR 范围

当前分支相对 develop 落后 27 个提交、超前 75 个提交,PR 包含 161 个文件和约 2.1 万行新增,并带入 19 个 EXE(约 532 MiB)。这与本 PR 的“通用恢复和 Engine 生命周期”范围不相符。

请从最新 develop 新建干净分支,只迁移本功能相关提交(553324f41ae8fd07d34e5),移除旧 AMD395 历史提交、二进制和无关文档。建议进一步拆为两个 PR:

  1. Deployment Intent / Reconciler / Runtime recovery。
  2. Engine inventory / ensure / rollback / import。

不要让 develop 为旧分支倒退;冲突应在新功能分支适配最新 develop

2. 必须修复的功能问题

  1. Engine 激活/回滚没有真正控制后续部署。 cmd/aima/resolve.go:368-395 从 inventory 选择第一个 available 记录,没有按 ActiveAssetName、platform、runtime 和 verification 状态筛选。engine.rollback 可能显示成功,但新部署仍使用已停用的新版本。

  2. Native 健康检查超时后可能永远停留在 starting internal/runtime/native.go:345-348, 722-723, 790-826 没有把健康超时记录为 failed/stalled;internal/recovery/state_machine.go:80-82 又明确忽略未 stalled 的 Native starting 状态,因此“不退出但永远不健康”的进程不会被恢复。

  3. 健康的 Docker/K3S 部署可能被误隔离。 新建/复用 Intent 时 ObservedRestartCount 从 0 开始;internal/recovery/state_machine.go:62-78 在检查 Ready 之前把累计历史重启数计入本窗口。一个当前健康、历史已有 3 次重启的容器,首次巡检就可能进入 quarantine 并被删除。

  4. 敏感配置会以字面值 [REDACTED] 被回放。 cmd/aima/tooldeps_deploy.go:1391-1403 将脱敏值写入 Intent,cmd/aima/tooldeps_deploy.go:545-551 恢复时又将该 map 作为真实 overrides 使用。带 token/API key 的部署会用错误凭据恢复并反复失败。敏感值应从安全来源重新解析;无法重新解析时应明确拒绝恢复。

  5. Catalog 更新会破坏固定版本恢复。 cmd/aima/tooldeps_deploy.go:102-108 只把 Intent 版本与当前 Catalog 版本比较;版本变化后直接失败,没有从 Engine inventory 定位 Intent 固定的旧版本。

  6. 新扫描的预装 Native Engine 无法进入 lifecycle。 cmd/aima/main.go:1132-1159 未保存 active/verification 状态,存储后默认为 inactive/unverified;internal/engine/lifecycle.go:123-132 会阻止复用,且当前没有完成验证并激活该记录的路径。

  7. 无可信摘要的 Native 离线包被标记为 verified。 cmd/aima/engine_lifecycle.go:439-446 在 Catalog 没有 SHA256 时直接通过,随后 302-318 仅计算自身哈希就标记 verified。自计算哈希不能证明包与预期资产一致。

  8. 隔离删除失败后不会重试。 quarantine delete 失败后 Intent 仍是 quarantined,但 quarantined Intent 被 internal/sqlite.go:1598-1601 排除,后续控制循环不会再次执行删除。

3. 需要补充的回归测试

  • ensure v2 → rollback v1 → 新部署实际使用 v1。
  • Native 进程存活但健康检查超时后触发恢复。
  • 健康容器带历史 restart count 时不会被误隔离。
  • 带 API key/token 的恢复不会使用 [REDACTED]
  • Catalog 升级后仍能恢复 Intent 固定的旧 Engine 版本。
  • 无可信 SHA256/digest 的离线导入不能进入 verified/active。
  • quarantine 删除遇到瞬时失败后可重试,且不会重新部署。

4. 验证说明

当前 HEAD 上 go test ./...go vet ./...、关键包 race 测试和四平台交叉构建均通过。但现有 GitHub 绿灯来自 amd395-win 的 push workflow,不是 PR 与最新 develop 的合并结果;上述端到端场景也没有被现有测试覆盖。

请完成范围清理、修复上述阻塞项,并在最新 develop 上通过合并结果 CI 后重新请求 Review。

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.

2 participants