Pattern // static output artifact

patterns/output-artifact/README.md · 20287 B · source sha256 57b659fb9dfb

A reusable static-artifact scaffold for downstream project-output artifacts — review packets, reports, dashboards, and similar human-readable deliverables that inherit the design-system-ASK visual language.

This is a Class B scaffold (project-output artifact templates), distinct from the Class A diagram patterns (the static diagram-static-H / -V / -SEQ / -FLOW and the interactive diagram-interactive-spine).

on this page

What this pattern is

A small consumption pattern. Four files:

  • README.md // this file
  • static-output-artifact.html // the template (output-artifact v3), on the document register
  • MANIFEST.md.example // the per-artifact provenance record (records the upstream SHA + per-file sha256)
  • hard-fail-checklist.md // the fails-inheritance test list

The pattern is not a component library, a generator, a build pipeline, an npm package, or a project-specific template. It is a starting point for downstream artifacts that consume design-system-ASK foundations. The renderer that seals an artifact for delivery (see "Sealed output") is the consuming project's tooling and is not shipped here.

On the document register

The template is a consumer of the document register and its surface treatments. Its text takes their roles. Each block text role sets its text's complete style — family, size, weight, leading, tracking and foreground; inline code and the disclosure's trigger inherit their leading from where they sit:

Artifact text Register role
Artifact textthe title Register roleh1.doc-title
Artifact textthe subtitle or one-line context Register rolep.doc-lede
Artifact texta section title Register roleh2.doc-section-title in a section.doc-section; deeper headings take .doc-subsection-title and .doc-deep-title
Artifact textprose and list items Register role.doc-body
Artifact texta link in artifact text Register rolea.surface-text-link
Artifact texta metadata or provenance name Register role.doc-label
Artifact texta metadata or provenance value Register role.doc-meta
Artifact textinline code Register rolecode.doc-code
Artifact textwords presented as someone's Register roleblockquote.doc-quote, on the violet rail
Artifact texta code or technical block Register rolepre.doc-pre, on the magenta rail
Artifact texta dense technical table Register roletable.doc-dense-table, with .doc-label headers and .doc-table-cell values
Artifact texta narrative table Register rolea table without the dense marker, with .doc-label headers and .doc-body cells
Artifact textan adopted table's geometry Register rolethe document table composition: table.doc-table directly inside a .doc-table-scroll box named as a region (role="region" with a label), and .doc-table-num on a numeric column's header and cells. In print the template's own print adaptation adapts it to the printed column
Artifact textsecondary detail behind a disclosure Register rolethe treatments' disclosure, composed as the template composes it: details.surface-disclosure.surface-material-panel.surface-attach-free.surface-elevation-flush, with its label, indicator and body

The register's other compositions — an authorial callout, a section framing, a section synthesis — are available to an artifact that needs them, in the same markup the register's key uses. The template's own CSS sets no type metric and no foreground on text, and no screen geometry on a table that adopts the document table composition. It owns the geometry the register leaves to its consumer — the column, the metadata strip's and provenance footer's layout, list geometry, the geometry of a table that does not adopt the composition, and rules — and one print adaptation for an adopted table, described below. Every other geometry rule on an element the register may also style is written at zero specificity, so none outranks a register rule.

Tables adopt the document table composition. The template's dense table and its narrative table each carry table.doc-table directly inside a .doc-table-scroll box named as a region, and the composition draws their rules, spacing, numeral alignment and line breaking. The template's own table rules exclude an adopted table, so on screen nothing in the template competes with the composition. The dense marker and the narrative assignment draw nothing themselves; inside the composition they select its variation — a narrative table's 32rem measure, a dense value that keeps its line. A table wider than the column scrolls inside its box, and the page never scrolls sideways. The template loads no script, so without the register's optional overflow helper a box that scrolls shows no scroll cue. On screen the template adds nothing to an adopted table.

In print, the template adapts an adopted table to the page. A box does not scroll on paper, so the template's own @media print rules relax the composition's choices that rely on scrolling: a narrative table drops its 32rem measure, and a dense value outside a numeric column, like code in any adopted cell, wraps. Where the printed column is narrower than the table's natural width, such a value or code may break between any two characters, short tokens included, rather than be cut. The table's markup, text roles and type, cell spacing, rules and numeric alignment are unchanged, and nothing on screen changes. The adaptation belongs to this scaffold, not to the composition, and reaches only an adopted table inside .artifact. It does not make every table fit every page: a table whose columns cannot sit side by side in the printed column still overflows it and is cut at its box's edge.

Adoption is per table and stays the consuming project's decision. A table that must not scroll sideways, that stacks its rows or that needs a print treatment the adaptation does not give it does not adopt the composition. Without both markers it keeps the template's own table geometry: full width, rules in the Class B line intensity, and cells that wrap a long token rather than widen the page. Stacked rows, or any other table geometry, are the consuming project's to supply.

Run the register's rendered check on a delivered artifact — node tools/check-role-conformance.mjs --url <artifact>, from a design-system-ASK checkout at the commit the artifact's MANIFEST.md records. It proves that every element carrying a role computes to that role, and it reports a page with no governed text as vacuous. It does not fail text that carries no role: it lists that text as unmapped, and the hard-fail checklist requires that list to be empty.

Foreground is inherited // no local rebind

The foundation (colors_and_type.css) resolves the --fg-* ramp in light and dark, and the register's roles bind text to it. Since the foundation light-mode foreground ramp landed (the approved dark-purple foreground — #6A637F — on the light lavender field, not near-black ink), prose reads correctly in both modes with no local foreground CSS. This template therefore takes its text foreground from the register's roles on the foundation --fg-* and does not rebind --fg-* / --line-*. Do not reintroduce a local --fg rebind — it is no longer needed and would fork the foreground from the foundation.

The one sanctioned Class B override // line intensity

Report rules, borders, table lines, and dividers read too faint at the foundation hairline (white .45 / .22) on the light lavender field. The template carries a Class B-scoped token — --artifact-line / --artifact-line-soft — that uses stronger white lines in light mode and inherits the foundation lavender lines in dark mode. It is applied to the artifact's own geometry (the metadata strip, the rules on the cells of a table that does not adopt the document table composition, the provenance footer, hr) — never to a table the composition draws, a text foreground, a passage rail or the disclosure's panel — so it cannot affect prose color or a register treatment. An adopted table takes the composition's own approved line treatment instead, on the foundation lines: --line-2 under each row and --line-1 under the header row. This is the single legitimate token override for the class.

This mirrors how Class A diagrams scope color: a class-targeted --diagram-* token layer whose text roles alias the foundation --fg-* ramp while its structural stroke roles stay local — not a base-token rebind. The rule across the family:

Class Color is applied to… So foreground binds to…
ClassA — diagrams Color is applied to…SVG elements via classes So foreground binds to…foundation --fg-*, via aliased --diagram-* text roles; structural strokes use a local --diagram-line* overlay
ClassB — output artifacts Color is applied to…the document register's role classes So foreground binds to…foundation --fg-*, through the register's roles, plus a class-scoped --artifact-line* overlay for the artifact's own structural lines
ClassB — message archive Color is applied to…bubble elements, via role classes So foreground binds to…role-scoped foregrounds. --fg-high-contrast reaches participant ink and search-highlight text on the sanctioned colored fills. The author / frosted role foregrounds sit elsewhere. No global --fg-* rebind. Registered in design-system-ASK under High-contrast foreground — registered uses

The two document-and-diagram classes bind text to the foundation --fg-* ramp; they differ only in how color reaches the element — Class B through the document register's role classes, Class A through class-targeted diagram roles that alias the foundation (SVG elements need class-targeted fills, and the diagram speaks in diagram roles). Each keeps a single scoped overlay for structural lines only (--diagram-line* / --artifact-line*), never for foreground — so neither forks the foreground from the foundation. The Class B message-archive is the one implemented case where bubble text does not read --fg-*: its bubble foregrounds are role-scoped per participant fill (identity, not state), and its participant ink takes the opt-in high-contrast role. That is one registered bounded use — see design-system-ASK High-contrast foreground — registered uses. It still adds no global rebind: every role color is applied by class to the archive's own elements, so inherited prose is untouched.

How to use it

  1. Copy the four files in patterns/output-artifact/ into your consuming project.
  2. Sync colors_and_type.css, fonts, and any required assets from design-system-ASK into a local mirror (e.g. ./_dsa-tokens/), pinned to a known upstream commit SHA. Vendor the four document-register modules — surface-panel.css, surface-text-link.css, surface-document.css, surface-treatments.css — beside the template, from the same commit. They are visual modules, not part of the token mirror. (For a single-file artifact the mirror and the modules are only build inputs you inline and seal away; only a multi-file package keeps them linked — see Single file vs shared mirror below.)
  3. Edit static-output-artifact.html: replace placeholder content (title, sections, meta, footer references) with your artifact's actual content. Replace the sample list, quotation, tables, code block and disclosure, keeping each element's register role and each adopted table's composition markers, and name each table's box — do not restyle a role, add type declarations, or add table geometry over the composition. Do not edit the token references, the line overlay, or the theme behavior.
  4. Add any project-specific chrome (banners, status rails, review-status strips, branding) in the Tier 3 overlay slot — see below.
  5. Fill out a MANIFEST.md from MANIFEST.md.example: record the upstream commit SHA, per-file sha256 (the token mirror and the register modules), your consuming project, artifact path, template version, and render timestamp.
  6. Render, seal, and freeze (see "Sealed output"). The rendered artifact is auditable against the recorded SHA.

Sealed output (contract, not tooling)

A delivered output artifact must be self-contained: it must open with full styling from any location (local file, email attachment, copied folder) with no network and no sidecar. Review artifacts have to survive delivery without a stylesheet or font going missing.

This is a contract the consuming project's renderer meets — typically by inlining the token CSS and embedding fonts at render time, then inlining the four register modules verbatim after it, in the order the template loads them: surface-panel.css, surface-text-link.css, surface-document.css, surface-treatments.css. None of the four loads a resource or imports a stylesheet. A review document that adopts Review Semantics inlines spectral-state.css, evidence-state.css and review-semantics.css after them, in that order; none of the three loads a resource either. The renderer is consumer-owned and is not part of this pattern (no generator / build pipeline lives in design-system-ASK). The template here links the local mirror (./_dsa-tokens/colors_and_type.css) as the editable starting point; sealing happens in the consumer's render step. The hard-fail checklist enforces the self-contained requirement on the delivered artifact.

Single file vs shared mirror

The _dsa-tokens/ mirror is the right shape for a multi-file package — it is not a mandatory sidecar on every artifact. Choose by how many HTML files share the foundation:

  • A single HTML payload ships as one self-contained file. Inline the token CSS and base64-embed the fonts at render time, so the artifact is literally one .html with no sidecar. The mirror, if used at all, is a build input that does not travel with the delivered file — do not ship a _dsa-tokens/ folder next to a lone HTML.
  • A package of multiple HTML files that share the foundation vendors one shared _dsa-tokens/ mirror the files link, pinned to a known commit, and links the four register modules once from the package as well. The tokens and modules live once for the package rather than being duplicated into every file.

The rule, in one line: link a shared mirror only when more than one file consumes it; a single payload seals to a single file. Either way the delivered artifact still meets the self-contained contract above — sealed-inline for one file, folder-portable for a package.

Snapshot / retention convention

A rendered output artifact is a frozen audit object once it is reviewed, accepted, or externally shared. The render → seal → freeze step is not the end of the story: how a regenerated artifact is retained is part of the contract.

Required principle. This is fixed across all consumers:

  • A reviewed, accepted, or shared artifact is frozen. Regenerating it produces a new artifact, not an edit of the old one.
  • Do not overwrite or delete a prior reviewed artifact as "stale". Superseding means history, not deletion — prior reviewed renders stay retained.

Naming // consumer-owned. The audit rule above is fixed; the filename shape is not. The scaffold prescribes no single default — choose the flavor that matches the artifact's rhythm:

  • Date-driven outputs: YYYY-MM-DD_<artifact-name>.html
  • Iterative / revision-driven outputs: <artifact-name>_v<N>.html

A consumer may also keep a stable canonical copy under a consumer-owned name for convenience, but prior reviewed renders must remain retained as dated or versioned snapshots. The consuming project picks the flavor; the design system fixes only the retention doctrine, not the filesystem convention.

Tier 3 overlay slot

static-output-artifact.html carries a clearly marked, intentionally empty Tier 3 overlay slot. Project-specific identity — banners, status rails, review-status strips, project branding — belongs there, layered on top:

  • Bind to foundation tokens (--fg-*, --artifact-line, type/spacing tokens) and give any text a register role. Do not redefine Tier 1/2 tokens, and do not restyle a register role.
  • Stay inside the closed palette; introduce no new hues.
  • Review, evidence and state marks drawn with the opt-in Review Semantics composition are not overlay chrome: a document that adopts it places and scopes them as that composition's contract specifies, and the project supplies its records' values and mints no review palette of its own. Another owner's presentation, such as a consumer's own Evidence State assignment, stays governed by that owner.
  • Do not propagate the design-system's own identity (logo-ASK, the ASK wordmark, "ASK Design System" chrome) into the artifact unless the consuming project is itself an ASK-instance surface that has explicitly accepted that overlay, or, for the logo-ASK wordmark alone, ASK has explicitly assigned that wordmark to the consuming project as its locally supplied Tier 3 and the artifact falls within the assignment's recorded scope. An assignment is not inheritance, and it does not make that project ASK-the-entity.

A project that needs a distinct aesthetic (e.g. a sub-brand) layers it here as Tier 3, or maintains a child design-system layer — it does not fork this shared Class B foundation.

What downstream must replace

  • All placeholder content (title, subtitle, section headings, body text, the sample links, meta values, and the sample list, quotation and attribution, tables and each table box's label, code, preformatted block and disclosure)
  • The relative path to colors_and_type.css if your local mirror lives at a different path than ./_dsa-tokens/, and the paths to the four register modules if you vendor them anywhere but beside the template
  • The provenance footer values (from your MANIFEST.md)
  • Any Tier 3 overlay (in the slot) belongs to the consuming project, not to this pattern

What not to edit

  • The token references themselves (var(--fg-1), var(--bg-gradient), var(--artifact-line), etc.)
  • The line-intensity overlay tokens and their light/dark blocks
  • The light/dark inheritance behavior (no hardcoded data-theme; foreground inherited from the foundation, never rebound locally)
  • The register role on each piece of text, and the register modules themselves (text takes its role, never a local type declaration)
  • The closed palette
  • The hard-fail checklist baseline; downstream projects may add project-specific checks, but should not weaken or remove the inherited checks

Static vs dynamic inheritance

Static artifacts inherit at generation time and freeze for audit. The rendered HTML reads the local copies of colors_and_type.css and the register modules synced into the artifact bundle (or inlined at seal time), not a live upstream URL. Re-render only when upstream tokens or the consuming template change in a way that affects the rendered surface; record a new SHA each time.

Production code, by contrast, may use a live dependency or import model.

Source-truth boundary

design-system-ASK supplies the foundations (Tier 1 + Tier 2). The consuming project supplies its own Tier 3 identity, its own source-truth posture, and the artifact's content and domain structure. Hosting this scaffold in design-system-ASK does not make this repo the owner of downstream artifact content.

Class A vs Class B

This is Class B (project-output artifact templates). Class A (system / architecture diagram templates) are separate patterns — the static diagram-static-H / -V / -SEQ / -FLOW and the interactive diagram-interactive-spine. The classes stay distinct; do not fuse. All inherit Tier 1 + Tier 2 from design-system-ASK, but they serve different artifact classes and — per the table above — bind color differently because they apply it differently.