Release Notes

Curated highlights, migration guidance, and structured summaries of Glueful framework releases.

This page is a curated layer over the raw authoritative CHANGELOG.md. For complete detail (including every Added/Changed/Removed/Fix line) consult the full changelog.

v1.91.6 - Alshain

Released: November 3, 2026

Patch: login reports a confirmed email as verified. Low risk: the login response gains no new fields and nothing in configuration changes; only the value of user.email_verified is corrected.

Key Highlights

email_verified is true once the address is confirmed

Migration Notes

  • Update glueful/users to 2.5.6 as well: the framework reads the claim, the users extension sets it. On an older users version the response keeps reporting false, as before.
composer update glueful/framework glueful/users

v1.91.5 - Alshain

Released: November 2, 2026

Patch: upload folders start at the bucket root. Low risk: only uploads that send a path_prefix while uploads.path_prefix is empty change, and only in where the object is stored.

Key Highlights

A per-upload path_prefix no longer starts the key with a slash

Migration Notes

  • None. Objects already stored keep their keys; only new uploads with a path_prefix land under the intended folder.
composer update glueful/framework

v1.91.4 - Alshain

Released: October 31, 2026

Patch: login events see the user on provider logins. Low risk: the login response body is unchanged, no configuration or default changes.

Key Highlights

LoginResponseBuildingEvent always knows who signed in

Migration Notes

  • None. Listeners that read $event->getUser()['id'] now receive it on every login route; nothing to change in apps.
composer update glueful/framework

v1.91.3 - Alshain

Released: October 27, 2026

Patch: job retries and timeouts work, migrations run queued schema changes, typed route/query fields validate. Moderate risk: queue workers now honour per-job retry counts and stop jobs that run past --timeout, and three scaffold:job options are removed. Read the migration notes before deploying workers.

Key Highlights

A job's getMaxAttempts() takes effect

queue:work --timeout is enforced

Migrations run what they queue

Typed route and query fields validate

scaffold:job writes jobs that keep their context

Migration Notes

  • Retry counts can change: jobs that override getMaxAttempts() now get that many attempts (capped by --tries), instead of 3.
  • Run workers under a process manager (Supervisor, systemd) that restarts them: with pcntl, a job past --timeout (default 60s) stops the worker. Raise --timeout for long jobs, and keep queue.connections.*.retry_after above it.
  • scaffold:job --backoff, --timeout and --unique are removed; drop them from scripts. In jobs generated earlier, make the constructor forward the context: __construct(array $data = [], ?ApplicationContext $context = null) calling parent::__construct($data, $context).
composer update glueful/framework

v1.91.2 - Alshain

Released: October 27, 2026

Patch: seeders and factories work in an app. Low risk: additive API only, no configuration or default changes.

Key Highlights

db:seed runs the seeders you generate

Model::factory()->create() has a context

Migration Notes

  • No action needed. Factories still need fakerphp/faker (dev) and the HasFactory trait on the model.
composer update glueful/framework

v1.91.1 - Alshain

Released: October 27, 2026

Patch: migrate:run works in development again, and the generators produce code that runs. Low risk: no configuration or default changes.

Key Highlights

The development query log writes under your app

Generators write code your app can load

Console commands use your app's container

Migration Notes

  • No action needed. If you are on 1.91.0, update to pick this up before running migrations in development.
  • migrate:create now names new files NNN_ClassName.php. Existing migrations are unaffected. A file generated by 1.91.0 (NNN_create_tasks_table.php) never loaded; rename it to match its class.
composer update glueful/framework

v1.91.0 - Alshain

Released: October 27, 2026

Minor with breaking changes: features that do what they say. A framework-wide correctness sweep from a full audit of the docs against the code. High risk: security settings that were silently ignored now apply, the ORM behaves as documented, and several APIs, options and config keys are removed. Read the Upgrading guide before you update.

Key Highlights

Security settings that were ignored now apply

Routing and auth do what the attributes say

The ORM works as named

Subsystems wired end to end

Config that did nothing is removed or honoured

Migration Notes

  • Run the migrations (new webhooks leaf) and clear the route cache (format v3) on deploy.
  • Apps with their own config/schedule.php must add the scheduled_notifications and queue_maintenance jobs; apps with their own config/security.php should change webhooks/* to webhooks/inbound/* and mount inbound receivers under /webhooks/inbound/<provider>.
  • Removed: Utils::buildSearchConditions() (use whereContains()), FailedJobProvider::setMaxRetries()/getMaxRetries(), queue:scheduleradd|remove|enable|disable|history and --parallel.
  • ORM: paginate()['data'] is a model Collection; forceDelete() permanently deletes; returning false from a cancellable event cancels the write.
  • unique:/exists: rules are enforced and throw without a connection; expect new 422s where invalid data used to pass.
  • Behaviour that now switches on: CSRF exemptions and lifetimes, CORS patterns, LOG_LEVEL filtering, rate limits from attributes, webhook dispatch from #[Webhookable].

The full checklist, with before/after snippets, is in Upgrading.

composer update glueful/framework
php glueful migrate:run
php glueful route:cache:clear

v1.90.0 - Alsciaukat

Released: October 11, 2026

Minor: the file cache and .env stay usable when the web server cannot write the code. Moderate risk: the framework config's default file-cache path changed from the framework's own folder to the app's storage/cache.

Key Highlights

The file cache lives in your app

.env keeps who can read it

Migration Notes

  • An app whose config/cache.php sets the file-cache path (the API skeleton does) is unaffected.
  • An app relying on the framework's default now caches in <app>/storage/cache: make sure the web server can write it, or set CACHE_FILE_PATH. Old entries under vendor/glueful/framework/storage can be deleted.
composer update glueful/framework

v1.89.0 - Alsafi

Released: October 11, 2026

Minor: queue:restart asks running workers to pick up new code. Low risk: additive, no configuration or default changes.

Key Highlights

Restart workers after a deploy

Migration Notes

  • No action needed. Add php glueful queue:restart to your deploy or upgrade steps, after the code and migrations are in place.
composer update glueful/framework

v1.88.5 - Alrescha

Released: October 7, 2026

Patch: an after-commit callback that commits its own transaction no longer loops. Low risk: no configuration or default changes.

Key Highlights

After-commit callbacks run once

Migration Notes

  • No action needed. Each after-commit and after-rollback callback now runs exactly once.
composer update glueful/framework

v1.88.4 - Alrescha

Released: October 5, 2026

Patch: large resized images no longer fail after their first request. Low risk: no configuration or default changes.

Key Highlights

A cached image variant is always readable

Migration Notes

  • No action needed. Variants already cached over the limit are rendered again. A variant over the cache limit is now served uncached, so it is rendered on each request.
  • RedisCacheDriver::set(), setNx() and mset() return false for a value the serializer refuses, instead of storing it; code that relied on such a write had a value it could never read.
composer update glueful/framework

v1.88.3 - Alrescha

Released: October 3, 2026

Patch: enabling an extension over HTTP takes effect under OPcache. Low risk: no configuration or default changes.

Key Highlights

The extension files are invalidated when written

Migration Notes

  • No action needed. A change made from the CLI (extensions:enable, extensions:cache) reaches PHP-FPM when OPcache next checks the file's timestamp; with opcache.validate_timestamps=0, reload PHP-FPM after it.
composer update glueful/framework

v1.88.2 - Alrescha

Released: October 3, 2026

Patch: a new project installs cleanly. composer create-project no longer fails at its extensions:cache step before the database is configured. Low risk: no configuration or default changes.

Key Highlights

The extension-state lock needs no database

Migration Notes

  • No action needed. ExtensionStateMutex::within() still accepts its $db argument and ignores it; an application that passed one can stop.
composer update glueful/framework

v1.88.1 - Alrescha

Released: October 3, 2026

Patch: a change to the extension list that can't get the lock says so. Low risk: no configuration or default changes.

Key Highlights

Extension-list lock timeouts are lock contention

Migration Notes

  • No action needed. Code that catches RuntimeException keeps working; catch LockContentionException to tell contention apart.
composer update glueful/framework

v1.88.0 - Alrescha

Released: October 3, 2026

Minor: route tables that know the state they were compiled under, and one lock for every change to the enabled extensions. An application can add its own state to the compiled route table's signature, and every command that edits config/extensions.php or rebuilds the extension cache now holds the same lock. Low risk: additive, with no configuration or default changes.

Key Highlights

Route-table signature inputs

One lock for every enabled-list change

Migration Notes

  • No action needed. An application that edits config/extensions.php or rebuilds the extension cache itself should do it inside ExtensionStateMutex::within().
composer update glueful/framework

v1.87.0 - Alrakis

Released: September 22, 2026

Minor: responses carry security headers, uploads keep their promises, and search matches what you typed. Every response now gets X-Content-Type-Options: nosniff and a referrer policy where it set none. Uploaded images are stripped of their embedded metadata, deleted uploads are purged after a grace period, and a resized image follows its blob when the file changes. Text search folds case on every database and treats % and _ literally. Mail no longer pretends to be configured. Moderate risk: read the Migration Notes; mail needs MAIL_HOST and MAIL_FROM, and image metadata is removed by default.

Key Highlights

Baseline security headers on every response

Uploads that do what the config says

Search that matches what you typed

Honest mail and console

Migration Notes

  • Set MAIL_HOST and MAIL_FROM if your app sends mail; without them the email channel reports itself unavailable.
  • List blob_purge in your config/schedule.php to purge deleted uploads (an app's schedule replaces the framework's list). UPLOADS_PURGE_DELETED_AFTER_DAYS sets the grace period.
  • Uploaded images lose their metadata by default. Set UPLOADS_STRIP_EXIF=false to keep it.
  • PostgreSQL searches now match any case, and % or _ in a term is matched literally. A custom WhereClauseInterface implementation must add the four text-match methods.
  • Deprecated: Utils::buildSearchConditions() (it writes the term into raw SQL unescaped); use QueryBuilder::whereContains(). Removal in 1.88.
composer update glueful/framework

v1.86.2 - Alpherg

Released: September 22, 2026

Patch: an empty array in config adds nothing again. 1.86.0 made a config list replace the list below it, and PHP counts [] as a list, so a package that ships a key as [] wiped the value another package or the app contributed to it (in Thallo, the uploads root admin imports read their file from). An empty array now leaves the value below it alone, as it did before 1.86.0; a non-empty list still replaces. Low risk: restores the earlier meaning of [].

Migration Notes

  • None. Upgrade from 1.86.0 or 1.86.1.
composer update glueful/framework

v1.86.1 - Alpherg

Released: September 22, 2026

Patch: a job that releases itself is retried. The worker runs a fresh instance of the job class, with no driver, so a job's own release($delay) (a scheduled retry) only set a flag: the queue wrapper deleted the row and the job never ran again. A failed webhook delivery was marked "retrying" and never retried. DatabaseJob and RedisJob now carry out the release on the queued job, with the delay the job asked for. Low risk: no behaviour change beyond scheduled retries running.

Migration Notes

  • None.
composer update glueful/framework

v1.86.0 - Alpherg

Released: September 22, 2026

Minor: webhooks deliver, failed jobs come back, and config means what it says. Webhook deliveries failed to queue on every dispatch; they now reach the queue, and a test send is guarded against private addresses. Failed queue jobs can be listed, retried and removed on the database and Redis drivers. An ORM-created model carries its real id, stored text is never refused as SQL, and the scheduled backup takes a real dump. App config lists now replace the framework's instead of merging by position. Moderate risk: read the Migration Notes; security:check can now fail where it passed, and a custom config/schedule.php no longer inherits framework jobs.

Key Highlights

Webhooks that deliver

queue:failed, queue:retry, queue:forget, queue:flush

What you store is what you get

Config that means what it says

Migration Notes

  • Your config/schedule.php list replaces the framework's. Add any framework job you relied on inheriting, and the new webhook_cleanup job if you want it.
  • Delete the dead config from your copies: the sync/null queue connections, the schedule's settings block, queue_mapping and per-job queue/timeout/retry_attempts, app.force_https, security.headers, and HSTS_HEADER, FORCE_HTTPS, SCHEDULE_QUEUE_*, MAIL_BCC. Leaving it changes nothing.
  • Run security:check and fix what it now reports.
  • The scheduled backup needs pg_dump or mysqldump on the scheduler host.
  • Enforce permissions in route middleware? List it in permissions.enforcing_middleware.
  • Deprecated: FailedJobProvider::setMaxRetries() / getMaxRetries() (nothing enforces them; removal in 1.88).
composer update glueful/framework

v1.85.8 - Alphard

Released: September 15, 2026

Patch: a scheduled framework job never fails its tick on the logger lookup. With their context restored in 1.85.7, NotificationRetryJob, SessionCleanupJob, LogCleanupJob, CacheMaintenanceJob and DatabaseBackupJob resolved LogManager from the container unguarded, and a container that binds none — a skeleton install — failed every due tick with Service 'Glueful\Logging\LogManager' not found, so queue:scheduler run still failed every tenth minute on a fresh install. The five jobs share one guarded lookup that falls back to the static instance. Low risk: no behaviour change beyond the jobs running as intended.

Migration Notes

  • None.
composer update glueful/framework

v1.85.7 - Alphard

Released: September 15, 2026

Patch: scheduled framework jobs keep the application context. JobHandlerResolver hands the context to a job's constructor, but NotificationRetryJob, SessionCleanupJob, LogCleanupJob, CacheMaintenanceJob and DatabaseBackupJob overrode that constructor without the parameter and dropped it. The notification retry job then threw NotificationContextRequiredException on every due tick, so queue:scheduler run failed every tenth minute on a fresh install; the others ran context-less. Every one now forwards the context. Low risk: no behaviour change beyond the jobs running as intended.

Migration Notes

  • None.
composer update glueful/framework

v1.85.6 - Alphard

Released: September 13, 2026

Patch: an SVG served with a width hint is the original, not a 422. GET /blobs/{uuid}?width=160 sent every image/* blob through the resizer, whose raster validator only knows JPEG, PNG, GIF and WebP, so any thumbnail request for an SVG answered 422 Unprocessable Content. Only raster formats take the variant path now; SVG falls through to the original bytes with the resize parameters ignored. Low risk: no behaviour change for raster images.

Migration Notes

  • None.
composer update glueful/framework

v1.85.5 - Alphard

Released: September 13, 2026

Patch: a failed token generation can no longer poison every later login. When JWT generation threw (a missing or invalid key), the provider answered empty tokens, a session was stored anyway, and a refresh token of "" was issued; its constant hash made every later login answer 409 A conflicting record already exists, unlogged. Empty tokens are a failed login now, the refresh-token store refuses an empty token, the cause is logged, and unique-constraint violations are reported at warning. Moderate: an install already affected must delete the poisoned row once.

Migration Notes

  • If logins on an install answer 409 today, delete the poisoned rows once, then log in again:
-- the token rows reference the sessions, so they go first
CREATE TEMP TABLE poisoned AS SELECT session_uuid FROM auth_refresh_tokens
  WHERE token_hash = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
DELETE FROM auth_refresh_tokens
  WHERE token_hash = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
DELETE FROM auth_sessions WHERE uuid IN (SELECT session_uuid FROM poisoned);
  • Then fix what made generation throw: the log now names it ([Auth] Token generation failed: …).
composer update glueful/framework

v1.85.4 - Alphard

Released: September 12, 2026

Patch: jobs declared in config/schedule.php now actually run. The scheduler registered each config job as a callback that only returned its handler class name, so queue:scheduler run logged "Executed job (0ms)" and never ran the handler — every config-declared job was a no-op unless persisted to the database. Config jobs now resolve and run their handler like database jobs, enabled => false is honoured, the command hands the scheduler the booted context, and list tolerates a missing enabled key. Moderate: jobs you believed were running will start running on the next tick.

Migration Notes

  • Review config/schedule.php before upgrading: every enabled job will now execute on its cron expression. Set enabled => false on any you do not want.
  • Make sure a cron entry ticks the scheduler: * * * * * php /path/to/app/glueful queue:scheduler run.
composer update glueful/framework

v1.85.3 - Alphard

Released: September 12, 2026

Patch: the boot environment is read the way env() reads everything else. Framework::create() and console commands chose the environment from $_ENV['APP_ENV'] alone, so a process-exported APP_ENV (a CI job, a container) was ignored: a CLI run booted as the wrong environment, skipped its config/{env}/ overrides, and extensions:cache compiled the wrong provider list for whoever booted next. The extension cache now records the environment it was compiled for and is not consumed under another one outside production. Low risk: an exported value that was ignored is honoured now, and older bare-list caches still load.

Migration Notes

  • Skeleton bootstraps: pass env('APP_ENV', 'development') to withEnvironment() instead of $_ENV['APP_ENV'] ?? 'development'.
  • Rebuild the extension cache on deploy as usual (php glueful extensions:cache); the new file shape is read by this release and the bare-list shape remains readable.
composer update glueful/framework

v1.85.2 - Alphard

Released: September 12, 2026

Patch: env() sees variables the real process environment holds. It read $_ENV alone, which PHP fills only when variables_order includes "E", and Dotenv skips keys the real environment already holds — so a CI job or container exporting DB_* fell to the sqlite default for a fresh install's first connections. env() now also reads $_SERVER and getenv(). Low risk: a value that was invisible before is honoured now.

Migration Notes

  • No action required. Tests that want a key absent must clear the real environment too (putenv('KEY')).
composer update glueful/framework

v1.85.1 - Alphard

Released: September 12, 2026

Patch: migrate:run adopts previous sources even with nothing pending. The command returned at "No pending migrations found" before adoption ran, so an up-to-date database kept its rows under a lane's previous source names. Low risk: only lanes declaring previous_sources are affected.

Migration Notes

  • No action required.
composer update glueful/framework

v1.85.0 - Alphard

Released: September 12, 2026

Minor: migrations can change owner without breaking existing databases. A migration lane may declare the source names its files were recorded under before (previous_sources); rows under those names count as applied and are adopted under the current source on the next run. Low risk: an optional key, no behaviour change without it.

Key Highlights

previous_sources in the manifest, or from a provider

Adoption, scoped to what the lane ships

Migration Notes

  • No action required. Use the key when your package takes over migrations previously recorded under another source: an application that became a package, a rename, a split lane.
composer update glueful/framework

v1.84.0 - Alnitak

Released: September 11, 2026

Minor: the API reference moves from /docs to /api-docs. The reference UI and its openapi.json are served at the path in documentation.route_prefix (env API_DOCS_PATH), and the default is now /api-docs, leaving /docs to your application's own documentation. Moderate risk: links, bookmarks and tooling that used /docs need the new address, or set API_DOCS_PATH=/docs to keep it.

Key Highlights

One setting, four consumers

Your /docs is yours

Migration Notes

  • Update links to the reference (/api-docs), or set API_DOCS_PATH=/docs to keep the old address.
  • Regenerate the UI page with php glueful generate:openapi --ui: a page generated before 1.84.0 still loads /docs/openapi.json.
  • Mirror API_DOCS_PATH=/api-docs into your .env.example if you keep one.
composer update glueful/framework

v1.83.4 - Alnilam

Released: September 11, 2026

Patch: a mounted SPA document may frame itself and its own blob: documents. The document CSP had no frame-src, so default-src 'self' applied and browsers refused an iframe pointing at a blob: URL the page had minted itself — an admin previewing its own rendered output showed nothing. Low risk: SPA document responses only; no third-party origin is allowed.

Key Highlights

frame-src 'self' blob: on the document policy

Migration Notes

  • No action required. Mounts that pass their own csp keep it verbatim; add frame-src 'self' blob: to it if your SPA previews its own documents in an iframe.
composer update glueful/framework

v1.83.3 - Alnilam

Released: September 9, 2026

Patch: the production container is compiled once, atomically, under a signed name. Every PHP-FPM worker compiled the container on its own boot and rewrote one shared file before requiring it: a 783 KB write per request, workers requiring a half-written file ("Unclosed '{' on line 9557") and silently falling back to the runtime container, and — with OPcache not revalidating timestamps — workers executing whatever version they cached first, long after a deploy rewrote it. Low risk: the production boot path only.

Key Highlights

DefinitionSignature names the artifact

Atomic writes, signed precompiles

Migration Notes

  • No action required. After updating, the first production boot compiles one signed artifact; later boots require it. Re-run php glueful di:container:compile if you rely on a precompiled container — the pre-1.83.3 file is unsigned and will be ignored.
composer update glueful/framework

v1.83.2 - Alnilam

Released: September 8, 2026

Patch: the Installer publishes freshly written database credentials to the running process. A fresh create-project boots with the sample's placeholder credentials; the operator types real ones at the provision prompt. They reached .env and the injected migration connection, but any migration that opens its own connection still read the placeholders and failed with "role your_database_user does not exist". Low risk: installer-only; nothing changes when .env already held real credentials.

Key Highlights

ApplicationContext::forgetConfig()

Migration Notes

  • No action required. Installed hosts are unaffected; fresh installs stop failing at migrate when credentials are entered at the prompt.
composer update glueful/framework

v1.83.1 - Alnilam

Released: September 8, 2026

Patch: production recommendations stop spamming the error log and stop degrading health. PHP-FPM boots the framework on every request, so each applicable [security] RECOMMENDATION (an empty CSP_HEADER, for instance) landed in the error log on every hit, and the health service folded the same recommendations into a warning status that monitors alerted on. Both were advisory information presented as trouble. Low risk: logging and one optional payload key.

Key Highlights

RecommendationLog: once per boot cache

Health: advisory stays advisory

Migration Notes

  • No action required. The next boot after updating logs the current recommendations one more time, then stays quiet until they change. Monitors that alerted on the warning status for recommendation-only hosts go quiet.
composer update glueful/framework

v1.83.0 - Alnilam

Released: September 8, 2026

Minor: CSP_HEADER now does what its name says. The variable shipped in every .env.example and was recommended at production boot, yet nothing in the framework read it. From this release a non-empty value is sent verbatim as Content-Security-Policy on every response that does not already carry a policy, and the new CSP_REPORT_ONLY=true switches it to the report-only header. Moderate risk only for hosts that had already set the variable: review the value before upgrading. Empty stays a no-op.

Key Highlights

One chokepoint, precedence to the response

CSP_REPORT_ONLY and an honest boot message

Migration Notes

  • Empty CSP_HEADER (the shipped default): no action.
  • Non-empty CSP_HEADER: it will start being sent. Test it with CSP_REPORT_ONLY=true first; a policy written for a different app can block inline styles or third-party embeds.
  • Mirror CSP_REPORT_ONLY=false into your .env.example if you keep one.
composer update glueful/framework

v1.82.3 - Alnasl

Released: September 7, 2026

Patch: the php -S … router.php quickstart serves deep links under a mounted SPA. With public/admin/index.html present, PHP's built-in server resolved /admin/setup to that directory index (SCRIPT_NAME=/admin/index.html, PATH_INFO=/setup), Symfony inferred /admin as a base path and stripped it, and every admin deep link or reload 404'd locally — while nginx and Apache served them. Low risk: local development only.

Key Highlights

router.php presents the front controller like a real web server

Migration Notes

  • No action required. Restart any running php -S after composer update.
composer update glueful/framework

v1.82.2 - Alnasl

Released: September 7, 2026

Patch: a mounted SPA's index.html gets a document Content-Security-Policy, not the static-asset one. SpaMountController applied SecurityHeaders::defaultStaticAssetHeaders() — whose style-src 'self' forbids inline styles — to the HTML document as well. A built front-end injects style elements at runtime, so the served app lost those styles: a primary button with no background, in every environment. Low risk: behaviour-restoring.

Key Highlights

SecurityHeaders::defaultDocumentHeaders() and the csp mount option

Migration Notes

  • No action required. If you had worked around the missing styles with a custom header in front of PHP, remove it; the framework now sends a correct document policy itself.
composer update glueful/framework

v1.82.1 - Alnasl

Released: September 7, 2026

Patch: boot-time re-pins reach the compiled container. A provider that re-binds a service after the container is built ($this->app->load([...]) in boot()) used to guard on instanceof Glueful\Container\Container, which the compiled container is not. With 1.82.0 making compilation succeed, such re-pins silently no-op'd in production and the service reverted to the compiled binding. Low risk: behaviour-restoring.

Key Highlights

RebindableContainer

Migration Notes

  • If a provider guards a boot-time load() with instanceof Glueful\Container\Container, change the guard to instanceof Glueful\Container\RebindableContainer — otherwise the re-pin skips the compiled container in production.
  • Optional constructor dependencies (nullable or defaulted) absent from the container now resolve to their default / null under the compiled container, exactly as at runtime.
composer update glueful/framework

v1.82.0 - Alnasl

Released: September 7, 2026

Minor: the compiled container finally engages, and a never-installed production checkout boots quietly. Every production boot used to log [Container][WARNING] container compilation failed and fall back to the runtime container — the framework's own core factories were all "unsupported" by the compiler. Static factories now compile to direct calls, closure factories and live objects such as the ApplicationContext are handed in after construction, and the artifact lives under the app's storage/cache/container. Separately, a checkout that has not been installed yet (no security keys) skips the boot-time security validation and resolves extensions live once, writing the cache, instead of failing with "Extension cache missing". Moderate risk: production runs a different (faster) container implementation from this release on; installed hosts are otherwise unchanged.

Key Highlights

Compiled container, hydrated at boot

First run bootstraps itself

Migration Notes

  • Compiled container now active in production. If something behaves differently only in production, set APP_DEBUG=true to compare against the runtime container and report it. Delete <app>/storage/cache/container/ to force a fresh compile.
  • Recompile a container:compile artifact built before 1.82.0 once — it is still loaded but carries no runtime values.
  • FORCE_HTTPS unset in production no longer draws a recommendation; unset means enabled.
composer update glueful/framework

v1.81.2 - Alnair

Released: September 7, 2026

Patch: the production command manifest is app-owned and validated. The cached console command list lived in the framework package's own storage/cache, which never exists in a dist install, so every host fell through to one shared /tmp/glueful_commands_manifest.php and loaded it verbatim. A manifest written by an older framework on the same host fed phantom command classes into every production boot: container compilation failed on the unknown class, and resolving the tagged commands threw a 500 out of the console. Low risk: behaviour-restoring, no API change.

Key Highlights

Manifest under the app, validated on load

Migration Notes

  • No action required. On a host that showed Cannot compile autowire definition for unknown class: … at boot, the next production boot after updating rewrites the manifest. Running php glueful commands:clear once removes the old shared temp file explicitly.
composer update glueful/framework

v1.81.1 - Alnair

Released: September 7, 2026

Patch: providers loaded from the extension cache get register() called. discover() used to construct the cached providers and return, so register() ran only on live discovery — never in production, where the cache is mandatory. Console commands and runtime bindings registered there silently vanished on every production boot. Low risk: behaviour-restoring, no API change.

Key Highlights

register() runs on every boot

Migration Notes

  • No action required. If an extension of yours registers commands or bindings in register() and they were missing in production, they appear after this update.
composer update glueful/framework

v1.81.0 - Alnair

Released: September 6, 2026

Minor: the boot profiler dump is opt-in and best-effort. Every boot used to write a hard-coded /tmp/boot_profile.log. On any host where a different OS user had created that file first — a second site, or a CLI run as root followed by one as the site user — the denied write was promoted to a fatal ErrorException by the framework's error handler, and no command (including first-run provisioning) could boot. The dump is now enabled only by BOOT_PROFILE_LOG, and a dump that cannot be written is skipped silently. Low risk: no framework code read the file; minor only because a default changed and an env var is new.

Key Highlights

BOOT_PROFILE_LOG

Migration Notes

  • No action required. If external tooling tailed /tmp/boot_profile.log, set BOOT_PROFILE_LOG=/tmp/boot_profile.log to keep it.
composer update glueful/framework

v1.80.2 - Almach

Released: August 19, 2026

Patch: untouched migration sources classify pending, never divergent. A source with zero receipts whose effects are absent or unverifiable is simply not migrated yet — the healthy state of every disabled extension's schema on a fresh install. Previously it classified Divergent, making migrate:verify exit non-zero on perfectly healthy installs and breaking the documented migrate:run && migrate:verify upgrade chain for hosts shipping disabled engines. Low risk: classification-only.

Key Highlights

AdoptionState::Pending

Migration Notes

  • No action required. If your monitoring keyed on migrate:verify output, disabled engines now read pending instead of divergent.
composer update glueful/framework

v1.80.1 - Almach

Released: August 18, 2026

Patch: the protected migration lane can record its own operation on PostgreSQL.extension_operations.operation was created as string(16), but 1.80.0's migrateProtected() writes protected_migrate (17 chars) — a hard 22001 truncation error on PostgreSQL that SQLite-based tests never saw. The column is now 32 wide, with a width tripwire test pinning every operation and status value against the declared DDL.

Migration Notes

  • A database provisioned on exactly 1.80.0 reports the create migration Divergent (its checksum changed) — re-provision, or widen the column and update the recorded checksum by hand.
composer update glueful/framework

v1.80.0 - Almach

Released: August 18, 2026

Minor: schema custody closure — provision, protected providers, and host-enforced manifests complete the schema-on-enable program. Installer provision now applies the app path and every manifest core descriptor in one locked custody sequence; protected providers get their own migration lane on the shared executor; and hosts can opt into refusing undeclared package schema. Breaking for any host still leaning on 1.79's legacy seams (none are known to exist): manifest declaration is unconditional, and the beta-era legacy-alias receipt machinery (including migrate:normalize-receipts) is gone — no supported installs carry pre-manifest ledgers.

Key Highlights

Provision is a complete locked pass

A migration lane for protected providers

Manifest declaration is unconditional

Migration Notes

  • Declare every installed Glueful package's schema (descriptors or "migrations": "none") before upgrading — an undeclared package's provider now throws at migration-path registration. First-party packages all declare as of this release.
  • If you used beta-era pre-manifest ledgers: migrate:normalize-receipts and the legacyAliases descriptor field are removed. Re-provision, or rewrite ledger source values by hand before upgrading.
composer update glueful/framework

v1.79.1 - Alkaid

Released: August 18, 2026

Patch: tolerant index drops no longer poison the per-migration transaction.SchemaBuilder::dropIndex() has always swallowed a failed drop, but under v1.79.0's per-migration transaction the errored statement aborted the whole transaction on PostgreSQL (25P02) and failed every later statement — surfaced by fresh-chain migrations that defensively drop-then-recreate an index. dropIndex now emits DROP INDEX IF EXISTS on PostgreSQL and SQLite, so a missing index is a no-op instead of a transaction abort. Schema-internal; no API, env, or config changes.

Migration Notes

  • composer update glueful/framework — nothing else.
composer update glueful/framework

v1.79.0 - Alkaid

Released: August 17, 2026

Minor: schema-on-enable — extension enablement becomes a migrate-first, lock-serialized operation with a truthful record. Manifest migration descriptors (extra.glueful.migrations) are now the sole schema inventory, and extensions:enable/disable (CLI and HTTP alike) drive one bootstrap-ordered executor: dependency dry-resolve, source-scoped locks, migrations first, checksum-verified readiness, enabled state written last, terminal state persisted in a core-owned extension_operations ledger. Moderate risk with one required upgrade step: run php glueful migrate:run once after updating, before any extension enable — the executor refuses until the new core operation ledger exists. Undeclared legacy packages keep booting and migrating globally, but the new enable/readiness/adoption operations fail closed on them.

Key Highlights

Manifest migration descriptors as the single schema inventory

The enable executor and the operation ledger

Checksum-driven readiness, receipt normalization, and verifier-gated adoption

Migration Notes

  • Required, once, before any extension enable: run the core migration that creates the operation ledger — the executor refuses with SchemaNotBootstrappedException until it exists.
  • Package authors: declare extra.glueful.migrations (or "none") in your manifest; extensions:enable now refuses undeclared packages with the manifest remedy. Undeclared packages still boot and migrate via legacy global migrate:run.
  • Global runs are policy-scoped: migrate:run skips disabled on_enable descriptors and validates explicit file arguments against scope before any DDL.
composer update glueful/framework
php glueful migrate:run

v1.78.4 - Alioth

Released: August 17, 2026

Patch: the lazy-ledger contract completes v1.78.3. That release deferred database work in the three migrate commands, but every extension provider still constructed MigrationManager at boot via loadMigrationsFrom() — and its constructor connected and ran version-table DDL, creating the migrations table as whatever role .env named. The manager now resolves its connection on first database operation: only migrate() creates the ledger, status and pending reads treat a missing ledger as zero applied migrations, and rollback() reports nothing-to-rollback. Migration discovery and registration perform zero database work, and read-only operational commands work with read-only credentials. Migration-internal; no API, env, or config changes.

Migration Notes

  • composer update glueful/framework — nothing else.
composer update glueful/framework

v1.78.3 - Alioth

Released: August 16, 2026

Patch: the console works before the database does. migrate:run/rollback/status resolved their migration manager — which connects and runs version-table DDL — at console registration, so every glueful command required a reachable database just to list commands: exactly the state a first-run provisioning flow exists to repair. Resolution now happens on first use, pinned by a refusing-container regression test. Console-internal; no API, env, or config changes.

Migration Notes

  • composer update glueful/framework — nothing else.
composer update glueful/framework

v1.78.2 - Alioth

Released: August 15, 2026

Patch: the Rector experiment concludes — value harvested, tool retired. Every parent-class method override in the framework now carries #[\Override], so signature drift against a parent fails at parse time, and the long-dead setAccessible(true) reflection calls (no-ops since PHP 8.1) are removed. Rector itself — the dev dependency, its config, and the composer scripts — is retired: its dry-run surface held zero bugs on an already-modern PHP 8.3 codebase whose correctness is enforced by PHPStan level 8 with no baseline and a 2,100+ test suite. Internal-only: no API, env, config, or behavioral changes for applications. Low risk.

Migration Notes

  • Nothing to do: composer update glueful/framework picks up the patch; no application-facing changes.
  • Framework contributors: composer rector/rector:fix no longer exist. For future PHP-version or PHPUnit major migrations, install Rector ad hoc — that episodic use is its sweet spot.
composer update glueful/framework

v1.78.1 - Alioth

Released: August 14, 2026

Patch: API documentation now generates with the route cache in place. A leftover storage/cache/routes_dev.php made generate:openapi abort with Route name '…' already exists — the generator's cache-detected reset replayed every route registration onto a router whose named-route registry boot had already populated. The reset is gone; generation relies on the manifest's idempotent load, and a cache-populated run now produces a byte-identical document to a cache-free one. Low risk: generation-only, runtime routing untouched.

Migration Notes

  • composer update glueful/framework — no config or code changes; the old "delete the route cache before generating" workaround is no longer needed.
composer update glueful/framework

v1.78.0 - Alioth

Released: August 12, 2026

Credentials in URL paths stop reaching the logs. Redaction has always been keyed on parameter names — query strings and body fields — but a secret carried in the path itself (signed payment links, magic links, one-time download URLs) was logged verbatim by the request logger at info level and by the exception handler at error level in every profile. Applications can now register credential-bearing route templates and have the secret segment masked in every framework log sink. Moderate risk: one new config key (logging.sensitive_paths) and env var (LOG_SENSITIVE_PATHS); with the default empty list, every path is logged byte-identically to 1.77.0.

Key Highlights

Configurable sensitive path redaction

Every framework path sink swept

Migration Notes

  • No action required for apps without credential-bearing paths: the default pattern list is empty and log output is byte-identical.
  • Apps issuing tokened URLs: register the templates — 'sensitive_paths' => ['/checkout/pay/{token}'] — without any base-URL prefix.
  • Redaction covers framework log sinks only: reverse-proxy, web-server and CDN access logs still record the raw request line and remain the operator's responsibility.
  • Exception messages that interpolate a URI are still logged verbatim — put the URI in the exception context (redacted), not the message (see docs/SECURITY_NOTES.md).
composer update glueful/framework

v1.76.0 - Algol

Released: August 8, 2026

The complete database-layer roadmap in one release — the native alternative to Doctrine DBAL. Database failures are now typed (\PDOException-rooted hierarchy, so every existing catch keeps working), retries run on one honest, configurable budget shared between deadlocks and connection losses, SQLite alterations are fail-closed (six paths that silently did nothing now really execute via audited atomic rebuilds, or throw before mutation), and connections recover — provably-uncommitted transactions replay after reconnection, while commit-ambiguous losses are never replayed. Moderate risk: new env keys, three interface additions for external implementors, and SQLite migrations that previously "passed" by doing nothing now take effect or fail loudly.

Key Highlights

Typed database exceptions

SQLite alterations are fail-closed

Reconnect resilience

Migration Notes

  • Applications: composer update glueful/framework; optionally tune DB_RETRY_MAX_ATTEMPTS/DB_RETRY_BACKOFF_MS.
  • Audit SQLite-targeting migrations that modify/drop columns or foreign keys: their intent now actually applies (or fails loudly) instead of silently passing.
  • External implementors of framework interfaces: TransactionManagerInterface::transaction() gained an optional ?RetryBudget param; SchemaBuilderInterface gained executeSqliteRebuild() and executeSqliteNativeAlteration(); TableBuilderInterface gained rename().
  • Connection::transaction() retry tuning moved to config — setMaxRetries() still governs direct TransactionManager use only.
  • Replay callbacks must build query chains inside the callback from the supplied connection; prebuilt builders retain the stale PDO.
  • Code that retried on commit-phase ConnectionLostException was risking duplicate commits — it now sees CommitOutcomeUnknownException (still a PDOException subclass); audit any such handler.
composer update glueful/framework

v1.75.0 - Algieba

Released: August 7, 2026

The whole framework now type-checks at PHPStan level 8 with zero suppressed errors. A 31-area campaign cleaned 914 errors of typing debt, raised the CI gate from level 6 to level 8 over src/ and config/, upgraded the engine to PHPStan 2.x, and finished by fixing all 111 baseline entries and deleting the baseline file. Along the way the sweep surfaced and fixed genuinely latent bugs — a reachable orHas() fatal, auth request attributes that were always null, an unreachable soft-delete branch. Moderate risk: the diff surface is wide, but every area landed behind the full test suite and the few contract-visible changes are listed in the migration notes.

Key Highlights

Level 8 everywhere, with no baseline

The sweep fixed real bugs, not just annotations

Honest contracts and hardened edges

PHPStan 2.x engine and advisory Rector

Migration Notes

  • Applications: composer update glueful/framework is enough — no new env vars, config keys, migrations, or default changes.
  • If you implement WhereClauseInterface (rare): add the orWhereRaw() method.
  • If you subclass ORM relation classes: parents/related instances are typed Model, not object.
  • If you catch around toJson(): unencodable payloads now throw a named error instead of returning false.
  • Installs with an empty query-cache keyPrefix get the intended default prefix — the query cache re-keys once after upgrade (one round of cache misses, not an error).
  • Contributors / CI forks: the analysis gate is now level 8 with no baseline file.
composer update glueful/framework

v1.74.1 - Algenib

Released: July 30, 2026

Session enumeration no longer recurses into itself. Listing, counting, or bulk-managing a user's sessions through the container-resolved session store triggered an unbounded mutual recursion between SessionStore::listByUser() and the cache manager's findUserSessions() — each deferred to the other with no base case — and exhausted memory. The common login, logout, and refresh flows operate on a single session by token and were never affected, which is why it stayed latent. A pure bugfix, low risk.

Key Highlights

Cache-index enumeration is the manager's sole authority

Migration Notes

  • Nothing to do: a pure bugfix with no API, config, or schema change. Any feature that lists or bulk-manages a user's sessions simply stops exhausting memory.
composer update glueful/framework

v1.74.0 - Algenib

Released: July 30, 2026

Username validation now matches the column, not a product rule. UsernameDTO and UserDTO accepted 3–30 characters, which quietly ruled out a whole category of application: one that uses a normalized email address as the username. Plenty of valid addresses exceed 30 characters. The framework now enforces only storage-safe invariants — required, trimmed, at least 3 characters, within the varchar(255) column, unique — and leaves narrower policies to the applications that actually know what their usernames are for. Strictly more permissive, no schema change, nothing previously valid becomes invalid.

Key Highlights

Storage-safe invariants in the framework, product rules in the app

Migration Notes

  • Strictly more permissive: every username that validated before still validates. No migration — the column has always been varchar(255).
  • If your application relied on the framework rejecting usernames longer than 30 characters, add that rule at your own input boundary; it is no longer enforced centrally.
composer update glueful/framework

v1.73.0 - Algedi

Released: July 29, 2026

Browsers get a first-class transport, and CSRF finally binds to the session. An opt-in HttpOnly cookie session now sits alongside the unchanged bearer path: one middleware adapts a cookie into the header auth already reads, one issuer owns every cookie attribute, and one login orchestrator means no transport can reach session issuance around the two-factor gate. Shipping alongside it is a security fix the transport depends on — CSRF tokens were binding to an IP + User-Agent fingerprint for every authenticated request, not to the session. The transport is off by default and bearer behavior is byte-identical, but the CSRF fix invalidates tokens held by authenticated callers at upgrade time. Read the migration notes before upgrading.

Key Highlights

Opt-in HttpOnly session cookies, without touching bearer auth

One login path, one two-factor gate

Session refresh and logout that never leak tokens

CSRF tokens bind to the session, not a fingerprint

Migration Notes

  • CSRF tokens issued to authenticated callers before this release stop validating. There is no compatibility window and no automatic recovery: an affected client receives a 403 and must fetch a new CSRF token or reload the page. Old fingerprint-keyed cache entries expire on their own. Unauthenticated forms are unaffected.
  • The browser session transport is opt-in and off by default. No action is required to keep bearer-only behavior; bearer extraction, POST /auth/login and its JSON response, /auth/refresh-token and /auth/logout are all unchanged.
  • To enable it, set SESSION_COOKIE_ENABLED=true and add session_cookie before auth on the routes that should accept cookies (session_cookie:optional for pages that must survive a lapsed session). See docs/BROWSER_SESSIONS.md.
composer update glueful/framework

v1.72.1 - Alderamin

Released: July 26, 2026

Activation writes now recompile the extension cache from what was just written. Every activation surface runs a read→write→recompile sequence in one process: reading the enabled list primes the context config cache, ExtensionStateWriter mutates config/extensions.php, and the recompile previously resolved through the stale cache — persisting the PRE-write activation state. A just-enabled provider could be missing from the compiled cache; a just-disabled one could remain. Pure fix — upgrade and run.

Key Highlights

No-arg writeCacheNow() resolves from current file state

Migration Notes

  • No new env vars, no migrations, no default changes, no API changes.
composer update glueful/framework

v1.72.0 - Alderamin

Released: July 26, 2026

Three additive extension seams: one provider order, one provider owner, one activation gatekeeper. A declarative cross-phase load-order contract shared by container compilation, discovery, cache generation, and cached boot; type-agnostic provider-to-package attribution so app-integrated provider packages keep honest managed_by; and a extensions.protected guard that makes generic enable/disable refuse providers owned by domain lifecycle flows. Hosts adopting none of the new contracts see byte-identical behavior — upgrade and run.

Key Highlights

One declarative provider order for every phase

Provider ownership survives any package type

Protected providers refuse generic toggles

Migration Notes

  • No action needed: the new config key defaults to [] and all three seams are inert until adopted. If you ship a lifecycle-managed extension (e.g. glueful/tenancy runtime enablement), declare it in extensions.protected so generic toggles can no longer corrupt its state machine.
composer update glueful/framework

v1.71.3 - Alcor

Released: July 25, 2026

Console fix: extension-discovered commands no longer run in a parallel, never-booted world. Commands discovered from extensions (rather than registered as container services) were instantiated bare, which sent BaseCommand down its no-args path — a fresh ApplicationContext plus a fresh container in which extension boot() never ran. Those commands silently operated without capabilities, boot-registered contributors, or event listeners, so a CLI run could see (and write) different state than the running application. Pure fix — upgrade and run.

Key Highlights

Discovered commands receive the real booted container and context

Migration Notes

  • No new env vars, no migrations, no default changes, no API changes. If you ship extension commands, they now observe the same booted state as HTTP requests — remove any workarounds that re-registered boot-time state inside command constructors.
composer update glueful/framework

v1.71.2 - Alcor

Released: July 22, 2026

Follow-up fix: non-pooled connection reuse is now scoped to framework-managed connections. 1.71.1's identity-keyed PDO reuse could collapse an intentionally independent, hand-built new Connection([...]) into the framework's shared session when their configs resolved identically (typical in CI) — turning session-level semantics (advisory locks, open transactions) into self-interactions and deadlocking race-style code. Reuse now requires the constructor's ApplicationContext; context-less constructions always get a fresh backend. The 1.71.1 leak fix is fully preserved. Pure fix — upgrade and run.

Key Highlights

Ad-hoc new Connection([...]) always gets its own backend again

Migration Notes

  • No new env vars, no migrations, no default changes, no API changes. If you construct Connection directly and want the shared framework backend, pass the ApplicationContext as the second constructor argument; without it you get an independent session.
composer update glueful/framework

v1.71.1 - Alcor

Released: July 22, 2026

Two runtime bugfixes: non-pooled connection reuse and OPcache-off route-cache warmup. Without pooling, Connection leaked a database backend per instance — enough short-lived containers exhausted the server's connection ceiling ("too many clients"). And route-cache warmup threw on every boot when OPcache was loaded but disabled. Pure fixes: no new env vars, no migrations, no default changes, no API changes.

Key Highlights

Non-pooled Connection no longer leaks a backend per instance

Route-cache warmup no longer throws when OPcache is loaded but disabled

Migration Notes

  • No new env vars, no migrations, no default changes, no API changes. Both are internal runtime fixes; upgrade and run.
composer update glueful/framework

v1.71.0 - Alcor

Released: July 20, 2026

Outbound-webhook security & reliability seams: strict event dispatch, an SSRF-safe outbound-target resolver, and hardened API-key rotation. Three additive, application-agnostic building blocks extracted while hardening the commerce marketplace's seller webhooks. No new env vars, no migrations, no default changes. One behavioral note: API-key rotation no longer extends a predecessor's expiry (see Migration Notes).

Key Highlights

EventService::dispatchOrFail() — strict, at-least-once event dispatch

SafeOutboundTargetResolver — one SSRF-safe URL → validated, IP-pinned target

Hardened ApiKeyService::rotate()

Migration Notes

  • API-key rotation no longer extends a predecessor's expiry. Before 1.71.0, rotating a key with a grace window could push a superseded key's expires_at later than its original value; it now takes the earlier of the two. If you relied on rotation to lengthen an old key's lifetime, issue a fresh key instead. Otherwise no action is required — the new new_uuid field is purely additive.
  • No new env vars, no migrations, no default changes. The event and HTTP additions are opt-in seams; dispatch() and the existing safeRequest*() SSRF behavior are byte-identical to 1.70.x.
composer update glueful/framework

v1.70.0 - Albireo

Released: July 16, 2026

A blob-policy composition seam plus two long-standing database fixes. Extensions can now contribute blob access policies simultaneously through BlobAccessPolicyRegistry; whereIn() works on update()/delete(); and createTable() plain indexes are no longer silently discarded on SQLite/PostgreSQL. Additive API, no new env vars, no migrations. One operational note for pre-existing SQLite/PostgreSQL dev databases (see Migration Notes).

Key Highlights

Blob access policy composition — BlobAccessPolicyRegistry + CompositeBlobAccessPolicy

whereIn() / whereNotIn() on write operations

createTable() plain indexes on SQLite/PostgreSQL

Migration Notes

  • SQLite/PostgreSQL databases migrated before 1.70.0 are missing every plain index declared inline in a createTable() callback — they were silently discarded. Fresh migrations are correct automatically; for existing databases, re-run the relevant CREATE INDEX statements or re-migrate dev databases. Performance-only: data and query results were never affected.
  • No other action required — the registry seam is additive, and the whereIn() write fix turns a previously throwing call into the behavior its builders already advertised.
composer update glueful/framework

Older releases (v1.69.0 and earlier) live in the Release Archive. For the full machine-readable history see the CHANGELOG.