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
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased] — `crd-well-oiled-machine`

### Slice 3b.1 — ClawMemory operator UX (inspect CLI + Headlamp panel)

Operator-facing surface for the §3 echo loop closed in Slice 3a. The
producer-side facts (`compiledDigest`, `loadedDigest`, `Ready` reason)
now light up where operators already look:

* `azureclaw inspect <sandbox>` — the `Memory` wire kind now maps to
the user-facing display label `ClawMemory` (was the stale planning
name `MemoryStore`). The tree groups Memory entries under their own
header next to `ToolPolicy` and `InferencePolicy`.
* Headlamp plugin `RouterPolicyStatusPanel` — now renders for
`clawmemories` (in addition to `toolpolicies` + `inferencepolicies`),
surfacing the compiled/loaded digest pair and the `Ready` reason
chip. Zero new API traffic — pure read of fields the controller
already writes in Slice 3a.

### Slice 3a — ClawMemory router-echo

Closes principles.md §3 ("Ready ⇔ router echo") for the third CRD
Expand Down
29 changes: 21 additions & 8 deletions cli/src/commands/inspect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,22 +97,35 @@ describe("inspect — renderEntry", () => {
});

describe("inspect — POLICY_KIND_LABEL", () => {
it("maps every PolicyKind wire string we render today + the planned ones", () => {
// Today the router only emits `AgtProfile` + `InferencePolicy`
// (`inference-router/src/policy_status.rs::PolicyKind::as_str`).
// The CLI carries defensive mappings for the kinds Slice 1b/3/4/5
// will add (ToolPolicy/MemoryStore/Egress) so a partial-rollout
// cluster where the router is ahead of the CLI still prints
// sensible labels.
it("maps every PolicyKind wire string the router emits today", () => {
// Wire kinds emitted by
// `inference-router/src/policy_status.rs::PolicyKind::as_str`:
// AgtProfile (Slice 1a) — controller-side AGT profile aggregate.
// ToolPolicy (Slice 1b/c) — compiled ToolPolicy artifacts.
// InferencePolicy (Slice 2a) — compiled InferencePolicy.
// Egress (future) — defensive carry-over.
// Memory (Slice 3a) — compiled ClawMemory binding.
//
// A partial-rollout cluster where the router is ahead of the CLI
// still prints sensible labels for the kinds the CLI knows.
for (const wire of [
"ToolPolicy",
"AgtProfile",
"InferencePolicy",
"Egress",
"MemoryStore",
"Memory",
]) {
expect(POLICY_KIND_LABEL[wire]).toBeTypeOf("string");
expect(POLICY_KIND_LABEL[wire]).not.toBe("");
}
});

it("renders the Slice 3a `Memory` wire kind as `ClawMemory`", () => {
// Slice 3a contract: the router emits `PolicyKind::Memory`
// (as_str="Memory") for the compiled binding mounted at
// `/etc/azureclaw/memory/binding.json`. The CLI must display
// the user-facing CRD name so `inspect` reads naturally next
// to `kubectl get clawmemory`.
expect(POLICY_KIND_LABEL["Memory"]).toBe("ClawMemory");
});
});
5 changes: 4 additions & 1 deletion cli/src/commands/inspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ const POLICY_KIND_LABEL: Record<string, string> = {
AgtProfile: "AGT profile",
InferencePolicy: "InferencePolicy",
Egress: "Egress",
MemoryStore: "ClawMemory",
// Slice 3a: router emits `PolicyKind::Memory` (as_str="Memory") for
// the compiled ClawMemory binding at /etc/azureclaw/memory/binding.json.
// Display as the user-facing CRD name.
Memory: "ClawMemory",
};

interface PolicyStatusEntry {
Expand Down
6 changes: 5 additions & 1 deletion tools/headlamp-plugin/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,11 @@ function RouterPolicyStatusPanel({ crd, item }: { crd: CrdDescriptor; item: Kube
// Only the policy CRDs that the router actually loads carry these
// fields. ClawSandbox, McpServer, etc. don't participate in the
// digest-echo loop yet.
if (crd.plural !== "toolpolicies" && crd.plural !== "inferencepolicies") {
if (
crd.plural !== "toolpolicies" &&
crd.plural !== "inferencepolicies" &&
crd.plural !== "clawmemories"
) {
return null;
}
const status = getStatus(item);
Expand Down
Loading