Skip to main content

Brand kit release checks

The API and console are deployed to production; acceptance is partial as recorded below. Signed-in management and MCP read/edit checks pass; deployed font/media, provider and export checks remain incomplete. The local browser fixture uses real API routes, auth, database, validation and translation, with simulated storage, font cooking and extraction. Its successful callbacks and queued render payloads do not prove a deployed farm render, CDN access, TasteLabs timing or a commercial licence. Defaults: BRAND_KIT_MIN_PLAN is unset, BRAND_EXTRACTION_PROVIDER=framelane, and PDF import is deferred. The user has confirmed the signed embedding Order is obtained and filed; no contract or filing location was independently inspected. TasteLabs remains disabled in production pending its deployed acceptance checks and an explicitly authorized provider rollout. Do not treat the plan’s historical farm commit or deployment document as proof of the currently deployed image.

Current production status (2026-10-30)

The user explicitly requested merge, deploy and test again. That authorization superseded the earlier manual-GCP restriction for this release. API PR 59 and console PR 18 were merged and deployed. The deployment evidence records:
  • Initial API merge commit 65958eb803846aa5019b4507de6e6384ad61535d; Cloud Build 945b251b-e8c1-4ee2-8c01-f2d3ce867e55 succeeded with image digest sha256:304b8d2649ed1555194ada525a0042b3a95dcfa72528bc0c3e31fcc4da111b84.
  • Migration execution framelane-migrate-hdqpd succeeded from 0022 through 0025. Initial Cloud Run revision framelane-api-00115-5l7 was deployed before the hotfix below.
  • API hotfix PR 61 merged as 06ec2578808c8781e62e4fd71e1608b95f01fa62. Cloud Build 2229c81b-dc97-4c1d-9f08-65e1cc246c1a succeeded with image digest sha256:e96913109507cc35a3cb02ead1745871c3dc8456d600eaf4853e6651e480d8d5. Revision framelane-api-00116-k8t now serves 100% of traffic. No further migration was required beyond 0025.
  • Console merge commit 53007cde3162d9ee76b2480fd64e6cea6c2f2f5f; Vercel deployment dpl_BY6oUDaM4wH8PHztdfa2EsiuTsgf was promoted to https://framelane.io.
  • API health and readiness returned HTTP 200, with database and Redis healthy. Live OpenAPI exactly matches the committed schema’s 59 paths. Three checked new feature routes exist and reject unauthenticated requests with HTTP 401.
  • An HTML request to https://framelane.io/brand-kit returned HTTP 307 to /login, confirming the signed-out Clerk boundary. A non-HTML unauthenticated request can return 404 as authentication behavior; it is not evidence that the deployed page is absent.
The initial signed-in test saved a name and colour, then exposed a reload HTTP 500: the parameterized ON CONFLICT predicate could no longer infer the partial unique index when PostgreSQL reused a generic prepared plan. The failure was reproduced against a disposable real PostgreSQL database. The hotfix uses the same static predicate as the migration, while keeping user data parameterized. Its 31 focused checks pass, including four real PostgreSQL checks and 21 generic plan insert/reload executions that preserve one kit and its manual edits. Main CI run 41035828066 passes 4,190 tests with 18 skips and all 10 upload-panel tests; the image spec check confirms 59 OpenAPI paths. Signed-in browser acceptance passed at 09:58 UTC after the hotfix:
  • Eight concurrent workspace-kit reads returned one kit. An unsupported font/woff2 upload request returned 422 unsupported_content_type without creating a font row or starting work.
  • Rename/reload/restore and colour add/remove/reload/re-add/cleanup passed. The empty font UI rendered, and an empty project’s Brand panel showed the persisted swatch and management link without changing its scene.
  • There were no page errors or forbidden request attempts. Render and task lists were empty before and after; extraction usage stayed zero. No media/font bytes, cooking, extraction, preview, thumbnail or render submission was exercised.
The live MCP endpoint initialized with 31 tools. get_brand_kit and edit_brand_kit succeeded, REST independently verified persistence, and 20 repeated MCP reads succeeded. Initial values were restored. No MCP upload, extraction or render calls were made. A generated Clerk identity using a reserved example.com address with Null MX 0 . completed authentication and workspace sync; the earlier .invalid rejection was not a blocker. The generated workspace and Clerk user were deleted, and the test API key returned HTTP 401 afterward. The existing real user account was untouched. Temporary credentials and browser-state files were removed. At 09:59:16 UTC, the final bounded log checks returned zero error entries for API revision framelane-api-00116-k8t and zero console errors after the fix at 09:52:02 UTC; the console log query exited successfully. The renderer group was stable at target zero and the instance list was empty. This records the checked revision and time window, not an assertion about all historical or future logs. Licence evidence is user confirmation: the user instructed us to consider the signed embedding Order obtained and filed. No contract or filing location has been independently inspected. The historical three-site live captures below remain complete. Capacity and spending constraint: the user instructed us not to restore GPU capacity because of cost. Capacity was briefly requested at one and immediately returned to zero; the stable target is zero and the instance list was confirmed empty. No font-processing, render or paid-provider jobs were submitted during this deployment verification. Keep BRAND_EXTRACTION_PROVIDER=framelane, do not restore capacity, and do not repeat paid captures. Deployed font cooking, farm image inspection, new cooked-font CDN/browser checks and completed video exports remain unproved and must wait for renewed authorization and available capacity. The completed management and cleanup checks do not establish uploaded-object cleanup, retained-font rendering, provider flow or alert delivery. Those checks remain outstanding; deployment alone does not prove them.

Historical production authorization and preflight (2026-10-29)

This section records the state before the 30 October deployment. Its deployment and permission limitations are superseded by the current status above. The user authorized production for the remaining acceptance checks. Use https://api.framelane.io and a dedicated disposable acceptance workspace once the feature is deployed. This replaces the earlier staging-only requirement for kit, font, CDN and export checks. It does not enable TasteLabs for customers or change the render-node instruction that the user runs every GCP command. The read-only production probe found API commit d0508d459335c6b8d9b75aee0544829eb89cfd40. Its OpenAPI schema has only the older /v1/brand-kits and /v1/brand-kits/{brand_kit_id} routes; workspace-kit and font routes are absent. https://framelane.io/brand-kit returns 404. The app.framelane.io and console.framelane.io example hosts do not resolve from this executor. Both feature PRs remain open drafts. Deploying the reviewed API and console is the next prerequisite; no production writes were performed during this preflight. The version response reports renderer SHA 5bc7a6f5a2cb17092a69d775dcbd1699eda34d5a, taken from the latest completed or cancelled render callback. This is useful provenance for that callback, not proof of the currently running image or all active farm versions. After deployment, use a new controlled acceptance email for POST /v1/signup and /v1/signup/verify, or a separate Clerk test identity. Do not call signup with an existing customer’s email: it rotates their keys and resets email verification. A Clerk identity with the same verified test email can adopt that workspace. Store its API key privately as FRAMELANE_API_KEY; record and verify the dedicated workspace ID with GET /v1/workspace before mutations and cleanup. Do not use the existing connected workspace for destructive acceptance tests.

Live provider evidence (2026-10-29)

A user-supplied test key completed the three planned provider captures with one submission per site: framelane.io in 180.019 seconds, stripe.com in 6.180 seconds, and linear.app in 6.158 seconds. Linear’s page and a fingerprinted Next CSS asset were independently fetched. All three reached completed within five minutes. TasteLabs reported two credits for each submission, including the Stripe and Linear cache hits: six credits total. Free list/result reads recovered only these submissions for asset verification; no additional extraction was submitted. The live report links the sanitized envelope sequences, elapsed times, response status counts and stylesheet proof. The real shapes exposed nested typography.*.variants, semantic button-radius labels, Primary logo roles and a brand colour also used for text. Mapper regressions now preserve those values. Offline API persistence tests replay each recorded shape, preserve manual name/heading edits, store the detected body font and reuse the same URL without a second submission. All three sites returned mirrored logos on sb.engine.thetaste.ai. One logo from each was fetched through the actual DNS-pinned, byte-limited logo proxy: a PNG for FrameLane and sanitized SVGs for Stripe and Linear. That exact host is the tested storage allowlist candidate. Stripe also returned two direct URLs on images.stripeassets.com; those are source-site assets and were not added to the provider-storage allowlist. No signed URL, raw provider asset path or credential is included in the evidence. The key was used only for this local test run. These are live provider and proxy checks from the local executor. They do not prove a deployed provider API/console flow, concurrent deployed pollers, alert delivery, a completed video, or the signed embedding Order. The Order’s current status is the user confirmation recorded above; the remaining deployed checks are listed below, and the production provider default remains framelane.

Local cooker evidence (2026-10-28)

The machine-readable proof pins the cached amd64 image, cooker source and binary hashes, generated input hashes, metadata hashes and actual chunk hashes. This used image sha256:6f7fb604936a93df5cdf36a4c18136fedb3f3926db3e739e60671c1e7ab37b7c (tagged git-sha-90682fd1ccdee625324359c10e2e49e7feaab288; that tag does not establish the currently deployed farm revision). A generated TTF with a nonempty glyf outline and a generated OTF with a nonempty CFF outline both ran through the image’s real process_user_font.py and legacy slugfont binary. They completed in 1.340 s and 1.311 s respectively, each writing V3 metadata and one 2,364-byte .slug chunk. The API’s actual validate_font and verify_font_objects accepted both; the latter read the real output files through a local signer shim, with no GCS requests. These tiny synthetic inputs establish format and output-contract compatibility, not a full-font latency guarantee. The containers used the explicit font-tool Python entrypoint, --network none, --read-only, --cpus 1, --memory 512m, --pids-limit 64, --cap-drop ALL and no-new-privileges. Only generated inputs and a temporary output directory were mounted. No renderer worker, GPU, credentials or cloud connection was used. The deployed callback, CDN and rendered-frame gates below remain outstanding.

Local Claude Code evidence (2026-10-28)

The S4 client proof records a real Claude Code 2.1.312 session over initialized Streamable HTTP on a separate local fixture at 127.0.0.1:8039. Its strict MCP configuration connected only that server; built-in tools and hooks were disabled, and only the four acceptance tools were allowed. All four calls succeeded: get_brand_kit("workspace"), edit_brand_kit, extract_brand_kit into the same kit, and inline font create_upload using a generated TTF. An unauthenticated MCP request returned 401. Independent REST and read-only SQLite checks confirmed one workspace kit, one completed extraction job, preserved manual name/color/heading, filled body font and logo suggestion, and the uploaded font ready after one attempt. Its stored source bytes matched the generated input. The schema-budget suite passed all 16 tests. Reproduction steps use a temporary directory and do not modify the user’s MCP configuration. This closes the plan’s local Claude Code round-trip check. The fixture simulates storage, font cooking, website DNS and TasteLabs; this evidence does not establish Clerk OAuth, deployed callbacks, CDN access, paid extraction or rendered output. The independent real CPU cooker proof above covers actual local cooking.

1. Deployment procedure (completed for the 2026-10-30 release)

The 30 October deployment was executed under the user’s explicit merge/deploy/test authorization; its results are recorded above. The commands below remain the reference procedure, not a request to repeat the completed deployment. The names come from the repository’s production deployment docs; verify them against the existing resources first. Preserve their database, network, service-account and secret configuration. Run from the reviewed, clean API feature checkout, after resolving any review changes. Cloud Build updates :latest as well as the commit tag; the migration and service use the commit tag. Keep BRAND_EXTRACTION_PROVIDER=framelane and BRAND_KIT_MIN_PLAN unset.
Record the current revision before proceeding. Then build, migrate and deploy:
Save the commit, immutable image digest, successful migration revision 0025, and /v1/version response in the release evidence. Migration order is build, migrate, deploy; do not execute the old migration job image. The existing README has infrastructure setup instructions, but do not recreate production resources to resolve a name mismatch. Deploy the console’s exact packed editor rc.24 after the API is ready, then run the farm/browser checks below. Confirm the actual console origin from that deployment before checking CORS.

2. Operator: farm, subscription and CDN evidence (S0/S2)

These checks remain incomplete. The current user instruction is to keep GPU capacity at zero; do not start a worker, upload a font that dispatches processing, or submit a preview/render job to advance them. Read-only subscription metadata can be inspected without restoring capacity. Running-container and new cooked-font checks must wait until the user authorizes capacity again. Use the operator-verified production names. The documented farm MIG below is a starting point, not live deployment evidence. Supply the actual push-subscription names; these read-only commands identify the template and filters:
For the Docker-based farm documented in render-node’s deployment_plan.md, use an instance and its zone returned by the preceding list. The following commands are for the operator to run, not evidence that an inspection has happened:
Inside that VM, list the running containers and select the actual renderer name (render-node in the documented deployment). Inspect only these fields; a full container inspection would also disclose its environment:
Save the instance/zone, container ID/start time, image ID, immutable repository digest and startup gitSha together. The startup marker is emitted by the running binary (src/offlineRenderer/main.cpp), unlike a mutable image tag. If the logging driver does not expose docker logs, retrieve that same marker from Cloud Logging for this instance and container start. If RepoDigests is empty or the source marker is unknown, reconcile the inspected image ID with the build/deployment provenance before declaring this gate passed. Repeat for every active version during a rolling deployment; do not start another worker or substitute the locally cached cooker image for a running instance. Confirm the identified source contains processUserFont (request field 107, response field 108). /v1/version exposes the latest render completion/cancellation callback SHA; it does not identify the current image. Confirm the result push reaches /internal/metadata/complete and its filter permits font results. Confirm object-finalize events reach /internal/gcs/notify. The API’s 60-second font sweep is a fallback for a missing finalize event; it cannot replace a missing farm result subscription. Fix any infrastructure filter using the operator’s normal reviewed change process; do not guess a replacement filter. Upload one licensed TTF and one CFF-outline OTF to the dedicated acceptance workspace using the console. Both must reach ready within two minutes, return a source URL plus chunk metadata, and render a frame showing the chosen face. Save request/attempt IDs, timestamps, the output frame, and farm logs. There must be no Can't process brandkit font ranges error. The API preserves canonical .json and .slug objects under its exact first-party /fonts/ CDN prefix, so metadata and relative chunks retain their public CDN base. Raw /uploads/ font sources still rewrite to storage.googleapis.com for service-account reads. The current farm downloader may itself convert CDN URLs to authenticated storage URLs and fall back to CDN reads; verify both metadata and relative chunks on the deployed farm. If a fetch fails, investigate its credentials/rewrite/CDN configuration; the local fixture cannot validate this path. If CFF fails, restrict upload acceptance to TTF and adjust the UI/docs before shipping rather than advertising unproven OTF. Using URLs from that acceptance upload, test the console’s actual Origin/Referer and a public chunk URL. The response must permit the console origin for sources and public CORS reads for /fonts/:
Also verify a real browser FontFace load; a successful curl is insufficient for browser CORS. Compare preview/export text metrics side by side. Tombstone the font, reload the existing project, and confirm preview and export still use it; it must disappear from the library/picker. A new live face with the same canonical family must take precedence. In the disposable workspace, confirm simultaneous first kit reads return one ID, upload membership appears, and asset/kit/workspace deletes leave no owned rows. Workspace deletion removes source files and the fonts/{workspace}/ prefix; check storage and cleanup logs, including late farm callbacks. Copies owned by another workspace retain their document/history and source kind, with the deleted source reference cleared. Before deleting the test workspace, finish or cancel its outstanding render jobs, save the accepted output and re-check GET /v1/workspace against the recorded test ID. DELETE /v1/workspace removes all its rows, keys and owned files; never run it with an existing customer workspace’s key. Keep this cleanup separate from tombstone testing, which must retain the workspace and saved project until the second export completes.

3. Operator: TasteLabs gates (S3, still separate from production core checks)

Keep trial credentials out of source control and use a separate production key after licensing. The signed Order must cover embedded use, stored mapped results, copying selected logos, rate/concurrency limits, DPA/subprocessor terms, separate environment keys and future PDF support. The plan contains a licence request draft; sending it is a separate user action. A test key was supplied for the 29 October local live checks above. On 30 October the user confirmed that the signed embedding Order is obtained and filed; this is user confirmation, not an independent review of the contract or its filing location. Deployed provider acceptance remains incomplete. Production test authorization does not make a global provider flag workspace-scoped. Keep the shared production API on framelane; no new paid checks are authorized under the current spending constraint. Any later provider acceptance or rollout requires renewed scope for that work. Core browser checks can proceed without changing the provider; font and export checks also require the GPU constraint to be lifted. Run the reviewed spec check and one deliberate fixture capture per approved test site if another capture is required. The three 29 October captures already exist and must not be repeated merely to regenerate fixtures. Each capture command consumes a provider submission; never retry it blindly after an unknown outcome. The script reads TASTELABS_API_KEY from the operator’s environment without printing it and requires a new output directory.
Review new captures before committing them. The 29 October recorded sequences are sanitized real trial captures; older fixtures also cover synthetic cases. The capture anonymizer replaces every HTTP URL with fixture.example, so its saved sequence cannot establish the real storage allowlist. During each authorized capture, inspect the logo URLs in the provider’s response viewer or the controlled test response inspection, and separately save only their non-secret hostnames, the UTC observation time and capture-folder name in the release evidence. Do not save signed URL paths/query strings, headers, keys or raw provider responses. Confirm these are the exact HTTPS hosts serving the returned logos; use the hostname without a scheme, path, port or wildcard in TASTELABS_STORAGE_HOSTS. Do not infer a host from synthetic fixtures or allow all provider subdomains. On an isolated internal deployment, enable tastelabs with the trial key and require all three sites to reach ready within five minutes through the API and console. Verify one apply under concurrent polls, one paid submit per running kit, quota rejection, 24-hour reuse without a new paid submit, usage totals and the provider flag switched back to framelane. Verify logo preview/save produces an owned asset and never injects provider SVG as markup. Only then, with the signed Order filed, approve production provider enablement. Before that enablement, verify delivery of the dispatch-failure alert required by the plan. The application emits brand_extraction.submit_failed at ERROR with job_id and status_code, then attempts the heuristic fallback. A successful fallback must not hide exhausted provider credits. Configure the existing operator-owned log alert using this filter, replacing the service placeholder with the actual isolated test service (and the production service on rollout):
Use the operator’s approved fault-injection method on a dedicated isolated instance to return a controlled dispatch 401, 402 and 5xx from a provider stub; these checks need no real TasteLabs key or paid extraction. For each case confirm the matching structured event, the heuristic fallback result, and delivery to the alert policy’s actual notification destination within its configured evaluation window. In particular, 402 must reach the credit-exhaustion operator. Record the policy ID, destination name, test job/status code, event timestamp and notification receipt timestamp; redact contact addresses where evidence is shared. A matching log entry or a notification-channel test alone is insufficient. Never inject provider failures into the shared production service. Restore the isolated provider configuration afterward. If no alert policy or notification destination exists, record that operator setup as an open release gate; the application log by itself is not delivered alerting.

4. Final acceptance evidence

Current status: deployment, signed-out authentication, signed-in kit management, MCP read/edit persistence and empty-workspace cleanup checks pass. Font/media, provider and export acceptance remains incomplete; farm-dependent checks are pending capacity authorization. The following is the remaining procedure, not evidence that those checks ran. Do not dispatch farm or paid-provider work under the current constraint. Keep API/console/editor commits, generated SDK versions, test reports and the deployment artifacts together. The local Claude Code check above covers workspace read, edit_brand_kit, extraction into that kit and font upload. The deployed MCP read/edit subset now also passes; only exercise its remaining external-service calls when separately authorized. Then complete the console acceptance flow to add/delete/re-add image, video, audio and font, then insert media, apply a colour, set a font, reload and export the composition. A locally queued job is not an exported video. Confirm the upload licence notice and Terms sentence are present. PDF import remains out of this release.

Review packaging

S1 core, S2 fonts, S3 extraction and S4 MCP share the service, schemas, routers, worker and generated SDKs. The implementation is packaged as one coherent local feature commit so each reviewed revision builds and tests; this deliberately replaces the plan’s separate API slice commits. The console/editor remain their own changes. No production deployment or provider enablement is implied by this packaging.