# Platform Changelog

## [Unreleased]

### Added

#### ops control plane (`crates/ops-keeper`, `crates/ops-controller`)

New two-component ops control plane implementing secure, auditable operation dispatch.

**ops-keeper** — policy gate before any operation reaches the orchestrator:
- Glob-based `PolicyDef` matching on `op_type`, `image_patterns`, `target_patterns`
- `Signer` issues compact Ed25519 JWTs (`OpsClaims`) on policy approval
- NATS JetStream pull consumer on `ops.pending.*`
- `AuditEvent` emission to `ops.audit.*` on every terminal decision

**ops-controller** — durable executor with at-least-once delivery:
- Verifies keeper-signed JWT before dispatching to orchestrator HTTP API
- SurrealDB idempotency store; `reconcile_pending` reconciles stale ops on startup
- Structured `AckResult` (Ack / Nak / Term) per JetStream semantics
- Emits audit events to `ops.audit.*` on every terminal outcome

**ADR**: ADR-038 (ops control plane design)

#### audit-mirror (`crates/audit-mirror`)

Sidecar that consumes `ops.audit.*` and creates a signed git commit per event in a local Radicle repository, then announces the repo. JTI deduplication prevents double-commits on consumer redelivery.

**ADR**: ADR-038

#### contract-tests (`crates/contract-tests`)

G3 contract test suite verifying semantic equivalence across three tiers:
- **Tier A**: direct registry invocation (reference baseline)
- **Tier B**: axum HTTP daemon on ephemeral port
- **Tier C**: in-process MCP `handle_request`

Normaliser strips volatile fields; JSON schema validates every tier output against `listing_output_schema`. Regression guard for CLI↔HTTP↔MCP drift.

#### control-center: NATS→WebSocket bridge (`src/handlers/nats_bridge.rs`)

Eliminates long-polling between control-center UI and orchestrator. Durable JetStream consumer `cc-task-status-bridge` subscribes to `TASKS` stream and re-broadcasts each `TaskStatusPayload` to all connected WebSocket clients via `WebSocketManager`.

#### API catalog endpoints (`crates/ai-service`, `crates/control-center`)

`GET /api-catalog` added to ai-service and control-center. Each handler uses `inventory::iter::<ApiRouteEntry>()` to emit a sorted JSON catalog of all registered routes — self-describing API surface without a separate OpenAPI toolchain.

#### SOLID boundary pre-commit check (`.pre-commit-hooks/solid-boundary-check.sh`)

Shell hook enforced in `.pre-commit-config.yaml`. Fails the commit if a crate imports across declared SOLID layer boundaries, keeping dependency direction consistent before code reaches CI.

### Removed / Lifted

- **`crates/backup-manager`** — lifted to `cloudatasave` (LibreCloud/cloudDataSave). **ADR-041**.
- **`crates/buildkit-launcher`** — lifted to `lian-build`. **ADR-040**.
- **`crates/daemon`** — `Cargo.toml` removed; binary consolidated into `provisioning-daemon`.
- **`prov-ecosystem/crates/nu-daemon`** / **`daemon-cli`** — excluded from workspace; `rustls=0.23.28` pin conflicts with surrealdb@3 (`^0.23.36`). Build standalone with `cargo build -p nu-daemon` until `nu-command` relaxes the pin.

---

## [3.6.0] — 2026-04-17

### Added

#### ncl-sync daemon (`crates/ncl-sync/`)

New Rust daemon that eliminates `nickel export` latency from CLI commands by pre-compiling NCL files and maintaining a shared cache.

- **File watching**: `notify` watcher on workspace NCL directories; re-exports automatically on file change
- **Warm-up**: on `prvng platform start`, scans all NCL files in the workspace and exports stale entries concurrently (configurable concurrency)
- **Shared cache**: `~/.cache/provisioning/config-cache/` — same directory and key strategy as `nu_plugin_nickel`
- **Content-addressed keys**: `SHA256(file_content + sorted_import_paths + format)` — zero coordination overhead between daemon and plugin
- **Sync requests**: Nu processes write `.sync-<pid>.json` sidecars after mutations; daemon drains them within 500 ms
- **CLI subcommands**: `daemon`, `warm`, `invalidate`, `key`, `stats`
- **Config-driven** via `platform-config`: `platform/config/ncl-sync.ncl` — idle timeout, concurrency, poll interval, extra import paths
- **No platform dependencies**: intentionally avoids NATS, SurrealDB, and orchestrator to prevent bootstrap circularity

#### Platform lifecycle integration

- `prvng platform start` now launches `ncl-sync daemon` (via `ncl-sync-start` in `service-manager.nu`)
- `prvng platform stop` stops ncl-sync (via PID file)
- `prvng platform status` shows ncl-sync running state

#### Nu cache layer

- `lib_provisioning/config/cache/core.nu`: implemented `cache-lookup`, `cache-write`, `write-sync-request` (previously no-ops)
- `lib_provisioning/config/cache/nickel.nu`: implemented `lookup-nickel-cache`, `derive-ncl-cache-key`, `request-ncl-sync`

#### nickel_processor wrappers

New `lib_provisioning/utils/nickel_processor.nu` functions:
- `ncl-eval`: drop-in for `^nickel export ... | from json` — checks plugin cache, propagates error on failure
- `ncl-eval-soft`: soft-failure variant with configurable fallback value

#### nu_plugin_nickel updates

- `nickel-eval` and `nickel-export` now accept `--import-path LIST` flag (`-I`)
- New command `nickel-cache-key`: prints the cache key for a file (parity testing)
- Cache key derivation updated to `SHA256(file_content + sorted_import_paths + format)` — aligned with ncl-sync
- Cache key now includes import paths: same file with different import paths produces different cache entries

#### Hot-path migration (C1)

Replaced `^nickel export ... | from json` with `ncl-eval`/`ncl-eval-soft` in the four highest-frequency call sites:
- `main_provisioning/dispatcher.nu` — commands-registry load
- `main_provisioning/components.nu` — workspace settings export
- `main_provisioning/workflow.nu` — workflow NCL exports
- `main_provisioning/extensions.nu` — per-extension metadata

#### Extended migration (C2 + C3)

Migrated remaining high-value call sites (~55 additional sites across 30+ files) including `config/export.nu`, `taskservs/discover.nu`, `servers/create.nu`, `ontoref-queries.nu`, `service-manager.nu`, `dag.nu`, and others.

#### ADRs

- `adrs/adr-022-ncl-sync-daemon.ncl`: daemon design decisions, key strategy rationale, constraint enforcement
- `adrs/adr-023-ncl-export-wrapper.ncl`: `ncl-eval`/`ncl-eval-soft` wrapper design, migration strategy

#### Tests

- `tests/cache/test_key_parity.nu`: validates that ncl-sync and nu_plugin_nickel produce identical keys for the same `(file, import_paths, format)` triple

### Performance

| Command | Before | After (warm cache) |
|---------|--------|--------------------|
| `prvng component list` | 3–7 s | ~1.5 s |
| `prvng workflow list` | 3–5 s | ~1.5 s |
| `prvng deploy` | 15–30 s | ~3–5 s |
| Multi-export commands (ontoref) | 12–30 s | ~1.5 s |

Nu module parse startup (~1.2 s) is unaffected — separate concern.

---

## [3.5.0] — 2025-10-07

Initial platform version with orchestrator, control center, installer, MCP server, vault service, and extension registry.
