diff --git a/.changeset/bindings-gc-crash.md b/.changeset/bindings-gc-crash.md deleted file mode 100644 index 47f12eea..00000000 --- a/.changeset/bindings-gc-crash.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -The Go runtime bindings no longer risk a rare fatal crash (`invalid pointer found on stack`) under GC pressure. The runtime's integer session handles could appear in pointer-typed stack slots during FFI calls; if the GC moved the stack while a callback was running mid-call, the process aborted. Handles now stay integer-typed end-to-end on the Go side, with all casting done in C shims. The crash could hit anything embedding the bindings, including the CLI. diff --git a/.changeset/classify-wrapped-errors.md b/.changeset/classify-wrapped-errors.md deleted file mode 100644 index 09c8ac25..00000000 --- a/.changeset/classify-wrapped-errors.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -Projection errors that reach the CLI wrapped in another error now keep their original error code and diagnostics. Previously a wrapped feed error was classified as `unexpected-error` and its diagnostics were dropped. diff --git a/.changeset/config-drift-warning.md b/.changeset/config-drift-warning.md deleted file mode 100644 index 46ca2d21..00000000 --- a/.changeset/config-drift-warning.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer deploy` and `gaffer status` warn when the target node's live engine settings diverge from a declared `[database_config]`: one line per differing knob, read from the node's options endpoint. Fixtures and local runs assumed the declared values, so a server enforcing a different `max_state_size` or timeout is visible before it bites. The check is advisory: a server that doesn't expose its options, or refuses the read, skips it silently, and a non-positive `max_state_size` declares the engine default rather than a value. - -`gaffer status --json` now emits an object: a `projections` array (the previous per-projection entries) plus a `configDrift` array of `{"knob", "server", "local"}` when the target diverges. Machine consumers see the divergence without a second call. `gaffer deploy --json` is unchanged; its warning prints on stderr, keeping the stdout payload clean while CI logs still show it. diff --git a/.changeset/dap-restart-shutdown.md b/.changeset/dap-restart-shutdown.md deleted file mode 100644 index 71dba744..00000000 --- a/.changeset/dap-restart-shutdown.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer dev --debug` no longer hangs when a Restart arrives as the session is tearing down; the restart returns cleanly during shutdown instead of leaving the debug adapter's read goroutine waiting forever. diff --git a/.changeset/database-config.md b/.changeset/database-config.md deleted file mode 100644 index 165cc4cd..00000000 --- a/.changeset/database-config.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@kurrent/gaffer": minor ---- - -**Breaking:** `gaffer.toml` gains a `[database_config]` section for node-level engine settings, and the top-level `compilation_timeout` / `execution_timeout` keys move into it. A file that still sets them at the top level now fails to load, with a message pointing at the new section. - -`[database_config]` declares the engine configuration expected on a deployment target: - -- `max_state_size` (newly exposed) caps a projection's serialized state in bytes, defaulting to the server's 16 MiB. It is enforced on local runs, so a projection that would exceed the cap faults locally, catching state bloat before deploy. -- `compilation_timeout` and `execution_timeout` are declaration only: gaffer records them for deploy-time configuration checks but does not apply them to local runs, since a wall-clock budget measured on a dev machine isn't comparable to the server's. To bound how long a local projection may run before gaffer treats it as hung, set the `GAFFER_TIMEOUT_MS` environment variable (default 5000ms). A per-`[[projection]]` `execution_timeout` is likewise declaration only and no longer affects local runs. diff --git a/.changeset/deploy-ci-mode.md b/.changeset/deploy-ci-mode.md deleted file mode 100644 index 733c0658..00000000 --- a/.changeset/deploy-ci-mode.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer deploy` gains `--dry-run` and a stable exit-code contract for CI. `--dry-run` shows the plan and applies nothing. The exit code is now `0` succeeded or nothing to do, `1` an error, and `2` changes are pending (`--dry-run` only). A new `3` means refused by a guardrail: confirmation was needed but there was no terminal or `--yes`, or `--no-validate` was used against production. - -`--dry-run` reuses the same per-projection plan output as a confirmed deploy, and its `--json` is the same array shape, so a pipeline can branch on exit `2` or parse the would-be outcomes. The guardrail exit code `3` also applies to `recreate` and the operate verbs when they can't confirm non-interactively. A production `--no-validate` refusal now prints its reason instead of exiting silently. diff --git a/.changeset/deploy-column-alignment.md b/.changeset/deploy-column-alignment.md deleted file mode 100644 index d0df50b5..00000000 --- a/.changeset/deploy-column-alignment.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer deploy` now measures its per-projection verdict column by terminal display width, so projection names with multi-byte or full-width characters no longer over-pad the column and misalign the verdicts. diff --git a/.changeset/deploy-command.md b/.changeset/deploy-command.md deleted file mode 100644 index 47d8247e..00000000 --- a/.changeset/deploy-command.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer deploy` creates or updates projections on an environment from `gaffer.toml`: it creates the ones not yet on the server, updates the ones whose definition changed, and skips the ones already in sync (matched by content hash). The emit flag is always sent explicitly, so an update never clears it. - -With no argument it deploys every projection in `gaffer.toml`; name one to deploy just it. A change to engine version or track-emitted-streams can't be applied in place (it would mean recreating the projection and dropping its state), so `gaffer deploy` reports it and leaves the projection untouched. On a terminal it shows live per-projection progress; pass `--json` for machine-readable output. diff --git a/.changeset/deploy-final-row.md b/.changeset/deploy-final-row.md deleted file mode 100644 index e52d6555..00000000 --- a/.changeset/deploy-final-row.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer deploy`'s interactive view no longer drops the last projection's result line when the run finishes. The final row's commit and the program quit now run as one ordered step, so the verdict is always flushed before the view tears down (a single-projection deploy previously showed only the summary). diff --git a/.changeset/deploy-flag-external-change.md b/.changeset/deploy-flag-external-change.md deleted file mode 100644 index 75c89cf1..00000000 --- a/.changeset/deploy-flag-external-change.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer deploy` now flags a projection whose deployed definition was changed outside gaffer since its last deploy, so a deploy doesn't silently revert an out-of-band change. - -- The plan preview and the non-interactive (`--yes`) apply warnings show a caution ("`` was changed outside gaffer since its last deploy; deploying overwrites it"), naming the tool when another tool made the change. -- `gaffer deploy --json` carries `externalChange: true` on the affected item, alongside `logicChange`, so CI can alert. - -Gaffer is the canonical source of truth, so it still deploys - the drift is surfaced, not refused. Degrades silently against a KurrentDB without the deploy-metadata field. diff --git a/.changeset/deploy-guardrails.md b/.changeset/deploy-guardrails.md deleted file mode 100644 index f610fab6..00000000 --- a/.changeset/deploy-guardrails.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer deploy` now plans the whole run before touching the server and confirms before applying. It shows what would change per projection (`created` / `updated` / `skipped` / `refused`) against the target's reported cluster name, then asks before writing. `--yes` skips the prompt; without a terminal (or with `--json`) it won't apply unconfirmed, so pass `--yes` in scripts. An update whose deployed projection is currently faulted is flagged, since updating won't clear the fault. - -A server that reports itself as production gets a louder confirmation and refuses `--no-validate`. Production is read from the server's own `$server-info`, never inferred from the environment name, so a connection that points at production is guarded even if its env is labelled otherwise. Databases that don't report production status are unaffected. diff --git a/.changeset/deploy-ledger.md b/.changeset/deploy-ledger.md deleted file mode 100644 index 79613b77..00000000 --- a/.changeset/deploy-ledger.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer deploy` now records tool metadata on every projection it creates or updates, so a projection carries who deployed it and from where: the tool (`Gaffer`) and version, the operation, the source revision, and the acting identity. It follows a shared convention that other KurrentDB tools can write and display. - -- **`revision`** defaults to the project's git commit (suffixed `+changes` when the working tree is dirty); set `GAFFER_REVISION` in CI to record the canonical commit. -- **`actor`** defaults to the identity gaffer connects as (the basic-auth user or OAuth client), omitted for an anonymous connection; set `GAFFER_ACTOR` in CI to record the pipeline identity. - -The metadata rides on the projection's definition event and is best-effort: against a KurrentDB that predates the feature it is silently ignored and deploy behaves exactly as before. diff --git a/.changeset/deploy-plan-preview.md b/.changeset/deploy-plan-preview.md deleted file mode 100644 index d3534c02..00000000 --- a/.changeset/deploy-plan-preview.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer deploy`'s plan preview now lists each projection, not just totals. Every projection that would change shows a verdict - `create`, `update`, `rebuild`, `refused`, or `failed` - and a dimmed detail column carrying the refusal reason or the failure error in full. In-sync projections stay a count only, so unchanged ones don't drown the signal. diff --git a/.changeset/deploy-preflight.md b/.changeset/deploy-preflight.md deleted file mode 100644 index 047e890d..00000000 --- a/.changeset/deploy-preflight.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer deploy` now compiles every projection before sending anything to the server. If any fails to compile, or compiles but carries errors that would fault on the server (such as a quirk that reproduces an upstream engine crash), the whole deploy is refused up front, so a bad projection can't leave the earlier ones already applied. The check runs locally, before connecting, and `--no-validate` skips it. diff --git a/.changeset/deploy-reset-awareness.md b/.changeset/deploy-reset-awareness.md deleted file mode 100644 index 8489f564..00000000 --- a/.changeset/deploy-reset-awareness.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer deploy` now treats a changed projection query as a logic change. The new code may read already-processed events differently, so the accumulated state could be wrong. By default deploy keeps the checkpoint, applies the update, and flags the change in the plan. Pass `--reset-on-logic-change` to rebuild instead: each logic-changed projection is stopped, updated, reset to the beginning, and restarted so it reprocesses from zero with the new logic. An emitting projection re-emits on a rebuild and may duplicate into its target streams, so the plan warns and points at `gaffer recreate --delete-emitted` for a clean-emit rebuild. - -A continued logic change shows as `logicChange: true` on its `--json` item, so CI can alert on it. A change to engine version or track-emitted-streams still can't be applied in place; deploy now points at `gaffer recreate` rather than just refusing. diff --git a/.changeset/diff-command.md b/.changeset/diff-command.md deleted file mode 100644 index e9ba890f..00000000 --- a/.changeset/diff-command.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer diff ` compares a projection's local definition against what's deployed on KurrentDB and reports its state: in sync, drifted, not deployed, or untracked. - -When the query differs, the source is shown in an external diff viewer. By default this is `git diff --no-index`; set `GAFFER_EXTERNAL_DIFF` to override. Pass `--json` for machine-readable output. diff --git a/.changeset/diff-in-process.md b/.changeset/diff-in-process.md deleted file mode 100644 index 4ccf0c45..00000000 --- a/.changeset/diff-in-process.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer diff` renders the query source diff itself instead of shelling out to an external viewer. Every line of both sides is shown with the changes marked in place: dual line-number gutters, +/- colouring, and the span that changed within a line highlighted. The diff is computed on the same canonical form as the drift verdict, so it always matches the `+N -M` stat that `gaffer diff` and `gaffer status` report. It now works without git installed, when piped, and in CI. - -Set `GAFFER_EXTERNAL_DIFF` to open an external viewer instead (e.g. `git diff`, `delta`, `difft`); it is no longer the default path. diff --git a/.changeset/emits-events.md b/.changeset/emits-events.md deleted file mode 100644 index 63a3f272..00000000 --- a/.changeset/emits-events.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@kurrent/gaffer": patch -"@kurrent/gaffer-runtime": patch -"@kurrent/projections-testing": patch ---- - -Projection info now reports whether a projection writes events. `ProjectionInfo` gains an `emitsEvents` flag, true when the projection calls `emit`, `linkTo`, `linkStreamTo`, or `copyTo`. It is detected on every compile from the source, so consumers no longer need to inspect shape counts. - -`gaffer info` shows it ("Emits events: yes"); `gaffer info --json` and the MCP `get_projection_info` and `validate_projection` tools include `emitsEvents`; the testing library exposes it as `info.settings.emitsEvents`. diff --git a/.changeset/gaffer-rollback.md b/.changeset/gaffer-rollback.md deleted file mode 100644 index e40336a7..00000000 --- a/.changeset/gaffer-rollback.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer rollback ` rolls a deployed projection back to a prior version from its history, stamped `operation: rollback` in the deploy ledger. The target is named by its content hash from `gaffer history`; any unique prefix of 4 or more characters works. It confirms first with the current-to-target query diff (`--yes` skips). The apply is in place: processing continues from the current checkpoint, and local files stay untouched, so `gaffer diff` shows the rollback as drift until local is reconciled. A version differing in engine version or emitted-stream tracking is refused, pointing at `gaffer recreate`. - -The `gaffer history` timeline gains `r`: it opens the same confirm as a modal for the selected entry, applies on `y`, and reloads the timeline so the new rollback entry appears on top. diff --git a/.changeset/handler-error-wedge-diagnostic.md b/.changeset/handler-error-wedge-diagnostic.md deleted file mode 100644 index 7c182e54..00000000 --- a/.changeset/handler-error-wedge-diagnostic.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@kurrent/gaffer": patch -"@kurrent/gaffer-runtime": patch ---- - -Event-processing errors under `engine_version 2` now carry the `quirk.handlerError.wedgesOnV2` (error severity) diagnostic. On deployed V2, an exception thrown while processing an event never faults the projection. It wedges silently: `status` stays `Running` while processing and persistence have stopped, and nothing is logged. Gaffer keeps faulting the event locally, which is the behaviour V2 should have, and the diagnostic rides the error to explain the divergence. It fires for any event-processing throw (handler, state load, `$created`, `$deleted`, state serialization, timeout); a throwing `partitionBy` is exempt because the server computes partition keys on its read loop, which faults properly. diff --git a/.changeset/history-command.md b/.changeset/history-command.md deleted file mode 100644 index 7c4bd653..00000000 --- a/.changeset/history-command.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer history ` shows a deployed projection's history: every operation on it, newest first, with who made it and how. - -- On a terminal it opens an interactive timeline: a scrolling list on the left, the selected entry's full detail on the right, and a footer naming the projection and target. Navigate with `↑`/`↓` (or `j`/`k`), `g`/`G`, `PgUp`/`PgDn`; `q` or `Esc` quits. Older entries page in as you scroll. -- Each entry is one write to the projection. One carrying gaffer metadata shows its operation (deploy, rollback, reset), the actor, and the source revision. One without is attributed by what changed: `edited-externally` when the definition changed outside gaffer, `changed-by` (with the tool named) for another tool's write, `enabled`/`disabled` for a lifecycle change, `reconfigured` when a checkpoint or performance setting moved, `rewritten` for an identical redeploy, or `created`/`deleted`. -- A content hash identifies each deployed definition, so a reverted definition is recognisable at a glance: the timeline draws a revert as a branch off the live line, linking the restored definition back to the earlier one it matched (nested reverts included). -- Piped or with `--json` it prints the latest entries instead (`--limit`, default 100, or `--all`). Each `--json` entry carries the full content hash, its classification and flags, the tool metadata, and any configuration knobs that moved. - -Against a KurrentDB without the deploy-metadata field it degrades to the history with timestamps and content hashes only. diff --git a/.changeset/history-diff-modal.md b/.changeset/history-diff-modal.md deleted file mode 100644 index 43bab00e..00000000 --- a/.changeset/history-diff-modal.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer history` gains `d`: a diff of the selected entry against the version before it, shown in an overlay on the timeline. It answers "what changed at this entry" the way `git show` does. The previous *content* version is the baseline (state changes are skipped; their definition is identical), the first version diffs from empty, and a state-change entry reports "no definition change". - -The diff uses the same aligned renderer and tints as `gaffer diff`, with any engine version, emit, or tracking change named above it. The arrow keys keep scrubbing the timeline underneath, so the diff re-renders entry by entry, walking a definition's evolution in place. `PgUp`/`PgDn` scroll a long diff; `esc`, `d`, or `q` closes back to the timeline. A baseline on an older page is fetched automatically. diff --git a/.changeset/json-output-write-error.md b/.changeset/json-output-write-error.md deleted file mode 100644 index 84196eea..00000000 --- a/.changeset/json-output-write-error.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer dev --json` now exits non-zero if it fails to write its output stream (for example a broken pipe to the editor), instead of silently finishing with a truncated stream. diff --git a/.changeset/ledger-aware-status-diff.md b/.changeset/ledger-aware-status-diff.md deleted file mode 100644 index 5e707d13..00000000 --- a/.changeset/ledger-aware-status-diff.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer status` and `gaffer diff` are now ledger-aware, reading the tool metadata gaffer stamps on deploy to say more than `untracked` or `drifted`. - -- **Ownership** of a projection on the server but not in local config: `orphan` (gaffer deployed it, now gone from `gaffer.toml` - a deletion candidate) or plain `untracked`, with the deploying tool named when its metadata is present. `--json` reports this as `owner`, including `foreign` for a projection another tool manages. -- **Drift attribution** of an in-config projection that differs from what's deployed: `local ahead` (you've edited local since your deploy) or `changed externally` (a tool or a direct write changed the server since). `--json` splits the latter into `changed-by-tool` and `changed-server`. - -Both surface in the status table and detail and in `gaffer diff`. The status table gains **LAST DEPLOY** and **DEPLOYED VIA** columns, and naming a projection (or running `gaffer diff`) shows the deploy provenance behind it: when, the tool and version, the deployer, and the source revision. The last-deploy date comes from the event itself, so it shows even for a projection with no tool metadata. In `--json`: `owner`, `attribution`, a top-level `lastDeployed` timestamp, and `lastWrite` (the tool and actor). Against a KurrentDB without the deploy-metadata field it degrades to the previous behaviour. diff --git a/.changeset/mcp-deploy-apply.md b/.changeset/mcp-deploy-apply.md deleted file mode 100644 index ec11969a..00000000 --- a/.changeset/mcp-deploy-apply.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -The MCP server gains **`deploy_apply`**, so an assistant can deploy projections from `gaffer.toml` like `gaffer deploy`: - -- The same all-or-nothing compile and diagnostics preflight, with no validation bypass. -- The same per-item results as `gaffer deploy --json`, and every write stamped `operation: deploy` in the ledger. -- A production deploy requires a confirmation answered through the MCP client (elicitation). The prompt names the changed projections, rebuilds, out-of-band overwrites, faulted targets, and any `[database_config]` divergence. -- A plan containing `resetOnLogicChange` rebuilds destroys state, so it always asks; on production that confirmation requires typing the environment name. diff --git a/.changeset/mcp-deploy-read-tools.md b/.changeset/mcp-deploy-read-tools.md deleted file mode 100644 index 6ac854e9..00000000 --- a/.changeset/mcp-deploy-read-tools.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -The MCP server gains read-only deploy visibility, mirroring the CLI's machine output: - -- **`deploy_status`** shows each projection's runtime state and drift verdict on an environment, plus any `[database_config]` divergence, like `gaffer status --json`. -- **`deploy_plan`** previews what a deploy would change without applying anything, like `gaffer deploy --dry-run --json`. -- **`deploy_history`** reads a projection's per-deploy audit log with paging, like `gaffer history --json`. - -All three accept an `env` argument and default to the default environment. Applying changes stays in the CLI, behind its confirmation gates. diff --git a/.changeset/mcp-operate-verbs.md b/.changeset/mcp-operate-verbs.md deleted file mode 100644 index 38652d17..00000000 --- a/.changeset/mcp-operate-verbs.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -The MCP server gains the operate verbs, so an assistant can manage a deployed projection's lifecycle with a human in the loop: - -- **`deploy_pause`** / **`deploy_resume`** / **`deploy_abort`** mirror `gaffer disable` / `enable` / `disable --abort`. -- **`deploy_recreate`** rebuilds from local config like `gaffer recreate`, gated on the compile and diagnostics preflight, and stamps `operation: recreate` in the deploy ledger. -- **`deploy_rollback`** redeploys a prior version by content hash from `deploy_history`, like `gaffer rollback`, and stamps `operation: rollback`. -- **`deploy_delete`** mirrors `gaffer delete`, including `deleteEmitted`. - -Writes against a server that reports itself as production require a confirmation answered through the MCP client (elicitation); the assistant cannot answer it. The prompt front-loads `PRODUCTION [env.]:` and states each verb's consequence. Recreate and delete destroy state with no undo, so they ask every time; on production their confirmation requires typing the projection name. A client without elicitation support cannot perform gated writes; the refusal names the CLI command to run instead. `deploy_status` and `deploy_plan` now also echo the resolved target and production flag. diff --git a/.changeset/operate-verbs.md b/.changeset/operate-verbs.md deleted file mode 100644 index 4578288c..00000000 --- a/.changeset/operate-verbs.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer enable`, `gaffer disable`, and `gaffer delete` manage deployed projections on an environment, named directly (they need not be in `gaffer.toml`). - -- `gaffer enable ` starts a projection so it resumes from its last checkpoint. -- `gaffer disable ` stops it, writing a final checkpoint; `--abort` skips that checkpoint so a later enable replays from the last one. Disabling is recoverable, so it confirms only against production. -- `gaffer delete ` removes the projection with its state and checkpoint streams, keeping emitted streams unless `--delete-emitted` is passed. It always confirms, and disables the projection first since the server won't delete an enabled one. - -`--yes` skips the confirmation; without a terminal (or with `--json`) a guarded verb won't proceed unconfirmed. Production gets a louder confirm and is read from the server's `$server-info`, never the env label. diff --git a/.changeset/per-projection-config-errors.md b/.changeset/per-projection-config-errors.md deleted file mode 100644 index 01455ef1..00000000 --- a/.changeset/per-projection-config-errors.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -A per-projection config error (e.g. `track_emitted_streams` with `engine_version 2`) no longer blocks every command. Previously one misconfigured projection failed `gaffer.toml` loading outright, so `gaffer info ` died on an *unrelated* projection's error. Now config validation splits into structural checks (environments, duplicate names) that stay fatal, and per-projection checks that are deferred; a bad projection only blocks operations on itself. The inspection commands (`status`, `diff`, `info`) show it as `invalid` through one shared rendering; `deploy` refuses just that one; `recreate` and the operate verbs fail only when you name it. Mirrors the per-projection degradation already used for compile errors. diff --git a/.changeset/recreate-ledger-stamp.md b/.changeset/recreate-ledger-stamp.md deleted file mode 100644 index 54fd26f2..00000000 --- a/.changeset/recreate-ledger-stamp.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer recreate` now stamps its rebuild in the deploy ledger, so `gaffer history` attributes it to gaffer instead of showing anonymous lifecycle steps. The create carries `operation: recreate` with the usual tool, actor, and source revision. - -`gaffer history` shows a recreate as a single entry: the disable and delete writes it performs are folded into the `recreate` row, and the detail panel notes the projection was reprocessed from zero. `--json` keeps every write as its own entry, with the create's `kind` set to `recreate`. diff --git a/.changeset/recreate.md b/.changeset/recreate.md deleted file mode 100644 index 7a1b8efe..00000000 --- a/.changeset/recreate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer recreate ` destroys and rebuilds a deployed projection from local config: stop it, delete it (with its state and checkpoint streams), and create it fresh, reprocessing from zero. It applies a create-only change that deploy can't make in place (engine version, track-emitted-streams), or rebuilds a wedged projection an in-place reset can't fix. The projection is compiled before anything is deleted, so a broken local definition can't leave you with nothing to rebuild; `--no-validate` skips that check (production refuses it). It always confirms, more prominently against production, with `--yes` for non-interactive use. `--delete-emitted` also wipes the emitted streams so the rebuild doesn't re-emit duplicates. diff --git a/.changeset/reject-absolute-paths.md b/.changeset/reject-absolute-paths.md deleted file mode 100644 index 1a1fbd2b..00000000 --- a/.changeset/reject-absolute-paths.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kurrent/gaffer": minor ---- - -**Breaking:** `gaffer.toml` now rejects absolute `entry` and `fixtures.` paths at load time. Previously an absolute path (e.g. `entry = "/etc/passwd"`, or a Windows drive-letter form like `C:\...`) slipped past validation while the scaffold write path already rejected it. Both surfaces now enforce the same rule: paths must be relative to the project root and must not escape it. diff --git a/.changeset/status-command.md b/.changeset/status-command.md deleted file mode 100644 index e6f6603b..00000000 --- a/.changeset/status-command.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer status` shows the runtime state of projections on an environment and how they compare to local config: running, stopped or faulted, progress, and whether each is in sync, drifted, not deployed, or untracked. - -With no argument it lists every local and deployed projection as a table; name a projection for its detail. Pass `--json` for machine-readable output. diff --git a/.changeset/status-diff-invalid.md b/.changeset/status-diff-invalid.md deleted file mode 100644 index c4c48463..00000000 --- a/.changeset/status-diff-invalid.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@kurrent/gaffer": patch ---- - -`gaffer status` and `gaffer diff` no longer abort when a local projection fails to compile. A compile error is now a per-projection condition, not a whole-command failure. `gaffer status` shows the broken projection as `invalid` and still renders the rest of the table with their real runtime state and drift. `gaffer diff` still shows the source diff, engine version, and track-emitted-streams, marking `emit` unknown because deriving it needs a successful compile. Both exit 0, and the compile error is shown so you know what to fix. diff --git a/.changeset/track-emitted-streams-v2-diagnostic.md b/.changeset/track-emitted-streams-v2-diagnostic.md deleted file mode 100644 index f5048663..00000000 --- a/.changeset/track-emitted-streams-v2-diagnostic.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@kurrent/gaffer": patch -"@kurrent/gaffer-runtime": patch ---- - -`track_emitted_streams` with `engine_version 2` is now reported as a diagnostic rather than a config-load error. The runtime emits `quirk.trackEmittedStreams.unsupportedOnV2` (error severity) off the resolved definition, whether the flag comes from `gaffer.toml` or `options({ trackEmittedStreams: true })` in the source. This matches how the other V2 incompatibilities (bi-state, `outputState`) already surface. - -`gaffer info`, `gaffer dev`, and `gaffer diff` now compile such a projection and show its full analysis plus the flag, instead of failing with a bare config error. `gaffer deploy` and `gaffer recreate` still refuse it at preflight (recreate before deleting anything), and the MCP `validate` tool reports it invalid with the diagnostic. The projection session no longer throws on the combination. diff --git a/bindings/js/CHANGELOG.md b/bindings/js/CHANGELOG.md index 360bfc54..ca273a1e 100644 --- a/bindings/js/CHANGELOG.md +++ b/bindings/js/CHANGELOG.md @@ -1,5 +1,18 @@ # @kurrent/gaffer-runtime +## 0.3.1 + +### Patch Changes + +- ce0de95: Projection info now reports whether a projection writes events. `ProjectionInfo` gains an `emitsEvents` flag, true when the projection calls `emit`, `linkTo`, `linkStreamTo`, or `copyTo`. It is detected on every compile from the source, so consumers no longer need to inspect shape counts. + + `gaffer info` shows it ("Emits events: yes"); `gaffer info --json` and the MCP `get_projection_info` and `validate_projection` tools include `emitsEvents`; the testing library exposes it as `info.settings.emitsEvents`. + +- eeaff5f: Event-processing errors under `engine_version 2` now carry the `quirk.handlerError.wedgesOnV2` (error severity) diagnostic. On deployed V2, an exception thrown while processing an event never faults the projection. It wedges silently: `status` stays `Running` while processing and persistence have stopped, and nothing is logged. Gaffer keeps faulting the event locally, which is the behaviour V2 should have, and the diagnostic rides the error to explain the divergence. It fires for any event-processing throw (handler, state load, `$created`, `$deleted`, state serialization, timeout); a throwing `partitionBy` is exempt because the server computes partition keys on its read loop, which faults properly. +- e59a851: `track_emitted_streams` with `engine_version 2` is now reported as a diagnostic rather than a config-load error. The runtime emits `quirk.trackEmittedStreams.unsupportedOnV2` (error severity) off the resolved definition, whether the flag comes from `gaffer.toml` or `options({ trackEmittedStreams: true })` in the source. This matches how the other V2 incompatibilities (bi-state, `outputState`) already surface. + + `gaffer info`, `gaffer dev`, and `gaffer diff` now compile such a projection and show its full analysis plus the flag, instead of failing with a bare config error. `gaffer deploy` and `gaffer recreate` still refuse it at preflight (recreate before deleting anything), and the MCP `validate` tool reports it invalid with the diagnostic. The projection session no longer throws on the combination. + ## 0.3.0 ### Minor Changes diff --git a/bindings/js/native/darwin-arm64/CHANGELOG.md b/bindings/js/native/darwin-arm64/CHANGELOG.md index 134aef08..e71f29fd 100644 --- a/bindings/js/native/darwin-arm64/CHANGELOG.md +++ b/bindings/js/native/darwin-arm64/CHANGELOG.md @@ -1,5 +1,7 @@ # @kurrent/gaffer-runtime-darwin-arm64 +## 0.3.1 + ## 0.3.0 ## 0.2.0 diff --git a/bindings/js/native/darwin-arm64/package.json b/bindings/js/native/darwin-arm64/package.json index f1b48723..e5dc23af 100644 --- a/bindings/js/native/darwin-arm64/package.json +++ b/bindings/js/native/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@kurrent/gaffer-runtime-darwin-arm64", - "version": "0.3.0", + "version": "0.3.1", "description": "Gaffer projection runtime native binary for macOS arm64", "license": "LicenseRef-KurrentLicenseV1", "repository": { diff --git a/bindings/js/native/darwin-x64/CHANGELOG.md b/bindings/js/native/darwin-x64/CHANGELOG.md index 37797660..6793f8de 100644 --- a/bindings/js/native/darwin-x64/CHANGELOG.md +++ b/bindings/js/native/darwin-x64/CHANGELOG.md @@ -1,5 +1,7 @@ # @kurrent/gaffer-runtime-darwin-x64 +## 0.3.1 + ## 0.3.0 ## 0.2.0 diff --git a/bindings/js/native/darwin-x64/package.json b/bindings/js/native/darwin-x64/package.json index 3f461eb4..e373575a 100644 --- a/bindings/js/native/darwin-x64/package.json +++ b/bindings/js/native/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@kurrent/gaffer-runtime-darwin-x64", - "version": "0.3.0", + "version": "0.3.1", "description": "Gaffer projection runtime native binary for macOS x64", "license": "LicenseRef-KurrentLicenseV1", "repository": { diff --git a/bindings/js/native/linux-arm64/CHANGELOG.md b/bindings/js/native/linux-arm64/CHANGELOG.md index dd3f2332..c4aac446 100644 --- a/bindings/js/native/linux-arm64/CHANGELOG.md +++ b/bindings/js/native/linux-arm64/CHANGELOG.md @@ -1,5 +1,7 @@ # @kurrent/gaffer-runtime-linux-arm64 +## 0.3.1 + ## 0.3.0 ## 0.2.0 diff --git a/bindings/js/native/linux-arm64/package.json b/bindings/js/native/linux-arm64/package.json index 0f1e34ba..a60bb517 100644 --- a/bindings/js/native/linux-arm64/package.json +++ b/bindings/js/native/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@kurrent/gaffer-runtime-linux-arm64", - "version": "0.3.0", + "version": "0.3.1", "description": "Gaffer projection runtime native binary for Linux arm64", "license": "LicenseRef-KurrentLicenseV1", "repository": { diff --git a/bindings/js/native/linux-x64/CHANGELOG.md b/bindings/js/native/linux-x64/CHANGELOG.md index b84e5202..e6f1aff6 100644 --- a/bindings/js/native/linux-x64/CHANGELOG.md +++ b/bindings/js/native/linux-x64/CHANGELOG.md @@ -1,5 +1,7 @@ # @kurrent/gaffer-runtime-linux-x64 +## 0.3.1 + ## 0.3.0 ## 0.2.0 diff --git a/bindings/js/native/linux-x64/package.json b/bindings/js/native/linux-x64/package.json index 5b33b833..fd557b6c 100644 --- a/bindings/js/native/linux-x64/package.json +++ b/bindings/js/native/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@kurrent/gaffer-runtime-linux-x64", - "version": "0.3.0", + "version": "0.3.1", "description": "Gaffer projection runtime native binary for Linux x64", "license": "LicenseRef-KurrentLicenseV1", "repository": { diff --git a/bindings/js/native/win32-x64/CHANGELOG.md b/bindings/js/native/win32-x64/CHANGELOG.md index 65718a61..58abecc9 100644 --- a/bindings/js/native/win32-x64/CHANGELOG.md +++ b/bindings/js/native/win32-x64/CHANGELOG.md @@ -1,5 +1,7 @@ # @kurrent/gaffer-runtime-win32-x64 +## 0.3.1 + ## 0.3.0 ## 0.2.0 diff --git a/bindings/js/native/win32-x64/package.json b/bindings/js/native/win32-x64/package.json index 432cb794..f950c7c4 100644 --- a/bindings/js/native/win32-x64/package.json +++ b/bindings/js/native/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@kurrent/gaffer-runtime-win32-x64", - "version": "0.3.0", + "version": "0.3.1", "description": "Gaffer projection runtime native binary for Windows x64", "license": "LicenseRef-KurrentLicenseV1", "repository": { diff --git a/bindings/js/package.json b/bindings/js/package.json index 071d485b..a1dfc990 100644 --- a/bindings/js/package.json +++ b/bindings/js/package.json @@ -1,6 +1,6 @@ { "name": "@kurrent/gaffer-runtime", - "version": "0.3.0", + "version": "0.3.1", "description": "Node.js bindings for the Gaffer projection runtime", "license": "LicenseRef-KurrentLicenseV1", "repository": { diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index f20d078a..c49adf36 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -1,5 +1,137 @@ # @kurrent/gaffer +## 0.5.0 + +### Minor Changes + +- 8aec336: **Breaking:** `gaffer.toml` gains a `[database_config]` section for node-level engine settings, and the top-level `compilation_timeout` / `execution_timeout` keys move into it. A file that still sets them at the top level now fails to load, with a message pointing at the new section. + + `[database_config]` declares the engine configuration expected on a deployment target: + - `max_state_size` (newly exposed) caps a projection's serialized state in bytes, defaulting to the server's 16 MiB. It is enforced on local runs, so a projection that would exceed the cap faults locally, catching state bloat before deploy. + - `compilation_timeout` and `execution_timeout` are declaration only: gaffer records them for deploy-time configuration checks but does not apply them to local runs, since a wall-clock budget measured on a dev machine isn't comparable to the server's. To bound how long a local projection may run before gaffer treats it as hung, set the `GAFFER_TIMEOUT_MS` environment variable (default 5000ms). A per-`[[projection]]` `execution_timeout` is likewise declaration only and no longer affects local runs. + +- 331f061: **Breaking:** `gaffer.toml` now rejects absolute `entry` and `fixtures.` paths at load time. Previously an absolute path (e.g. `entry = "/etc/passwd"`, or a Windows drive-letter form like `C:\...`) slipped past validation while the scaffold write path already rejected it. Both surfaces now enforce the same rule: paths must be relative to the project root and must not escape it. + +### Patch Changes + +- 9b1f7e8: The Go runtime bindings no longer risk a rare fatal crash (`invalid pointer found on stack`) under GC pressure. The runtime's integer session handles could appear in pointer-typed stack slots during FFI calls; if the GC moved the stack while a callback was running mid-call, the process aborted. Handles now stay integer-typed end-to-end on the Go side, with all casting done in C shims. The crash could hit anything embedding the bindings, including the CLI. +- ee1f52e: Projection errors that reach the CLI wrapped in another error now keep their original error code and diagnostics. Previously a wrapped feed error was classified as `unexpected-error` and its diagnostics were dropped. +- 733e9d1: `gaffer deploy` and `gaffer status` warn when the target node's live engine settings diverge from a declared `[database_config]`: one line per differing knob, read from the node's options endpoint. Fixtures and local runs assumed the declared values, so a server enforcing a different `max_state_size` or timeout is visible before it bites. The check is advisory: a server that doesn't expose its options, or refuses the read, skips it silently, and a non-positive `max_state_size` declares the engine default rather than a value. + + `gaffer status --json` now emits an object: a `projections` array (the previous per-projection entries) plus a `configDrift` array of `{"knob", "server", "local"}` when the target diverges. Machine consumers see the divergence without a second call. `gaffer deploy --json` is unchanged; its warning prints on stderr, keeping the stdout payload clean while CI logs still show it. + +- f1c46c3: `gaffer dev --debug` no longer hangs when a Restart arrives as the session is tearing down; the restart returns cleanly during shutdown instead of leaving the debug adapter's read goroutine waiting forever. +- f118249: `gaffer deploy` gains `--dry-run` and a stable exit-code contract for CI. `--dry-run` shows the plan and applies nothing. The exit code is now `0` succeeded or nothing to do, `1` an error, and `2` changes are pending (`--dry-run` only). A new `3` means refused by a guardrail: confirmation was needed but there was no terminal or `--yes`, or `--no-validate` was used against production. + + `--dry-run` reuses the same per-projection plan output as a confirmed deploy, and its `--json` is the same array shape, so a pipeline can branch on exit `2` or parse the would-be outcomes. The guardrail exit code `3` also applies to `recreate` and the operate verbs when they can't confirm non-interactively. A production `--no-validate` refusal now prints its reason instead of exiting silently. + +- ff67802: `gaffer deploy` now measures its per-projection verdict column by terminal display width, so projection names with multi-byte or full-width characters no longer over-pad the column and misalign the verdicts. +- 6ef7402: `gaffer deploy` creates or updates projections on an environment from `gaffer.toml`: it creates the ones not yet on the server, updates the ones whose definition changed, and skips the ones already in sync (matched by content hash). The emit flag is always sent explicitly, so an update never clears it. + + With no argument it deploys every projection in `gaffer.toml`; name one to deploy just it. A change to engine version or track-emitted-streams can't be applied in place (it would mean recreating the projection and dropping its state), so `gaffer deploy` reports it and leaves the projection untouched. On a terminal it shows live per-projection progress; pass `--json` for machine-readable output. + +- 0614520: `gaffer deploy`'s interactive view no longer drops the last projection's result line when the run finishes. The final row's commit and the program quit now run as one ordered step, so the verdict is always flushed before the view tears down (a single-projection deploy previously showed only the summary). +- 69aceed: `gaffer deploy` now flags a projection whose deployed definition was changed outside gaffer since its last deploy, so a deploy doesn't silently revert an out-of-band change. + - The plan preview and the non-interactive (`--yes`) apply warnings show a caution ("`` was changed outside gaffer since its last deploy; deploying overwrites it"), naming the tool when another tool made the change. + - `gaffer deploy --json` carries `externalChange: true` on the affected item, alongside `logicChange`, so CI can alert. + + Gaffer is the canonical source of truth, so it still deploys - the drift is surfaced, not refused. Degrades silently against a KurrentDB without the deploy-metadata field. + +- 1edbb21: `gaffer deploy` now plans the whole run before touching the server and confirms before applying. It shows what would change per projection (`created` / `updated` / `skipped` / `refused`) against the target's reported cluster name, then asks before writing. `--yes` skips the prompt; without a terminal (or with `--json`) it won't apply unconfirmed, so pass `--yes` in scripts. An update whose deployed projection is currently faulted is flagged, since updating won't clear the fault. + + A server that reports itself as production gets a louder confirmation and refuses `--no-validate`. Production is read from the server's own `$server-info`, never inferred from the environment name, so a connection that points at production is guarded even if its env is labelled otherwise. Databases that don't report production status are unaffected. + +- 36cd18b: `gaffer deploy` now records tool metadata on every projection it creates or updates, so a projection carries who deployed it and from where: the tool (`Gaffer`) and version, the operation, the source revision, and the acting identity. It follows a shared convention that other KurrentDB tools can write and display. + - **`revision`** defaults to the project's git commit (suffixed `+changes` when the working tree is dirty); set `GAFFER_REVISION` in CI to record the canonical commit. + - **`actor`** defaults to the identity gaffer connects as (the basic-auth user or OAuth client), omitted for an anonymous connection; set `GAFFER_ACTOR` in CI to record the pipeline identity. + + The metadata rides on the projection's definition event and is best-effort: against a KurrentDB that predates the feature it is silently ignored and deploy behaves exactly as before. + +- a59afe0: `gaffer deploy`'s plan preview now lists each projection, not just totals. Every projection that would change shows a verdict - `create`, `update`, `rebuild`, `refused`, or `failed` - and a dimmed detail column carrying the refusal reason or the failure error in full. In-sync projections stay a count only, so unchanged ones don't drown the signal. +- cc92ece: `gaffer deploy` now compiles every projection before sending anything to the server. If any fails to compile, or compiles but carries errors that would fault on the server (such as a quirk that reproduces an upstream engine crash), the whole deploy is refused up front, so a bad projection can't leave the earlier ones already applied. The check runs locally, before connecting, and `--no-validate` skips it. +- 1206961: `gaffer deploy` now treats a changed projection query as a logic change. The new code may read already-processed events differently, so the accumulated state could be wrong. By default deploy keeps the checkpoint, applies the update, and flags the change in the plan. Pass `--reset-on-logic-change` to rebuild instead: each logic-changed projection is stopped, updated, reset to the beginning, and restarted so it reprocesses from zero with the new logic. An emitting projection re-emits on a rebuild and may duplicate into its target streams, so the plan warns and points at `gaffer recreate --delete-emitted` for a clean-emit rebuild. + + A continued logic change shows as `logicChange: true` on its `--json` item, so CI can alert on it. A change to engine version or track-emitted-streams still can't be applied in place; deploy now points at `gaffer recreate` rather than just refusing. + +- ad83f81: `gaffer diff ` compares a projection's local definition against what's deployed on KurrentDB and reports its state: in sync, drifted, not deployed, or untracked. + + When the query differs, the source is shown in an external diff viewer. By default this is `git diff --no-index`; set `GAFFER_EXTERNAL_DIFF` to override. Pass `--json` for machine-readable output. + +- b5cbc4e: `gaffer diff` renders the query source diff itself instead of shelling out to an external viewer. Every line of both sides is shown with the changes marked in place: dual line-number gutters, +/- colouring, and the span that changed within a line highlighted. The diff is computed on the same canonical form as the drift verdict, so it always matches the `+N -M` stat that `gaffer diff` and `gaffer status` report. It now works without git installed, when piped, and in CI. + + Set `GAFFER_EXTERNAL_DIFF` to open an external viewer instead (e.g. `git diff`, `delta`, `difft`); it is no longer the default path. + +- ce0de95: Projection info now reports whether a projection writes events. `ProjectionInfo` gains an `emitsEvents` flag, true when the projection calls `emit`, `linkTo`, `linkStreamTo`, or `copyTo`. It is detected on every compile from the source, so consumers no longer need to inspect shape counts. + + `gaffer info` shows it ("Emits events: yes"); `gaffer info --json` and the MCP `get_projection_info` and `validate_projection` tools include `emitsEvents`; the testing library exposes it as `info.settings.emitsEvents`. + +- 36ee512: `gaffer rollback ` rolls a deployed projection back to a prior version from its history, stamped `operation: rollback` in the deploy ledger. The target is named by its content hash from `gaffer history`; any unique prefix of 4 or more characters works. It confirms first with the current-to-target query diff (`--yes` skips). The apply is in place: processing continues from the current checkpoint, and local files stay untouched, so `gaffer diff` shows the rollback as drift until local is reconciled. A version differing in engine version or emitted-stream tracking is refused, pointing at `gaffer recreate`. + + The `gaffer history` timeline gains `r`: it opens the same confirm as a modal for the selected entry, applies on `y`, and reloads the timeline so the new rollback entry appears on top. + +- eeaff5f: Event-processing errors under `engine_version 2` now carry the `quirk.handlerError.wedgesOnV2` (error severity) diagnostic. On deployed V2, an exception thrown while processing an event never faults the projection. It wedges silently: `status` stays `Running` while processing and persistence have stopped, and nothing is logged. Gaffer keeps faulting the event locally, which is the behaviour V2 should have, and the diagnostic rides the error to explain the divergence. It fires for any event-processing throw (handler, state load, `$created`, `$deleted`, state serialization, timeout); a throwing `partitionBy` is exempt because the server computes partition keys on its read loop, which faults properly. +- 15a6296: `gaffer history ` shows a deployed projection's history: every operation on it, newest first, with who made it and how. + - On a terminal it opens an interactive timeline: a scrolling list on the left, the selected entry's full detail on the right, and a footer naming the projection and target. Navigate with `↑`/`↓` (or `j`/`k`), `g`/`G`, `PgUp`/`PgDn`; `q` or `Esc` quits. Older entries page in as you scroll. + - Each entry is one write to the projection. One carrying gaffer metadata shows its operation (deploy, rollback, reset), the actor, and the source revision. One without is attributed by what changed: `edited-externally` when the definition changed outside gaffer, `changed-by` (with the tool named) for another tool's write, `enabled`/`disabled` for a lifecycle change, `reconfigured` when a checkpoint or performance setting moved, `rewritten` for an identical redeploy, or `created`/`deleted`. + - A content hash identifies each deployed definition, so a reverted definition is recognisable at a glance: the timeline draws a revert as a branch off the live line, linking the restored definition back to the earlier one it matched (nested reverts included). + - Piped or with `--json` it prints the latest entries instead (`--limit`, default 100, or `--all`). Each `--json` entry carries the full content hash, its classification and flags, the tool metadata, and any configuration knobs that moved. + + Against a KurrentDB without the deploy-metadata field it degrades to the history with timestamps and content hashes only. + +- bf1f2ef: `gaffer history` gains `d`: a diff of the selected entry against the version before it, shown in an overlay on the timeline. It answers "what changed at this entry" the way `git show` does. The previous _content_ version is the baseline (state changes are skipped; their definition is identical), the first version diffs from empty, and a state-change entry reports "no definition change". + + The diff uses the same aligned renderer and tints as `gaffer diff`, with any engine version, emit, or tracking change named above it. The arrow keys keep scrubbing the timeline underneath, so the diff re-renders entry by entry, walking a definition's evolution in place. `PgUp`/`PgDn` scroll a long diff; `esc`, `d`, or `q` closes back to the timeline. A baseline on an older page is fetched automatically. + +- 95a5410: `gaffer dev --json` now exits non-zero if it fails to write its output stream (for example a broken pipe to the editor), instead of silently finishing with a truncated stream. +- 15602f4: `gaffer status` and `gaffer diff` are now ledger-aware, reading the tool metadata gaffer stamps on deploy to say more than `untracked` or `drifted`. + - **Ownership** of a projection on the server but not in local config: `orphan` (gaffer deployed it, now gone from `gaffer.toml` - a deletion candidate) or plain `untracked`, with the deploying tool named when its metadata is present. `--json` reports this as `owner`, including `foreign` for a projection another tool manages. + - **Drift attribution** of an in-config projection that differs from what's deployed: `local ahead` (you've edited local since your deploy) or `changed externally` (a tool or a direct write changed the server since). `--json` splits the latter into `changed-by-tool` and `changed-server`. + + Both surface in the status table and detail and in `gaffer diff`. The status table gains **LAST DEPLOY** and **DEPLOYED VIA** columns, and naming a projection (or running `gaffer diff`) shows the deploy provenance behind it: when, the tool and version, the deployer, and the source revision. The last-deploy date comes from the event itself, so it shows even for a projection with no tool metadata. In `--json`: `owner`, `attribution`, a top-level `lastDeployed` timestamp, and `lastWrite` (the tool and actor). Against a KurrentDB without the deploy-metadata field it degrades to the previous behaviour. + +- 189eebd: The MCP server gains **`deploy_apply`**, so an assistant can deploy projections from `gaffer.toml` like `gaffer deploy`: + - The same all-or-nothing compile and diagnostics preflight, with no validation bypass. + - The same per-item results as `gaffer deploy --json`, and every write stamped `operation: deploy` in the ledger. + - A production deploy requires a confirmation answered through the MCP client (elicitation). The prompt names the changed projections, rebuilds, out-of-band overwrites, faulted targets, and any `[database_config]` divergence. + - A plan containing `resetOnLogicChange` rebuilds destroys state, so it always asks; on production that confirmation requires typing the environment name. + +- 33ffb38: The MCP server gains read-only deploy visibility, mirroring the CLI's machine output: + - **`deploy_status`** shows each projection's runtime state and drift verdict on an environment, plus any `[database_config]` divergence, like `gaffer status --json`. + - **`deploy_plan`** previews what a deploy would change without applying anything, like `gaffer deploy --dry-run --json`. + - **`deploy_history`** reads a projection's per-deploy audit log with paging, like `gaffer history --json`. + + All three accept an `env` argument and default to the default environment. Applying changes stays in the CLI, behind its confirmation gates. + +- 15cc888: The MCP server gains the operate verbs, so an assistant can manage a deployed projection's lifecycle with a human in the loop: + - **`deploy_pause`** / **`deploy_resume`** / **`deploy_abort`** mirror `gaffer disable` / `enable` / `disable --abort`. + - **`deploy_recreate`** rebuilds from local config like `gaffer recreate`, gated on the compile and diagnostics preflight, and stamps `operation: recreate` in the deploy ledger. + - **`deploy_rollback`** redeploys a prior version by content hash from `deploy_history`, like `gaffer rollback`, and stamps `operation: rollback`. + - **`deploy_delete`** mirrors `gaffer delete`, including `deleteEmitted`. + + Writes against a server that reports itself as production require a confirmation answered through the MCP client (elicitation); the assistant cannot answer it. The prompt front-loads `PRODUCTION [env.]:` and states each verb's consequence. Recreate and delete destroy state with no undo, so they ask every time; on production their confirmation requires typing the projection name. A client without elicitation support cannot perform gated writes; the refusal names the CLI command to run instead. `deploy_status` and `deploy_plan` now also echo the resolved target and production flag. + +- 73af704: `gaffer enable`, `gaffer disable`, and `gaffer delete` manage deployed projections on an environment, named directly (they need not be in `gaffer.toml`). + - `gaffer enable ` starts a projection so it resumes from its last checkpoint. + - `gaffer disable ` stops it, writing a final checkpoint; `--abort` skips that checkpoint so a later enable replays from the last one. Disabling is recoverable, so it confirms only against production. + - `gaffer delete ` removes the projection with its state and checkpoint streams, keeping emitted streams unless `--delete-emitted` is passed. It always confirms, and disables the projection first since the server won't delete an enabled one. + + `--yes` skips the confirmation; without a terminal (or with `--json`) a guarded verb won't proceed unconfirmed. Production gets a louder confirm and is read from the server's `$server-info`, never the env label. + +- b2071d0: A per-projection config error (e.g. `track_emitted_streams` with `engine_version 2`) no longer blocks every command. Previously one misconfigured projection failed `gaffer.toml` loading outright, so `gaffer info ` died on an _unrelated_ projection's error. Now config validation splits into structural checks (environments, duplicate names) that stay fatal, and per-projection checks that are deferred; a bad projection only blocks operations on itself. The inspection commands (`status`, `diff`, `info`) show it as `invalid` through one shared rendering; `deploy` refuses just that one; `recreate` and the operate verbs fail only when you name it. Mirrors the per-projection degradation already used for compile errors. +- 6571975: `gaffer recreate` now stamps its rebuild in the deploy ledger, so `gaffer history` attributes it to gaffer instead of showing anonymous lifecycle steps. The create carries `operation: recreate` with the usual tool, actor, and source revision. + + `gaffer history` shows a recreate as a single entry: the disable and delete writes it performs are folded into the `recreate` row, and the detail panel notes the projection was reprocessed from zero. `--json` keeps every write as its own entry, with the create's `kind` set to `recreate`. + +- 42b7612: `gaffer recreate ` destroys and rebuilds a deployed projection from local config: stop it, delete it (with its state and checkpoint streams), and create it fresh, reprocessing from zero. It applies a create-only change that deploy can't make in place (engine version, track-emitted-streams), or rebuilds a wedged projection an in-place reset can't fix. The projection is compiled before anything is deleted, so a broken local definition can't leave you with nothing to rebuild; `--no-validate` skips that check (production refuses it). It always confirms, more prominently against production, with `--yes` for non-interactive use. `--delete-emitted` also wipes the emitted streams so the rebuild doesn't re-emit duplicates. +- 6625608: `gaffer status` shows the runtime state of projections on an environment and how they compare to local config: running, stopped or faulted, progress, and whether each is in sync, drifted, not deployed, or untracked. + + With no argument it lists every local and deployed projection as a table; name a projection for its detail. Pass `--json` for machine-readable output. + +- 6602c5f: `gaffer status` and `gaffer diff` no longer abort when a local projection fails to compile. A compile error is now a per-projection condition, not a whole-command failure. `gaffer status` shows the broken projection as `invalid` and still renders the rest of the table with their real runtime state and drift. `gaffer diff` still shows the source diff, engine version, and track-emitted-streams, marking `emit` unknown because deriving it needs a successful compile. Both exit 0, and the compile error is shown so you know what to fix. +- e59a851: `track_emitted_streams` with `engine_version 2` is now reported as a diagnostic rather than a config-load error. The runtime emits `quirk.trackEmittedStreams.unsupportedOnV2` (error severity) off the resolved definition, whether the flag comes from `gaffer.toml` or `options({ trackEmittedStreams: true })` in the source. This matches how the other V2 incompatibilities (bi-state, `outputState`) already surface. + + `gaffer info`, `gaffer dev`, and `gaffer diff` now compile such a projection and show its full analysis plus the flag, instead of failing with a bare config error. `gaffer deploy` and `gaffer recreate` still refuse it at preflight (recreate before deleting anything), and the MCP `validate` tool reports it invalid with the diagnostic. The projection session no longer throws on the combination. + ## 0.4.2 ### Patch Changes diff --git a/cli/native/darwin-arm64/CHANGELOG.md b/cli/native/darwin-arm64/CHANGELOG.md index ae86d34f..cbbea31e 100644 --- a/cli/native/darwin-arm64/CHANGELOG.md +++ b/cli/native/darwin-arm64/CHANGELOG.md @@ -1,5 +1,7 @@ # @kurrent/gaffer-darwin-arm64 +## 0.5.0 + ## 0.4.2 ## 0.4.1 diff --git a/cli/native/darwin-arm64/package.json b/cli/native/darwin-arm64/package.json index 159a4ec5..d87cefbf 100644 --- a/cli/native/darwin-arm64/package.json +++ b/cli/native/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@kurrent/gaffer-darwin-arm64", - "version": "0.4.2", + "version": "0.5.0", "description": "Gaffer CLI binary for macOS arm64", "license": "LicenseRef-KurrentLicenseV1", "repository": { diff --git a/cli/native/darwin-x64/CHANGELOG.md b/cli/native/darwin-x64/CHANGELOG.md index 4e2d3c3f..626f236e 100644 --- a/cli/native/darwin-x64/CHANGELOG.md +++ b/cli/native/darwin-x64/CHANGELOG.md @@ -1,5 +1,7 @@ # @kurrent/gaffer-darwin-x64 +## 0.5.0 + ## 0.4.2 ## 0.4.1 diff --git a/cli/native/darwin-x64/package.json b/cli/native/darwin-x64/package.json index 3cfe9c6c..0f34d441 100644 --- a/cli/native/darwin-x64/package.json +++ b/cli/native/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@kurrent/gaffer-darwin-x64", - "version": "0.4.2", + "version": "0.5.0", "description": "Gaffer CLI binary for macOS x64", "license": "LicenseRef-KurrentLicenseV1", "repository": { diff --git a/cli/native/linux-arm64/CHANGELOG.md b/cli/native/linux-arm64/CHANGELOG.md index aa8abe4d..c8559a5f 100644 --- a/cli/native/linux-arm64/CHANGELOG.md +++ b/cli/native/linux-arm64/CHANGELOG.md @@ -1,5 +1,7 @@ # @kurrent/gaffer-linux-arm64 +## 0.5.0 + ## 0.4.2 ## 0.4.1 diff --git a/cli/native/linux-arm64/package.json b/cli/native/linux-arm64/package.json index 23f88f5e..7c327166 100644 --- a/cli/native/linux-arm64/package.json +++ b/cli/native/linux-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@kurrent/gaffer-linux-arm64", - "version": "0.4.2", + "version": "0.5.0", "description": "Gaffer CLI binary for Linux arm64", "license": "LicenseRef-KurrentLicenseV1", "repository": { diff --git a/cli/native/linux-x64/CHANGELOG.md b/cli/native/linux-x64/CHANGELOG.md index 45817383..3cb1186a 100644 --- a/cli/native/linux-x64/CHANGELOG.md +++ b/cli/native/linux-x64/CHANGELOG.md @@ -1,5 +1,7 @@ # @kurrent/gaffer-linux-x64 +## 0.5.0 + ## 0.4.2 ## 0.4.1 diff --git a/cli/native/linux-x64/package.json b/cli/native/linux-x64/package.json index eb97c8de..d756e9a5 100644 --- a/cli/native/linux-x64/package.json +++ b/cli/native/linux-x64/package.json @@ -1,6 +1,6 @@ { "name": "@kurrent/gaffer-linux-x64", - "version": "0.4.2", + "version": "0.5.0", "description": "Gaffer CLI binary for Linux x64", "license": "LicenseRef-KurrentLicenseV1", "repository": { diff --git a/cli/native/win32-x64/CHANGELOG.md b/cli/native/win32-x64/CHANGELOG.md index ff8675e5..5f924b9f 100644 --- a/cli/native/win32-x64/CHANGELOG.md +++ b/cli/native/win32-x64/CHANGELOG.md @@ -1,5 +1,7 @@ # @kurrent/gaffer-win32-x64 +## 0.5.0 + ## 0.4.2 ## 0.4.1 diff --git a/cli/native/win32-x64/package.json b/cli/native/win32-x64/package.json index 2391e3ae..f7911845 100644 --- a/cli/native/win32-x64/package.json +++ b/cli/native/win32-x64/package.json @@ -1,6 +1,6 @@ { "name": "@kurrent/gaffer-win32-x64", - "version": "0.4.2", + "version": "0.5.0", "description": "Gaffer CLI binary for Windows x64", "license": "LicenseRef-KurrentLicenseV1", "repository": { diff --git a/cli/package.json b/cli/package.json index 112f9f6d..2bfa626a 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "@kurrent/gaffer", - "version": "0.4.2", + "version": "0.5.0", "description": "Develop, test, debug, and deploy KurrentDB projections from the command line", "license": "LicenseRef-KurrentLicenseV1", "repository": { diff --git a/testing/js/CHANGELOG.md b/testing/js/CHANGELOG.md index 768e4a9e..118c05ab 100644 --- a/testing/js/CHANGELOG.md +++ b/testing/js/CHANGELOG.md @@ -1,5 +1,18 @@ # @kurrent/projections-testing +## 0.2.2 + +### Patch Changes + +- ce0de95: Projection info now reports whether a projection writes events. `ProjectionInfo` gains an `emitsEvents` flag, true when the projection calls `emit`, `linkTo`, `linkStreamTo`, or `copyTo`. It is detected on every compile from the source, so consumers no longer need to inspect shape counts. + + `gaffer info` shows it ("Emits events: yes"); `gaffer info --json` and the MCP `get_projection_info` and `validate_projection` tools include `emitsEvents`; the testing library exposes it as `info.settings.emitsEvents`. + +- Updated dependencies [ce0de95] +- Updated dependencies [eeaff5f] +- Updated dependencies [e59a851] + - @kurrent/gaffer-runtime@0.3.1 + ## 0.2.1 ### Patch Changes diff --git a/testing/js/package.json b/testing/js/package.json index a9385249..b9516a28 100644 --- a/testing/js/package.json +++ b/testing/js/package.json @@ -1,6 +1,6 @@ { "name": "@kurrent/projections-testing", - "version": "0.2.1", + "version": "0.2.2", "description": "Test library for KurrentDB projections", "license": "Apache-2.0", "repository": {