Skip to content
CAI
Software that uses CAICheck a score

guardian/grid

42.7

Weak · 27 September 2026

50.3k

lines of production code

Scala

with Java, JavaScript, TypeScript

3

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

This system is a comprehensive media asset management platform, known as Grid, designed to ingest, store, and manage images for a news organization. It provides a suite of microservices that handle authentication, image processing, cropping, and hierarchical collection management, backed by AWS infrastructure including S3, DynamoDB, and Elasticsearch. The platform also features a modern web interface for editors to search, edit metadata, and manage usage rights, alongside AI-driven capabilities for image similarity search via vector embeddings.

How it got here

2013–2015 — Grid platform modernization and microservice expansion

109 changes.

This period established the Grid image management system by scaffolding the project and migrating core infrastructure to AWS SDK v2, Play 3, and SBT 1. The architecture evolved from a monolithic API into a suite of specialized microservices, including Thrall for stream processing, metadata-editor for rights management, and collections for hierarchical organization. Concurrently, the Kahuna frontend was rebuilt with a reactive stack to support advanced search, AI-driven image similarity, and granular usage rights workflows.

2016–2020 — Microservices architecture and media management features

60 changes.

The project transitioned to a microservices architecture by extracting standalone applications for authentication, image loading, cropping, and leases, while centralizing configuration and health checks. Concurrently, the Kahuna frontend was enhanced with a new chip-based search interface, improved image cropping tools, and comprehensive UI components for managing media leases and collections.

2021–2026 — Authentication overhaul and AI embedding infrastructure

54 changes.

This period focused on refactoring the authentication and authorization framework into a pluggable, multi-principal system with stricter permission enforcement, while simultaneously introducing AI-powered image search via a new embedding Lambda and vector storage infrastructure. The work also included significant frontend modernization by migrating core UI components to React, expanding the E2E test suite with Playwright, and adding features for image undeletion, metadata templates, and takedowns.

Features

Add 'More like this' search button

A new 'More like this' button has been added to the image view interface. When clicked, it initiates a search for images similar to the currently viewed one by leveraging the AI search capability, provided the feature is enabled in the client configuration.

kahuna/public/js/components/gr-more-like-this · high confidence

Add batch full-frame cropping with confirmation step

A new 'Crop full frame' button has been added to the results bar, allowing users to apply a full-frame crop to all selected images in a single action. The feature includes a two-step confirmation process to prevent accidental execution: the first click prompts for confirmation, and the second click initiates the batch crop operation. The button's state updates dynamically, showing a loading indicator during processing and disabling the control once all selected images have been cropped.

kahuna/public/js/components/gr-batch-export-original-images · high confidence

Add component to delete all image usage information

A new 'gr-delete-usages' component has been introduced, providing users with the ability to remove all usage metadata associated with an image. The component checks for user permissions and, upon confirmation via a text prompt, invokes the image usages service to clear the usage details, while explicitly noting that the image itself remains in its original locations.

kahuna/public/js/components/gr-delete-usages · high confidence

Add crop option definitions for API responses

The media API now exposes a predefined list of supported crop variations (landscape, portrait, video, and square) with their respective aspect ratios. This change introduces the data structure and serialization logic required to return these specific crop options to users, enabling them to select from the available standardized formats.

media-api/app/lib/crops · high confidence

Add keyword input component for images

A new 'gr-add-keyword' component has been introduced, providing a user interface to add keywords to images. This component includes a button to trigger the input form, a text field for entering comma-separated keywords, and save/cancel actions. When saved, the keywords are appended to the image's metadata via the edits service, with the UI updating to reflect the change or alerting the user if the save fails.

kahuna/public/js/components/gr-add-keyword · high confidence

Add local development configuration templates and data files

New configuration files have been added to the dev/config directory to support local development environments. This includes a permissions template that generates access rules based on the EMAIL\_DOMAIN variable, a photographers configuration file defining BBC staff and contracted roles, quota limits for specific agencies (Rex, AAP, Getty), and a comprehensive usage rights configuration mapping supplier parsers and credit matches. Additionally, dummy user accounts and a sample email usage report template are now included to facilitate local testing and metadata processing workflows.

dev/config · high confidence

Add undelete functionality for soft-deleted images

A new 'gr-undelete-image' component has been introduced to allow users to restore images that have been soft-deleted. This component provides a UI button that triggers an undeletion API call and subsequently polls the server to confirm the image is no longer marked as soft-deleted. Once the undeletion is confirmed, the system marks the image as archived to prevent it from being immediately reaped by background processes.

kahuna/public/js/components/gr-undelete-image · high confidence

Added 'Has Taken Date' tab selector component

A new UI component (gr-tab-swap) has been introduced to allow users to filter search results by whether they have a taken date. This component renders two tabs—'With taken date' and 'Without taken date'—and updates the query using the 'has:dateTaken' chip. It includes keyboard navigation support and dynamically displays the count of matches for the 'without' tab when results exist.

kahuna/public/js/components/gr-tab-swap · high confidence

Added JSON serialization utilities with GZIP compression support

The common library now includes new JSON helper utilities that enable automatic GZIP compression for JSON byte arrays. The \JsonByteArrayUtil\ object provides methods to serialize objects to compressed byte arrays and deserialize them back, using a specific marker byte to detect whether compression is present. Additionally, \PlayJsonHelpers\ introduces helper methods for logging JSON validation errors and extracting string or array values from JSON nodes, which are now available via the \json\ package object.

common-lib/src/main/scala/com/gu/mediaservice/lib/json · high confidence

Added stress-test scripts to reproduce GRID ES memory outage

New scripts have been added to the stress-test folder to help reproduce and monitor a specific Elasticsearch memory outage scenario. The \ping-grid-search.sh\ script continuously queries the media-api \/images\ endpoint, while \stress-upload.sh\ performs high-volume image uploads with modified metadata to simulate load. These tools allow engineers to observe system behavior and monitor the ES cluster using Cerebro during stress conditions.

stress-test · high confidence

Apply metadata templates to images

Users can now select and apply predefined metadata templates to images via a new UI component. This feature allows templates to automatically update image metadata, usage rights, and collection assignments, and supports adding or replacing image leases based on the template configuration.

kahuna/public/js/metadata-templates · high confidence

Batch image deletion with confirmation and status polling

The new gr-delete-image component allows users to delete multiple images at once from the preview page. It wraps a confirmation dialog and, upon confirmation, sends delete requests for all selected images. The component then polls the API to verify that the images have been soft-deleted or removed, emitting an 'images-deleted' event to update the results page once the operation is complete.

kahuna/public/js/components/gr-delete-image · high confidence

Collections service application wiring and controller initialization

The Collections service now initializes its core components through a new AppLoader and CollectionsComponents setup. This includes instantiating the CollectionsController and ImageCollectionsController, setting up the CollectionsStore and ImageCollectionsStore for data access, and registering the InnerServiceStatusCheckController to monitor connectivity to other internal services. The router is configured to route requests to these controllers, enabling the Collections service to handle image collection management and internal health checks.

collections/app · high confidence

The application now supports configuring additional navigation links, system announcements, and metadata templates via configuration files. Users can define custom links with specific targets, set up categorized announcements (such as warnings or information) with expiration dates, and apply metadata templates that automatically populate image fields, manage leases, and set usage rights based on configurable rules.

kahuna/app/lib · high confidence

Configurable usage rights properties and lease model

The metadata editor now supports a new, configurable model for usage rights properties and leases. A new \UsageRightsLease\ model allows lease details (category, type, start date, duration, notes) to be loaded from application configuration. The \UsageRightsProperty\ model defines the specific fields required for each usage rights category (such as Agency, StaffPhotographer, CreativeCommons, etc.), including dynamic options for photographers, illustrators, and suppliers derived from the application's configuration provider. This enables the UI to present the correct input fields and validation rules based on the selected usage rights type.

metadata-editor/app/model · high confidence

Cropper app initialization and component wiring

The Cropper application now initializes via a dedicated AppLoader and CropperComponents setup, wiring together core services including the CropperController, CropStore, ImageOperations, and Notifications. This change also integrates the InnerServiceStatusCheckController for health checks and exposes build information through the management endpoints, establishing the foundational structure for the cropper service within the Play framework.

cropper/app · high confidence

Cropper service controller implementation with oriented dimension validation

The CropperController is introduced to handle image cropping operations, including adding exports, retrieving crops, and deleting them. A key behavioral change is that crop validation now uses oriented dimensions (accounting for EXIF orientation) to ensure consistency with the UI, rather than raw pixel dimensions. The controller also supports performing operations on behalf of other users via an 'onBehalfOfPrincipal' mechanism and uses the Play WS client for communication with the media API.

cropper/app/controllers · high confidence

Cropper service exposes crop management and internal health endpoints

The cropper service now defines its HTTP routes, exposing endpoints to add, retrieve, and delete crops by ID, alongside standard management routes for health checks, manifest info, and an inner service status check that accepts a depth parameter. It also includes a robots.txt handler to disallow web crawlers.

cropper/conf · high confidence

E2E test environment now boots a full local Grid stack via Testcontainers

The e2e-tests/setup directory has been restructured to provide a self-contained, reproducible local environment for running end-to-end tests. Instead of relying on external infrastructure or manual setup, the new \stack.ts\ module orchestrates a complete Grid stack using Testcontainers, including Elasticsearch, LocalStack, and the Grid application services on a shared network. The setup automatically provisions core AWS infrastructure via CloudFormation, seeds necessary data (such as Elasticsearch image fixtures and KCL lease tables to reduce startup latency), and generates per-service configuration files that correctly route internal service calls. A Caddy reverse proxy is included to handle subdomain routing and TLS, ensuring the environment mimics the production-like domain structure required by the application. This change allows developers to run the full test suite locally with a single command, significantly improving setup consistency and reducing flakiness caused by missing or misconfigured external dependencies.

e2e-tests/setup · high confidence

Initial API routing for Media Leases and internal service checks

This change introduces the HTTP routing configuration for the new Media Leases feature, defining endpoints to manage leases associated with specific media items (GET, POST, PUT, DELETE on /leases/media/:id) as well as general lease management and a reindex operation. It also registers routes for standard management health checks and a new internal service status check endpoint that accepts a depth parameter to verify connectivity to other services.

leases/conf · high confidence

Initial Kahuna application routing setup

The Kahuna application now defines its URL routing structure via a new \conf/routes\ file. This configuration maps user-facing paths for image management (including viewing, cropping, and takedown actions), search, upload, quotas, and notifications to the \KahunaController\. It also exposes standard management endpoints for health checks, manifest information, and service status verification, while ensuring that search engine crawlers are blocked via a robots.txt handler.

kahuna/conf · high confidence

Initial configuration for the Metadata Editor service

This change introduces the foundational configuration files for the new Metadata Editor service. It defines a systemd unit file to manage the service lifecycle and establishes the HTTP routing table, which exposes endpoints for managing image metadata, labels, usage rights, and syndication details (including photoshoots), alongside standard management and health-check routes.

metadata-editor/conf · high confidence

Initial image-loader routing configuration

The image-loader service now exposes a defined set of HTTP endpoints for managing image assets. Users can upload images directly or via pre-signed S3 URLs, import images from URIs, and enqueue derivative images. The service also provides endpoints to restore images from replicas, retrieve project metadata for ElasticSearch, and track upload statuses. Additionally, management routes are available for health checks, manifest information, and internal service status checks, while a robots.txt route is included to block search engine crawlers.

image-loader/conf · high confidence

Initial project skeleton and development environment setup

This change introduces the foundational structure for the Grid image management system, including the Apache 2.0 license and NOTICE files, and establishes a standardized local development environment. It adds configuration files for tooling (\.editorconfig\, \.java-version\, \.nvmrc\, \.tool-versions\, \.sbtopts\), a \Brewfile\ for macOS dependencies, and a \docker-compose.yml\ to run local services like Elasticsearch 8, LocalStack, and an OIDC provider. Additionally, it defines the deployment manifest (\riff-raff.yaml\) for the full suite of microservices (auth, collections, cropper, image-loader, kahuna, media-api, etc.) and updates the \README.md\ to reflect the new project identity and architecture.

(repo-wide) · high confidence

Initial setup of the image-embedder-lambda with local development and testing infrastructure

The image-embedder-lambda service is introduced with documentation for running locally via Localstack and executing against real AWS Bedrock and S3 Vectors. The project includes TypeScript configuration with strict mode enabled, Jest test configurations for unit and integration tests, and a README detailing local execution, prerequisites, and integration test procedures.

image-embedder-lambda · high confidence

Initial stylesheet for Kahuna UI

This change introduces the primary stylesheet (main.css) for the Kahuna application, establishing the foundational visual design. It includes comprehensive font-face definitions for the 'Open Sans' typeface across multiple weights, styles, and language subsets (Cyrillic, Greek, Hebrew, etc.) to ensure correct text rendering. Additionally, it integrates the Material Symbols icon font and defines a z-index layering system to manage UI components such as overlays, panels, and the top bar.

kahuna/public/stylesheets · high confidence

Integrate Sentry for client-side error monitoring

The application now integrates Sentry to capture and report client-side errors. This change adds a new Sentry module that initializes the Sentry SDK with a CaptureConsole integration to log warnings and errors. It decorates the AngularJS $exceptionHandler to send unhandled exceptions to Sentry, while explicitly filtering out failed HTTP request errors to reduce noise. Additionally, it sets the session ID context for error reports and ensures user data is not included in the captured events.

kahuna/public/js/sentry · high confidence

Introduce CollectionsManager for image collection management

A new CollectionsManager object has been added to handle core logic for image collections, including adding, removing, and finding collections by path. It enforces validation rules that disallow slashes and double quotes in collection name segments, ensures case-insensitive path matching by lowercasing path IDs, and provides a mapping of specific collection names (such as sport, travel, and australia) to specific CSS color swatches for UI display.

common-lib/src/main/scala/com/gu/mediaservice/lib/collections · high confidence

Introduce DynamoDB value type system

Added a new DynamoValue module defining a sealed trait for DynamoDB elements (DbString, DbLong, DbInt, DbNestedMap) with methods to convert these types into AWS SDK AttributeValues, enabling structured serialization of case classes to DynamoDB format.

common-lib/src/main/scala/com/gu/mediaservice/lib/dynamo · high confidence

Introduce Node model for hierarchical collection structures

Added a new \Node\ case class in the collections model to represent hierarchical data structures, enabling proper tree-based organization of collections. This model supports recursive child nodes, path tracking (full and correct paths), and data attachment, with built-in JSON serialization and a \fromList\ factory method that constructs the tree from flat lists by grouping and sorting by basename.

collections/app/model · high confidence

Introduce common library utilities and S3 image storage abstractions

The common-lib module now provides a set of shared utilities and storage abstractions, including a new S3ImageStorage implementation for handling image upload and deletion, dedicated operations for quarantine and optimized PNG storage, and helper objects for date/time handling, MD5 hashing, vector cosine similarity, and feature toggles. These components establish the foundational storage and utility layer for the media service.

common-lib/src/main/scala/com/gu/mediaservice/lib · high confidence

Introduce configurable base layout and dedicated quotas page

The application now uses a new \main.scala.html\ template that serves as the central layout, injecting a comprehensive \\_clientConfig\ object into the page to drive UI behavior via configuration (including settings for agency picks, download restrictions, warning flags, and telemetry). This layout also implements client-side tracking via a MutationObserver on the page pathname. Additionally, a new \quotas.scala.html\ view has been added to provide a dedicated interface for displaying user quotas, styled with a dark theme and linked to the main application styles.

kahuna/app/views · high confidence

Introduce lease storage and notification infrastructure

This change adds the core library components for managing media leases, introducing a new DynamoDB-backed store (LeaseStore) for persisting lease records and a notifier (LeaseNotifier) that publishes lease lifecycle events (add, replace, remove, reindex) to the message bus. It also includes configuration support (LeasesConfig) to define the DynamoDB table name and relevant URIs, enabling the system to track and communicate lease status changes for media assets.

leases/app/lib · high confidence

Introduce local OIDC provider for development environments

A new local OpenID Connect (OIDC) provider has been added to the development tooling, accessible via the \--with-local-auth\ flag during setup and startup. This service, running on port 9014, authenticates users against a static JSON file located at \etc/grid/users.json\, validating that the user's email matches the configured domain. It is configured to skip PKCE requirements and exposes standard OpenID claims (sub, email, name) to support local authentication workflows without requiring an external identity provider.

dev/oidc-provider · high confidence

Introduce metadata-editor service for managing edits and syndication rights

A new metadata-editor service has been added to manage image edits and syndication rights. It introduces dedicated DynamoDB stores for edits and syndication data, a configuration layer for usage rights leases and custom instructions, and a SQS message consumer to handle image deletion events. The service also implements logic to track and publish changes to syndication rights associated with photoshoots, ensuring that updates to an image's photoshoot or explicit syndication settings are correctly propagated via notifications.

metadata-editor/app/lib · high confidence

Introduce preset label management component

A new \gr-preset-labels\ component has been added, allowing users to manage a list of preset labels that automatically apply to uploads. The component displays existing preset labels as clickable search links (respecting the current non-free state) and provides a form to add new labels via an auto-suggest datalist. Preset labels are persisted in local storage, and users can remove individual labels. The component uses isolated scope and includes accessibility improvements such as ARIA labels.

kahuna/public/js/components/gr-preset-labels · high confidence

Introduces a new chips-based search interface with advanced filtering and negation

The search input has been replaced by a new \gr-chips\ component that displays search terms as interactive chips. This change introduces support for negated text searches (using a leading minus sign) and allows users to create structured filters by typing a key followed by a colon (e.g., \label:\). The interface includes a filter chooser chip to select valid keys and supports toggling between inclusion and exclusion for filters. The text input is now a dedicated 'text chip' that handles caret positioning and keyboard navigation (Home/End, Backspace) across the entire sequence of chips.

kahuna/public/js/components/gr-chips · high confidence

Introduces image upload status tracking and pre-signed S3 upload support

The image loader now supports tracking the progress of image uploads via a new DynamoDB-based status table, allowing clients to monitor transitions from 'Prepared' to 'Queued' states. Additionally, a new mechanism for generating pre-signed S3 upload URLs has been added, enabling direct uploads to S3 from the client side rather than routing files through the image loader service. This change also includes new body parsers for validating file integrity during ingestion and metrics to track successful, failed, and abandoned ingest operations from the queue.

image-loader/app/lib · high confidence

Introduction of React-based notification banner component

A new React component (gr-notifications-banner) has been added to display system notifications. This component fetches active notifications from the server, merges them with any currently displayed notifications, and renders them with specific styling based on their category (announcement, information, warning, error, success). It supports dismissing notifications via user interaction (click, scroll, keydown) and persists dismissed notification IDs in a cookie to prevent re-display. The component also listens for custom window events ('newNotification', 'removeNotification') to dynamically update the banner content.

kahuna/public/js/components/gr-notifications-banner · high confidence

Introduction of React-based notification banner component

A new React notification banner component has been added to the application, integrated via the \gr-notifications-banner\ directive within the AngularJS \kahuna.notifications\ module. This change introduces a new UI element for displaying announcements, sourced from the client configuration, while maintaining separation from global error handling mechanisms.

kahuna/public/js/notifications · high confidence

Introduction of standardized Argo response helpers

The codebase now includes a new \ArgoHelpers\ trait that provides structured methods for generating API responses (\respond\, \respondCollection\, \respondError\, \respondNotFound\) using the \application/vnd.argo+json\ media type. These helpers wrap data in \EntityResponse\ or \CollectionResponse\ models, ensuring consistent serialization and linking across the service. A companion \WriteHelpers\ trait offers a utility for handling optional lists.

common-lib/src/main/scala/com/gu/mediaservice/lib/argo · high confidence

Keyboard shortcut tracking via new analytics service

The application now tracks when users successfully trigger keyboard shortcuts. A new \gr-keyboard-shortcut\ component wraps the \angular-hotkeys\ library to emit a 'track:event' analytics signal (category: Keyboard, action: Shortcut) whenever a bound shortcut is executed, allowing usage metrics to be collected without altering the existing shortcut behavior.

kahuna/public/js/components/gr-keyboard-shortcut · high confidence

Keyboard shortcuts for scrolling search results

A new directive, gu-lazy-table-shortcuts, has been added to enable keyboard navigation within the lazy table component. Users can now scroll through search results one row or one page at a time using Up, Down, Page Up, and Page Down keys. Additionally, Home and End keys allow jumping to the start or end of the results list. Notably, the Up and Down keys are configured to work even when focus is inside an INPUT field, while Home and End are restricted to non-input contexts to preserve native text-editing behavior.

kahuna/public/js/components/gu-lazy-table-shortcuts · high confidence

Leases app initializes with internal service health checks

The Leases application now includes an InnerServiceStatusCheckController that verifies connectivity to other internal services, exposing this status via the management endpoints. This change also establishes the core application loader and components structure, wiring up the lease store, notifier, and media lease controller within the GridComponents framework.

leases/app · high confidence

New 'Crop full frame' export component

A new UI component has been added to allow users to initiate a 'full frame' crop action. This feature introduces a button that triggers the creation of a full-frame crop via the media cropper service, provides visual feedback during the processing state, and automatically navigates the user to the newly created crop once it is ready.

kahuna/public/js/components/gr-export-original-image · high confidence

New 'My Uploads' filter control with keyboard and responsive support

A new 'My Uploads' toggle control has been added to the interface, allowing users to filter uploads by the current user. The component supports keyboard navigation (Space key) for accessibility and includes responsive CSS that switches to a short label on narrower screens. It integrates with the application by listening for logo clicks, filter changes, and user-specific upload events to keep its state synchronized, and dispatches events to manage related payable image settings.

kahuna/public/js/components/gr-my-uploads · high confidence

New API service layer for collections, leases, and media operations

This change introduces a dedicated API service layer in the Kahuna frontend, replacing ad-hoc calls with structured Angular services for managing collections, image leases, and media assets. The new \collections-api\ service enables adding/removing images from collections and batch operations, while the \leases\ service and its \leases-helper\ utility provide reliable, polled updates for lease metadata changes. Additionally, new services for \edits-api\ (usage rights categories), \loader-api\ (file preparation and uploads), \media-cropper\ (crop creation and management), and \witness-api\ (Guardian Witness report parsing) centralize interactions with the backend, ensuring consistent state synchronization and error handling across the application.

kahuna/public/js/services/api · high confidence

New BBC usage rights summary component with sport category support

A new usage rights summary component has been introduced for BBC assets, rendering a table of applicable rights based on image metadata. This update adds a 'Usable for Sport' category alongside existing 'Payable', 'Usable for all', and 'Usable for News' options, each with distinct icons and logic (e.g., sport eligibility requires PA supplier status without payable costs). The component also displays the image category and agency source details, replacing the previous 'No Rights' label with 'Unknown' when no specific rights are detected.

kahuna/public/js/components/gr-usagerights-summary · high confidence

New C2PA manifest detection and refined image metadata handling

The image loader now detects embedded C2PA (Content Credentials) manifests in JPEG, PNG, and TIFF files, exposing this availability in the image metadata. This is supported by a new lightweight detector that checks for specific container structures (APP11 segments, PNG chunks, and TIFF tags) without fully parsing the manifest. Additionally, the system now handles DNG detection failures more robustly by distinguishing them from standard TIFFs, and refines color model information for JPEGs and PNGs. XMP metadata extraction has been updated to redact fields longer than 5,000 characters to prevent downstream memory issues, while preserving specific long fields like descriptions and headlines.

image-loader/app/lib/imaging · high confidence

New CDK infrastructure for image embedding and backfilling

The CDK directory now defines the AWS infrastructure for the image-embedder system, deploying separate stacks for PROD and TEST in eu-west-1. This includes an S3 Vector Bucket and a Cohere V4 vector index (1536 dimensions, cosine distance) for storing embeddings, alongside an S3 bucket for downscaled images. The deployment provisions two Lambda functions: a scheduled backfiller (Node.js 24, ARM64) that reads from an SQS queue and writes to Elasticsearch, and an event-driven embedder (Node.js 24, ARM64) triggered by SQS batches to process images and write vectors. Both functions run within the account VPC, with concurrency limits and memory settings configured per stage.

cdk · high confidence

New CQL search input component with advanced parsing and styling

A new \gr-cql-input\ directive has been introduced to replace the previous search interface, leveraging the \@guardian/cql\ library for parsing. This component supports advanced query syntax including negations (e.g., \-term\), field filters (chips like \has:chip\), and reserved character handling. It features a custom dark theme, typeahead suggestions, and specific keyboard navigation support (Arrow keys, Page Up/Down). The underlying parser logic ensures that consecutive text fields are combined into single entries unless an exclusion is present, and it correctly maps CQL expressions to the application's structured query format.

kahuna/public/js/components/gr-cql-input · high confidence

New Edits API and Syndication endpoints for metadata management

The metadata editor now exposes dedicated REST endpoints for managing image edits and syndication rights. The new EditsApi controller provides a service index and endpoints to retrieve usage rights categories, including a filtered list for standard users based on their permissions. The EditsController handles core metadata operations, allowing users to get, set, and archive image metadata and labels, with specific logic to automatically update metadata fields (byline, credit, copyright, imageType) when usage rights are applied. Additionally, the new SyndicationController introduces endpoints to get, set, and delete photoshoot details and syndication rights for images, integrating with the existing edits store and notification system.

metadata-editor/app/controllers · high confidence

New Lambda function to count and report Media API image metrics

A new AWS Lambda function has been added to fetch image counts from the Media API and publish them as CloudWatch metrics. The function retrieves API credentials from an S3 configuration file, queries the \/management/imageCounts\ endpoint, and sends the resulting counts (cat, search, and index stats) to CloudWatch under a namespace based on the environment stage. The handler is exported for testing and invocation.

image-counter-lambda/src · high confidence

New Media Leases API controller

A new MediaLeaseController has been added to expose endpoints for managing media leases, including creating, retrieving, updating, and deleting individual or batch leases, as well as fetching leases by media ID. The controller enforces authentication for all operations, validates input (ensuring no more than one syndication lease per image), and integrates with a notification system to signal lease changes.

leases/app/controllers · high confidence

New Playwright-based E2E test suite with BDD scenarios and Testcontainers integration

Added a new end-to-end testing framework using Playwright and Playwright-BDD, allowing users to run Gherkin-based scenarios against a full Grid stack. The suite integrates Testcontainers to automatically boot the required services (including Kahuna and an image-loader) via a new \dev:e2e\ command, which supports both CI production mode and local development with live recompilation. Users can now execute tests via standard Playwright commands, utilize a UI mode for interactive debugging, and benefit from automatic trace capture on retry.

e2e-tests · high confidence

New Takedown page for removing images from content and Grid

A new Takedown page has been added to Kahuna, allowing users to remove images from active web content and the Grid. The page guides users through a two-step process: first, it checks for and lists any pending or published web articles (including fronts) and print usages where the image is currently used, requiring removal from those locations before proceeding. Second, it provides options to delete the image from the Grid itself, supporting hard delete, soft delete, or denying the lease, with logic to handle cases where published print usages exist. The feature includes UI components for displaying crops and usages, handling API interactions for fetching content and usages, and managing the state of the takedown process.

kahuna/public/js/takedown, kahuna/public/js/types · high confidence

New UI directives for input sizing, image loading, and scroll persistence

This update introduces several new AngularJS directives to enhance the user interface experience. The \grAutoWidth\ directive allows input fields to automatically adjust their width based on their content, ensuring labels and placeholders are fully visible without manual sizing. The \grImageFadeOnLoad\ directive improves perceived performance by hiding images until they are fully loaded, then fading them in smoothly, while also handling timeouts to prevent indefinite loading states. Additionally, the \grRememberScrollTop\ directive persists the scroll position of collections panels in local storage, allowing users to resume browsing from where they left off. Supporting utilities include \grAutoFocus\ for automatically focusing on specific inputs and \grChipExample\ for rendering filter chips.

kahuna/public/js/directives · high confidence

New URI encoding and security utilities

A new URI utility object has been added to the common library, providing methods to correctly encode and decode URIs (handling plus signs and spaces) and a helper to ensure URIs use the HTTPS scheme for security.

common-lib/src/main/scala/com/gu/mediaservice/lib/net · high confidence

New Usage Rights Editor component with category-based restrictions

A new Usage Rights Editor component has been introduced to manage image usage rights, featuring a category-driven interface that dynamically displays required properties, restrictions, and special instructions based on the selected rights category. The editor supports batch editing for multiple images, includes validation for invalid categories, and allows users to add or remove restrictions, with specific handling for default restrictions mandated by certain rights categories. It also integrates with the image list service to handle property aggregation and provides visual warnings when multiple rights categories are selected.

kahuna/public/js/usage-rights · high confidence

New Usage service for tracking image usage across platforms

A new Usage service has been introduced to manage and record how images are used across digital, print, syndication, and other platforms. The service operates in two modes: an API mode that exposes endpoints for querying and updating usage records, and a stream mode that consumes content updates from Crier Kinesis streams to automatically sync usage data. Usage records are persisted in a DynamoDB table and include metadata for digital usage (such as web title and section), print usage, syndication, front pages, downloads, and child usages (derivatives or replacements). The service integrates with the Content API to fetch content details and sends notifications to Thrall to keep downstream systems like Elasticsearch in sync.

usage · high confidence

New and updated development scripts for local infrastructure and debugging

The dev/script directory now includes several new tools to streamline local development and debugging. A new \create-root-collection.sh\ script allows developers to create root collections via the API using arguments or .env values. An \es-ssh-ssm-tunnel.sh\ script provides a dedicated way to establish an SSM port-forwarding tunnel to the TEST stage's Elasticsearch instance, which is utilized by \start.sh\ when the \--use-TEST\ flag is passed. \start.sh\ has been updated to support \--use-TEST\ (reusing existing tunnels and loading specific config), \--with-local-auth\, and \--no-auth\ flags, and now uses \docker compose\ instead of \docker-compose\. Additionally, \mkapikey.sh\ simplifies API key generation, \get-local-kinesis-records.sh\ aids in inspecting local Kinesis data, and \the\_pingler.sh\ offers a continuous health-check view of internal services.

dev/script · high confidence

New archiver component for library management

A new \gr-archiver\ component has been introduced to handle adding, removing, and undeleting images from the Library. This component provides a unified interface that displays state-specific buttons (Add to Library, Remove from Library, Kept in Library, or Undelete) based on the image's current status and user permissions. It includes logic to determine if images can be archived, displays explanations for why an image is kept in the library, and handles the undeletion process with polling to confirm the image has been restored.

kahuna/public/js/components/gr-archiver · high confidence

New archiver status component with undelete capability

A new \gr-archiver-status\ component has been introduced to display and manage the archival state of images. This component allows users to archive, unarchive, and, for deleted images, undelete their own uploads (subject to permission checks). It provides visual feedback on whether an image is kept, archived, or unarchived, and includes interactive buttons for these actions, along with styling for disabled states and hover effects.

kahuna/public/js/components/gr-archiver-status · high confidence

New backfiller Lambda to generate image embeddings for free images

A new scheduled Lambda function has been introduced to backfill missing image embeddings by querying ElasticSearch for images that lack a Cohere v4 embedding and are not soft-deleted. The process filters results to include only 'free' images (based on usage rights and supplier exclusions) and queues them via SQS for processing, while respecting queue capacity limits to prevent overload. This feature ensures that eligible free images are systematically processed for embedding generation.

image-embedder-lambda/src/backfiller · high confidence

New collection overlay component for adding images to collections

A new \gr-collection-overlay\ component has been introduced, providing a user interface to add the current image to an existing collection. This feature includes a button to trigger the overlay, a modal dialog displaying a tree of available collections, and logic to fetch collection data and handle the addition process. The component also supports an edit mode for the collection tree and includes specific CSS adjustments to ensure proper display within the info panel context.

kahuna/public/js/components/gr-collection-overlay · high confidence

New collections and image collection API endpoints

The application now exposes a new set of RESTful endpoints for managing collections. Users can retrieve, add, and remove collections via GET, POST, and DELETE requests on the /collections path. Additionally, image-specific collections are supported through /images/:imageId, allowing users to get, add, and remove collections associated with a specific image. A new endpoint /corrected-collections is also available for correcting collection data. Standard management endpoints for health checks, manifest info, and service status (whoAmI) remain accessible under /management.

collections/conf · high confidence

New collections management API endpoints

The application now exposes a new set of REST endpoints for managing media collections, implemented in the new CollectionsController and ImageCollectionsController classes. Users can now create, read, update, and delete collections via HTTP requests, with support for hierarchical collection structures (parent-child relationships). The API enforces validation rules, such as prohibiting slashes and double quotes in collection paths, and prevents deletion of collections that contain child nodes. Additionally, image-specific collection operations are handled separately, allowing users to associate collections with specific images and ensuring only the latest collection definitions are published to downstream systems.

collections/app/controllers · high confidence

New component to display and download image crops

A new \gr-display-crops\ component has been added to the product, allowing users to view a list of available image crops categorized by aspect ratio and dimensions. The component includes a toggle to show or hide the crop list and provides links to individual crop assets; these links support direct file access or a download endpoint depending on the \canDownloadCrop\ client configuration.

kahuna/public/js/components/gr-display-crops · high confidence

New crop image button component with lease-aware validation

A new \gr-crop-image\ component has been added to the UI, providing a 'Crop image' button that navigates to the crop tool and includes a dropdown for exporting the original image. The component's availability is now dynamically controlled by lease status and image validity: an image is considered cropable only if it is valid and not soft-deleted, and the component listens for lease updates to reflect these changes in real-time. The button includes tracking attributes for analytics and displays a 'Cannot crop' state when the image is invalid or deleted.

kahuna/public/js/components/gr-crop-image · high confidence

New crop screen with manual dimension inputs and cost restriction display

The crop interface now includes numeric input fields for X, Y, width, and height, allowing users to specify exact crop dimensions. It also displays cost restriction states (Pay, Quota exceeded, Restricted use) directly in the top bar and provides a loading state while the image is being prepared for cropping.

kahuna/public/js/crop · high confidence

New datalist component for form inputs

A new datalist directive and its associated HTML template have been added to the forms module. This component provides an autocomplete-style dropdown for input fields, allowing users to search for and select options via keyboard navigation (up/down arrows, Enter to select, Escape to close) or mouse interaction. The implementation includes logic to manage selection state, handle input changes, and ensure the dropdown only appears when results are available, integrating with Angular's model binding for seamless data flow.

kahuna/public/js/forms · high confidence

New date range filter component with preset options and field selection

A new \gu-date-range\ component has been introduced to allow users to filter content by a specific date field (such as uploaded, taken, or modified) using a calendar interface. The component supports selecting custom start and end dates, applying predefined time presets, and clearing individual date fields. It features a collapsible overlay with distinct 'From' and 'To' pickers, synchronized to prevent invalid ranges, and includes UI styling overrides for the underlying Pikaday library to match the application theme.

kahuna/public/js/components/gu-date-range · high confidence

New feature switch panel for toggling client-side settings

A new UI panel has been added to allow users to toggle feature switches directly from the browser. Accessible via the Shift+F12 keyboard shortcut, the panel lists available feature switches defined in the client configuration and allows users to enable or disable them by clicking On/Off buttons. Changes are persisted in browser cookies, and a notice indicates that some settings require a page refresh to take effect. The component is implemented as a React component integrated into the Angular application, using CSS modules for styling.

kahuna/public/js/components/gr-feature-switch-panel · high confidence

New file upload prompt with preset label integration

The upload interface now displays a dedicated prompt component that guides users to drag-and-drop or select files, while also providing a section to apply preset labels to all uploads. This component integrates with the preset label service to dynamically show or hide the label application section based on whether any preset labels are currently active, and displays an example label to help users understand the feature.

kahuna/public/js/upload/prompt · high confidence

New generic confirmation modal component

A new generic React-based confirmation modal component has been added to the application. This component provides a reusable dialog for user confirmations, featuring a title, message, and customizable action buttons (confirm/cancel). It includes accessibility improvements such as focus trapping within the modal, keyboard navigation support (ESC to close, TAB cycling), and ARIA attributes. The modal is exposed as an Angular component via react2angular, allowing it to be triggered via a custom 'displayModal' event with dynamic content.

kahuna/public/js/components/gr-confirmation-modal · high confidence

New gr-icon component with dedicated library and syndication icons

The gr-icon component now provides a standardized way to display icons using Material Icons, supporting small variants and warning states. It introduces specific directives for library management actions (add, added, locked, remove) and syndication status (sent to Photo Sales, unpublished), allowing users to visually distinguish image states and library interactions within the interface.

kahuna/public/js/components/gr-icon · high confidence

New gr-radio-list component for selectable options

A new reusable radio-list component has been added to the application, allowing users to select from a list of options via radio buttons. The component renders a horizontal list of labels that highlight the selected option and supports disabled states. It includes responsive styling that hides full text labels on narrower viewports (below 1294px) to save space, and ensures consistent user experience across browsers by handling vendor-prefixed user-select properties.

kahuna/public/js/components/gr-radio-list · high confidence

New gr-toggle-button component with accessibility and tracking

Added the gr-toggle-button component, which provides a toggleable button interface for gallery controls. The component now includes an aria-label for improved accessibility and emits a 'track:event' analytics event whenever the button is clicked, allowing usage of this feature to be monitored.

kahuna/public/js/components/gr-toggle-button · high confidence

New gr-tooltip component with safe text rendering and optional live updates

A new gr-tooltip directive has been introduced to manage tooltips using the Titip library. This component improves safety by rendering tooltip content as plain text (using .text()) rather than HTML, preventing potential injection issues. It supports configurable positioning (defaulting to bottom) and includes an optional live-update feature: when the gr-tooltip-updates attribute is present, the tooltip text will automatically refresh as the bound attribute changes. The component also ensures that tooltips are not displayed if the attribute value is falsey.

kahuna/public/js/components/gr-tooltip · high confidence

New image cost and restriction message component

A new UI component has been introduced to display image usage costs and restrictions. It specifically handles the 'conditional' state, showing a 'Restricted use' notice with dynamic restriction text derived from the image's usage rights when applicable, otherwise falling back to the standard cost state.

kahuna/public/js/components/gr-image-cost-message · high confidence

New image data aggregation and metadata diffing capabilities

The media service now aggregates image data from multiple sources (collections, edits, leases, usages, crops, syndication rights) in parallel via the new GridClient and ImageDataMerger components, ensuring that original metadata is not overwritten and calculating the last modified date based on the most recent user-editable field rather than the image's own modification timestamp. Additionally, a new JsonDiff utility and projection diff endpoint allow users to see specific changes (additions, removals, or modifications) in image metadata projections.

common-lib/src/main/scala/com/gu/mediaservice · high confidence

New image editor and batch editing components for uploads

This change introduces the \image-editor\ component and \list-editor\ directives within the edits module, providing a dedicated UI for managing image metadata on the uploads page. Users can now edit usage rights and leases, with the ability to batch-apply these changes to all current uploads. The editor also supports undeleting soft-deleted images, displays clear status indicators (such as 'Unusable' for invalid images), and includes a metadata diffing utility to accurately track changes to fields like keywords and labels.

kahuna/public/js/edits · high confidence

New image metadata component and syndication rights display

The image metadata sidebar now uses a dedicated \gr-image-metadata\ component that consolidates the display and editing of rights, image type, title, leases, and other fields, including support for metadata templates and keyboard shortcuts (Escape to cancel, Ctrl/Cmd+Enter to save). A new \gr-syndication-rights\ component has been added to show whether syndication rights have been acquired, improving visibility of licensing status for users.

kahuna/public/js/components/gr-image-metadata · high confidence

New image operations service with low-res download support

A new \imgops\ service has been introduced to centralize image URI generation, featuring a configurable quality setting of 85 and specific handling for Firefox's device pixel ratio in full-screen previews. This service adds a \getLowResDownloadUri\ method, enabling users to download lower-resolution images (capped at 800x800 pixels) via the API, while also standardizing how optimized PNG and standard optimized image URIs are retrieved.

kahuna/public/js/imgops · high confidence

New image upload status tracking and management endpoints

The image-loader service now exposes dedicated endpoints for tracking and managing image upload states. Users can poll the status of specific uploads via the new GET /uploadStatus/{id} endpoint, retrieve a list of uploads by the current user or a specific user via GET /uploadStatuses, and explicitly update upload statuses (including marking failures) via POST /uploadStatus/{id}. These changes are implemented in the new UploadStatusController and integrated into the main ImageLoaderController, which also introduces a 'prepare' endpoint for generating pre-signed S3 upload URLs and distinguishes between UI uploads (identified by mediaId) and other ingestion sources. Additionally, the health check now monitors the ingest queue processor to ensure it remains active.

image-loader/app/controllers · high confidence

New image view and crop selection interface

The image view page has been restructured to include a dedicated crop selection panel on the left, displaying the original image, full frame, and available crops with their dimensions and creator details. Users can now select specific crops to view, and the interface supports keyboard shortcuts for cropping (C) and fullscreen (F). The view also integrates metadata and usage tabs, allowing users to edit metadata and view usage history directly within the image context.

kahuna/public/js/image · high confidence

New image-loader application with upload status tracking and quarantine support

The image-loader service is now a standalone Play application that exposes endpoints for managing image ingestion, including a new upload status API for polling upload progress and support for uploading images to a quarantine bucket for virus scanning. The application integrates with SQS for queue-based processing, supports optional image embedding via Bedrock, and includes health checks that monitor internal service connectivity and queue consumer status.

image-loader/app · high confidence

New inner service status check and management endpoints

Added the InnerServiceStatusCheckController, which exposes /management/whoAmI and /management/statusCheck endpoints to verify connectivity across internal services using a depth-based traversal and InnerServicePrincipal authentication. Also introduced the Management and HealthCheck traits in Management.scala, providing standard management endpoints such as /management/healthCheck, /management/buildInfo, and /management/robots.txt, along with an ElasticSearchHealthCheck that validates Elasticsearch connectivity and exposes image counts.

rest-lib/src/main/scala/com/gu/mediaservice/lib/management · high confidence

New leases management UI with syndication and batch support

The leases component has been rewritten to provide a dedicated interface for managing image usage rights, including support for syndication leases (with options for Call Agency and Premium clauses) and batch application of leases across multiple uploads. The new UI features a full-width form for adding leases, displays active and inactive lease counts, and includes visual indicators for lease status (teal for allow-use, red for deny). It also integrates with metadata templates to apply leases automatically and handles conflicts when overwriting existing syndication leases.

kahuna/public/js/leases · high confidence

New local development configuration generator script

A new Node.js script (\dev/script/generate-config\) has been introduced to automate the creation of local configuration files for Grid services. By reading environment variables and AWS CloudFormation stack outputs, the script generates service-specific \.conf\ files (e.g., for Kahuna, Image Loader, Collections) in the user's home directory. This replaces manual configuration steps, enabling features like local authentication bypass, S3 ingest queues, and soft-delete metadata handling out-of-the-box for local development.

dev/script/generate-config · high confidence

New media-api library components for image validity, persistence, and usage tracking

This change introduces several new core libraries for the media-api service. ImageExtras defines validity checks (e.g., rights, leases, quotas) and downloadability logic, while ImagePersistenceReasons determines which images should be retained based on identifiers, exports, usages, and collections. ImageResponse integrates these checks to populate API responses with validity reasons, persistence states, and download links. Additionally, ContentApi adds a client for searching Content API via IAM authentication, UsageStore and UsageQuota manage supplier usage quotas and status from email/S3 sources, and MediaApiConfig centralizes configuration for these features.

media-api/app/lib · high confidence

New metadata validity warning component

A new \gr-metadata-validity\ component has been introduced to display image validity status and warnings. It renders specific messages for deleted images, images with invalid metadata, and those with syndication restrictions, with styling that distinguishes between strong warnings (e.g., deleted, unpaid) and standard warnings (e.g., overridden validity). The component's text and visibility logic are driven by client configuration and image data, including usage rights and lease status.

kahuna/public/js/components/gr-metadata-validity · high confidence

New operational scripts and embedded configuration library for Grid maintenance

This update introduces a suite of new operational scripts and a bundled configuration library to support Grid maintenance and development workflows. The \scripts/\ directory now includes a comprehensive README documenting tools for Elasticsearch management (Reindex, UpdateMapping, UpdateSettings, DownloadAllEsIds) and S3 operations (BulkDeleteS3Files). New shell scripts in \scripts/cleanup-s3/\ allow for targeted deletion of images by prefix or root. The \scripts/mass-deletion/\ script enables bulk image deletion via the Grid API with progress tracking. For development, \scripts/sample-images/\ provides a Node.js tool to upload random images from Unsplash. Additionally, \scripts/embedder-deploy/\ contains build and deployment scripts for the image embedder Lambda, including handling of native dependencies like Sharp. Finally, a shaded copy of the Typesafe Config library has been imported into \scripts/src/main/java/com/gu/typesafe/\ to support configuration handling within these scripts.

scripts · high confidence

New panel toggle and lock controls

A new gr-panel-button component has been introduced to manage panel visibility and state. It provides UI controls that allow users to show or hide panels, as well as lock or unlock them to prevent accidental closure. The component supports two visual variants (standard and small) and includes click tracking for analytics.

kahuna/public/js/components/gr-panel-button · high confidence

New quarantine-status Lambda to update image upload status

A new AWS Lambda function has been added to the quarantine-status service. It subscribes to an SNS topic for virus alert notifications and, upon receiving a scan result, updates the image upload status by posting to the image-loader service's /uploadStatus/:imageId endpoint. The implementation includes retry logic for failed API calls and is deployed via a CloudFormation template.

quarantine-status · high confidence

New recent uploads component with live updates

A new 'Recent Uploads' component has been added to the upload interface, allowing users to view their uploaded images, delete them if permitted, and see the list update in real-time when images are modified or removed. The component uses an isolated scope and listens for 'images-updated' and 'images-deleted' events to keep the displayed data current without requiring a page refresh.

kahuna/public/js/upload/recent · high confidence

New reusable date and date-range picker components

The application now includes new \gu-date\ and \gu-date-range-x\ Angular components for selecting dates and date ranges. These components replace previous implementations with a unified interface that displays dates in a 24-hour format (DD MMM YYYY HH:mm) and integrates the Pikaday library. The \gu-date\ component provides a button to toggle a calendar overlay, supports minimum and maximum date constraints, and includes a clear button, while \gu-date-range-x\ composes two date pickers for selecting a start and end date. Styling has been updated to match the application's theme and fix layout issues with the calendar height.

kahuna/public/js/components/gu-date · high confidence

New search wrapper component with filter toggle and date range

A new \gr-search-wrapper\ component has been introduced to the application. This component provides a user interface for search operations, featuring a toggleable 'Search filters' button that reveals a date range picker (\gu-date-range\) for filtering by time. It also integrates \permissions-filter\ and \my-uploads\ components, effectively centralizing the search control layout and styling within this new wrapper.

kahuna/public/js/components/gr-search-wrapper · high confidence

New service layer for image management, UI state, and telemetry

This change introduces a dedicated service layer in the frontend to improve code organization and add new capabilities. It extracts image metadata access into a new \imageAccessor\ service and adds business logic for syndication status, agency picks, and persistence reasons via \imageLogic\. Batch operations for archiving, labeling, and photoshoots are now handled by dedicated services (\archiveService\, \labelService\, \photoshootService\) that track progress and poll for API consistency. UI state management is improved with a new \panelService\ for persistent panel locking/hiding and a \scrollPosition\ service to manage scroll retention. Additionally, a \graphicImageBlurService\ centralizes the logic for blurring sensitive content, and a new \telemetry\ service begins tracking user search and filter interactions.

kahuna/public/js/services · high confidence

A new standalone authentication service has been introduced in the auth/app/auth directory, comprising AuthComponents, AuthConfig, and AuthController. This service exposes endpoints for user login, logout, and session inspection, returning user details and specific permissions (showPaid, canUpload, canDelete) based on the authenticated principal. The session cookie configuration has been explicitly set to have no SameSite restriction (sameSite = None) to ensure compatibility with local development and specific browser behaviors. The controller integrates with pluggable authentication providers and an authorisation layer to verify user permissions during session retrieval.

auth/app/auth · high confidence

New structured query input with chip-based filtering and CQL support

A new structured-query component has been introduced to replace the previous search input mechanism. This component parses search strings into structured 'chips' (filters and text) using a new TypeScript-based syntax parser, enabling features like autocomplete suggestions for fields (e.g., subject, category, supplier) and dynamic filtering. It also integrates a feature switch to toggle between this new chip-based interface and the legacy CQL (Common Query Language) input, allowing for a gradual migration. The change includes specific styling for the new chip UI and handles the conversion between the structured internal representation and the plain text query string used by the backend.

kahuna/public/js/search/structured-query · high confidence

New syntax helpers for message subjects, JSON handling, and request headers

The common library now exposes a consolidated syntax package providing convenient implicit classes and constants for internal development. This includes a MessageSubjects object defining string constants for various image and usage operations (such as soft-delete, reingest, and usage status updates), Play JSON syntax for logging parse errors and serializing/deserializing Java URIs, and a RequestHeader extension to easily access the X-Forwarded-Proto header. These utilities are aggregated in the syntax package object for easy import across the codebase.

common-lib/src/main/scala/com/gu/mediaservice/syntax · high confidence

New upload job interface with required metadata editing and batch application

The upload interface now includes a dedicated metadata editor for required fields (image type, description, byline, credit, copyright, and special instructions) that automatically saves changes and supports batch application to all current uploads via a new 'apply-to-all' button. The upload job list displays real-time status updates (uploading, queued, indexing, completed, failed) with preview images, and allows users to remove failed uploads directly from the job view.

kahuna/public/js/upload/jobs · high confidence

New utility for managing asynchronous resource lifecycles

A new \FutureResources\ utility has been added to the common library, providing a \bracket\ method to manage the lifecycle of resources created via \Future\. This allows code to safely acquire a resource and ensures that a specified cleanup action is executed regardless of whether the asynchronous operation succeeds or fails, simplifying safe resource management in asynchronous contexts.

common-lib/src/main/scala/com/gu/mediaservice/lib/resource · high confidence

New utility modules for async, batch processing, and crop management

This change introduces a suite of new utility modules in kahuna/public/js/util to standardize and improve core application behaviors. The new async.js module provides an apiPoll helper with exponential backoff and concurrency control via PQueue, alongside helpers for nextTick, delay, and race conditions. Batch operations are now managed by batch-tracking.js, which uses PQueue to process items with progress reporting and error handling. Crop functionality is centralized in crop.js, introducing cropSettings for managing crop types and custom ratios via storage, and pollUntilCropCreated for waiting on export availability. Additional utilities include digest.js for safe Angular $apply calls, eq.js for object-equality change detection, storage.js for explicit localStorage/sessionStorage handling, idleTimeout.js for non-blocking execution, and TypeScript helpers for error checking (errors.ts), polling (poll.ts), and sequencing (seq.ts).

kahuna/public/js/util · high confidence

Redesigned collections panel with tree view and editing capabilities

The collections panel has been rebuilt to feature a hierarchical tree view of collections, allowing users to expand and collapse nodes. A new editing mode enables users to create sub-collections, delete existing ones, and manage the structure. Users can now add or remove selected images from collections directly via the panel, with visual feedback for saving and removing actions. The panel also persists the open/closed state of collection nodes in local storage and includes error handling for loading and saving operations.

kahuna/public/js/components/gr-collections-panel · high confidence

Support for collection and label filters in search queries

The search query syntax now supports filtering by collections and labels. Users can include collections in their queries using the tilde (\~) prefix (e.g., \\~"path/to/collection"\), and labels using the hash (\#) prefix (e.g., \\#labelName\). The system provides utilities to add, remove, and check for these filters within the query string, allowing for more precise data retrieval based on collection hierarchy and label associations.

kahuna/public/js/search-query · high confidence

Thrall application initialization and core components

The Thrall application is introduced as a new service that reads messages from a Kinesis stream to update an Elasticsearch index. This entry covers the foundational setup including the Play application loader, dependency injection components, and core controllers. It includes the ThrallController for managing migration workflows (starting, completing, and viewing failures), the ReaperController for scheduled image deletion (soft and hard reaping), and the HealthCheck controller which verifies Elasticsearch connectivity and stream status. The code also establishes the Kinesis event consumer, the migration source with sender logic for scrolling through Elasticsearch to find images to migrate, and the SyncChecker to identify discrepancies between S3 and Elasticsearch.

thrall · high confidence

Removals

Removal of jQuery 1.9.0 library

The bundled jQuery 1.9.0 library has been removed from the public assets directory. Any client-side functionality previously relying on this specific version of jQuery will no longer work unless the library is re-introduced or replaced with an alternative.

media-api/public · high confidence

Architecture

Media API restructured to use GridAppLoader and new component wiring

The Media API application entry point has been refactored to extend GridAppLoader, centralizing initialization logic. MediaApiComponents now explicitly wires up core services including ElasticSearch, S3, usage quota management, and the embedder, while introducing new controllers for inner service status checks and configuration. A new UsagesInContent model has been added to serialize content usage data from the Content API.

media-api/app · high confidence

Metadata editor application structure and service wiring

The metadata editor application has been restructured to use a standard GridAppLoader pattern, introducing AppLoader and MetadataEditorComponents to centralize initialization. This change wires up core components including the edits and syndication stores, a SQS message consumer for processing updates, and specific controllers for edits, syndication, and API interactions. It also integrates an InnerServiceStatusCheckController to monitor connectivity to other internal services and ensures proper lifecycle management for metrics and message consumers during shutdown.

metadata-editor/app · high confidence

Behavioural changes

Add confirmation dialog for deleting all crops

A new 'Delete ALL crops' button has been added to the image editor interface. When clicked, it triggers a confirmation prompt requiring the user to explicitly type 'DELETE' to proceed, ensuring that crop deletion is a deliberate action with a clear warning about potential site breakage if crops are still in use.

kahuna/public/js/components/gr-delete-crops · high confidence

Add two-step confirmation for image deletion

The gr-confirm-delete component now requires users to click the delete button twice to confirm the action. The first click changes the button's appearance to a red 'Confirm delete' state, and the confirmation is only executed if the second click occurs within 5 seconds; otherwise, the button reverts to its original state. This prevents accidental deletions by introducing a brief confirmation window.

kahuna/public/js/components/gr-confirm-delete · high confidence

Advanced search help panel now documents usage history and new filter chips

The Advanced Search Information flyout has been updated to include guidance on filtering by usage history (such as filtering by date added or platform) and new filter chips like 'has' (to check for field existence) and 'is' (to identify images with free usage quota). The panel also now provides examples for searching by people and clarifies that the 'in' filter searches both city and country fields.

kahuna/public/js/search/syntax · high confidence

Centralized application configuration and logging setup

The application now uses a unified \application.conf\ in \common-lib\ to define core settings, including Play framework session and proxy configurations, Elasticsearch connection details, and pluggable authentication and authorization providers. This configuration introduces new capabilities such as restricting downloads based on image validity (\restrictDownload\), filtering usage rights for standard users (\usageRights.stdUserExcluded\), and configuring usage rights leases. Additionally, a new \logback.xml\ standardizes logging behavior, directing logs to disk in non-DEV environments and suppressing console output in DEV, while also configuring specific log levels for Play and request logging.

common-lib/src/main/resources · high confidence

Centralized configuration for UI features and content in Kahuna

The Kahuna application controller now serves a comprehensive set of configuration values to the frontend, enabling dynamic control over the user interface without code changes. This includes feature switches (such as CQL chips), scripts to load (with iframe and permission filtering), additional navigation links, domain-specific metadata specs, metadata templates, announcements, and interim filter options. It also exposes UI-specific settings like the cost filter label and chargeable status, the organization-owned image filter checkbox, image type names, and agency pick ingredients. This change consolidates previously hard-coded or scattered settings into a single \KahunaConfig\ object passed to the main view, allowing administrators to customize the look, feel, and functionality of the Kahuna interface via configuration.

kahuna/app/controllers · high confidence

Centralized configuration management and pluggable provider architecture

The system now uses a unified \CommonConfig\ to centralize settings for services, ElasticSearch aliases, and usage rights, replacing scattered configuration files. A new \ProviderLoader\ framework allows components like image processors and usage rights to be dynamically loaded and configured via config files, enabling runtime customization without code changes. Additionally, domain metadata and field aliases are now fully configurable through \common.conf\, allowing editors to define custom metadata fields and search hints.

common-lib/src/main/scala/com/gu/mediaservice/lib/config · high confidence

Collections store migrates to Scanamo and AWS SDK v2

The collections persistence layer has been rewritten to use the Scanamo library and the AWS SDK v2 (DynamoDbAsyncClient), replacing the previous DynamoDB client implementation. This change introduces new store implementations for managing collection metadata (CollectionsStore) and image-to-collection mappings (ImageCollectionsStore), providing standard CRUD operations (get, add, update, remove) backed by DynamoDB tables. The migration includes updated data formats for DateTime and custom model types, and centralizes DynamoDB response handling through a new DynamoHelpers trait to improve error management.

collections/app/store · high confidence

Configurable Content Security Policy and new service health check

The Kahuna application now enforces a comprehensive, configurable Content Security Policy (CSP) that explicitly allows resources from internal service URIs (API, loader, cropper, etc.), Google user photos, YouTube, Sentry, and data/blob sources, while removing Google Analytics. This policy is driven by new configuration properties such as \security.fontSources\, \scriptsToLoad\, and \frameAncestors\. Additionally, a new \InnerServiceStatusCheckController\ has been added to provide a health check endpoint that verifies connectivity to all other internal services.

kahuna/app · high confidence

Consolidated Grid E2E test images with separate CI and development modes

The Grid E2E test environment now uses a single Dockerfile to produce two distinct images: \grid-e2e-ci\ for continuous integration and \grid-e2e-dev\ for local development. The CI image builds the Kahuna frontend and stages all Play services (auth, collections, cropper, image-loader, kahuna, leases, media-api, metadata-editor, thrall) for production-mode execution, while the dev image runs services in Play dev mode with live source recompilation and a continuous webpack watcher. Both images share a common toolchain (JDK, sbt, Node, and native image-processing tools) installed via mise, bind-mount the repository at runtime, and require an explicit \--target\ flag to build.

e2e-tests/images · high confidence

Consolidated application entry point

The application initialization logic has been consolidated into a new AppLoader class that extends GridAppLoader, providing a single entry point for the auth service setup.

auth/app · medium confidence

Custom save and cancel buttons for xeditable forms

The xeditable integration now uses a custom template for the save and cancel buttons, reordering them so that Cancel appears before Save. This change also sets the blur behavior to 'ignore' to prevent accidental form dismissal when clicking outside the editable element.

kahuna/public/js/forms/gr-xeditable · high confidence

Default graphic image blurring with configurable explainer and user controls

The application now blurs potentially graphic images by default, controlled by a new cookie and a service that evaluates metadata to determine which images to blur. Users can toggle this setting on or off via the secondary navigation menu (user-actions), and are presented with a mandatory explainer tooltip that must be acknowledged before the default state is accepted; this explainer content is dynamically loaded based on the organization's configuration. Additionally, the user-actions component now supports configurable additional navigation links and uses a dedicated feedback form link, while the usage rights utilities have been updated to support batch updating of leases based on rights categories.

kahuna/public/js/common · high confidence

Enforce grid\_access permission for all user interactions

Users must now hold the 'grid\_access' permission to interact with the Grid service. The authentication flow has been updated to check this permission during user validation, and the authorization provider enforces it for all basic access checks. This change ensures that only users with explicit grid access can use the system, moving beyond previous logging-only enforcement.

rest-lib/src/main/scala/com/gu/mediaservice/lib/guardian · high confidence

Extracted crop and edit options to configurable constants and added Photo Sales integration strings

Crop and edit options are now defined in dedicated constant files (cropOptions.js, editOptions.js), making the default crop ratio 'freeform' and replacing the 'landscape' ratio from 5:3 to 5:4 while retaining the old 5:3 option as hidden. Additionally, new constants for Photo Sales interactions (sendToCapture-config.js) provide UI text and notification IDs for sending images to Photo Sales, and a new theme override file (standThemeOverride.ts) adjusts styling for Guardian Stand components to compensate for Kahuna's global font-size scaling.

kahuna/public/js/util/constants · high confidence

Image cropper now corrects orientation metadata and displays visual crop guides

The image cropping interface now automatically corrects for image orientation metadata (EXIF rotation) upon loading, ensuring the preview matches the intended orientation regardless of how the image was captured. Additionally, visual aids have been introduced to improve cropping precision: a circular guideline is displayed for 1:1 aspect ratios, and vertical 'warning gutters' appear for 5:3 crops to indicate which parts of the image will be clipped if used in a 5:4 space. These changes are supported by new CSS overrides for the cropper component and updated JavaScript logic to handle orientation data and coordinate updates.

kahuna/public/js/directives/ui-crop-box · high confidence

Image embedder now uses Cohere v4 with downscaling and S3 vector storage

The image-embedder Lambda function has been updated to use the Cohere embed-v4 model, which generates 1536-dimensional embeddings stored in S3 Vectors. To comply with Bedrock's 5 MiB image limit and Cohere v4's pixel constraints, images exceeding 30,000 pixels are automatically downscaled and cached in a dedicated S3 bucket. Embeddings are also truncated to 256 dimensions for Elasticsearch compatibility before being published to Kinesis. The implementation includes connection pooling limits to prevent resource leaks and uses eu-west-1 for all AWS services.

image-embedder-lambda/src/embedder · high confidence

Imaging operations now configurable via ImageMagick or GraphicsMagick

The imaging subsystem in common-lib now supports selecting between ImageMagick and GraphicsMagick for image conversion and identification tasks. This is controlled by a boolean flag passed to the runConvertCmd and runIdentifyCmd methods, allowing callers to explicitly force the use of GraphicsMagick when needed. The implementation includes a dedicated configuration object for the imaging thread pool size and new helper methods for ExifTool operations, providing a unified interface for these image processing commands.

common-lib/src/main/scala/com/gu/mediaservice/lib/imaging/im4jwrapper · high confidence

Improved request logging and error handling in the Play framework layer

The Play application layer now includes enhanced request logging via a new RequestLoggingFilter that attaches unique request IDs and captures detailed context (such as origin IP, method, duration, and authentication details) for better observability. Error handling has been refined to suppress noisy 501 alarms by converting unsupported HTTP method errors to 400 Bad Request, and upload failures caused by broken connections (EntityStreamException) are now returned as 422 Unprocessable Entity instead of generic 500 errors. Additionally, the application loader and component wiring have been restructured to encapsulate initialization logic and support pluggable authentication and authorization providers.

rest-lib/src/main/scala/com/gu/mediaservice/lib/play · high confidence

Introduce dedicated configuration, metrics, and notification infrastructure for the Collections service

The Collections application now uses a dedicated \CollectionsConfig\ class to load DynamoDB table names and the base URI, replacing ad-hoc configuration loading. A new \CollectionsMetrics\ component initializes CloudWatch metrics (including processing latency) tied to the application lifecycle, and a \Notifications\ class is added to send messages via the Thrall message sender to Kinesis.

collections/app/lib · high confidence

Introduce structured Argonaut response models with actions support

The library now includes new case classes (Action, Link, EmbeddedEntity, EntityResponse, CollectionResponse, ErrorResponse) to represent API responses. This change adds an 'actions' property to entity and collection responses, allowing clients to receive actionable links (name, href, method) alongside data and links. It also introduces ExtraCounts and FilterPoolCounts to support displaying AI search pool sizes and ticker-based agency pick counts in the UI.

common-lib/src/main/scala/com/gu/mediaservice/lib/argo/model · high confidence

Introduce structured authentication and authorization framework

The authentication and authorization logic in the REST library has been refactored into a new, pluggable structure. A new \Authentication\ class now centralizes request handling, supporting three principal types: \UserPrincipal\ (human users), \MachinePrincipal\ (internal services), and \InnerServicePrincipal\ (inter-service calls). It introduces a grace period mechanism where recently expired sessions are still accepted for specific actions. The \Authorisation\ class provides a unified way to enforce permissions via action filters, supporting checks for specific permissions (like \UploadImages\, \ArchiveImages\, \DeleteCropsOrUsages\) or uploader status. A new \Permissions\ object defines these permission types. Additionally, a \BaseControllerWithLoginRedirects\ trait simplifies login redirection logic for controllers.

rest-lib/src/main/scala/com/gu/mediaservice/lib/auth · high confidence

The application now uses a dedicated \gr-top-bar\ component to manage the top navigation area. This change introduces a fixed-position header that stays above other content (z-index 30) and includes a home link that navigates to \/search\. The home link's HTML content is now configurable via the \homeLinkHtml\ client configuration, allowing for custom branding or text. The component structure separates navigation (\gr-top-bar-nav\) and actions (\gr-top-bar-actions\), with the latter always appending user actions at the end. The styling uses Open Sans font and ensures the bar is responsive and visually consistent with the rest of the interface.

kahuna/public/js/components/gr-top-bar · high confidence

Introduce tiered API access control and S3-backed key storage

The authentication library now enforces access based on API key tiers (Internal, ReadOnly, Syndication) rather than simple existence. Internal keys have unrestricted access, ReadOnly keys are limited to GET requests, and Syndication keys are restricted to GET requests on specific image paths from the configured API host. API keys and their associated tiers are now stored and retrieved from an S3 bucket via a new KeyStore, replacing previous storage mechanisms.

common-lib/src/main/scala/com/gu/mediaservice/lib/auth · high confidence

Introduction of API Key Authentication trait

A new trait, ApiKeyAuthentication, has been added to the common library to define the standard header name (X-Gu-Media-Key) used for API key authentication. This change centralizes the configuration of the authentication header, allowing other components to reference a single source of truth for this credential mechanism.

common-lib/src/main/scala/com/gu/mediaservice/lib/auth/provider · high confidence

Introduction of syndication lease types and updated lease serialization

The leases model now supports syndication-specific permissions, introducing AllowSyndicationLease and DenySyndicationLease types alongside the existing use-based leases. This change enforces specific business rules: syndication leases cannot have an end date, and deny-syndication leases cannot have a start date. Additionally, the serialization logic for leases has been updated to include an 'active' status field in the JSON output and to sanitize empty notes before saving, ensuring data consistency in the underlying storage.

common-lib/src/main/scala/com/gu/mediaservice/model/leases · high confidence

Local imgops service now strips image parameters before proxying to LocalStack

The local imgops development environment has been updated to strip query parameters (q, w, h, r, and timestamp) from image proxy requests before forwarding them to the LocalStack backend. This change ensures that parameters which could interfere with AWS signature verification are removed during the proxy pass, while still applying the image transformations (resize, rotate, quality) locally via Nginx's image filter module.

dev/imgops · high confidence

Media API controllers restructured into specialized service endpoints

The monolithic MediaApi controller has been refactored into distinct, specialized controllers to improve separation of concerns. New endpoints are now exposed via AggregationController (for date histogram aggregates), SuggestionController (for metadata, edits, and credit suggestions), UsageController (for supplier quotas and usage status), and ConfigurationController (for crop variations). The legacy Application controller and its associated Play framework views have been removed as the API no longer serves HTML pages.

media-api/app/controllers · high confidence

Media API route restructuring and new endpoint additions

The Media API's routing configuration has been significantly reorganized, replacing the previous generic application router with specific controllers for image metadata, search, usage, and management. New endpoints have been introduced to support soft-delete operations (including undelete and hard-delete), retrieve image exports and downloads (both original and optimized), and query usage quotas by supplier. The API now exposes metadata and edits search suggestions, date histogram aggregations, and a diff projection endpoint, while management routes now include health checks against Elasticsearch, manifest information, image counts, and an inner service status check.

media-api/conf · high confidence

Metadata extraction and supplier mapping logic moved to common-lib

The logic for converting raw file metadata into structured image metadata has been consolidated into the common-lib module. This includes a new ImageMetadataConverter that standardizes the extraction of dates, people, keywords, and location data from XMP, IPTC, and EXIF fields, while also normalizing color spaces and subject categories. Additionally, a UsageRightsMetadataMapper has been introduced to automatically populate image metadata fields such as byline, credit, and image type based on the image's usage rights (e.g., distinguishing between staff photographers and illustrators). The SoftDeletedMetadataTable has also been moved to this location to centralize DynamoDB interactions for metadata status tracking.

common-lib/src/main/scala/com/gu/mediaservice/lib/metadata · high confidence

Migrate AWS client infrastructure to SDK v2 and introduce AI embedding capabilities

The AWS client layer in common-lib has been rewritten to use the AWS SDK for Java v2, replacing the previous v1 implementation across S3, DynamoDB, Kinesis, SQS, and SNS services. This migration includes a new unified client builder utility for consistent credential and endpoint configuration, improved error handling, and batched operations for DynamoDB and S3 vectors. Additionally, the library now supports AI-driven image search by integrating with AWS Bedrock for text embeddings and AWS S3 Vectors for storing and querying image vector embeddings, alongside a new SQS-based message consumer for processing embedding tasks.

common-lib/src/main/scala/com/gu/mediaservice/lib/aws · high confidence

Migrate build tooling to Webpack 5 with TypeScript and CSS Modules support

The Kahuna application's build pipeline has been upgraded to Webpack 5, replacing the previous setup. This change introduces native TypeScript compilation via ts-loader and ForkTsCheckerWebpackPlugin, enabling developers to write and type-check .ts and .tsx files. Additionally, the build now supports CSS Modules for scoped styling and allows HTML and SVG assets to be imported directly as strings. The configuration is split into shared, development, and production profiles, with the production build utilizing ImageMinimizerPlugin for asset optimization and generating source maps for debugging.

kahuna · high confidence

Migrate description warning component to React with CSS Modules

The description warning component has been rewritten as a React component, replacing the previous implementation. It now uses CSS Modules for styling, ensuring that the warning text (displayed when a description is too short or lacks sufficient words) is scoped locally to avoid global style conflicts. The component logic remains focused on validating description length and word count, but the underlying technology stack has shifted to React, integrated via angular2react for compatibility with the existing Angular application.

kahuna/public/js/components/gr-description-warning · high confidence

New CloudWatch metrics infrastructure with actor-based aggregation

The metrics subsystem has been replaced with a new implementation that uses an Akka actor to aggregate and batch CloudWatch metric data before sending it, ensuring metrics are reported on a regular schedule and flushed gracefully on shutdown. This change introduces a new CloudWatchMetrics abstraction with CountMetric and TimeMetric types, supports dimensional metrics (recording values both with and without dimensions to work around CloudWatch limitations), and provides a FutureSyntax trait for convenient instrumentation of asynchronous operations. Additionally, a RequestMetricFilter has been added to automatically track HTTP request counts and durations, configurable via the requestMetricsEnabled setting.

common-lib/src/main/scala/com/gu/mediaservice/lib/metrics · high confidence

New authentication and internal service status routes added

The application now exposes a new set of routes for user authentication and internal health monitoring. Users can log in, log out, and manage sessions via /login, /logout, and /session, with OAuth support at /oauthCallback. A debug endpoint /cookieMonster allows forcing a reset of the panda cookie. Additionally, management endpoints have been added, including a new /management/whoAmI route that checks connectivity to other internal services with an optional depth parameter, alongside existing health check and manifest routes.

auth/conf · high confidence

New cost calculation logic for usage rights

The media API now uses a new CostCalculator to determine the cost of usage rights. This logic prioritizes restrictions (marking them as Conditional), then falls back to the default category cost, and finally checks supplier-specific rules (marking as Free or Overquota if applicable). If none of these apply, it defaults to Pay.

media-api/app/lib/usagerights · high confidence

New dedicated component for adding labels to images

Introduces the \gr-add-label\ component, replacing the previous prompt-based input with a dedicated UI form. Users can now add one or multiple labels by typing them into a text field separated by commas (e.g., 'label1, label2'), with auto-suggestions provided via the datalist service. The component includes a cancel button, a save button that shows a loading state during submission, and tooltips for accessibility.

kahuna/public/js/components/gr-add-label · high confidence

New download and usage services for image management

This change introduces two new services to handle image downloads and usage tracking. The \imageDownloadsService\ consolidates download logic, supporting both high-resolution and low-resolution downloads via API, and correctly handles file extensions for PNG, TIFF, and JPG formats when creating zip archives. The \imageUsagesService\ separates usage data into distinct streams for print and digital platforms, enabling independent tracking of 'recent' usages (defined as within the last 7 days) and supporting new usage types such as 'child' usages for derivatives or replacements.

kahuna/public/js/services/image · high confidence

New global error banner with auto-dismiss and specific HTTP error handling

A new global error banner component has been introduced to centralize user-facing error messages. It now displays specific, user-friendly messages for HTTP 401 (unauthorized), 419 (authentication re-establishment failed), 500, and 503 errors, as well as success states for clipboard actions. The banner includes auto-dismiss functionality that hides notifications when the user scrolls, presses Escape, or clicks outside the element, and provides direct links for re-authentication or contacting support.

kahuna/public/js/errors · high confidence

New image model and asset structure with orientation support

The image domain model has been restructured to include a new Asset type that captures file details, dimensions, and orientation metadata (including corrected dimensions and orientation based on EXIF tags). The central Image model now incorporates this Asset structure, along with new fields for soft deletion metadata, syndication rights, and image embeddings. Additionally, new models for Collections, Edits, Crops, and Usage Rights have been introduced to support more granular image management and metadata handling.

common-lib/src/main/scala/com/gu/mediaservice/model · high confidence

New inline photoshoot editing component with search and batch support

The gr-photoshoot component has been rewritten to provide an inline editing experience for photoshoot metadata. Users can now edit photoshoot titles directly via an inline form that includes a datalist with search-as-you-type functionality, replacing the previous display-only or modal-based interaction. The component supports batch operations, allowing a single photoshoot title to be applied to multiple selected images simultaneously. It also respects the 'nonFree' state when generating search links for existing photoshoots and includes specific styling for the inline edit button.

kahuna/public/js/components/gr-photoshoot · high confidence

New panel layout system with scroll-to-hide behavior

The interface now uses a new \gr-panels\ component system to manage side panels. This change introduces a layout where panels can be locked or hidden, and specifically adds behavior to automatically hide panels when the user scrolls, provided the panel is not locked. The panel height dynamically adjusts based on whether the search interface displays a single or double toolbar, and scroll positions are remembered for specific panels to improve navigation continuity.

kahuna/public/js/components/gr-panels · high confidence

New pluggable authentication and authorisation provider architecture

The authentication and authorisation system has been refactored into a pluggable provider model, introducing new traits and implementations for user, machine, and inner-service authentication. This change adds specific providers for local development (LocalAuthenticationProvider and LocalAuthorisationProvider, which bypass real checks) and API key-based machine access (ApiKeyAuthenticationProvider), alongside a new InnerServiceAuthentication mechanism for signing and verifying inter-service calls. The architecture now requires organisations to explicitly implement the AuthorisationProvider interface, removing the previous default implementation for basic access checks to ensure stricter permission enforcement.

rest-lib/src/main/scala/com/gu/mediaservice/lib/auth/provider · high confidence

New query syntax parser with expanded search capabilities

The media-api now uses a new query syntax parser that supports a wider range of search filters, including nested usage fields (e.g., \usages@status:replaced\), file type filtering (\fileType:\), and label searching (\\#label\ or \label:\). The parser automatically hides deleted images and replaced usages by default unless explicitly included. It also introduces new search terms like \has:\, \is:\, and \similar:\, and supports date constraints with operators like \\<\ and \\>\. Field names are mapped to their internal equivalents (e.g., \person\ to \peopleInImage\), and quoted strings are treated as exact phrases. The parser also handles Unicode characters and normalizes consecutive terms into single matches.

media-api/app/lib/querysyntax · high confidence

New structured logging infrastructure with request markers and performance timing

The logging subsystem in common-lib has been restructured to support structured logging via Logstash markers and automatic performance tracking. A new LogMarker API allows developers to attach contextual metadata (such as API key details and image IDs) to log entries, which are then passed through the processing stream. Additionally, a Stopwatch utility has been introduced to easily measure and log the duration of synchronous and asynchronous operations, providing visibility into processing times for messages and commands.

common-lib/src/main/scala/com/gu/mediaservice/lib/logging · high confidence

New usage metadata types and DynamoDB mapping logic

The usage module now supports 'child' usage metadata (tracking derivative or replaced media) and 'download' usage metadata, alongside existing print, digital, syndication, and front metadata. This is implemented via new ItemToMediaUsage and UsageBuilder components that map these fields to and from DynamoDB documents, including specific handling for the new 'syndicatedBy' field in syndication metadata.

common-lib/src/main/scala/com/gu/mediaservice/lib/usage · high confidence

Optimised image downloads and stricter MIME type enforcement

The image loader now supports downloading optimised versions of images, specifically using pngquant to convert PNGs and TIFFs into smaller, optimised PNG files. This change enforces correct MIME types for these optimised files and thumbnails, ensuring that the system accurately identifies and serves the processed assets. Additionally, the logic for determining which images should be optimised has been refined to prevent browser images from being incorrectly labelled as storable, and user metadata handling has been sanitised for security.

image-loader/app/model/upload · high confidence

Permissions filter refactored into React with keyboard support and responsive design

The Permissions Filter component has been rewritten in React, introducing keyboard navigation (including Escape to close and Space to toggle) and responsive CSS that adapts the layout for screens narrower than 1200px and 880px. The filter now reads its options and default settings from the client configuration (\window.\_clientConfig.interimFilterOptions\), allowing for dynamic permission sets, while maintaining the ability to toggle the display of chargeable (payable) images via a dedicated switch and event listeners.

kahuna/public/js/components/gr-permissions-filter · high confidence

Pluggable authentication and authorization provider loading

The service now supports pluggable authentication and authorization providers. New loader components have been introduced in the configuration layer to dynamically instantiate machine and user authentication providers, as well as the authorization provider, allowing these security mechanisms to be swapped or extended without modifying core logic.

rest-lib/src/main/scala/com/gu/mediaservice/lib/config · high confidence

Re-architected media-api search into modular Elasticsearch components with hybrid search support

The monolithic Elasticsearch client in media-api has been refactored into a modular package (lib.elasticsearch) containing dedicated components for query building, filtering, and result handling. This change introduces a hybrid search capability that combines lexical (BM25) and semantic (KNN/vector) scores, allowing users to search using both text queries and similar-image signals. The new architecture includes a structured query parser, an \IsQueryFilter\ system for boolean-style filters (e.g., \is:agency-pick\, \is:deleted\), and migration-aware getters that seamlessly search across current and migration indices. Users benefit from more robust search filtering, support for AI-driven similar image searches, and improved handling of syndication status and usage rights constraints.

media-api/app/lib/elasticsearch · high confidence

Redesigned image preview with usage, rights, and graphic content indicators

The image preview component has been rebuilt to display richer metadata and status indicators directly on the image tile. Users now see overlays and icons indicating lease status, usage rights (pay, restricted, no rights), and syndication status. Recent print and digital usages are highlighted with warning icons. Additionally, images flagged as potentially graphic are blurred by default, requiring a hover to reveal the content. The preview also shows collection paths, upload/taken dates, and staff photographer ownership, with styling that adapts to selection mode and configuration flags.

kahuna/public/js/preview · high confidence

Redesigned image usage panel with PhotoSales support and usage status grouping

The image usage panel has been rebuilt to display usages grouped by status (e.g., Published, Pending, Downloads, Taken down) with collapsible lists for better readability. A new dedicated section now shows PhotoSales (Capture) syndication usages when enabled, displaying the partner name and date added. The panel also highlights recent usages with a warning icon, links to child images for 'replaced' or 'derivative' statuses, and includes a delete button to remove usages. Frontend and Composer links are now displayed with specific icons for each usage record.

kahuna/public/js/components/gr-image-usage · high confidence

Refactored Elasticsearch client into a modular, migration-aware library

The Elasticsearch interaction logic in common-lib has been restructured into a new \lib.elasticsearch\ package, separating concerns into distinct components: \ElasticSearchClient\ (handling index creation, alias management, and health checks), \ElasticSearchExecutions\ (standardizing request logging and error handling), and \MigrationStatusProvider\ (tracking migration progress via aliases). This change introduces explicit support for migration workflows by managing \imagesCurrentAlias\ and \imagesMigrationAlias\ separately, allowing the system to safely switch between indices during reindexing operations. Additionally, the new \Mappings\ object defines strict schemas for images, including support for dense vector embeddings for similarity search, while \PersistedQueries\ and \ReapableEligibility\ centralize the logic for determining which images should be retained or reaped.

common-lib/src/main/scala/com/gu/mediaservice/lib/elasticsearch · high confidence

Refactored crop processing logic and storage metadata handling

The cropper service has been restructured to improve how crop specifications are stored and processed. A new AspectRatio calculation module now supports customizable tolerance for matching image dimensions to known ratios. Crop metadata is now managed via a dedicated trait that handles serialization to/from S3 object metadata, including backward compatibility for legacy underscore-based keys. The CropStore class now extends S3ImageStorage to handle storing and listing crops, distinguishing between master crops and resized variants. The main Crops class manages the full export pipeline, creating master crops with specific quality settings (95 for JPEG, 1 for PNG) and generating multiple resized variants based on configured dimensions. PNG transparency handling has been improved to ensure true color PNGs are correctly converted to JPEGs when appropriate.

cropper/app/lib · high confidence

Refactored download control with configurable restrictions and crop support

The download component has been restructured into a dedicated module with updated styling and logic. It now supports a configurable 'restrictDownload' setting that disables downloads for images lacking a valid download link or marked as soft-deleted, displaying a warning icon when a mixed selection is made. Additionally, if the 'canDownloadCrop' configuration is enabled, users can download specific image crops via a new dropdown menu option. The component also improves accessibility with ARIA labels and ensures single-image downloads are tracked as usage.

kahuna/public/js/components/gr-downloader · high confidence

Refactored image ingestion model with new upload status tracking and quarantine support

The image-loader model layer has been restructured to support a more robust ingestion workflow. A new \UploadStatus\ model introduces granular status types (Prepared, Queued, Pending, Completed, Failed) to allow clients to poll the progress of uploads via a new status endpoint. The \Projector\ class now handles image projection from S3 metadata, while a new \QuarantineUploader\ enables storing files in a quarantine bucket for virus scanning. Additionally, the \S3IngestObject\ model simplifies reading S3 messages by extracting only the necessary key and metadata, and the \Uploader\ logic has been refactored to better handle metadata extraction and file storage operations.

image-loader/app/model · high confidence

Refactored image processing with explicit color profile handling and TIFF support

The image processing logic in common-lib has been consolidated into a new ImageOperations class, replacing previous scattered implementations. This change introduces explicit support for TIFF images, ensuring they are processed via ImageMagick rather than assumed to be JPEG or PNG. It also enforces correct color profiles by mapping specific ICC profiles (sRGB, CMYK, Greyscale) to image color models and stripping mismatched profiles, while applying the Facebook TINYsRGB profile to optimized outputs. Additionally, thumbnails are now generated using the thumbnail operator with interlacing and unsharpening, and browser-viewable PNGs are forced to 8-bit depth.

common-lib/src/main/scala/com/gu/mediaservice/lib/imaging · high confidence

Replaced legacy sort control with new React-based component

The sort control in the search interface has been rewritten in React, introducing a new dropdown UI with keyboard navigation and responsive styling. This change adds support for sorting by 'Taken date' alongside existing options like upload date and collection addition, and updates the 'Added to Collection' label. The new implementation includes both a simple sort control and an extended version that integrates with tab controls for filtering by taken date presence, replacing the previous Angular-based logic.

kahuna/public/js/components/gr-sort-control · high confidence

Replaces legacy Angular app with modular, reactive architecture and new standalone tools

The Kahuna application has been rebuilt using a modern stack: the main entry point (main.js) now uses ES6 modules, RxJS, and Immutable.js to manage reactive state for lists and ordered sets (via new list-factory.js and ordered-set-factory.js), while integrating Sentry for error tracking and handling 401 authentication errors via a dedicated interceptor. This refactor introduces new UI components like a fade-in directive for images and a global icon/tooltip system, and adds standalone client-side tools for managing usage quotas (quotas.js) and defining client configuration types (window.ts).

kahuna/public/js · high confidence

Restore SHA-1 hashing for backwards-compatible image IDs

The system now uses SHA-1 to generate image IDs to maintain backwards compatibility with existing records. A new Java wrapper class, DeprecatedHashWrapper, has been introduced to access Guava's SHA-1 implementation, which is otherwise deprecated due to security concerns, thereby avoiding fatal compilation warnings in the Scala codebase.

common-lib/src/main/java · high confidence

Rewrite of gu-lazy-table to use reactive streams and virtualized rendering

The gu-lazy-table component has been rewritten to use RxJS observables for position calculation and rendering, introducing a new virtualized rendering model. This change adds placeholder support to display cell positions while content loads, reduces DOM weight by only rendering visible cells, and exposes discrete scrolling methods (prev/next row/page, start/end) via the table controller. The implementation also includes observable utility helpers for reactive arithmetic and shares subscriptions to optimize performance.

kahuna/public/js/components/gu-lazy-table · high confidence

Search module restructured into modular components with new query-filter logic

The search functionality in kahuna/public/js/search has been reorganized into a modular structure, introducing dedicated files for query filtering (query-filter.js) and a new test suite (query-filter.spec.js). This change adds a new query-filter module that provides utilities for building structured search queries, including handling reserved characters and double quotes. The search module now imports and uses these new components, including the gr-top-bar, gr-info-panel, gr-collections-panel, and gr-keyboard-shortcut components, to enhance the search interface. The query-filter module introduces functions like fieldFilter and maybeQuoted to properly format search queries, ensuring that values with reserved characters are correctly quoted. Additionally, the search module now includes a new test file (query-filter.spec.js) that validates the query-filter functionality, ensuring that the new filtering logic works as expected.

kahuna/public/js/search · high confidence

Standardize local development configuration via .env and nginx mappings

Local development setup now uses a dedicated .env file for environment variables (such as domain, OIDC credentials, and AWS settings) and a new nginx-mappings.yml.template to define service routing. This change centralizes configuration, allowing developers to manage service ports and domain prefixes more consistently without hardcoding them in scripts or other config files.

dev · high confidence

Standardized date parsing and formatting in common library

The formatting package now provides a unified, UTC-based date parser that accepts standard ISO datetime strings (including those with milliseconds) and duration-based relative queries (e.g., '30.days'). This change ensures consistent date handling across the service by exposing public formatters and parsers for serializing and deserializing dates, replacing ad-hoc parsing logic.

common-lib/src/main/scala/com/gu/mediaservice/lib/formatting · high confidence

Standardized metadata cleaning and supplier attribution logic

The metadata cleanup pipeline has been refactored into a modular, pluggable architecture using a new \ImageProcessor\ trait and a \MetadataCleaner\ interface. This change introduces a standardized chain of cleaners that now handles byline and credit normalization (splitting names from agencies via 'via', '/', or '\#'), capitalization fixes for names and locations, removal of redundant tokens (like 'Handout' or 'Stringer'), and country code expansion. Additionally, supplier-specific logic for agencies such as Getty, AP, PA, and Reuters is now encapsulated in dedicated processors that correctly attribute usage rights and canonicalize credit strings, ensuring consistent metadata across the platform.

common-lib/src/main/scala/com/gu/mediaservice/lib/cleanup · high confidence

Support for full-image exports and EXIF rotation tracking

The cropper now supports exporting the entire image without cropping via a new 'full' export type, which is automatically selected when a crop selection covers the whole image. Additionally, the system now records the rotation applied based on EXIF orientation metadata in the export specification, ensuring that the final output respects the original image's orientation data.

cropper/app/model · high confidence

Syndication status now displayed with traffic-light colors

The syndication icon component now visually indicates the current syndication status of an image using a color-coded system: green for sent, orange for queued, red for blocked, and white for review. This is implemented by binding the status to a CSS class on the icon, replacing previous inline styling approaches, and providing a tooltip with the specific syndication reason.

kahuna/public/js/components/gr-syndication-icon · high confidence

Time-bound photographer assignment and usage rights configuration

The system now supports time-sensitive photographer-to-publication mappings, allowing specific photographers (such as Andy Hall, Antonio Olmos, and Gary Calton) to be automatically assigned to 'The Observer' before April 28, 2025, and to 'The Guardian' from that date onwards. This change introduces a pluggable configuration structure for usage rights, updating the internal staff, contracted, and illustrator lists to reflect current personnel and their associated publications.

common-lib/src/main/scala/com/gu/mediaservice/lib/guardian · high confidence

Unify and enhance the image info panel with cost state visualization

The gr-info-panel component has been refactored to unify the browser and viewer views, now displaying a consolidated list of cost states (free, no rights, paid, over quota, restricted) for selected images. It introduces visual indicators for leased percentages using teal and red/orange gradients, and delegates metadata display to the gr-image-metadata component while enforcing edit permissions via the edits service.

kahuna/public/js/components/gr-info-panel · high confidence

Upload page restructured with permission checks and drag-and-drop support

The upload interface has been reorganized into distinct components: a file picker, a drag-and-drop zone, and a job status list. A new permission check now gates access to the upload UI, displaying an error message and support link for users without upload rights. The drag-and-drop functionality has been enhanced to support importing Guardian Witness images via URL and to prevent accidental uploads of internal grid thumbnails. Additionally, the upload manager now supports a new ingestion flow using pre-signed S3 URLs and SHA-1 hashes for files exceeding a configurable size limit, while also marking uploads as 'queued' in the status table upon successful S3 transfer.

kahuna/public/js/upload · high confidence

Usage models refactored with new types and metadata structures

The usage data models in the common library have been restructured to support a more granular and type-safe representation of media usage. New usage types (print, digital, syndication, download, derivative, replaced) and reference types (indesign, frontend, composer, syndication, front, download, grid) are now explicitly defined. The system introduces specific metadata classes for different usage contexts, including ChildUsageMetadata for derivatives and replacements, DownloadUsageMetadata for downloads, FrontUsageMetadata for front page placements, and SyndicationUsageMetadata which now tracks the syndicator. Usage statuses have been expanded to include 'downloaded', 'derivative', 'replaced', and 'failed'. Additionally, PrintUsageMetadata has been updated to include publication names and image sizes, while the core MediaUsage model now uses a stricter equality check that excludes date fields to improve database update logic.

common-lib/src/main/scala/com/gu/mediaservice/model/usage · high confidence

Test coverage

1 commit adding/updating tests in image-loader/test/resources/c2pa; Added comprehensive test suite for Thrall's stream processing and Elasticsearch integration; Added empty test resource files for invalid image handling; Added end-to-end test coverage for upload functionality and service health; Added integration tests for the image backfiller; Added shared Elasticsearch Docker test base for v8; Added test coverage for image metadata extraction, C2PA detection, and upload workflows; Added test fixtures for email parsing; Added test resources for usage rights configuration and S3/SQS message parsing; Added tests for AI query parsing, hybrid search scoring, and Elasticsearch integration; Added tests for AWS library components; Added tests for CollectionsManager path handling and validation; Added tests for DateTimeUtils and VectorUtils; Added tests for DynamoDB v2 usage item transformation; Added tests for JSON compression utilities and field ordering; Added tests for JSON diff functionality; Added tests for MediaApi usage recording logic; Added tests for Node tree construction and hackmap transformation; Added tests for authentication and authorization components; Added tests for config loading and usage rights resolution; Added tests for image colour model detection; Added tests for image metadata conversion and usage rights mapping; Added tests for image validity, persistence, response normalization, and usage store parsing; Added tests for logging utilities; Added tests for model serialization and syndication logic; Added tests for navigation links, feature switches, and metadata template configuration; Added tests for syndication rights logic; Added tests for the image embedder backfiller logic; Added tests for the query syntax parser; Added tests for usage rights cost calculation logic; Added unit and integration tests for image embedding pipeline; Added unit tests for aspect ratio calculation, crop spec metadata, and crop output logic; Added unit tests for metadata cleanup and supplier processing logic; Added unit tests for the image counter Lambda handler; Expanded end-to-end test coverage for the image upload workflow; New E2E test utilities for health checks and drag-and-drop; Removed default Play Framework test scaffolding; Restructure E2E test infrastructure and add upload page setup.

Dependencies

Build infrastructure upgraded to SBT 1.10.3 and Play 3.0.10

The build system has been significantly modernized: the root SBT project has been removed in favor of a flat structure, the SBT version has been bumped from 0.12.4 to 1.10.3, and the Play framework plugin has been upgraded from 2.1.3 to 3.0.10. New build plugins have been added to support asset fingerprinting (sbt-digest), Gzip compression (sbt-gzip), and build-time code generation (sbt-buildinfo), alongside a dependency tree plugin. To resolve version conflicts between the newer SBT runtime and existing plugins, the build now explicitly tolerates binary incompatibility in the scala-xml library.

project · high confidence

Initial project scaffolding and dependency configuration

This change introduces the foundational build and dependency configuration for the project. It adds a comprehensive \build.sbt\ file defining the Scala 2.13.18 build, Play framework integration, and dependencies for core services (auth, kahuna, media-api, etc.), including AWS SDK v2, Elastic4s, and Jackson. It also initializes infrastructure and tooling dependencies via \package.json\ and lockfiles for the CDK module (AWS CDK v2, TypeScript), the OIDC provider development tool, the config generation script, and the end-to-end test suite (Playwright, Testcontainers).

(dependencies) · high confidence

Housekeeping

Added README for image-loader component; Cropper module documentation added.

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

How this codebase got here

Score

  • CAI 36 → 43 (+6.5)
  • Rubric changed (rubric-2026.08.15 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 49 → 60 (+10.3)
  • Architecture 80 → 61 (-19.2)
  • Maturity 59 → 51 (-8.3)
  • Readiness 17 → 36 (+19.3)
  • Security 51 → 42 (-8.4)

Resolved (163)

  • (anonymous) (cognitive 19) (kahuna/public/js/search/query.js)
  • Boundary-crossing change coupling: image-embedder-lambda.ts ↔ embedder.ts (cdk/lib/image-embedder-lambda.ts)
  • Boundary-crossing change coupling: image-embedder-lambda.ts ↔ imageEmbedder.ts (cdk/lib/image-embedder-lambda.ts)
  • Boundary-crossing change coupling: image-embedder-lambda.ts ↔ imageResolver.ts (cdk/lib/image-embedder-lambda.ts)
  • Change coupling: backfiller.ts ↔ localRun.ts (image-embedder-lambda/src/backfiller/backfiller.ts)
  • Change coupling: edits-api.js ↔ media-api.js (kahuna/public/js/services/api/edits-api.js)
  • Change coupling: embedder.ts ↔ imageEmbedder.ts (image-embedder-lambda/src/embedder/embedder.ts)
  • Change coupling: gr-chips.js ↔ gr-text-chip.js (kahuna/public/js/components/gr-chips/gr-chips.js)
  • Change coupling: gr-display-crops.js ↔ controller.js (kahuna/public/js/components/gr-display-crops/gr-display-crops.js)
  • Change coupling: imageResolver.ts ↔ models.ts (image-embedder-lambda/src/embedder/imageResolver.ts)
  • Change coupling: webpack.config.dev.js ↔ webpack.config.prod.js (kahuna/webpack.config.dev.js)
  • Consequences/trade-offs of adding a Stopwatch logging construct are not stated in the visible portion (e.g. overhead of wrapping every do_thing) (docs/02-running/03-logging.md)
  • Context/problem is thin; only authentication options and one short test example are stated (the key-creation command is shown but its purpose is not explained) (docs/99-archives/04.02-authentication.md)
  • Critical CVE: [GHSA redacted] (cdk/package-lock.json)
  • Critical CVE: [GHSA redacted] (image-embedder-lambda/package-lock.json)
  • Decision is an install list with no context/problem and no consequences/trade-offs (docs/01-setup/01-software-dependencies.md)
  • Dimension evaluation failed
  • Duplicated block (115 lines × 2) (scripts/src/main/java/com/gu/typesafe/config/impl/ConfigImpl.java)
  • Duplicated block (119 lines × 2) (scripts/src/main/java/com/gu/typesafe/config/impl/ConfigDocumentParser.java)
  • Duplicated block (13 lines × 2) (scripts/src/main/java/com/gu/typesafe/config/impl/ResolveSource.java)
  • …and 143 more

New (507)

  • (anonymous) (cognitive 17) (kahuna/public/js/forms/datalist.js)
  • (anonymous) (cognitive 18) (kahuna/public/js/components/gr-chips/gr-chip-input.js)
  • (anonymous) (cognitive 18) (kahuna/public/js/edits/list-editor.js)
  • (anonymous) (cognitive 18) (kahuna/public/js/preview/image.js)
  • (anonymous) (cognitive 19) (kahuna/public/js/components/gr-chips/gr-chips.js)
  • (anonymous) (cognitive 20) (kahuna/public/js/crop/controller.js)
  • (anonymous) (cognitive 21) (kahuna/public/js/edits/service.js)
  • (anonymous) (cognitive 25) (kahuna/public/js/upload/jobs/upload-jobs.js)
  • (anonymous) (cognitive 32) (kahuna/public/js/image/controller.js)
  • (anonymous) (cognitive 42) (kahuna/public/js/usage-rights/usage-rights-editor.js)
  • (anonymous) (cognitive 43) (kahuna/public/js/metadata-templates/metadata-templates.js)
  • (anonymous) (cognitive 52) (kahuna/public/js/edits/image-editor.js)
  • (anonymous) (cognitive 80) (kahuna/public/js/components/gr-image-metadata/gr-image-metadata.js)
  • (anonymous) (cyclomatic 16) (kahuna/public/js/forms/datalist.js)
  • (anonymous) (cyclomatic 18) (kahuna/public/js/crop/controller.js)
  • (anonymous) (cyclomatic 19) (kahuna/public/js/components/gr-chips/gr-chips.js)
  • (anonymous) (cyclomatic 20) (kahuna/public/js/components/gr-chips/gr-chip-input.js)
  • (anonymous) (cyclomatic 20) (kahuna/public/js/upload/jobs/upload-jobs.js)
  • (anonymous) (cyclomatic 21) (kahuna/public/js/preview/image.js)
  • (anonymous) (cyclomatic 24) (kahuna/public/js/edits/service.js)
  • …and 487 more

Changes since last survey

  • 300 commits — 279 feature/other, 21 fixes

By area

  • (repo) — 61 commits
  • kahuna/public — 27 commits
  • .github/workflows — 25 commits
  • e2e-tests/images — 24 commits
  • e2e-tests/setup — 20 commits
  • e2e-tests/features — 17 commits
  • e2e-tests/global-setup.ts — 17 commits
  • e2e-tests/steps — 15 commits
  • common-lib/src — 12 commits
  • (root) — 11 commits
  • e2e-tests/testcontainers — 10 commits
  • media-api/app — 9 commits
  • e2e-tests/README.md — 8 commits
  • .devcontainer/devenv.yaml — 6 commits
  • dev/script — 5 commits
  • e2e-tests/fixtures — 5 commits
  • e2e-tests/package.json — 3 commits
  • scripts/src — 3 commits
  • .devcontainer/shared — 2 commits
  • dev/oidc-provider — 2 commits

Notable commits

  • fix: Adjust whitespace in .tool-versions, which may fix setup-scala
  • fix: Fix a doc regression
  • fix: Fix cache bindmounts in stack
  • fix: Fix collection modal overlay z-index
  • fix: Fix git calls from sbt
  • fix: Fix ports to enable us to resolve with dev-nginx locally, and via a reverse proxy in CI
  • fix: Fix test
  • fix: Fix the delete alert, and add a test
  • fix: Fix top bar action CSS
  • fix: Merge pull request #4885 from guardian/em-ai-search-telemetry-fixes
  • fix: Merge pull request #4938 from guardian/jsh/fix-prompt
  • fix: Merge pull request #4944 from guardian/revert-4890-08-25-move_usagestore_logic_to_using_grid_quota_counting_instead_of_rcs_emails
  • fix: Potential fix for pull request finding
  • fix: Potential fix for pull request finding
  • fix: Potential fix for pull request finding
  • fix: Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions'
  • fix: Revert "Add better logging and early exit on startup failure"
  • fix: Revert "More logging"
  • fix: Revert "Move UsageStore logic to using Grid quota counting instead of RCS emails"
  • fix: Revert Java version change
  • …and 280 more

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

Survey your own repository

guardian/grid was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.

About this page

  • The score is its most recent published measurement, taken on 27 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
  • Measured at commit bf5bb2ffb842cb4ee6ed4741af8a024b95eeeab5 — the exact code this score is about.
  • Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
  • Measured by watchdog.canine.dev using codehealth-analyzer preprod-d00c643c3f66.