Skip to content
Updates

Updates

Release update notes and feature highlights, with direct links to current configuration and API docs.

Unreleased

v1.7.0-rc.16 Highlights — September 15, 2026

Home Assistant discovery and state publishing now agree for agent containers with the existing HASS_AGENTTOPICSEGMENT=true default. Canonical container names and plain MQTT topics are unchanged. Thanks to @depuits for the reproduction details in discussion #1201.

This candidate also refreshes dependencies and the Alpine timezone package pin, restores privacy-preserving website referrer reporting, and fixes Crowdin branch selection and dependency guards. The runtime changes start a fresh seven-day soak. Old retained MQTT payloads are not deleted automatically; check for other publishers before removing obsolete state. See CHANGELOG.md for the full release notes.

v1.7.0-rc.15 Highlights — September 10, 2026

Disconnected edge agents can no longer publish an in-flight component over their reconnected replacement. Retired registrations clean up only their own components, and disconnected proxy, log, delete, and exec requests fail immediately without allocating request state or sending frames. These runtime changes require a fresh seven-day soak for this candidate. See CHANGELOG.md for the full release notes.

v1.7.0-rc.14 Highlights — September 8, 2026

  • Rollback now applies the same runtime-config sanitization as an update, so an entrypoint or command introduced by the newer image is not copied onto an older image that cannot run it. Tag family matching requires an exact variant suffix, with a digit-only precision exception; a trailing dot no longer qualifies (#1134).
  • Maintenance image labels now name the release source SHA instead of the workflow's main-branch commit (#1126).

Full release notes are in CHANGELOG.md.

v1.7.0-rc.13 Highlights — September 8, 2026

  • Containers on a floating tag from before v1.5.0-rc.17 could stay marked Current forever, even with a newer digest availableimage.digest.watch is now re-derived every scan instead of being fixed at first discovery (#1108).
  • The weekly ZAP full scan of getdrydock.com hit its 60-minute job timeout on every run and never produced a report — the scan step now caps the spider at 10 minutes and the active scan at 35, leaving room for the passive scan and report inside the job budget (#1080).

v1.7.0-rc.12 Highlights — September 6, 2026

  • The demo site was missing Cross-Origin-Opener-Policy — the weekly DAST scan failed on ZAP rule 90004 every run; apps/demo/vercel.json now sends same-origin next to the existing Cross-Origin-Embedder-Policy header (#1050).
  • The arm64 pass of the release image-arch check failed on every multi-platform cutscripts/check-image-arch.sh now resolves each platform's own manifest digest out of the multi-arch index before probing it, instead of reusing a single index-digest reference docker's classic image store can't hold two platform variants under (#1046).
  • Moving a container to another agent, or removing an agent from config, no longer resets its update policy — the agent-removal prune and the agent's own stale-container prune now pass identityChangeExpected: true and stash the departing record's snooze, maturity mode, and skipped tags under its Docker id, the same way the startup prune already did (#1050).
  • A manual "check now" landing mid-scan could fire the same notification twice — the dashboard, the API, a webhook, and the controller polling an agent all route through the same single-flight scan orchestration the cron schedule uses, reporting a coalesced call via result.coalesced or an X-Drydock-Watch-Coalesced header instead of starting an independent scan (#1050).
  • A once=true notification whose trigger never replied held its dedup key forever — each reservation now expires on its own timer, four times the handler timeout, and logs a warning naming the key if nothing released it first (#1050).
  • DR-121: the session store and the main store wrote the same /store/dd.json, and whichever saved last erased the other's data — the session store now writes to its own sibling file, dd-sessions.json by default, and the main store drops a stale Sessions collection left behind by an older build (#1063).
  • The agents page's paired Gitea registry example had the controller talking HTTPS to an agent serving plain HTTP — the agent block now mounts its own certificate and sets DD_SERVER_TLS_ENABLED, so the example connects as written (#1042).

v1.7.0-rc.11 Highlights — September 5, 2026

  • OIDC login no longer bounces back to the login page — the service worker's navigation fallback answered every document navigation except /api/ from the cached app shell, so the identity provider's callback never reached Express for its code exchange; the fallback now skips every server-owned route (/api, /auth/, /health, /metrics) (#1016).
  • A controller with its own local watcher no longer refuses every container an agent reports under a same-named watcher — ownership of a container with no store row is now decided by what the controller's own watchers have actually enumerated, not by a watcher-name collision (#1018).
  • A rollback of a compose-managed container no longer redeploys the update it was undoing — the compose recreate now passes the caller's image through to the runtime refresh instead of re-deriving one from the container's update candidate, automatic rollback hands the health monitor the whole container instead of just its id and name, and the backup image is pulled, digest-pinned when the record carries one, before anything is stopped or removed (#1023, #1029).
  • The published arm64 image is a real arm64 build again — both base-image pins are back on multi-arch image index digests instead of a single amd64 manifest, and the release now refuses to sign, tag, or promote an image whose binaries don't match the platform it's published under, closing the exec format error a Raspberry Pi hit under #1021 (#1024).
  • A container moved to an agent no longer stays stranded when the controller's local watcher is off — the startup prune that clears stale controller-owned records now also runs when no local watcher was ever configured, so the agent's report is no longer refused as controller-owned (#1037).
  • A container handed from the controller to an agent no longer loses its update policy — the startup prune now stashes the snooze, maturity mode, and skipped tags under the container's Docker id, which the move leaves alone, instead of a key the incoming record could never look up (#1037).
  • One local watcher failing to register no longer deletes its containers' records when a second watcher registers fine — the prune now keeps any record whose watcher is still configured, whether or not it registered this run, and waits for every registration to settle before reading the registry (#1037).
  • The agents page now says registries have to be configured on every agent, not just the controller — a worked Gitea example shows both sides (#1010).
  • The agents page's registries example now mounts the CA file it references — instead of pointing DD_AGENT_REMOTE1_CAFILE at a path the compose service never volumed in (#1037).
  • The watchers page now says the maintenance window gates the entire scheduled scan, not just installing an update — a closed window leaves new containers invisible, container state stale, and update notifications deferred until it reopens; a manual scan still bypasses it, same as a manual update (#1010).

v1.7.0-rc.10 Highlights — September 4, 2026

  • Batch and digest once=true eligibility now takes the same reservation the simple notification path takes — the reservation added for #972 covered the simple path only, so a manual single-container scan overlapping a cron scan passed a plain history read in both evaluations and sent the same candidate twice; batch and digest eligibility now reserve synchronously, the batch releases every reservation it took in a finally, the digest flush holds one for exactly the results it is sending and skips and evicts a substituted result an earlier flush already sent, and the batch retry buffer no longer carries an unreserved entry to the trigger (#998).
  • A deregistered watcher no longer warns about a cron-scan deadline it no longer owns — the deadline timer and a cancel handle now live on the watcher state, so deregistering a watcher while its watch() is stalled clears the timer and settles the race with its own sentinel, every caller resolves to an empty result with no deadline warning, the per-scan cleanup is identity-guarded so a late settlement cannot clear a newer scan's handle, and a scan requested after teardown is refused outright, which also covers the just-debounce docker-events timeout that still fires up to five seconds after the watcher is gone (#998).
  • The getting-started guide says where hook scripts run, and the agent registry-lookup fix credits its contributor — hooks run inside the Drydock container with DD_HOOKS_ENABLED=true, so a path that only exists on the host or in the updated container fails (#996).
  • The same hooks paragraph names the pre-hook abort as the default and dd.hook.pre.abort=false as the opt-out — the sentence had described the abort as unconditional (#1001).

v1.7.0-rc.9 Highlights — September 3, 2026

  • watchFromCron() is now single-flight — overlapping scans on a large fleet no longer fire the same trigger multiple times for one update; a request while a scan is running records that a rescan was requested instead of starting a second one, exactly one follow-up scan runs once the current scan finishes, and an in-flight scan that never settles is raced against a deadline so it can't wedge later cron ticks either, reported by @tarzan77cz (#979, #972).
  • The once=true notification-history key is now stable under a rate-limited digest lookup — the tag-kind hash no longer swaps between the digest and the image's created timestamp when a registry rate-limits the digest lookup, so an update already announced does not re-fire hours later, and concurrent evaluations of the same history key are now atomic so overlapping scans can't both pass the check and both send, reported by @tarzan77cz (#979, #972).
  • Two deprecation banners and the marketing site's Get Started snippets are corrected — the UI's legacyConfigBody and curlHealthcheckBody banners (all 17 locales) now say the removed DD_TRIGGER_* env vars and curl-based healthcheck override are already gone instead of pointing at a removal deadline that already passed, and the marketing site's quick-start and hardened compose presets now configure authentication (DD_ANONYMOUS_AUTH_CONFIRM=true on the quick preset) and a /store volume so the deployed instance actually becomes healthy (#988).
  • A docs audit corrects the README, DEPRECATIONS.md, and the configuration/triggers/registries/API/monitoring/agents docs against this tree's actual code — compose secret escaping and /store volumes, mistranslated provider names and a backwards roadmap link, a wrong deprecation removal-status label plus four missing entries, hook/threshold/rollback claims that didn't match the code, missing trigger template variables and shared config keys, a nonexistent registry routing mechanism and a missing rate-limit row, a stale audit action list and log-filter semantics, and health-gate/signing-key/health-check claims that didn't match the code (#988).

v1.7.0-rc.8 Highlights — September 3, 2026

  • Update pull-to-deploy identity is now pinned on both paths — the Docker-native and Compose update executors inspect the pulled image once, match its RepoDigests against the reference's own repository, bind an immutable repo:tag@digest reference, and run signature verification, vulnerability scanning, SBOM generation, and the replacement create against that pinned reference, closing the registry-retag window that previously let a mutable tag point somewhere else between the gate and the deploy (#961, #952).
  • Self-update and agent snapshot handling survive more edge cases — self-update no longer rolls back a health-verified replacement when removing the old controller container fails, treating a missing old container as already cleaned up; and the watcher-snapshot handler now refuses to prune on an empty container list the same way its sibling entry points already do, closing the gap left after the cold-start race and the watch() fix, with the test that had frozen the old pruning behavior in place now inverted (#951, #929, #386, #922, #565).
  • dd.registry.lookup.image now applies to agent-reported containersbuildContainerReport() applies the registry lookup label (and its legacy dd.registry.lookup.url alias) the same way the local watcher already does, so containers reported by a controller-Docker-transport agent such as Portwing honor the override instead of silently checking a mirror's own sparse tag copy (#956, #336).
  • Two more agent-config and registry-state defects are fixedDD_AGENT_ALLOW_INSECURE_SECRET is excluded before the flat dd.agent prefix parser runs, so it no longer produces a phantom agent named allow; and a container whose stored registry name is unknown now re-enters the repair path on refresh instead of staying stamped unknown until it is recreated, both reported by @depuits (#954, #955, #945).
  • Debug dumps redact more provider-specific credential fields — Apprise service URLs, Rocket.Chat user IDs, and Telegram chat IDs are now redacted alongside the existing ordinary parse.urls configuration flags (#953).
  • Four findings from the rc.6 QA sweep are fixed — the Trivy supply-chain advisory now matches the image's actual bundled version and digest, backed by a coupling test; the site has a real 404 page in the marketing shell instead of Next's bare fallback; the audit log's search count is now scoped to the fetched page instead of comparing against the server's unfiltered total; and the servers detail panel re-resolves its selection after every refetch instead of showing stale data behind its own Refresh button (#928).

v1.7.0-rc.7 Highlights — August 29, 2026

  • Registry tag discovery now handles real OCI pagination — Drydock follows each registry's opaque Link cursor, validates pagination URLs stay on the registry origin, caps runaway listings, and applies stricter rate limiting to ECR Public. Repositories such as public.ecr.aws/supabase/postgres can now resolve tags beyond the first page (#927).
  • Update operations keep healthy replacements healthy — cleanup failures after the health gate no longer trigger rollback, lifecycle SSE events use the compact container projection instead of shipping vulnerability and SBOM payloads, self-update helpers inherit the root-mode flags and restore renamed containers after an early exit, and duplicate caller-supplied operation IDs return 409. Self-updates now wait for active lifecycles before taking the exclusive gate, so later updates queue behind them (#931, #930, #942).
  • Secrets are scrubbed across triggers, debug dumps, registries, and commands — HTTP bearer credentials, compound environment names, URL credentials, and provider fields are redacted; debug dumps use the same sanitized container data as the API, are audited and rate-limited; registry host matching rejects lookalikes before credentials are sent; and command or lifecycle-hook scalar values are protected from splitting, globbing, and leading options (#932).
  • Compose, agent pruning, and logs close four correctness gaps — compose rewrites reject a repository mismatch even when reconciliation is off, repeat the check under the file lock against the freshly read multi-file chain, and create backups only after it passes; foreign container IDs are filtered before agent pruning reaches processAuthoritativeContainer; ESC-prefixed and C1 CSI sequences plus the remaining C1 controls are removed correctly by sanitizeLogParam; and rollback-failed outcomes retain their intended lifecycle status (#933, #938).
  • Header-authenticated requests no longer create sessions — requests using an Authorization: Basic header authenticate without persisting an unreachable session, while cookie authentication continues to persist and reuse sessions (#935).
  • Comparison and roadmap documentation reflect the current product — the competitor tables now cover current update managers and management platforms, including Komodo's maintenance windows and limited dry-run; shipped capabilities and audited feature counts are corrected, including Drydock's 11-registry lead over WUD; and rotatable API keys plus the per-update approval queue are placed on the v1.8 roadmap (#936, #938).

v1.7.0-rc.6 Highlights — August 29, 2026

  • Two more gaps in agent container ownership are closed, on top of the earlier #904 fix — a brand-new container id had no ownership check at all, letting an agent claim a watcher name the controller itself owns; and the bulk ingestion paths (handshake, the watcher-snapshot fallback, on-demand watch/watchContainer, and edge handleContainerSync) reached processAuthoritativeContainer with no check in between, so an agent could still claim another agent's or the controller's container on its next routine snapshot. Both paths now enforce the same ownership checks the original fix added.
  • Registry pull auth, error-response leaks, and preview-error redaction are all tightened — thirteen registries (Hub, Custom, DHI, DOCR, Harbor, Gitea, Forgejo, Codeberg, Nexus, Artifactory, Alibaba CR, OCIR, IBM CR) authenticated for the version check and then pulled anonymously, because the pull-credential builder had no branch for a configured auth value; it now decodes that value the same way the lookup-credential builder already did, and a malformed value fails closed instead of silently returning nothing. Eight API handlers stopped interpolating a raw thrown message — which could carry an Authorization header or a credentialed webhook URL — into a 500 response, routing instead through the existing sanitizePreviewErrorReason scrubber, which now also redacts credentials embedded in a URL path segment (Telegram, IFTTT, and Discord webhook URLs), not just headers or userinfo.
  • Query-parameter validation is now consistent across the log, agent, and audit endpoints — a non-numeric tail or since used to put NaN into the ring-buffer read instead of being rejected, an empty ?tail= was read as absent rather than invalid, and a limit/offset with a numeric prefix like ?limit=25logs validated on its leading digits instead of failing; all three now reject anything that isn't a clean, whole integer.
  • Six UI defects are fixed — row selection never actually highlighted in seven views, because the shared data table declares selectedKey but every view was passing it active-row instead; white text as low as 1.37:1 on the trigger test button and two avatars is flattened to a token that clears 4.5:1 in all twelve themes; the notification outbox and a container's full-page detail view each had their own race where the view rendered before its data resolved, both now guarded; two dashboard watchers missed every in-place SSE update because they watched a bare ref instead of a length- or fingerprint-aware source; and status text that rendered as raw English enum values in five places is now translated in all 16 locales.
  • 2109 strings that were still showing English source text are now actually translated, across all 16 non-English locales — large parts of the container list, the update and rollback dialogs, the search palette, and the notification outbox had silently fallen back to English regardless of the language selected. The weekly Crowdin sync also no longer reverts the six translated READMEs to English: README.md is no longer registered as a Crowdin source, and the translated READMEs are now hand-authored in-repo and asserted phrase by phrase at every cut (#919).
  • Release and CI reliability fixes — the multi-architecture smoke build now retries around an open BuildKit race (moby/buildkit#7089) that could prepend the QEMU emulator path twice and kill a multi-arch build outright, and the release cut itself gains a full-build retry for the case where the first attempt produced no digest at all; the weekly DAST scan, which had never completed because ZAP alone consumed 39m46s of its 40-minute budget and starved Nuclei, now runs both scanners as separate parallel jobs; and the docs search, which returned roughly 1600 hits spread across five archived versions with the oldest changelog ranked first, now scopes to the version being read.

v1.7.0-rc.5 Highlights — August 27, 2026

  • A security hardening pass closes five findings in Portwing and the debug/diagnostics surface — a malformed Portwing hello payload is now validated before parsing instead of throwing outside the callback error boundary, agent container ownership is enforced at the update/removal boundary, redaction now catches *_PAT values and credentials embedded in URLs (including scheme-relative ones), and the rejected-origin diagnostics path is rate-limited (#904).
  • Dark themes meet the WCAG 2.2 contrast minimum — secondary/muted text, the tone colors, toast surfaces, and primary button labels are raised to clear 4.5:1 against the surfaces they're actually painted on, across all six dark themes (#850, #865).
  • Large fleets and slow clients no longer break the controller connection — an agent whose cached watcher replay exceeded 256 KiB could never reconnect, is now fixed by keeping the stream open for the authenticated handshake to supply state; SSE clients that fall behind now get bounded, drain-aware, in-order delivery instead of dropped or unbounded-memory writes; the system-log limiter no longer falls back to an empty identity; and an unsupported agent transport is now rejected at admission instead of failing later (#904).
  • Update and watcher lifecycle state stays accurate through restarts and teardown — startup recovery no longer marks an untouched container as updated, a restart no longer suppresses batch-completion events for updates still in flight, an update that never started is no longer reported as failed, a watcher torn down mid-setup can no longer be resurrected by a late callback, and concurrently parsed Docker event chunks no longer race a shared buffer (#904).
  • Backup, rollback, and container-list correctness fixes — backups carry a stable scoped identity instead of colliding on a shared container name, rollback restores the digest recorded with the backup instead of whatever a mutable tag now points at, concurrent digest scans no longer cancel each other, a successful container action no longer returns 500 when the follow-up refresh fails, and paginated container lists are sorted globally instead of only within a page (#904).
  • The Crowdin sync workflow no longer fails on non-default dev branches — a push to a dev/vX.Y branch that wasn't the newest one died with a checkout conflict because the base resolver always picked the highest dev branch regardless of which ref triggered the run; a push now targets its own branch directly (run 33047712284).

v1.7.0-rc.4 Highlights — August 26, 2026

  • WebSocket log streams work behind TLS-terminating proxies — with trust proxy enabled and X-Forwarded-Proto absent on the upgrade request, the origin check no longer falls back to the local socket's TLS state (plain HTTP behind TLS termination, so every browser connection 403'd); the protocol is treated as unknown and host validation is unchanged. Traefik forwards the upgrade's client-facing scheme as wss rather than https (traefik/traefik#6388), which the origin check rejected outright, so the first fix alone still 403'd behind a default Traefik setup; ws/wss now map to http:/https: for the Origin comparison (#867, #868, #887).
  • Startup no longer crashes when the store volume forbids chmod — the 1.6.0 permission tightening threw on EPERM, so mounts that reject chmod (NFS/CIFS volumes, non-root containers) took the whole process down at boot and blocked 1.6.0 upgrades outright; it now warns and continues on EPERM/EACCES/ENOTSUP; a genuinely read-only volume (EROFS) still fails fast at startup, because nothing could be persisted there anyway (#874, #886).
  • Debug dumps redact env var values, not names — env entries are {key, value} pairs, and the redaction walker was matching the literal property name key against its sensitive-token rule, so a var like HF_TOKEN came out with the name hidden and the secret in plain text; names now stay visible and values are redacted when the name matches a sensitive rule (#875, #885).
  • Bare integer tags no longer outrank dotted versions — a build-counter tag like 168 no longer coerces into a fake 168.0.0 that beats a real 1.43.3, in both the suggested-tag badge and the actionable includeTags recovery path, which now share one partition rule so they can't drift apart (#859, #871).
  • Base images clear six HIGH OpenSSL CVEs — the node:24-alpine and alpine:3.24 digest pins and the openssl apk pin roll forward to OpenSSL 3.5.8-r0 (#881).
  • The demo site sends the full security-header set — the headers DAST flagged as missing on the demo surface are now sent (#878).
  • Containers that leave watch scope are pruned from the store and UI — a container excluded by watchbydefault being off, or by its dd.watch label being removed, kept a stale record as long as it still inspected in Docker; stopped-but-watched containers keep their existing start-button behavior (#869, #888).

v1.7.0-rc.3 Highlights — August 23, 2026

  • Portwing edge tunnels carry non-JSON Docker response bodies — the controller's welcome frame now advertises an edge-response-body-b64 capability and decodes base64-negotiated response bodies (for example GET /_ping's plain-text OK) from agents that support it, falling back to the existing path otherwise. Additive and capability-gated, no protocol-version bump (#852).
  • README badges read live instead of being hand-bumped — the version, license, pull-count, and stars badges in the English README and all six translations now render from live shields.io endpoints instead of static images, and the star history chart ships as a <picture> block with theme-matched light and dark SVGs that regenerate from the release-cut workflow instead of a cron (#851, #844, #847).
  • DAST and workflow-lint gates fail closed — the ZAP scans no longer pass -I (which told ZAP to ignore every warning), so findings now actually fail the gate, and the pre-push zizmor step errors with an install hint instead of silently skipping when the binary is missing (#842).
  • A daily monitor asserts main carries a release tag — a scheduled, read-only workflow goes red when main's HEAD is untagged, deliberately not a required PR context since a promotion merge is untagged by definition until the cut lands (#846).
  • The release pipeline no longer trips over its own test infrastructure — the rc.2 cut failed on main's push-triggered CI: a global js-yaml v5 override broke Artillery's load-test jobs, reverted to the v3 range Artillery actually supports (#829), and two Playwright waits were budgeted tighter than the backend operations they cover, so promotion runs raced the app's own state machine, fixed by raising the ceilings past the app's budgets (#832, #836).

v1.7.0-rc.2 Highlights — August 20, 2026

  • Per-container action-policy resolution — the API and UI now surface the resolved blocked/manual/auto state and winning trigger for every container and candidate action trigger, plus a new dd.action.auto label and AUTO=onauto mode so a container can opt into manual-only access without picking up automatic dispatch (spec-6.0.1-action-policy.md, slice 5).
  • BREAKING changes take effect this cycle — the legacy DD_TRIGGER_* prefix and dd.trigger.* labels are fully removed, trigger-excluded/trigger-not-included become hard update blockers ending the v1.5.0–v1.6.x soft-severity grace period, the Home Assistant MQTT topic layout now scopes multi-agent deployments under an agent/<name> segment by default, GET /api/auth/methods returns 410, and curl is gone from the Docker image in favor of the compiled healthcheck binary.
  • Dependency-graph and admission fixes — a rejected dependency member no longer loses its restart context in wave 0, and Docker Compose refreshes no longer carry forward a stale image-inherited environment default (#718, #736).
  • Self-update state survives itself — the updatePolicyRetentionCache that lets a recreated container inherit its predecessor's policy overrides now persists write-through to the store instead of being silently dropped on drydock's own self-update restart (#743).
  • Update checks stop reporting false confidence — a registry error mid-check no longer reports "Up to date," a single malformed container no longer zeroes out an entire agent inventory sync, and nested OCI image indexes (Buildx SBOM/provenance builds) now resolve to the real manifest instead of erroring (#814).
  • Security — closed a remote-property-injection path in the container list's URL query sync, and scoped the Grype image gate around CVE-2026-14456 pending an upstream Alpine fix (#750).
  • Everything else — Greptile second-opinion review is available behind a label, release-cut.yml can cut a maintenance patch from a retired dev branch, the container SBOM attestation is now documented in the verification guide, the trivy qlty plugin gave way to Grype, the login screen's oversized logo asset was fixed, and the star-history chart moved to a committed SVG.

v1.7.0-rc.1 Highlights — August 14, 2026

  • Dependency-aware updates — labels or Compose metadata resolve into deterministic update waves, with preview-bound confirmation, restart-only dependents, cycle handling, and explicit skipped-dependency results (Discussion #219).
  • Operator UX additions — installable PWA support, clickable named port links, live container uptime, keyboard shortcuts, and a configurable settling window for newly discovered containers.
  • Trigger migration reaches removalDD_TRIGGER_* now fails startup and legacy dd.trigger.include / dd.trigger.exclude labels no longer route work; use the action/notification-specific replacements.
  • Security and lifecycle hardening — authentication, agent requests, logs, WebSockets, and registry requests have explicit resource bounds; sensitive command/hook values are redacted; Home Assistant discovery now resynchronizes after startup and drains retiring provider work without stale publishes (#708).
  • Portwing controller and Edge reliability — Edge refresh cadence is configurable with DD_PORTWING_POLL_INTERVAL; exec_end.reason reaches internal consumers without leaking sessions; and controller-owned Docker inventory/events normalize against configured registries so native watch-now checks no longer round-trip through Portwing's intentional 501 registry stub (#688, #635, #687).
  • Registry metadata failures stay visible — optional manifest/blob responses with status 301, 302, 303, 307, or 308 can omit created without discarding a resolved digest, while exhausted 4xx, 5xx, network, and non-object failures now propagate instead of silently becoming a successful result with unstable metadata (#606).
  • First-party star history — the same-origin /api/star-history provider serves allowlisted Drydock, Sockguard, and Portwing charts without relying on a third-party tracker.

v1.6.0 Highlights — August 11, 2026

Consolidates the 1.6.0-rc.11.6.0-rc.13 prereleases into one GA release. The biggest themes: Portwing edge/agent transport maturing into a first-class citizen, a declarative three-tier update policy with a maturity stabilization gate, per-rule notification templates and a new health-status event, every major list view going responsive with a consistent table/card toggle, /api/v1 parity with the unversioned /api/* alias removed, and fail-closed security hardening throughout. See CHANGELOG.md for the full release notes.

v1.6.0-rc.13 Highlights — August 8, 2026

  • Digest comparison anchors on repo-matched candidatesgetOrderedRepoDigests (app/watchers/providers/docker/docker-helpers.ts) filters a container's RepoDigests entries to the ones whose repo component matches its own image reference before comparing, instead of trusting an arbitrary RepoDigests[0]; a store already poisoned with a stale digest anchor self-heals on the next cycle (#670).
  • nanoid pinned to 3.3.18 across the root, app, apps/demo, apps/web, ui, and e2e workspaces (transitive override of postcss/artillery) for GHSA-2v37-7h3g-55p8 (CVE-2026-67213) and, in e2e, GHSA-28wg-ghj8-5hjv (CVE-2026-67214) (#673).
  • Star History chart is now self-hosted — a new same-origin GET /api/star-history route on the website replaces the third-party embed that went down in a global outage, edge-cached six hours with stale-while-revalidate and a short-lived fallback SVG on fetch failure (#672).
  • Base-image CVE sweepnode:24-alpine bumped to Node 24.19.0 (clearing 3 HIGH + 5 MEDIUM CVEs from Node's July 29 2026 security release) and the vendored aquasec/trivy build-stage pin bumped from 0.72.0 to 0.73.0 (clearing 4 HIGH / 6 MEDIUM CVEs in its vendored Go dependencies) (#682).

v1.6.0-rc.12 Highlights — August 4, 2026

  • Security dependency refreshbrace-expansion advanced to 5.0.9 across the app, UI, and e2e workspaces (CVE-2026-69152), ip-address to 10.3.1 in the app runtime (CVE-2026-54272, CVE-2026-69192, CVE-2026-69198), and fast-uri to 4.1.2 in app and UI (backslash-authority host confusion, CVE-2026-18446) (#659).
  • Maturity badge and gate agree again — the hot/mature badge now resolves each container's own updatePolicy.maturityMinAgeDays before the global DD_UI_MATURITY_THRESHOLD_DAYS, matching the gate, and registry publish-date lookup failures (including GHCR/LSCR auth errors) log at warn instead of vanishing at debug (#604).
  • No more transient "Agent Mismatch" — the container list and SSE stream soften agent-mismatch/no-update-trigger-configured to soft blockers while an agent's components are mid-(re)registration; update admission stays fail-closed throughout (#605).
  • WebSocket log streams accept anonymous-auth sessions — under DD_ANONYMOUS_AUTH_CONFIRM=true, both the system and container log-stream upgrades now pass the same auth gate as every REST endpoint (#636).
  • Explicit 501 for missing agent lifecycle transport — start/stop/restart/rollback on an agent-owned container without controller Docker transport returns a 501 naming the cause instead of an ambiguous 404 (#637).

v1.6.0-rc.11 Highlights — August 1, 2026

  • Portwing 0.9 Docker watcher, updates, and lifecycle actions now run controller-side — Drydock 1.6.0-rc.11+ recognizes the exact transport=docker-api, execution=controller, events=portwing watcher marker, starts its native registry checks and Docker action against a loopback-only authenticated bridge, and carries Docker calls over Standard HTTP or Edge correlated request/response/stream transport. Single/batch updates, start/stop/restart, update preview, and backup rollback use this path even though Portwing advertises no remote trigger. Portwing stays authoritative for lifecycle events, and raw false/unknown inventory no longer erases controller enrichment (#632, #637, Portwing #76).
  • Standard Portwing request signing matches signature version 2 — Ed25519 agents now receive five headers including X-Portwing-Signature-Version: 2; the signature covers the exact escaped request path plus its unmodified raw query instead of a decoded path with the query omitted.

v1.6.0-rc.10 Highlights — July 31, 2026

  • Infrastructure-mode self-updates no longer fail to spawn the helper container on Docker Hub installs — for containers labeled dd.update.mode=infrastructure, the helper image reference is now resolved through the registry provider's getImageFullName normalization instead of a raw Hub URL, so it matches the daemon-local image name and the helper actually pulls (#645, fixes #644).
  • Startup warning for minute-precise maintenance-window crons — the Docker watcher now logs a one-time warning at init when DD_WATCHER_{name}_MAINTENANCE_WINDOW's minute field doesn't contain *, a common copy-paste trap that opens the window for one minute per hour instead of the whole range; the update confirm dialog also links to the update-eligibility reasons reference (Discussion #639).
  • Unchanged update-available audit entries are no longer re-recorded on a timer — audit rows are now written only on first detection or when the update target/kind changes, instead of every time the dedupe window lapses (#642).
  • Maintenance-window documentation corrected — examples now use * 2-6 * * * instead of a minute-precise cron that was described as an hourly range, and the update confirm dialog's wording is documented verbatim in Update Eligibility & Blockers (#640).
  • Translations resynced from Crowdin (#620) and routine dependency maintenance across the app and UI workspaces, including the fast-uri security override advancing to 4.1.1 (#614, #615, #617, #646).

v1.6.0-rc.9 Highlights — July 28, 2026

  • Portwing edge log streaming is on by default — the authenticated container-log WebSocket now bridges correlated chunk/end/error frames from the edge gateway, cancels the agent stream when the viewer closes, and caps each downstream viewer at 1 MiB of buffered data; older Portwing agents degrade gracefully to their one-shot response. DD_EXPERIMENTAL_PORTWING=false remains available as an emergency disable.
  • The row status overlay is no longer clipped at the pinned-column edge — the "Updating/Queued/Scanning" chip is now layered above the sticky identity-cluster cells instead of being cut in half at the cluster boundary (#631).
  • Registry errors no longer replace the container's tag — a rate-limit/auth/not-found registry error used to overwrite or duplicate the tag cell with a danger pill; the tag column now always shows the actual tag, with the registry column glyph remaining the single error flag (#631).

v1.6.0-rc.8 Highlights — July 28, 2026

  • Agent-managed containers keep their update policy — remote agents never learn controller-side runtime overrides, so every agent report carried an empty override layer that the controller persisted verbatim, wiping maturity mode, min-age days, skip lists, and snoozes on every sync or recheck. The controller now reapplies its stored overrides when ingesting agent reports, and the store only honors an empty override layer when the update-policy API marks the clear as deliberate — so settings finally survive agent syncs while UI clears still stick (#565).
  • Auto-update keeps running when update notifications are scoped to specific channels — assigning any notification trigger to the update-available rule silently disabled every action trigger (Docker, Docker Compose, Command) fleet-wide, because action triggers were run through an allow-list they're structurally barred from joining. Action triggers are now exempt from the allow-list membership check; disabling the rule itself remains the kill switch (#623).

v1.6.0-rc.7 Highlights — July 26, 2026

  • Four identity-drift bugs fixed — the maturity soak clock no longer resets when a container is recreated, notification dedup no longer double-fires a once: true notification on a manual recheck, a finishing security scan no longer reverts an update the watcher detected mid-scan, and containers with no available update no longer surface under maturity/age filters or sorts. All four traced back to inconsistent candidate-identity comparisons, now unified behind one shared helper.
  • Icon bundle regeneratedui/src/boot/icon-bundle.json is back in sync with the locked iconify versions, fixing drift since the tabler 1.2.35 → 1.2.37 lockfile bump.

v1.6.0-rc.6 Highlights — July 26, 2026

  • Maturity-cleared updates get their own notification — when an update held back by the maturity gate (maturityMode: mature) finally clears its soak window, drydock now fires a dedicated maturity-cleared notification right away instead of waiting on the next scan's generic update-available message (Discussion #587). A background sweep checks gated containers every few minutes so the notification lands close to the moment the update actually becomes applicable, and it's deduplicated against update-available so nothing gets announced twice.
  • Routine dependency and translation maintenance — minor and patch bumps across the app, UI, demo, website, and end-to-end workspaces, plus a refreshed translation sync from Crowdin covering the container, dashboard, list, and shared-component catalogs.
  • CI scripts no longer choke on empty results — steps that piped a grep or find straight into a variable assignment could abort before their own "nothing found" fallback ever ran, since an empty match exits non-zero under bash -eo pipefail. Fallible commands are now guarded individually so a real failure still fails loudly and an empty result still falls through to its handler.

v1.6.0-rc.5 Highlights — July 23, 2026

  • Resources can give the table its space back — the Resources column remains visible by default, but the column picker can now hide it and preserve that choice. Source, release-note, and registry shortcuts move into each row's More menu while hidden; cards keep the same shortcuts in their footer without duplicating them.
  • Phone-width Dashboard and Containers stop overflowing — crossing into a single-column breakpoint re-syncs the dashboard widget layout so widgets no longer spill past the viewport, single-column card lists drop the empty band below reflowed cards, and long stack names in the Containers group header truncate instead of pushing the update-all button off-screen (#498).

v1.6.0-rc.4 Highlights — July 22, 2026

  • Pinned freshness is honest at a glance — an informational newer-version insight now reads Major, Minor, or Patch instead of contradicting the visible newer tag with “Current.” It remains non-actionable and cannot fire update actions or notifications.
  • Same-tag rebuilds are explained — “Image update” replaces “Digest update,” with tooltip copy explaining that the tag now points to a different image build and a redeploy pulls it.
  • The Containers layout keeps contextSoftware Version is explicitly named and folds before Host at constrained laptop widths. Users can also set, change, or clear a presentation-only group from a container's More menu; clearing an override restores Docker-derived grouping.
  • Release-gated E2E failures are attributable — Cucumber reuses the exact QA image built by CI, verifies a six-fixture manifest, restores scenario-mutated state, and publishes structured reports and diagnostics without blanket scenario retries. Playwright owns browser rendering and retains first-failure media without whole-test retries.

v1.6.0-rc.3 Highlights — July 21, 2026

  • Honest update states across the UI — digest-only changes read "Digest update" instead of a version label, an unrecognized update kind shows a neutral "Unknown" badge, the security bouncer's block state reads "Security hold", and the NEW/MATURE freshness badges are gone in favor of one maturity clock panel that names the clock the gate actually measures against.
  • Pinned is a tag property, not an update status — pinned containers carry a persistent pin glyph beside the tag (driven by the real pin-gate verdict, with the dd.tag.family remedy in its tooltip), and insight-only pinned rows read "Current" everywhere, including the container-detail Update Status panel.
  • Security hardening batch — anonymous access fails closed on upgrades (401 API responses, /health 503) unless explicitly confirmed, the HTTP notification trigger blocks SSRF against metadata/link-local targets including via redirects, WebSocket upgrades validate the complete origin, the session cookie is namespaced to drydock.sid, store files are owner-only, and icon CDN sources are pinned to exact revisions. Docs: Authentication, HTTP trigger.
  • Maturity countdown stability — a manual recheck no longer restarts the maturity soak when only display metadata wobbled; the clock resets only when the update candidate's tag or digest actually changes.
  • Container-list fit and follow-through fixes — the column picker labels columns auto-hidden to fit (and its "+N" badge tooltip stays fresh), registry deep-links from container detail land on the registry they name, and the removed-API-path banner pluralizes correctly.

v1.6.0-rc.2 Highlights — July 18, 2026

  • Watch errors no longer erase update state — a container whose registry check fails keeps its last successful comparison alongside the recorded error instead of appearing never-compared, errored containers reuse the same fast refresh path as healthy ones, and repair rebuilds preserve the registry-reconciled digest that keys security scan grouping.
  • "Version Update" container filter — a new filter kind shows only real semver upgrades (major/minor/patch) and hides digest-only churn; bookmarkable via ?filterKind=version.
  • Docs aligned with shipped behavior — FAQ and README corrections (registry list, scanner parity, runnable config migrate commands), the removed WS /api/log/stream alias documented in Deprecations, and the quickstart registry/tag matrix refreshed.

v1.6.0-rc.1 Highlights — July 15, 2026

  • Notification rules are now a complete control surface — configure delivery routing, audit-backed in-app bell categories, update severity threshold, and per-provider simple/batch templates in one detail panel; preview drafts before saving. Container-unhealthy events are bell-capable, and agent status changes refresh the bell promptly. Docs: Actions & Notifications, Notification rules API.
  • The dashboard uses a custom zero-dependency grid — edit-mode mouse/touch reorder, bounded resize, deterministic packing, hidden widgets, responsive layouts, reset, and local or opt-in cross-device persistence replace grid-layout-plus. Docs: Dashboard customization, UI preference sync.
  • v1.6 deprecation removals are enforced — only argon2id Basic hashes, HTTPS OIDC discovery, DD_* environment variables, and dd.* labels are active at runtime. Removed WUD names remain recognized only by the migration CLI. Trigger-taxonomy aliases stay functional for their final warning release but now log at error level. Docs: Deprecation schedule, Migrating from WUD.
  • Polling and log-view hot paths are hardened — per-poll repository tag lists are deduplicated, aggregate endpoints avoid full-collection deep clones, large log collections are virtualized, and the 2,000-row live system-log client buffer rolls forward without freezing newest-first views. Docs: Logs.
  • Compose updates resolve the active file chain explicitly — configured label, standard Compose project labels, live inspect fallback, then trigger-level FILE, with multi-file ordering, working-directory resolution, bind-mount mapping, and optional mount-prefix matching. Docs: Docker Compose auto-detection.

Documentation Refresh — v1.5.2

  • Podman and Docker socket security docs refreshed — The watcher docs now cover Podman's Docker-compatible API path (#152), direct socket vs proxy/TCP caveats, rootful/rootless socket paths, SELinux troubleshooting, remote Docker over TLS, and OIDC remote watcher auth. This is documentation and compatibility guidance. Docs: Podman Quick Start, Docker Socket Security, Podman FAQ.
  • Config and API reference parity — The current docs were reconciled against runtime config schemas, Express routes, and the OpenAPI spec. Configuration tables now match the implemented env vars and defaults more closely, while the API docs cover canonical /api/v1 routes, authentication component endpoints, registry webhook signature auth, notification outbox actions, bulk container updates, backup listing, and auth status aliases. Docs: Configuration, REST API, OpenAPI spec.

Release Highlights — v1.5.1-rc.4 (June 29, 2026)

  • Container Version and Uptime fieldsimage.softwareVersion now powers detail panels and the new Version column, while Docker State.StartedAt powers detail uptime and the optional Uptime column. Docs: Watcher container runtime details, Tag and Version columns.
  • Release notes expanded — The release-notes popover includes current, available, and intermediate semver releases. Trigger templates can reference ${currentReleaseNotes} alongside ${releaseNotes}. Docs: Release notes popover, Trigger template variables, Container release-notes API.
  • Docker Compose mount-prefix fallbackDD_ACTION_DOCKERCOMPOSE_{name}_MOUNTPREFIXFALLBACK=true can match compose paths by trailing <project-dir>/<file> when bind mounts expose a different prefix inside Drydock. Docs: Docker Compose trigger — Mount-prefix fallback.
  • Maintenance and maturity gates tightened — Auto-apply now respects maintenance windows on every detection path, Docker Hub/GHCR publish dates can clear mature updates immediately, and a changed pending tag/digest restarts the soak clock. Docs: Update eligibility blockers, Maturity filter configuration.
  • Upgrade note for v1.5.1+ stores — Newer dd.json fields are tolerated on later downgrades, but rolling back from v1.5.1 to v1.5.0 still requires removing details.startedAt and image.softwareVersion. Docs: Storage.
  • One-time mature-update burst — On the first poll after upgrade, Docker Hub or GHCR updates that are already older than maturityMinAgeDays may immediately fire notifications or action triggers. Docs: Maturity policy gate.

Release Highlights — v1.5.0 (June 22, 2026)

  • Default watcher cron changed to every 6 hours — The default DD_WATCHER_{name}_CRON value changed from 0 * * * * (hourly) to 0 */6 * * * (every 6 hours) to stay within anonymous Docker Hub and GHCR rate limits on larger inventories. Deployments that set DD_WATCHER_{name}_CRON explicitly are unaffected. To keep near-real-time detection, set DD_WATCHER_LOCAL_CRON=0 * * * *. Docs: Watchers configuration.
  • 17 UI locales — The UI now ships with English plus 16 non-English locales: Simplified Chinese, Traditional Chinese, Italian, Spanish, German, French, Brazilian Portuguese, Dutch, Polish, Turkish, Japanese, Korean, Russian, Vietnamese, Ukrainian, and Arabic. Switch language in Config > Appearance. Docs: UI Customization — Language.
  • DD_LOG_FORMAT default is now text — The official Docker image defaults to human-readable log output. Set DD_LOG_FORMAT=json for structured output consumed by log aggregators. Docs: Logs, FAQ.
  • Notification outbox — Failed notification deliveries are persisted and retried with exponential backoff. A new Notification outbox page (under Settings) shows pending, delivered, and dead-letter entries with retry and discard actions. Docs: Triggers.
  • Diagnostic debug dump — One-click export from Config > Diagnostics collects a redacted snapshot of recent events. GET /api/v1/debug/dump?minutes=30. Docs: Configuration > Diagnostics, API.

Release Highlights (March 2026)

  • Shared data table sizing — Tables now share one sizing model with stable columns, sticky actions, pointer/keyboard resize, double-click autosize, and persisted per-view widths. Containers also folds lower-priority metadata at narrow widths instead of compressing primary identifiers. Docs: UI customization — Data Tables.
  • System log live streaming — The Configuration Logs view now supports live WebSocket system logs with level/component filtering and tail backfill.
    Docs: Logs configuration, Log API stream endpoint.
  • Watcher run-time visibility — Watchers expose metadata.lastRunAt and metadata.nextRunAt, and the UI surfaces these in the Watchers and Agents views as Last run and Next run.
    Docs: Watcher API.
  • Container list query enhancements — Container list now supports order, runtime status filters (running, paused, etc.), and watched-state kind filters (watched, unwatched, all).
    Docs: Container API query parameters.
  • Digest notification mode — Triggers can accumulate updates and flush on schedule with MODE=digest + DIGESTCRON.
    Docs: Trigger modes.
  • Signed registry webhooks — Added HMAC-verified registry push webhook endpoint for targeted checks.
    Docs: Webhooks.
  • Podman API compatibility improvements — Watchers now handle Podman API-version differences more reliably (including redirect-prone unversioned API paths).
    Docs: Watchers Podman setup, Podman FAQ.
  • Container-action failure toasts — UI now surfaces update/delete failures as visible toast notifications instead of silent failures.
    Docs: Container actions.
  • Unified update-completion toasts (v1.5.0-rc.19) — Update, rollback, and cancel result toasts now appear the moment the operation completes, and are replayed correctly after a reconnect.

Per-container Update Policy (February 9, 2026)

This update adds skip/snooze controls per container to reduce noisy repeated notifications for known-bad versions.

What changed

  • Added container-level update policy in store:
    • skipTags
    • skipDigests
    • snoozeUntil
  • Added API endpoint:
    • PATCH /api/v1/containers/:id/update-policy
    • Actions: skip-current, clear-skips, snooze, unsnooze, clear
  • Added UI controls on container cards:
    • Skip current update
    • Snooze for 1/7/30 days
    • Clear snooze or all policy

Behavior

  • updateKind still reflects the detected remote update.
  • updateAvailable is suppressed while policy applies (skip/snooze), and becomes true again when a new unmatched version/digest is detected or snooze expires.

Trigger Coordination Improvements (February 9, 2026)

This update improves how triggers can be coordinated when they share the same trigger name (for example docker.update and discord.update).

What changed

1. Trigger execution ordering

You can now control trigger execution order with:

DD_ACTION_{trigger_type}_{trigger_name}_ORDER / DD_NOTIFICATION_{trigger_type}_{trigger_name}_ORDER

  • Lower values run first
  • Default is 100
  • If two triggers have the same ORDER, they are sorted by trigger id

Example:

DD_ACTION_DOCKER_UPDATE_ORDER=10
DD_NOTIFICATION_DISCORD_UPDATE_ORDER=20

This ensures the Docker update trigger runs before the Discord notification trigger for the same update event.

2. Trigger name aliases in container labels

Container labels dd.action.include / dd.notification.include (and their .exclude counterparts) now accept either:

  • full trigger id (docker.update)
  • trigger name alias (update)

Example:

dd.action.exclude=update

This applies to every action trigger named update (for example docker.update and dockercompose.update).

Each label filters only its own trigger category. dd.action.include / dd.action.exclude never filter notification triggers, and dd.notification.include / dd.notification.exclude never filter action triggers. To exclude both docker.update and discord.update, set both labels:

dd.action.exclude=update
dd.notification.exclude=update

The legacy labels dd.trigger.include / dd.trigger.exclude were removed in v1.7.0 and no longer resolve to anything; only the scoped dd.action.* / dd.notification.* labels are read.

3. Shared threshold by trigger name

Triggers sharing the same trigger name can share THRESHOLD automatically:

  • if exactly one threshold value is explicitly set among same-name triggers, that value is inherited by the others
  • if multiple different threshold values are set, no inheritance is applied

Example:

DD_ACTION_DOCKER_UPDATE_THRESHOLD=minor

With no explicit Discord threshold, discord.update inherits minor.

DD_ACTION_DOCKER_UPDATE_THRESHOLD=minor
DD_ACTION_DOCKER_UPDATE_ORDER=10
DD_ACTION_DOCKER_UPDATE_PRUNE=true

DD_NOTIFICATION_DISCORD_UPDATE_ORDER=20
DD_NOTIFICATION_DISCORD_UPDATE_URL=<discord_webhook_url>
DD_NOTIFICATION_DISCORD_UPDATE_SIMPLETITLE=Updated ${container.name}
DD_NOTIFICATION_DISCORD_UPDATE_SIMPLEBODY=Container ${container.name} has been updated from ${container.updateKind.localValue} to ${container.updateKind.remoteValue}

On this page

Unreleasedv1.7.0-rc.16 Highlights — September 15, 2026v1.7.0-rc.15 Highlights — September 10, 2026v1.7.0-rc.14 Highlights — September 8, 2026v1.7.0-rc.13 Highlights — September 8, 2026v1.7.0-rc.12 Highlights — September 6, 2026v1.7.0-rc.11 Highlights — September 5, 2026v1.7.0-rc.10 Highlights — September 4, 2026v1.7.0-rc.9 Highlights — September 3, 2026v1.7.0-rc.8 Highlights — September 3, 2026v1.7.0-rc.7 Highlights — August 29, 2026v1.7.0-rc.6 Highlights — August 29, 2026v1.7.0-rc.5 Highlights — August 27, 2026v1.7.0-rc.4 Highlights — August 26, 2026v1.7.0-rc.3 Highlights — August 23, 2026v1.7.0-rc.2 Highlights — August 20, 2026v1.7.0-rc.1 Highlights — August 14, 2026v1.6.0 Highlights — August 11, 2026v1.6.0-rc.13 Highlights — August 8, 2026v1.6.0-rc.12 Highlights — August 4, 2026v1.6.0-rc.11 Highlights — August 1, 2026v1.6.0-rc.10 Highlights — July 31, 2026v1.6.0-rc.9 Highlights — July 28, 2026v1.6.0-rc.8 Highlights — July 28, 2026v1.6.0-rc.7 Highlights — July 26, 2026v1.6.0-rc.6 Highlights — July 26, 2026v1.6.0-rc.5 Highlights — July 23, 2026v1.6.0-rc.4 Highlights — July 22, 2026v1.6.0-rc.3 Highlights — July 21, 2026v1.6.0-rc.2 Highlights — July 18, 2026v1.6.0-rc.1 Highlights — July 15, 2026Documentation Refresh — v1.5.2Release Highlights — v1.5.1-rc.4 (June 29, 2026)Release Highlights — v1.5.0 (June 22, 2026)Release Highlights (March 2026)Per-container Update Policy (February 9, 2026)What changedBehaviorTrigger Coordination Improvements (February 9, 2026)What changed1. Trigger execution ordering2. Trigger name aliases in container labels3. Shared threshold by trigger nameRecommended setup for "update then notify"