Resolves conflict in app/init/constants.php (kept 4327 cache buster, took 1.9.4 stable version).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
target stores free-form URLs or resource IDs. URLs in the wild can
exceed the prior 2048-char cap, so switch the column to VAR_TEXT
(65535). The _key_project_target index already declares an explicit
700-char prefix length, so indexing still works on both MariaDB and
MongoDB.
Bump APP_CACHE_BUSTER for the schema change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Switch markdown summaries, JSON CTA params, and the embedded
insights/ctas subQuery payloads from sized VAR_STRING to VAR_TEXT.
None of these fields are indexed and they all hold free-form data, so
removing the artificial size cap means we never have to revisit the
limit when an analyzer surfaces a longer report.
- reports.summary, insights.summary: markdown, no upper bound enforced
- reports.insights, insights.ctas: subQuery virtuals carrying full
child rows
- insightCTAs.params: JSON parameter blob for arbitrary CTA actions
Bump APP_CACHE_BUSTER for the schema change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Register dedicated reports.write scope and switch deleteReport to it
so cloud can issue narrowly-scoped delete keys without granting
insights.write.
- Make insights.parentResourceInternalId optional with null default to
match its companion parentResourceType/parentResourceId fields and
unblock insights with no parent (e.g. database-level performance
insights).
- Tighten Insight.reportId model description: insights always belong to
a report, ad-hoc insights are not supported.
- Add reports.write to default test API key and admin role so existing
e2e tests using serverHeaders() can hit the delete endpoint.
- Bump APP_CACHE_BUSTER for the schema change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Migration lib's `_databases.database` resolver now defaults to empty
when no callable is supplied (utopia-php/migration ff3b444). The
runtime falls back via `$project->getAttribute('database')`, but tests
hit DSN("mysql://") and a 500 because that fallback is also empty for
fresh test projects.
Pass an explicit resolver returning the destination project's `database`
attribute so migrated databases store a usable DSN.
testCreateRedirectRule reassigned $ruleId for the second redirect rule,
so only the second was tracked, and cleanupSite was called before
cleanupRule. Site deletion cascades to its rules, so cleanupRule then
saw a 404 and the strict assertEquals(204) blew up.
Track both rule IDs and tear them down before the site so the asserted
204 actually fires.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
testReadWithAdvisorScopes called getNewKey() as its first action, but
getNewKey reads self::$project['$id'] without triggering project
creation. ParaTest runs each test method in a fresh worker, so
self::$project is empty until getProject() is called. The empty id
produced /v1/projects//keys, which doesn't match any route and 404s.
Call getProject() first, like every other consumer of getNewKey.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The reports `_key_project_target` index was failing to create on MongoDB
because target's full size (2048) plus targetType (64) exceeded the 1024
character maximum. Set explicit lengths to truncate target to 700 chars
(total 765, under both Mongo 1024 and MariaDB 768 limits).
Also drop redundant explicit lengths from VAR_ID positions in the
insights and insightCTAs indexes — the validator rejects explicit
lengths on VAR_ID attributes, and they default to length 1 anyway.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Only call crop() when dimensions > 0 or gravity differs from center
- Only call setOpacity() when opacity !== 1.0 (was always called due to !empty(1.0))
- Only call setBorder() when borderWidth > 0
- Only call setBorderRadius() when borderRadius > 0
- Only call setRotation() when rotation !== 0
- Add Span::add() with actual values inside each transform condition
- Leave output() unconditional (format conversion always applies)