---
title: Changelog
path: changelog
status: published
---

# Changelog

This is the user-facing history of what shipped in each ScaiLog release, drawn
from the phased delivery plan. Entries describe the capabilities you can rely on,
newest first. ScaiLog is licensed under Apache-2.0.

## 1.0.2 — 2026-08-25

Python packaging fix. The `[agent]` extra was missing PyYAML, so
`pip install scailog[agent]` from 1.0.1 produced an agent that crashed on import
(the policy engine needs it). 1.0.2 completes the extra — this is the first
Python release where a clean `pip install "scailog[agent]==1.0.2"` yields a
runnable agent that carries the tenant fix below. The agent ships in this same
wheel, via the `[agent]` extra; there is no separate agent artifact. Python
1.0.1 has been withdrawn from downloads.

## 1.0.1 — 2026-08-25

Critical fix, plus the Go package.

- **BUGFIX (critical): the split-topology agent no longer flattens per-entry
  tenants.** In 1.0.0 the SDK made `tenant` per-entry and the server honoured
  it, but `scailog-agent` ignored the frame's tenant and stamped its own
  configured `--tenant` on every entry, encrypting PI under that single tenant's
  key. For a service logging on behalf of many tenants through one agent, that
  put one customer's PI under another's key — and because erasure and DSAR key
  on `(tenant, subject)`, the correct tenant's erasure could never reach it. The
  agent now threads `frame["tenant"]` through caching and encryption and enrols
  each tenant's key on demand; the configured `--tenant` is only a fallback for a
  single-tenant agent and never overrides an entry that named its own. **Anyone
  running the split-topology agent must upgrade** — the standalone/embedded agent
  was never affected. (The direct-HTTP ingest path was also never affected.)

- **Go SDK packaging.** The Go download is now a proper module archive
  (`scailog-go-1.0.1.tar.gz`) usable via a `replace` directive, and the import
  path is `scailabs.ai/scailog-go` — the previous github path never resolved.

## 1.0.0 — 2026-08-24

First stable release. The SDK wire format and the public API are now covered by
semantic versioning: no breaking change before 2.0.0. The breaking change below
is made deliberately *at* 1.0.0, before anyone can depend on the old behaviour.

- **A global tenant namespace (`_global`).** Not every event happens in a
  tenant's context — bootstrap, a system-wide failure, cross-tenant maintenance
  do not. Those entries now declare the reserved tenant `_global` rather than
  borrowing a real customer's identity or the single-tenant `default` sentinel.
  It must be stated explicitly: an entry with no tenant is still rejected, and a
  tenant-scoped API key may not write there.

- **Per-entry tenancy in all four SDKs.** `tenant` was bound once when the
  logger was constructed, so a process serving many tenants either built a
  logger per tenant or labelled everything with one static value. It is now
  resolved per entry — explicit argument, then request context
  (`context(tenant=…)`, `withContext`, `WithTenant`, `LogContext.Push`), then
  the logger default.

  **Breaking:** the fallback to the reserved `default` tenant is gone. A logger
  with no tenant from any source now fails loudly instead of silently
  mislabelling every entry, which is unrecoverable after the fact. Set
  `SCAILOG_TENANT`, bind per request, or pass it per call.

- **Call-site manifests are tenant-free.** A manifest is derived from a
  service's source, so the same declaration holds for every tenant it serves.
  Declarations are stored once per `(service, call_site_id)` — 100 sites across
  1,000 tenants is 100 rows, not 100,000 — and `scailog-ci push` no longer needs
  a tenant it cannot know. `GET /v1/sites/declarations` exposes them directly.

- **A provisioning role and suspendable keys.** `log_provisioner` can declare
  call sites and read the registry and nothing else, so a CI pipeline no longer
  needs the key-minting and policy-editing that `log_admin` carries. Any key can
  be suspended (reversible, unlike revocation) and resumed for a bounded window,
  and key administration is recorded in an audit trail readable with
  `scailog keys history`.

## Phase 2

Phase 2 broadens the SDK languages and adds the point-and-click and identity
surfaces on top of the Phase 1 core. Everything here is additive — the CLI and
built-in API keys from Phase 1 remain the primary, always-available path.

- **TypeScript and Go SDKs (plus .NET).** Wire-identical siblings of the Python
  reference SDK — same `pi()` markers, mandatory validated `call_site_id`,
  subject-required-for-PI, reserved-name rejection, ULIDs, and socket-NDJSON with
  stderr fallback. A log emitted from any language encrypts at ingest and decrypts
  back through DSAR identically.
- **Admin panel.** A thin SolidJS + Tailwind + DaisyUI single-page app over the
  server's `/v1` API: dashboard, log search (with explain and single-field
  decrypt), live tail over SSE, sites, subjects (DSAR/erase), policies, keys, and
  audit. The CLI remains the primary interface; the panel is the complement. It
  carries no ScaiLog runtime dependency.
- **OIDC / SSO login.** An optional identity plugin: the CLI logs in via the
  OAuth 2.0 device flow (`scailog login`), and the admin panel offers "Sign in
  with SSO" (Authorization Code + PKCE). The server validates the ID token and
  maps the `scailog_role` claim to a role. API keys stay the base mechanism and
  the system runs fully without OIDC.
- **`scailog-ci` full validation and manifest push.** The zero-dependency
  build-time validator checks call sites (constant, unique, well-formed ids; no
  message interpolation; `pi()` with a subject) and can push a call-site manifest
  to the server so drift shows up in `scailog sites --diff`.
- **Audit-guided targeted redaction.** `scailog audit redact` scrubs named
  plaintext fields that an audit flagged as untagged PI to `[AUDIT_REDACTED]`
  across a call site — an irreversible, `dpo`-only fix for PI that escaped
  tagging.
- **Signed report-key rotation.** The report-signing key becomes a rotating
  keyring (active plus retired keys); every DSAR report and erasure receipt embeds
  its signing key's public key and `key_id`, so documents stay verifiable after a
  rotation, and retired keys stay published at `GET /v1/report-keys`.
- **Prometheus `/metrics`.** The counters that must never be lost — panic drops,
  dead-letters, stderr fallbacks — are exposed as a Prometheus-format `/metrics`
  endpoint (and on `/v1/status`), so observability of the logger is
  metrics-shaped, avoiding a log-about-logging cycle.

## Phase 1 — initial release

The foundational release: the full GDPR-native logging path end to end, from SDK
emit through encryption, storage, query, DSAR, and cryptographic erasure. Erasure
by key-destruction ships here — it is the point of the product, not a later
hardening step.

- **Python SDK.** The reference emit library: mandatory `call_site_id`,
  field-level `pi()` markers, automatic context propagation, and socket-NDJSON
  emit with a non-silent, PI-redacting stderr fallback. The base install is pure
  stdlib with zero third-party dependencies.
- **Per-host agent.** `scailog-agent` terminates the local socket, encrypts PI
  immediately with per-subject keys, caches to a local SQLite file, and ships
  zstd-NDJSON batches to the server with idempotency, backoff, resume-after-restart,
  and per-entry dead-lettering. Panic mode refuses to cache plaintext PI when the
  server is unreachable.
- **Central server.** A single FastAPI service that ingests SLWP batches,
  validates entries, applies the policy engine, encrypts any PI not already
  encrypted by the agent, and writes to `scailog.db`. Hosts the built-in key
  manager and the separate `keymap.db`.
- **Policy engine.** Declarative YAML with most-specific resolution and
  versioning; four actions — `encrypt`, `redact`, `drop`, `keep` — applied per PI
  type, service, and environment.
- **Cryptographic erasure and DSAR.** Per-subject DEKs under a tenant KEK under
  the root key; erasure destroys the subject's key (crypto-shredding), leaving a
  tombstone and a signed erasure receipt. DSAR produces a signed subject report
  with decrypted PI.
- **Operator CLI.** `scailog` with `query`, `tail`, `sites`, `explain`, `dsar`,
  `erase`, `keys`, and `policy` commands.
- **Built-in API-key authentication.** Roles and capabilities, a
  minted-once bootstrap key, tenant/service scoping, expiry, rate limits, and IP
  allowlists — no external auth service required.
- **Retention sweeper.** Background enforcement of retention windows, including
  the deliberately short backup retention on `keymap.db`.
- **Standalone single-binary mode.** `scailog-server --standalone` embeds the
  agent role — one process, one directory of SQLite files — as a first-class
  supported deployment.
- **SLWP test-vector suite.** Normative Annex A crypto and wire-format vectors,
  re-checked by every SDK so the wire format cannot drift across languages.
