From e7258cb7de9bb26e9cc7553c749013f6d655efb4 Mon Sep 17 00:00:00 2001 From: konojunya Date: Sun, 6 Sep 2026 17:52:28 +0900 Subject: [PATCH] docs: define configured theme overrides --- README.md | 1 + SPECIFICATION.md | 14 +++++++-- .../expected.ir.json | 28 +++++++++++++++++ .../configured-theme-reference/source.stack | 7 +++++ .../0007-configured-theme-overrides.md | 30 +++++++++++++++++++ schemas/normalized-ir.schema.json | 2 +- 6 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 conformance/valid/configured-theme-reference/expected.ir.json create mode 100644 conformance/valid/configured-theme-reference/source.stack create mode 100644 docs/decisions/0007-configured-theme-overrides.md diff --git a/README.md b/README.md index 5306077..7c388f1 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ The language is currently a proposal for Stack 1.0. No compatibility guarantee a - [ADR-0004: Distribute shared editor language assets from the specification](./docs/decisions/0004-distribute-editor-language-assets.md) - [ADR-0005: Separate provider icon namespaces from theme icons](./docs/decisions/0005-provider-icon-namespaces.md) - [ADR-0006: Standardize protocol-neutral language intelligence](./docs/decisions/0006-standardize-language-intelligence.md) +- [ADR-0007: Let host configuration override theme palettes](./docs/decisions/0007-configured-theme-overrides.md) - [Examples](./examples) - [Conformance suite](./conformance) - [`@stack-sh/language`](./packages/language) diff --git a/SPECIFICATION.md b/SPECIFICATION.md index 7d62fe3..0412529 100644 --- a/SPECIFICATION.md +++ b/SPECIFICATION.md @@ -111,6 +111,8 @@ Identifiers match: Identifiers contain between 1 and 64 ASCII characters. Keywords are recognized contextually. A word that matches a keyword may also be used where the grammar expects an identifier, although authors SHOULD avoid identifiers that make a declaration difficult to read. The lowercase ASCII form avoids quoting, normalization, and visually confusable references. +The `--` edge operator is recognized before bare identifiers. An identifier written in Stack source therefore MUST NOT contain two consecutive hyphens, even though each individual hyphen is otherwise an identifier character. + ### 4.5 Strings Strings are enclosed in double quotes. Source text may contain Unicode directly. @@ -279,13 +281,19 @@ Failure to provide a required theme is a catalog or renderer implementation fail Theme identifiers use the normal Stack identifier syntax and have no namespace. The first catalog pull request merged for an identifier registers it. A registered identifier MUST NOT be assigned to a different theme later, even if its original theme is deprecated or removed. This first-merged rule makes theme selection globally unambiguous without adding package or contributor names to source. -A requested theme that is not present in the installed catalog version produces warning `STK6001` and falls back to `default`, so the topology remains renderable. +A host MAY provide validated, user-configured theme overrides outside Stack source. An override has a normal Stack theme identifier, extends one of the required `default`, `light`, or `dark` themes from the installed catalog, and replaces only a subset of the nine semantic palette slots defined by the theme catalog contract. It cannot replace typography, node-kind visuals, connector geometry, icons, or asset provenance. + +The override base is resolved from the installed catalog before any configured overrides are applied. A configured `default` that extends `default` therefore inherits the installed `default` theme without creating a self-reference. Configured themes do not extend one another. + +Theme selection resolves the requested identifier from configured overrides first and the installed catalog second. A configured theme MAY intentionally use the same identifier as an installed or registered catalog theme; the first-merged rule applies only to public catalog registration. When the source omits a theme statement, the requested identifier is `default`, so a configured `default` becomes the host's effective default theme. + +A requested theme that is absent from both configured overrides and the installed catalog version produces warning `STK6001` and falls back to the effective `default`, including a configured `default` override when present, so the topology remains renderable. -A theme may affect typography metrics and therefore exact element positions, but it MUST NOT change or hide nodes, groups, edges, labels, directionality, semantic kinds, or layout constraints. Every theme MUST preserve legibility, accessible contrast, and non-color distinctions required elsewhere in this specification. +A theme may affect typography metrics and therefore exact element positions, but it MUST NOT change or hide nodes, groups, edges, labels, directionality, semantic kinds, or layout constraints. Every catalog theme MUST preserve legibility, accessible contrast, and non-color distinctions required elsewhere in this specification. A host accepting user-configured colors SHOULD report contrast concerns, MUST preserve non-color distinctions, and MUST NOT silently rewrite the configured colors. Each theme owns its unnamespaced icon collection. This is a one-to-many relationship: one selected theme resolves zero or more authored unnamespaced icon identifiers to theme-specific SVG assets. The same logical icon may therefore use different SVG artwork in `light`, `dark`, or any other theme. Namespaced provider icons are resolved from separate explicitly installed provider packs and preserve their provider artwork independently of the selected theme. -Stack source cannot define theme values, inherit from a network resource, or add per-element visual overrides. The catalog is explicitly installed or bundled by the renderer and MUST NOT be fetched solely because a theme identifier appears in source. +Stack source cannot define theme values, inherit from a network resource, or add per-element visual overrides. The catalog is explicitly installed or bundled by the renderer and MUST NOT be fetched solely because a theme identifier appears in source. Configured overrides are finite caller-owned data, require no network access, and contribute to the effective catalog revision recorded in render metadata. ## 7. Node Semantics diff --git a/conformance/valid/configured-theme-reference/expected.ir.json b/conformance/valid/configured-theme-reference/expected.ir.json new file mode 100644 index 0000000..5a68b7e --- /dev/null +++ b/conformance/valid/configured-theme-reference/expected.ir.json @@ -0,0 +1,28 @@ +{ + "schemaVersion": "1.0", + "languageVersion": { + "major": 1, + "minor": 0 + }, + "title": "Configured theme reference", + "themeId": "custom-theme", + "children": [ + { + "type": "node", + "id": "app" + } + ], + "nodes": [ + { + "id": "app", + "label": "Application", + "kind": "service", + "iconId": null, + "detail": null, + "parentGroupId": null + } + ], + "groups": [], + "edges": [], + "layout": null +} diff --git a/conformance/valid/configured-theme-reference/source.stack b/conformance/valid/configured-theme-reference/source.stack new file mode 100644 index 0000000..16f8094 --- /dev/null +++ b/conformance/valid/configured-theme-reference/source.stack @@ -0,0 +1,7 @@ +stack 1.0 + +diagram "Configured theme reference" { + theme custom-theme + + node app "Application" +} diff --git a/docs/decisions/0007-configured-theme-overrides.md b/docs/decisions/0007-configured-theme-overrides.md new file mode 100644 index 0000000..6af4091 --- /dev/null +++ b/docs/decisions/0007-configured-theme-overrides.md @@ -0,0 +1,30 @@ +# ADR 0007: Let host configuration override theme palettes + +## Status + +Accepted + +## Context + +Stack diagrams need reusable organization-specific colors without adding visual values to source, duplicating complete catalog themes, or allowing arbitrary CSS and assets. The public catalog also has a first-merged identifier rule, while users reasonably expect a local `default` definition to become their effective default. + +Treating a configured `default` as an error would force a separate selection flag or a new source identifier. Letting configured themes extend one another would instead introduce ordering, recursion, and cycle handling that the initial palette-only feature does not need. + +## Decision + +Host configuration may supply named theme overrides. A configured name may intentionally match an installed catalog theme and takes precedence during theme selection. + +Each override extends exactly one installed builtin theme: `default`, `light`, or `dark`. The host resolves every base from the installed catalog before registering any override, so `default` extending `default` is deterministic and non-recursive. An override may replace only the nine semantic palette colors. Typography, node-kind visuals, connector geometry, icons, and provenance remain inherited from the builtin base. + +Omitting the source theme statement still requests `default`. If configuration contains a `default` override, that override is selected. Missing names retain `STK6001` and fall back to the effective `default`. + +The theme catalog contract owns the portable override shape, validation, normalization, and effective revision algorithm. Native and browser hosts supply only validated caller-owned data to the pure engine. No theme name triggers filesystem or network discovery. + +## Consequences + +- Existing sources and hosts without theme overrides keep their current behavior. +- A user's configuration can deliberately change `default`, `light`, `dark`, or another installed theme without changing Stack source. +- Rendered appearance can depend on host configuration, so metadata must identify the effective catalog revision. +- User-configured colors are preserved exactly; hosts surface contrast concerns instead of silently rewriting them. +- Older hosts may reject the new configuration key, and documentation must identify the first supporting release. +- Changing the shipped builtin palettes remains a catalog change rather than a user-configured override. diff --git a/schemas/normalized-ir.schema.json b/schemas/normalized-ir.schema.json index 47098a3..b50dc25 100644 --- a/schemas/normalized-ir.schema.json +++ b/schemas/normalized-ir.schema.json @@ -65,7 +65,7 @@ "$defs": { "identifier": { "type": "string", - "pattern": "^[a-z][a-z0-9_-]{0,63}$" + "pattern": "^(?!.*--)[a-z][a-z0-9_-]{0,63}$" }, "iconIdentifier": { "type": "string",