Skip to content

Commit 1badd31

Browse files
docs(spec): branding.logo is the app's one square icon (1:1, SVG preferred, at least 64 px) (#23095)
Fixes #23000 Clause-②: no `branding.logo` now says what the one asset is: a 1:1 square app icon, SVG preferred, at least 64 px. Description text only. The key stays an optional string, the accept set is byte-identical, and nothing refuses a non-square value. ## What changed - `packages/spec/src/ui/app.zod.ts`, the `logo` member of `AppBrandingSchema`. Before: `Custom logo URL for this app`. After: `Custom logo URL for this app: a 1:1 square app icon, SVG preferred, at least 64 px. It is the app's one logo asset — each surface scales it to the size it needs, and there is no second size or wordmark slot.` - `content/docs/references/ui/app.mdx`, the two generated rows that carry it (the `App.branding` nested shape and `AppBranding`). Regenerated with `check:generated --fix`, which proved `check:docs` the only stale artifact; no other generated shard moves (`json-schema.manifest/ui.json` does not carry descriptions). - `.changeset/23000-branding-logo-describe.md`, `@objectstack/spec` patch. ## Why The maintainer's ruling on objectstack-ai/objectui#12201 (2026-10-12), verbatim: 「应用 logo 建议只需要一个尺寸,放在顶部导航的应用名称左侧」, then 「同意」 on the mock. The rider on that card, verbatim: "the `@objectstack/spec` doc on `branding.logo` says "1:1 square app icon, SVG preferred, at least 64 px"; refuse a non-square value if the schema can express it, otherwise doc only." Triage on this card: "⛔ No refusal of a non-square value. A URL string does not carry its ratio, and a refusal would be a new validation gate, which defaults to no." The schema cannot express it: the value is a URL string and carries no ratio, so this is doc only and no refusal was added. ## Measured - Every other `logo` in `packages/spec/src` (case-insensitive grep). Updated: `ui/app.zod.ts` `AppBrandingSchema.logo`, the only description of this key. A different key, left alone: `identity/organization.zod.ts` `OrganizationSchema.logo` (the organization column), `kernel/plugin-registry.zod.ts` `media.logo` (a plugin registry entry), `marketplace/marketplace.zod.ts` `logoUrl` (publisher) and `iconUrl` (package). The same key with no description to update: the `logourl` alias in the branding block's alias table, and the app-level `logo` near-miss that points authors at `branding` (both in `ui/app.zod.ts`). `ui/app.form.ts` names "logo" in the Studio Branding section's copy but states no shape. - "Each surface scales it" holds at the pinned console. objectui at `.objectui-sha` (7578323) draws `branding.logo` as one image through `AppMark` (`packages/app-shell/src/layout/AppMark.tsx`): 22 px in the top-bar pill and the switcher rows, 26 px in the phone drawer, `object-contain`. There is no second asset field and no wordmark slot there either. - The gate reads this text. Before regeneration, `check:generated` exited 1 naming `check:docs` stale; after `--fix` it is green. No ablation file is kept. ## Verification, at head `ee37bc3c6` - `pnpm --filter @objectstack/spec build`: exit 0. After the merge of `origin/main` through `scripts/pm/os-regen-merge.sh`, the whole-repo `turbo run build` also exited 0 (73 tasks). - `pnpm --filter @objectstack/spec check:generated`: exit 0 (the first run, before `--fix`, exited 1 on `check:docs` alone). - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, no paths: 103 families, each run, each exit 0. `--ran` reconciles it: 103 derived, 103 run, 0 NOT-MEASURED, 0 UNRUN. In the first pass six families exited 3, PREREQUISITE NOT MET (unbuilt `@objectstack/lint`, `formula`, `client-react`, `objectql`, and the whole-repo build `check:dual-build-cjs-loads` reads); they were built and re-run, and none of those is a failure reading. - `pnpm --filter @objectstack/spec test` and `pnpm --filter @objectstack/spec typecheck`, one locked call: 657 test files and 19866 tests passed, typecheck passed, verdict command-exit 0. ## Acceptance notes - `packages/spec/liveness/app.json` still gives `branding.logo` the verdict `planned` ("RENDERED BY NOTHING THAT SHIPS", measured at an older pin), while `AppMark` renders it at the current pin. The description above is accurate; the ledger row is stale and owes its own flip to `live`. It is hand-edited evidence outside this card's surface, so this PR leaves it. - `ui/app.form.ts` tells the Studio Branding section's author "Primary/secondary colors, logo, theme", but the branding block has `primaryColor`, `accentColor`, `logo` and `favicon` (a `secondaryColor` or `theme` key is refused). Not reproduced in a running Studio, so noted and not filed. --- _Generated by [Claude Code](https://claude.ai/code/session_01GZSPSQ5ArPjSJdxxuqwGoZ)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 6662e3f commit 1badd31

3 files changed

Lines changed: 8 additions & 3 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
The description of `branding.logo` on an app now states the shape of the one asset it takes: a 1:1 square app icon, SVG preferred, at least 64 px, which each surface scales to the size it needs, with no second size and no wordmark slot. Text only; no schema changes: the key stays an optional string, the accept set is byte-identical, and a non-square value is not refused because a URL string does not carry its ratio.

‎content/docs/references/ui/app.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ const result = ActionNavItemSchema.parse(data);
9494
| :--- | :--- | :--- | :--- |
9595
| **primaryColor** | `string` | optional | Primary theme color hex code |
9696
| **accentColor** | `string` | optional | Accent color hex code (highlights, active states). Declared to match the objectui ConsoleLayout read of branding.accentColor (inverse-drift fix, liveness audit /). |
97-
| **logo** | `string` | optional | Custom logo URL for this app |
97+
| **logo** | `string` | optional | Custom logo URL for this app: a 1:1 square app icon, SVG preferred, at least 64 px. It is the app's one logo asset — each surface scales it to the size it needs, and there is no second size or wordmark slot. |
9898
| **favicon** | `string` | optional | Custom favicon URL for this app |
9999

100100
### Nested Shape: `App.navigation[number][type='object']`
@@ -311,7 +311,7 @@ Documentation entry on the app menu (ADR-0046). Targets a `book` and/or a `doc`
311311
| :--- | :--- | :--- | :--- |
312312
| **primaryColor** | `string` | optional | Primary theme color hex code |
313313
| **accentColor** | `string` | optional | Accent color hex code (highlights, active states). Declared to match the objectui ConsoleLayout read of branding.accentColor (inverse-drift fix, liveness audit /). |
314-
| **logo** | `string` | optional | Custom logo URL for this app |
314+
| **logo** | `string` | optional | Custom logo URL for this app: a 1:1 square app icon, SVG preferred, at least 64 px. It is the app's one logo asset — each surface scales it to the size it needs, and there is no second size or wordmark slot. |
315315
| **favicon** | `string` | optional | Custom favicon URL for this app |
316316

317317

‎packages/spec/src/ui/app.zod.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,7 @@ export const AppBrandingSchema = lazySchema(() => strictObject(
952952
{
953953
primaryColor: z.string().optional().describe('Primary theme color hex code'),
954954
accentColor: z.string().optional().describe('Accent color hex code (highlights, active states). Declared to match the objectui ConsoleLayout read of branding.accentColor (inverse-drift fix, liveness audit /).'),
955-
logo: z.string().optional().describe('Custom logo URL for this app'),
955+
logo: z.string().optional().describe("Custom logo URL for this app: a 1:1 square app icon, SVG preferred, at least 64 px. It is the app's one logo asset — each surface scales it to the size it needs, and there is no second size or wordmark slot."),
956956
favicon: z.string().optional().describe('Custom favicon URL for this app'),
957957
}));
958958

0 commit comments

Comments
 (0)