Skip to content

All versions since v3.0.0-rc.9 (2026-06-22)

v3.0.0-rc.9 (2026-06-22)

Fixed

  • LDAP discovery stays license-compatible across harmless directory metadata differences — Startup license checks no longer fail only because the connected directory exposes an equivalent identity dataset with a discovery-only distinguished-name metadata difference. Directory-specific UUID value forms still affect the fingerprint when they change how entries are identified.
  • LDAP paged-search counts no longer understate complete result sets — Simple paged LDAP responses now report an exact size only when IdentityScribe knows the complete result count. Clients that page through a result set, including Identity Hub, no longer see a final response that suggests fewer available entries than were actually returned.
  • Documentation pages render wider content and tables correctly — The published documentation now gives desktop pages more reading space and renders tables reliably.
  • Redacted Observe support exports work for signed-in operators — Operators can now prepare redacted Query Diagnostic and Workload support exports without extra Observe write access. Full exports remain limited to operators with write access, and the Operator UI no longer shows the Full option to operators who cannot use it.
  • Entry count toggle explains exact-count fallbacks — When an exact entry count takes too long, the Operator UI now keeps the exact-count toggle selected, shows that the displayed number is still an estimate, and labels the timeout instead of appearing to ignore the toggle.
  • Forwarded LDAP searches can use entry distinguished-name filters — LDAP searches forwarded to the connected directory can now use entryDN (or Active Directory’s distinguishedName) when filtering, sorting, requesting attributes, or evaluating assertions. Identity Hub lookups by entry DN no longer fail with “Request cannot be delegated to backend server” when IdentityScribe forwards the search.
  • LDAP bind failures stay attached to the bind log — Failed LDAP binds that already run inside an LDAP bind operation no longer also emit a separate “Untraced error” line. Operators still get the same bind events and client response; the failure is now recorded with the operation log.

v3.0.0-rc.10 (2026-06-25)

Added

  • eDirectory Identity Manager role and group setups have a ready-to-import profile — Deployments that track role and group membership on user entries can now include edirectory-idm.conf after their base config. The profile adds the IDM role, resource, and group attributes IdentityHub commonly queries, keeps high-fanout reverse membership views virtual, and documents the expected user, role, and group mappings in eDirectory Identity Manager Roles.
  • Query defaults can be set once and overridden per channelquery.default-count, query.default-limit, query.default-include, query.default-fields, and query.default-sort now provide shared defaults for integrations that do not set their own values. Named channel overrides such as channels.ldap.default-count, channels.rest.default-fields, channels.graphql.default-sort, and channels.mcp.default-limit still let each integration choose its own behavior.
  • Recent forwarded LDAP searches are visible in Observe, with a value-free request shape on every trace — When IdentityScribe forwards a directory search to the connected directory, its trace and wide log now describe the request without exposing directory data: the search scope, a structural filter pattern with the values stripped (for example objectclass?,uid=), stable digests of the base DN and filter, the requested controls, and a correlation id — under ldap.request.* and ldap.delegation.sample_id. This makes it possible to identify which forwarded search returned a “service unavailable” (or any other result) and trace it back to the responsible client call. The Operator UI’s LDAP Forwarding view adds an expandable list of recent forwarded searches for each forwarding reason, and the same samples are available at /observe/ldap/delegation with a downloadable export. The literal base DN and filter are held in a bounded in-memory window and shown only to operators with Observe write access; capture is on by default and can be turned off with monitoring.observe.capture-request-values = false. The window keeps the most recent monitoring.observe.max-samples searches (default 200) for monitoring.observe.ttl (default 15 minutes) and is never written to the database. Traces, metrics, and the redacted export never carry the literal base DN or filter.
  • MCP endpoints record tool usage, expose per-tool metrics, and limit concurrent tool calls — The data (/mcp) and Observe (/observe/mcp) MCP endpoints now record one audit log line per tool invocation (endpoint, tool name, result, duration, and request id — never the tool arguments), and export per-tool request-count and latency metrics under scribe.mcp.tool.*. Both endpoints bound how many tool calls may run at once: the cap auto-derives from the configured concurrency setting (the same knob that sizes the database pool and HTTP limits) when unset, and can be set explicitly via channels.mcp.max-concurrent-tools / monitoring.mcp.max-concurrent-tools (0 disables the limit). When the limit is reached, an incoming call waits for a free slot before being rejected with a clear error; the wait defaults to 1 second and is tunable via channels.mcp.tool-acquire-timeout / monitoring.mcp.tool-acquire-timeout.
  • Operators are alerted when the directory sends incomplete change notifications — The health checks (/observe/doctor) and the Observe Inbox now raise a signal when the connected directory sends change notifications that omit objectClass. A critical alert appears when such an update could not be completed and was held back — the stored entry keeps its previous values until the directory is fixed; a warning appears when IdentityScribe re-read the full entry from the directory to recover. Each card shows how many occurred in the last 5 minutes and points to the directory-side fix (check the directory’s objectClass attribute mapping and re-sync the affected entries); the exact attributes the directory dropped are recorded in the ingest logs. The same signals are available for dashboards under scribe.ingest.incomplete_notification.total (reason=repaired / reason=skipped).

Fixed

  • Stored entries keep their attributes when the directory sends an incomplete change notification — When IdentityScribe syncs a change from the connected directory, a change notification that arrives missing objectClass (a mandatory attribute every live entry has) is no longer treated as if the attribute had been removed. Such an update could previously drop objectClass — and potentially other attributes — from the stored entry, leaving an entry that clients relying on objectClass may reject or that attribute searches may miss. IdentityScribe now recognizes the notification as incomplete and re-reads the full entry from the directory; if a complete copy still cannot be obtained, it leaves the stored entry unchanged rather than corrupting it. Incomplete notifications are recorded under the new scribe.ingest.incomplete_notification.total metric (reason=repaired when the full entry was re-read, reason=skipped when the update was held back), so operators can spot a directory that is sending incomplete change notifications.
  • Pattern-based LDAP bind attributes accept quoted OID keys — Pattern entries under auth.ldap.bind-attribute keyed by a quoted object identifier (for example "1.2.840.113556.1.4.221") are now read with the correct attribute name. The surrounding quotes were previously kept as part of the name, so any bind that relied on that attribute was rejected. Unquoted dotted keys and ordinary attribute names are unchanged.
  • LDAP paged-search counts keep useful estimates — Simple paged LDAP responses now keep a server-side estimate when it is available, while ensuring the reported size is never lower than the returned page proves. The final page still reports the completed result size when IdentityScribe can determine it.
  • Bundled monitoring dashboards use the current planner metrics — The packaged Grafana and Helm dashboards now read the planner metrics introduced in the latest release, so planner-health panels continue to show data after upgrading.
  • Forwarded LDAP searches recover from a dropped backend connection — When IdentityScribe forwards a directory search to the connected directory and the backend connection has gone stale — for example after the directory restarted, or an idle connection was dropped by the network — the search now reconnects and retries once instead of returning a “service unavailable” error. First-page and non-paged searches recover automatically; a search already paging through results with a server-side cursor surfaces the interruption so the client can restart the sequence.
  • Operator UI API errors keep their request id — An error returned from an Operator UI action now retains the server-assigned request id, so a failure seen in the console can be correlated with its server-side trace and logs.

Changed

  • LDAP paging counts now default to exact totals unless a client opts out — LDAP Simple Paged Results and virtual-list-view responses use exact totals by default, so clients that display role or group member counts do not see a low estimate as the total. Clients that only need navigation can still opt out of counts, and operators can choose estimated or no-count behavior through the new count defaults.
  • MCP search and lookup default to data attributes — When an MCP client omits fields, search and lookup now request data attributes (*) by default, matching REST and the shared query default. Clients that need operational attributes can still pass fields="+" or fields="*,+", and operators can restore the previous default with channels.mcp.default-fields = "*,+".
  • Forwarded directory searches record why a “service unavailable” was returned — Traces and wide logs for a forwarded directory search now carry two diagnostic attributes. ldap.delegation.page shows whether the search started a result set (first) or resumed a server-side cursor (continuation); ldap.delegation.retry shows whether an automatic reconnect was not needed (none), recovered the search (recovered), or was exhausted because the directory stayed unreachable (exhausted). Together they separate a transient stale-connection blip that self-healed from a directory that is genuinely down, and flag the one case that cannot be retried automatically — a search resuming a cursor — so it is clear the client must restart that paging sequence.

v3.0.0-rc.11 (2026-07-01) Latest

Added

  • Early warning for memory leaks, with a downloadable diagnostic report — A new always-on sensor watches whether the memory that survives each garbage collection is trending upward without bound. When it is, IdentityScribe logs a warning, raises the scribe.memory.leak.suspected metric (alongside scribe.memory.live_set.bytes and scribe.memory.growth.per_hour) so unbounded growth shows up in Grafana, and raises a card in the Observe Inbox. From the card’s System → JVM view you can download a memory diagnostic report — a redacted version safe to attach to a support ticket and a full version for local investigation — capturing the JVM’s heap, memory pools, garbage-collector counters, and the sensor’s growth assessment, in the same way as the existing slow-query and workload exports. For deep analysis, an operator with Observe write access can trigger an on-demand heap dump (POST /observe/memory/heap-dump) for tools such as Eclipse MAT; only one runs at a time. Because a heap dump is a full copy of the heap — including credentials and personal data — capture is disabled by default, and enabling it requires setting monitoring.memory.heap-dump.directory to a private path (there is no default): the directory and every dump are created readable only by the account IdentityScribe runs as. The redacted report is safe to attach to a support ticket, and the report view’s email action opens a pre-addressed draft for you to attach the downloaded Markdown to. Tune the sensor under monitoring.memory — thresholds, observation window, and poll interval; it runs by default, independently of whether telemetry export is configured.

  • Searches that identify entries by object class resolve without forwarding — A directory search that selects entries by objectClass or structuralObjectClass — for example (structuralObjectClass=inetOrgPerson) against a base that several transcribes share — now resolves to the right entry type and is served by IdentityScribe instead of being forwarded to the connected directory. structuralObjectClass filters are matched the same way as objectClass filters. When the directory publishes its schema, IdentityScribe recognizes the structural subclasses of each transcribe’s configured object class automatically, so a transcribe filtered by (objectClass=person) also answers inetOrgPerson and organizationalPerson searches with no extra setup; when the schema is unavailable it falls back to the configured classes and logs why. The new transcribes.<type>.ldap.object-class-aliases option lists additional object class values that identify a transcribe for cases automatic detection cannot cover. All of this affects inbound query routing only — it never changes what is synced, stored, or forwarded upstream.

Fixed

  • Memory no longer grows without bound under sustained search load — Continuous LDAP, REST, or GraphQL search traffic caused heap use to climb for the life of the process until garbage collection thrashed and the LDAP channel stopped responding, typically after several hours of uptime. Memory now stays flat under the same load.

  • Substring-search row-count learning stays bounded when persistence is disabled — With database.gate-learning.enabled = false, the record of which substring-search row counts are exact was never trimmed, so memory could climb slowly under varied substring searches. It is now bounded regardless of that setting.

  • Full re-sync startup no longer fails on large stored datasets — When a subscription fingerprint change triggers a full re-sync, IdentityScribe now clears the old stored entries in a way that does not exhaust PostgreSQL lock memory. Large directories no longer fail startup with an out of shared memory message during that reset.

  • Searches return each matching entry only once — Free-text and fuzzy searches over several attributes no longer return duplicate rows when the same entry matches through more than one attribute or through several values of a multi-valued attribute. Sorting and cursor pagination keep their existing order.

  • Malformed LDAP paged-search cookies are recorded as client errors — An LDAP Simple Paged Results request with a corrupted continuation cookie already received the correct protocolError response; its trace, wide log, and error-rate signals now also classify it as a client error rather than a server-side failure, so a client sending a bad cookie no longer counts against server-error monitoring.

  • The eDirectory Identity Manager profile ships in the release archiveedirectory-idm.conf, documented since v3.0.0-rc.10 as an additive profile to layer on top of your base config, was missing from the downloadable release archive. The archive now includes it under the name used in eDirectory Identity Manager Roles.

  • Shutdown waits for sort-index backfill work to stop — When IdentityScribe is backfilling a sort index in the background (for example after adding a multi-valued attribute to indices.sortable), shutdown now waits for in-progress backfill workers to exit instead of signaling them and returning immediately. A shutdown that must wait past a bounded timeout logs a warning naming the workers still running.

  • Cancelled single-entry lookups no longer run their query — A request that resolves to a single entry uses a fast single-row lookup path; if the caller cancelled or timed out while that lookup’s parameters were still being bound, the query could still run against PostgreSQL. It is now skipped as soon as the cancellation is detected, so a request nobody is waiting on no longer does database work.

  • Reference deep links resolve Prometheus metric names, not just OpenTelemetry names/ref/* links and the embedded reference index now also recognize a metric’s Prometheus-exposition name (the underscored form scraped from /metrics, for example scribe_ingest_lag_seconds), alongside its dotted name (scribe.ingest.lag.seconds). Both forms resolve to the same reference page.

  • The Getting Started Dockerfile example fails clearly on a bad download — The custom-image Dockerfile shown in Getting Started now installs ca-certificates and downloads the release archive with curl -fSL --show-error, so an unauthorized or failed download (for example an expired token) stops the build with a visible error instead of continuing with an invalid archive.

  • Observe’s index-build detail list stays within its configured limit during large bursts — When many background index builds complete or fail within the same short window, the detail list behind Observe’s index-build status view could briefly hold more entries than its configured cap. The list is now trimmed to the cap after every burst.

  • Long sortable attribute names no longer report a false index-build failure — A sortable attribute whose combined type-and-attribute name is long (for example the srvprvlocalizednames attribute on the requestdef entry type) could show a permanent failed index build in Observe → Storage and log an index_create_failed warning on every startup, even though the index and its background maintenance were working correctly. These healthy builds are no longer reported as failed.