@nurix/etna 0.19.11 → 0.19.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/data/harness-index.json +1 -1
- package/data/harnesses/code/agents/maintenance.md +1 -1
- package/data/harnesses/code/harness.json +1 -1
- package/data/harnesses/code/rules/frontend.md +5 -5
- package/data/harnesses/code/skills/design/SKILL.md +70 -50
- package/data/harnesses/code/skills/design/components/charts.md +76 -0
- package/data/harnesses/code/skills/design/components/collections.md +132 -0
- package/data/harnesses/code/skills/design/components/feedback.md +47 -0
- package/data/harnesses/code/skills/design/components/hooks.md +35 -0
- package/data/harnesses/code/skills/design/components/index.md +143 -0
- package/data/harnesses/code/skills/design/components/inputs.md +327 -0
- package/data/harnesses/code/skills/design/components/layout.md +52 -0
- package/data/harnesses/code/skills/design/components/media.md +66 -0
- package/data/harnesses/code/skills/design/components/motion.md +82 -0
- package/data/harnesses/code/skills/design/components/navigation.md +29 -0
- package/data/harnesses/code/skills/design/components/overlays.md +72 -0
- package/data/harnesses/code/skills/design/components/setup.md +40 -0
- package/data/harnesses/code/skills/design/components/typography.md +46 -0
- package/data/harnesses/code/skills/design/components/utils.md +37 -0
- package/data/harnesses/code/skills/design/data/blueprints/browse.md +38 -0
- package/data/harnesses/code/skills/design/data/blueprints/creation-flow.md +38 -0
- package/data/harnesses/code/skills/design/data/blueprints/dashboard.md +38 -0
- package/data/harnesses/code/skills/design/data/blueprints/grid.md +38 -0
- package/data/harnesses/code/skills/design/data/blueprints/queue.md +38 -0
- package/data/harnesses/code/skills/design/data/blueprints/record-detail.md +38 -0
- package/data/harnesses/code/skills/design/data/blueprints/settings.md +38 -0
- package/data/harnesses/code/skills/design/data/chart-styling/Readme.md +33 -0
- package/data/harnesses/code/skills/design/data/chart-styling/carbon-accessible-alert-semantic.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/carbon-monochrome-sequential-trend.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/datadog-classic-six-aligned.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/datawrapper-tiered-gray-hierarchy.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/econ-red-rule-horizontal.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/financial-diverging-threshold-overlay.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/ft-vocabulary-ranked-muted.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/grafana-dark-threshold-bands.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/material-rounded-explicit-label.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/nyt-ghost-grid-direct-label.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/plot-currentcolor-inherit.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/saas-gradient-glow-area.md +19 -0
- package/data/harnesses/code/skills/design/data/chart-styling/shadcn-composable-css-vars.md +19 -0
- package/data/harnesses/code/skills/design/data/charts/census.csv +58 -0
- package/data/harnesses/code/skills/design/data/checklists/browse.md +21 -0
- package/data/harnesses/code/skills/design/data/checklists/creation-flow.md +20 -0
- package/data/harnesses/code/skills/design/data/checklists/dashboard.md +21 -0
- package/data/harnesses/code/skills/design/data/checklists/grid.md +21 -0
- package/data/harnesses/code/skills/design/data/checklists/queue.md +21 -0
- package/data/harnesses/code/skills/design/data/checklists/record-detail.md +21 -0
- package/data/harnesses/code/skills/design/data/checklists/settings.md +21 -0
- package/data/harnesses/code/skills/design/data/chrome/board-column.md +68 -0
- package/data/harnesses/code/skills/design/data/chrome/data-table.md +63 -0
- package/data/harnesses/code/skills/design/data/chrome/side-panel.md +60 -0
- package/data/harnesses/code/skills/design/data/chrome/sidebar.md +78 -0
- package/data/harnesses/code/skills/design/data/chrome/stat-cards.md +62 -0
- package/data/harnesses/code/skills/design/data/chrome/topbar.md +65 -0
- package/data/harnesses/code/skills/design/data/color/accent-presets.md +90 -0
- package/data/harnesses/code/skills/design/data/color/aesop-earth-mute.md +91 -0
- package/data/harnesses/code/skills/design/data/color/arc-peach-play.md +90 -0
- package/data/harnesses/code/skills/design/data/color/attio-hunter-teal.md +90 -0
- package/data/harnesses/code/skills/design/data/color/carbon-cyan-signal.md +90 -0
- package/data/harnesses/code/skills/design/data/color/clay-parchment.md +90 -0
- package/data/harnesses/code/skills/design/data/color/duolingo-feather.md +90 -0
- package/data/harnesses/code/skills/design/data/color/geist-mono-signal.md +90 -0
- package/data/harnesses/code/skills/design/data/color/linear-graphite-violet.md +90 -0
- package/data/harnesses/code/skills/design/data/color/mercury-onyx-cobalt.md +90 -0
- package/data/harnesses/code/skills/design/data/color/notion-paper-ink.md +90 -0
- package/data/harnesses/code/skills/design/data/color/radix-slate-iris.md +90 -0
- package/data/harnesses/code/skills/design/data/color/raycast-void-spectrum.md +90 -0
- package/data/harnesses/code/skills/design/data/color/spectrum-celery-fuchsia.md +90 -0
- package/data/harnesses/code/skills/design/data/color/stripe-blurple-ruby.md +90 -0
- package/data/harnesses/code/skills/design/data/color/superhuman-cod-picton.md +89 -0
- package/data/harnesses/code/skills/design/data/corpora/operations-review/companies.csv +15 -0
- package/data/harnesses/code/skills/design/data/corpora/operations-review/corpus.md +87 -0
- package/data/harnesses/code/skills/design/data/corpora/operations-review/people.csv +25 -0
- package/data/harnesses/code/skills/design/data/corpora/procurement-approvals/companies.csv +15 -0
- package/data/harnesses/code/skills/design/data/corpora/procurement-approvals/corpus.md +83 -0
- package/data/harnesses/code/skills/design/data/corpora/procurement-approvals/people.csv +25 -0
- package/data/harnesses/code/skills/design/data/corpora/revenue-analytics/companies.csv +15 -0
- package/data/harnesses/code/skills/design/data/corpora/revenue-analytics/corpus.md +89 -0
- package/data/harnesses/code/skills/design/data/corpora/revenue-analytics/people.csv +25 -0
- package/data/harnesses/code/skills/design/data/elevation/ant-design-directional-shadow.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/apple-liquid-glass-material.md +18 -0
- package/data/harnesses/code/skills/design/data/elevation/atlassian-surface-shadow-pairing.md +20 -0
- package/data/harnesses/code/skills/design/data/elevation/fluent-2-key-ambient-ramp.md +20 -0
- package/data/harnesses/code/skills/design/data/elevation/github-primer-sparing-shadow.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/ibm-carbon-layer-and-border.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/linear-dark-surface-ladder.md +17 -0
- package/data/harnesses/code/skills/design/data/elevation/material-2-key-ambient-dp-ramp.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/material-3-tonal-elevation.md +21 -0
- package/data/harnesses/code/skills/design/data/elevation/neobrutalist-hard-offset.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/neumorphic-soft-dual-shadow.md +18 -0
- package/data/harnesses/code/skills/design/data/elevation/notion-warm-minimal-hairline.md +17 -0
- package/data/harnesses/code/skills/design/data/elevation/polaris-elevation-inset-bevel.md +21 -0
- package/data/harnesses/code/skills/design/data/elevation/radix-themes-alpha-ring-scale.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/shadcn-neutral-derived-radius.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/stripe-brand-tinted-dual-shadow.md +18 -0
- package/data/harnesses/code/skills/design/data/elevation/tailwind-default-utility-scale.md +19 -0
- package/data/harnesses/code/skills/design/data/elevation/vercel-geist-shadow-as-border.md +20 -0
- package/data/harnesses/code/skills/design/data/gradients/amber-attention-fill.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/cloud-shadow-wash.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/confident-lavender-wash.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/ember-ship-flare.md +18 -0
- package/data/harnesses/code/skills/design/data/gradients/full-metal-wash.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/indigo-ruby-cta-band.md +18 -0
- package/data/harnesses/code/skills/design/data/gradients/linear-graphite-wash.md +18 -0
- package/data/harnesses/code/skills/design/data/gradients/marble-quartz-wash.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/midnight-aurora-panel.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/neutral-volume-fill.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/revenue-uptrend-fill.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/risk-decline-fill.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/signal-blue-develop.md +18 -0
- package/data/harnesses/code/skills/design/data/gradients/slate-mist-wash.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/stripe-atmosphere-mesh.md +18 -0
- package/data/harnesses/code/skills/design/data/gradients/teal-signal-accent.md +16 -0
- package/data/harnesses/code/skills/design/data/gradients/violet-magenta-promo.md +16 -0
- package/data/harnesses/code/skills/design/data/iconography.md +199 -0
- package/data/harnesses/code/skills/design/data/motion/accordion-expand.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/destructive-hold-confirm.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/drag-dismiss-momentum.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/empty-state-arrive.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/hover-lift.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/modal-center-arrive.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/number-ticker-roll.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/onboarding-bounce.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/panel-slide.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/press-feedback.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/progress-linear-loop.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/route-crossfade.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/rubber-band-overscroll.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/skeleton-shimmer.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/stagger-arrive.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/toast-enter-stack.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/tooltip-chain-instant.md +18 -0
- package/data/harnesses/code/skills/design/data/motion/trigger-anchored-reveal.md +18 -0
- package/data/harnesses/code/skills/design/data/tells.csv +34 -0
- package/data/harnesses/code/skills/design/data/typography/anton-work-sans.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/archivo-black-archivo.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/bitter-karla.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/dm-serif-dm-sans.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/fraunces-inter.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/geist-geist-mono.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/hubot-sans-mona-sans.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/ibm-plex-sans-operator-single-family.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/instrument-serif-instrument-sans.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/inter-operator-single-family.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/libre-baskerville-libre-franklin.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/newsreader-inter.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/playfair-display-source-sans.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/public-sans-operator-single-family.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/sohne-inter-fintech.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/source-serif-source-sans.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/space-grotesk-work-sans-space-mono.md +17 -0
- package/data/harnesses/code/skills/design/data/typography/spectral-manrope.md +17 -0
- package/data/harnesses/code/skills/design/data/voices/bright-collaborator.md +29 -0
- package/data/harnesses/code/skills/design/data/voices/direct-operator.md +29 -0
- package/data/harnesses/code/skills/design/data/voices/earnest-helper.md +29 -0
- package/data/harnesses/code/skills/design/data/voices/editorial-composed.md +29 -0
- package/data/harnesses/code/skills/design/data/voices/quiet-concierge.md +29 -0
- package/data/harnesses/code/skills/design/data/voices/warm-guide.md +29 -0
- package/data/harnesses/code/skills/design/design-md/SCHEMA.md +179 -0
- package/data/harnesses/code/skills/design/design-md/index.csv +67 -0
- package/data/harnesses/code/skills/design/design-md/library/airbnb.md +207 -0
- package/data/harnesses/code/skills/design/design-md/library/airtable.md +205 -0
- package/data/harnesses/code/skills/design/design-md/library/anthropic-claude.md +203 -0
- package/data/harnesses/code/skills/design/design-md/library/apple.md +206 -0
- package/data/harnesses/code/skills/design/design-md/library/binance.md +210 -0
- package/data/harnesses/code/skills/design/design-md/library/bmw.md +210 -0
- package/data/harnesses/code/skills/design/design-md/library/cal.md +209 -0
- package/data/harnesses/code/skills/design/design-md/library/clay.md +204 -0
- package/data/harnesses/code/skills/design/design-md/library/clickhouse.md +205 -0
- package/data/harnesses/code/skills/design/design-md/library/cohere.md +205 -0
- package/data/harnesses/code/skills/design/design-md/library/coinbase.md +198 -0
- package/data/harnesses/code/skills/design/design-md/library/composio.md +198 -0
- package/data/harnesses/code/skills/design/design-md/library/cursor.md +197 -0
- package/data/harnesses/code/skills/design/design-md/library/elevenlabs.md +199 -0
- package/data/harnesses/code/skills/design/design-md/library/expo.md +200 -0
- package/data/harnesses/code/skills/design/design-md/library/figma.md +199 -0
- package/data/harnesses/code/skills/design/design-md/library/framer.md +202 -0
- package/data/harnesses/code/skills/design/design-md/library/hashicorp.md +205 -0
- package/data/harnesses/code/skills/design/design-md/library/ibm.md +205 -0
- package/data/harnesses/code/skills/design/design-md/library/intercom.md +204 -0
- package/data/harnesses/code/skills/design/design-md/library/kraken.md +200 -0
- package/data/harnesses/code/skills/design/design-md/library/linear-app.md +198 -0
- package/data/harnesses/code/skills/design/design-md/library/lovable.md +199 -0
- package/data/harnesses/code/skills/design/design-md/library/meta.md +204 -0
- package/data/harnesses/code/skills/design/design-md/library/minimax.md +204 -0
- package/data/harnesses/code/skills/design/design-md/library/mintlify.md +210 -0
- package/data/harnesses/code/skills/design/design-md/library/miro.md +209 -0
- package/data/harnesses/code/skills/design/design-md/library/mistral-ai.md +201 -0
- package/data/harnesses/code/skills/design/design-md/library/mongodb.md +201 -0
- package/data/harnesses/code/skills/design/design-md/library/notion.md +204 -0
- package/data/harnesses/code/skills/design/design-md/library/nvidia.md +215 -0
- package/data/harnesses/code/skills/design/design-md/library/ollama.md +213 -0
- package/data/harnesses/code/skills/design/design-md/library/opencode-ai.md +216 -0
- package/data/harnesses/code/skills/design/design-md/library/posthog.md +218 -0
- package/data/harnesses/code/skills/design/design-md/library/raycast.md +214 -0
- package/data/harnesses/code/skills/design/design-md/library/replicate.md +202 -0
- package/data/harnesses/code/skills/design/design-md/library/resend.md +203 -0
- package/data/harnesses/code/skills/design/design-md/library/revolut.md +203 -0
- package/data/harnesses/code/skills/design/design-md/library/runwayml.md +203 -0
- package/data/harnesses/code/skills/design/design-md/library/sanity.md +200 -0
- package/data/harnesses/code/skills/design/design-md/library/sentry.md +201 -0
- package/data/harnesses/code/skills/design/design-md/library/shopify.md +202 -0
- package/data/harnesses/code/skills/design/design-md/library/slack.md +202 -0
- package/data/harnesses/code/skills/design/design-md/library/spacex.md +206 -0
- package/data/harnesses/code/skills/design/design-md/library/spotify.md +206 -0
- package/data/harnesses/code/skills/design/design-md/library/stripe.md +196 -0
- package/data/harnesses/code/skills/design/design-md/library/supabase.md +196 -0
- package/data/harnesses/code/skills/design/design-md/library/superhuman.md +194 -0
- package/data/harnesses/code/skills/design/design-md/library/tesla.md +198 -0
- package/data/harnesses/code/skills/design/design-md/library/theverge.md +199 -0
- package/data/harnesses/code/skills/design/design-md/library/together-ai.md +193 -0
- package/data/harnesses/code/skills/design/design-md/library/uber.md +195 -0
- package/data/harnesses/code/skills/design/design-md/library/vercel.md +195 -0
- package/data/harnesses/code/skills/design/design-md/library/voltagent.md +197 -0
- package/data/harnesses/code/skills/design/design-md/library/warp.md +196 -0
- package/data/harnesses/code/skills/design/design-md/library/webflow.md +197 -0
- package/data/harnesses/code/skills/design/design-md/library/wired.md +197 -0
- package/data/harnesses/code/skills/design/design-md/library/wise.md +198 -0
- package/data/harnesses/code/skills/design/design-md/library/x-ai.md +199 -0
- package/data/harnesses/code/skills/design/design-md/library/zapier.md +198 -0
- package/data/harnesses/code/skills/design/design-md/nurix.md +214 -0
- package/data/harnesses/code/skills/design/design-md/variants/editorial-luxury.md +184 -0
- package/data/harnesses/code/skills/design/design-md/variants/expressive-saas.md +216 -0
- package/data/harnesses/code/skills/design/design-md/variants/quiet-premium.md +211 -0
- package/data/harnesses/code/skills/design/design-md/variants/terse-dense-operator.md +212 -0
- package/data/harnesses/code/skills/design/design-md/variants/warm-approachable.md +216 -0
- package/data/harnesses/code/skills/design/references/compose.md +23 -0
- package/data/harnesses/code/skills/design/references/content.md +28 -0
- package/data/harnesses/code/skills/design/references/emission.md +21 -0
- package/data/harnesses/code/skills/design/references/existing-apps.md +27 -0
- package/data/harnesses/code/skills/design/references/intake.md +36 -0
- package/data/harnesses/code/skills/design/references/object-pass.md +24 -0
- package/data/harnesses/code/skills/design/references/ship-gate.md +29 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/Readme.md +195 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/ai-layer.md +49 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/attributes-lifecycle.md +43 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/container-choice.md +44 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/creation-paths.md +46 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/dashboards.md +42 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/modes.md +42 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/object-model.md +46 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/page-archetype.md +48 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/promotion-demotion.md +37 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/settings.md +42 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/standard-pages.md +46 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/state-matrix.md +41 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/table-mechanics.md +48 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/verbs.md +45 -0
- package/data/harnesses/code/skills/design/references/ux-patterns/viewer-context.md +40 -0
- package/data/harnesses/code/skills/design/scripts/README-validator.md +27 -0
- package/data/harnesses/code/skills/design/scripts/select-chart.mjs +596 -0
- package/data/harnesses/code/skills/design/scripts/validate-design-md.mjs +1198 -0
- package/data/harnesses/discussion/agents/discussion-baseline.md +1 -1
- package/data/harnesses/discussion/harness.json +1 -1
- package/data/harnesses/etna/agents/maintenance.md +1 -1
- package/data/harnesses/etna/harness.json +1 -1
- package/data/harnesses/hr/CLAUDE.md +1 -1
- package/data/harnesses/hr/harness.json +1 -1
- package/package.json +1 -1
- package/data/harnesses/code/skills/design/data/catalog/rules.csv +0 -137
- package/data/harnesses/code/skills/design/data/combinations/Readme.md +0 -33
- package/data/harnesses/code/skills/design/data/combinations/accent-presets.md +0 -113
- package/data/harnesses/code/skills/design/data/combinations/charts.csv +0 -33
- package/data/harnesses/code/skills/design/data/combinations/fonts-known.json +0 -448
- package/data/harnesses/code/skills/design/data/combinations/icons.csv +0 -157
- package/data/harnesses/code/skills/design/data/combinations/landing.csv +0 -38
- package/data/harnesses/code/skills/design/data/combinations/lucide-names.json +0 -2001
- package/data/harnesses/code/skills/design/data/combinations/manifest.json +0 -330
- package/data/harnesses/code/skills/design/data/combinations/motion.csv +0 -10
- package/data/harnesses/code/skills/design/data/combinations/palettes.csv +0 -92
- package/data/harnesses/code/skills/design/data/combinations/product-router.csv +0 -80
- package/data/harnesses/code/skills/design/data/combinations/styles.csv +0 -67
- package/data/harnesses/code/skills/design/data/combinations/typography.csv +0 -64
- package/data/harnesses/code/skills/design/data/design-md/SCHEMA.md +0 -106
- package/data/harnesses/code/skills/design/data/design-md/library/airbnb.md +0 -154
- package/data/harnesses/code/skills/design/data/design-md/library/airtable.md +0 -151
- package/data/harnesses/code/skills/design/data/design-md/library/anthropic-claude.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/apple.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/binance.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/bmw.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/cal.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/clay.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/clickhouse.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/cohere.md +0 -147
- package/data/harnesses/code/skills/design/data/design-md/library/coinbase.md +0 -156
- package/data/harnesses/code/skills/design/data/design-md/library/composio.md +0 -138
- package/data/harnesses/code/skills/design/data/design-md/library/cursor.md +0 -138
- package/data/harnesses/code/skills/design/data/design-md/library/elevenlabs.md +0 -137
- package/data/harnesses/code/skills/design/data/design-md/library/expo.md +0 -148
- package/data/harnesses/code/skills/design/data/design-md/library/figma.md +0 -141
- package/data/harnesses/code/skills/design/data/design-md/library/framer.md +0 -156
- package/data/harnesses/code/skills/design/data/design-md/library/hashicorp.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/ibm.md +0 -153
- package/data/harnesses/code/skills/design/data/design-md/library/intercom.md +0 -158
- package/data/harnesses/code/skills/design/data/design-md/library/kraken.md +0 -156
- package/data/harnesses/code/skills/design/data/design-md/library/linear-app.md +0 -122
- package/data/harnesses/code/skills/design/data/design-md/library/lovable.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/meta.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/minimax.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/mintlify.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/miro.md +0 -153
- package/data/harnesses/code/skills/design/data/design-md/library/mistral-ai.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/mongodb.md +0 -155
- package/data/harnesses/code/skills/design/data/design-md/library/notion.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/nvidia.md +0 -141
- package/data/harnesses/code/skills/design/data/design-md/library/ollama.md +0 -145
- package/data/harnesses/code/skills/design/data/design-md/library/opencode-ai.md +0 -142
- package/data/harnesses/code/skills/design/data/design-md/library/posthog.md +0 -152
- package/data/harnesses/code/skills/design/data/design-md/library/raycast.md +0 -137
- package/data/harnesses/code/skills/design/data/design-md/library/replicate.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/resend.md +0 -170
- package/data/harnesses/code/skills/design/data/design-md/library/revolut.md +0 -145
- package/data/harnesses/code/skills/design/data/design-md/library/runwayml.md +0 -137
- package/data/harnesses/code/skills/design/data/design-md/library/sanity.md +0 -168
- package/data/harnesses/code/skills/design/data/design-md/library/sentry.md +0 -163
- package/data/harnesses/code/skills/design/data/design-md/library/shopify.md +0 -147
- package/data/harnesses/code/skills/design/data/design-md/library/slack.md +0 -158
- package/data/harnesses/code/skills/design/data/design-md/library/spacex.md +0 -171
- package/data/harnesses/code/skills/design/data/design-md/library/spotify.md +0 -166
- package/data/harnesses/code/skills/design/data/design-md/library/stripe.md +0 -160
- package/data/harnesses/code/skills/design/data/design-md/library/supabase.md +0 -173
- package/data/harnesses/code/skills/design/data/design-md/library/superhuman.md +0 -145
- package/data/harnesses/code/skills/design/data/design-md/library/tesla.md +0 -153
- package/data/harnesses/code/skills/design/data/design-md/library/theverge.md +0 -167
- package/data/harnesses/code/skills/design/data/design-md/library/together-ai.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/uber.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/vercel.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/voltagent.md +0 -130
- package/data/harnesses/code/skills/design/data/design-md/library/warp.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/webflow.md +0 -140
- package/data/harnesses/code/skills/design/data/design-md/library/wired.md +0 -139
- package/data/harnesses/code/skills/design/data/design-md/library/wise.md +0 -137
- package/data/harnesses/code/skills/design/data/design-md/library/x-ai.md +0 -138
- package/data/harnesses/code/skills/design/data/design-md/library/zapier.md +0 -158
- package/data/harnesses/code/skills/design/data/design-md/nurix.md +0 -138
- package/data/harnesses/code/skills/design/data/design-tokens/SCHEMA.md +0 -695
- package/data/harnesses/code/skills/design/data/design-tokens/airbnb/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/airbnb/design.tokens.json +0 -1272
- package/data/harnesses/code/skills/design/data/design-tokens/airtable/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/airtable/design.tokens.json +0 -1268
- package/data/harnesses/code/skills/design/data/design-tokens/anthropic-claude/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/anthropic-claude/design.tokens.json +0 -1273
- package/data/harnesses/code/skills/design/data/design-tokens/apple/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/apple/design.tokens.json +0 -1262
- package/data/harnesses/code/skills/design/data/design-tokens/binance/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/binance/design.tokens.json +0 -1257
- package/data/harnesses/code/skills/design/data/design-tokens/bmw/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/bmw/design.tokens.json +0 -1270
- package/data/harnesses/code/skills/design/data/design-tokens/cal/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/cal/design.tokens.json +0 -1270
- package/data/harnesses/code/skills/design/data/design-tokens/clay/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/clay/design.tokens.json +0 -1261
- package/data/harnesses/code/skills/design/data/design-tokens/clickhouse/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/clickhouse/design.tokens.json +0 -1268
- package/data/harnesses/code/skills/design/data/design-tokens/cohere/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/cohere/design.tokens.json +0 -1281
- package/data/harnesses/code/skills/design/data/design-tokens/coinbase/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/coinbase/design.tokens.json +0 -1262
- package/data/harnesses/code/skills/design/data/design-tokens/composio/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/composio/design.tokens.json +0 -1271
- package/data/harnesses/code/skills/design/data/design-tokens/cursor/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/cursor/design.tokens.json +0 -1276
- package/data/harnesses/code/skills/design/data/design-tokens/elevenlabs/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/elevenlabs/design.tokens.json +0 -1293
- package/data/harnesses/code/skills/design/data/design-tokens/expo/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/expo/design.tokens.json +0 -1270
- package/data/harnesses/code/skills/design/data/design-tokens/figma/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/figma/design.tokens.json +0 -1276
- package/data/harnesses/code/skills/design/data/design-tokens/framer/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/framer/design.tokens.json +0 -1267
- package/data/harnesses/code/skills/design/data/design-tokens/goldens.json +0 -251
- package/data/harnesses/code/skills/design/data/design-tokens/hashicorp/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/hashicorp/design.tokens.json +0 -1273
- package/data/harnesses/code/skills/design/data/design-tokens/ibm/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/ibm/design.tokens.json +0 -1286
- package/data/harnesses/code/skills/design/data/design-tokens/intercom/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/intercom/design.tokens.json +0 -1290
- package/data/harnesses/code/skills/design/data/design-tokens/kraken/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/kraken/design.tokens.json +0 -1270
- package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.resolver.json +0 -23
- package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.tokens.dark.json +0 -599
- package/data/harnesses/code/skills/design/data/design-tokens/linear-app/design.tokens.json +0 -1272
- package/data/harnesses/code/skills/design/data/design-tokens/lovable/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/lovable/design.tokens.json +0 -1267
- package/data/harnesses/code/skills/design/data/design-tokens/meta/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/meta/design.tokens.json +0 -1289
- package/data/harnesses/code/skills/design/data/design-tokens/minimax/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/minimax/design.tokens.json +0 -1258
- package/data/harnesses/code/skills/design/data/design-tokens/mintlify/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/mintlify/design.tokens.json +0 -1284
- package/data/harnesses/code/skills/design/data/design-tokens/miro/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/miro/design.tokens.json +0 -1291
- package/data/harnesses/code/skills/design/data/design-tokens/mistral-ai/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/mistral-ai/design.tokens.json +0 -1263
- package/data/harnesses/code/skills/design/data/design-tokens/mongodb/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/mongodb/design.tokens.json +0 -1270
- package/data/harnesses/code/skills/design/data/design-tokens/notion/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/notion/design.tokens.json +0 -1261
- package/data/harnesses/code/skills/design/data/design-tokens/nurix/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/nurix/design.tokens.json +0 -1209
- package/data/harnesses/code/skills/design/data/design-tokens/nvidia/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/nvidia/design.tokens.json +0 -1265
- package/data/harnesses/code/skills/design/data/design-tokens/ollama/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/ollama/design.tokens.json +0 -1253
- package/data/harnesses/code/skills/design/data/design-tokens/opencode-ai/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/opencode-ai/design.tokens.json +0 -1268
- package/data/harnesses/code/skills/design/data/design-tokens/posthog/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/posthog/design.tokens.json +0 -1261
- package/data/harnesses/code/skills/design/data/design-tokens/raycast/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/raycast/design.tokens.json +0 -1263
- package/data/harnesses/code/skills/design/data/design-tokens/replicate/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/replicate/design.tokens.json +0 -1266
- package/data/harnesses/code/skills/design/data/design-tokens/resend/design.resolver.json +0 -23
- package/data/harnesses/code/skills/design/data/design-tokens/resend/design.tokens.dark.json +0 -623
- package/data/harnesses/code/skills/design/data/design-tokens/resend/design.tokens.json +0 -1276
- package/data/harnesses/code/skills/design/data/design-tokens/revolut/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/revolut/design.tokens.json +0 -1264
- package/data/harnesses/code/skills/design/data/design-tokens/runwayml/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/runwayml/design.tokens.json +0 -1268
- package/data/harnesses/code/skills/design/data/design-tokens/sanity/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/sanity/design.tokens.json +0 -1270
- package/data/harnesses/code/skills/design/data/design-tokens/sentry/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/sentry/design.tokens.json +0 -1288
- package/data/harnesses/code/skills/design/data/design-tokens/shopify/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/shopify/design.tokens.json +0 -1272
- package/data/harnesses/code/skills/design/data/design-tokens/slack/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/slack/design.tokens.json +0 -1265
- package/data/harnesses/code/skills/design/data/design-tokens/spacex/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/spacex/design.tokens.json +0 -1287
- package/data/harnesses/code/skills/design/data/design-tokens/spotify/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/spotify/design.tokens.json +0 -1286
- package/data/harnesses/code/skills/design/data/design-tokens/stripe/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/stripe/design.tokens.json +0 -1285
- package/data/harnesses/code/skills/design/data/design-tokens/supabase/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/supabase/design.tokens.json +0 -1287
- package/data/harnesses/code/skills/design/data/design-tokens/superhuman/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/superhuman/design.tokens.json +0 -1278
- package/data/harnesses/code/skills/design/data/design-tokens/tesla/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/tesla/design.tokens.json +0 -1269
- package/data/harnesses/code/skills/design/data/design-tokens/theverge/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/theverge/design.tokens.json +0 -1285
- package/data/harnesses/code/skills/design/data/design-tokens/together-ai/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/together-ai/design.tokens.json +0 -1303
- package/data/harnesses/code/skills/design/data/design-tokens/uber/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/uber/design.tokens.json +0 -1274
- package/data/harnesses/code/skills/design/data/design-tokens/vercel/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/vercel/design.tokens.json +0 -1296
- package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.resolver.json +0 -23
- package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.tokens.dark.json +0 -612
- package/data/harnesses/code/skills/design/data/design-tokens/voltagent/design.tokens.json +0 -1282
- package/data/harnesses/code/skills/design/data/design-tokens/warp/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/warp/design.tokens.json +0 -1287
- package/data/harnesses/code/skills/design/data/design-tokens/webflow/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/webflow/design.tokens.json +0 -1268
- package/data/harnesses/code/skills/design/data/design-tokens/wired/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/wired/design.tokens.json +0 -1276
- package/data/harnesses/code/skills/design/data/design-tokens/wise/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/wise/design.tokens.json +0 -1273
- package/data/harnesses/code/skills/design/data/design-tokens/x-ai/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/x-ai/design.tokens.json +0 -1296
- package/data/harnesses/code/skills/design/data/design-tokens/zapier/design.resolver.json +0 -20
- package/data/harnesses/code/skills/design/data/design-tokens/zapier/design.tokens.json +0 -1286
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/command-center.tsx +0 -249
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/create-edit.tsx +0 -249
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/dashboard.tsx +0 -225
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/entity-detail.tsx +0 -249
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/list-detail.tsx +0 -224
- package/data/harnesses/code/skills/design/data/operator-pack/exemplars/log-stream.tsx +0 -249
- package/data/harnesses/code/skills/design/data/operator-pack/fixtures.md +0 -88
- package/data/harnesses/code/skills/design/data/operator-pack/surface-catalog.md +0 -132
- package/data/harnesses/code/skills/design/data/operator-pack/trust-rubric.md +0 -76
- package/data/harnesses/code/skills/design/references/create.md +0 -173
- package/data/harnesses/code/skills/design/references/diagnosis.md +0 -108
- package/data/harnesses/code/skills/design/references/hard-rules.md +0 -177
- package/data/harnesses/code/skills/design/references/improve.md +0 -116
- package/data/harnesses/code/skills/design/references/interaction.md +0 -77
- package/data/harnesses/code/skills/design/references/introspect.md +0 -100
- package/data/harnesses/code/skills/design/references/lifecycle.md +0 -73
- package/data/harnesses/code/skills/design/references/personality.md +0 -575
- package/data/harnesses/code/skills/design/references/structure.md +0 -159
- package/data/harnesses/code/skills/design/scripts/convert-design-md.mjs +0 -1312
- package/data/harnesses/code/skills/design/scripts/derive-personality.mjs +0 -1498
- package/data/harnesses/code/skills/design/scripts/generate-fixtures.mjs +0 -551
- package/data/harnesses/code/skills/design/scripts/lib/checks.mjs +0 -1092
- package/data/harnesses/code/skills/design/scripts/lib/golden.mjs +0 -26
- package/data/harnesses/code/skills/design/scripts/lib/vocabulary.mjs +0 -65
- package/data/harnesses/code/skills/design/scripts/phase-gate.mjs +0 -538
- package/data/harnesses/code/skills/design/scripts/preship-sweep.mjs +0 -312
- package/data/harnesses/code/skills/design/scripts/render-rung.mjs +0 -890
- package/data/harnesses/code/skills/design/scripts/scaffold.mjs +0 -769
- package/data/harnesses/code/skills/design/scripts/self-integrity.mjs +0 -675
- package/data/harnesses/code/skills/design/scripts/snapshot-goldens.mjs +0 -164
- package/data/harnesses/code/skills/design/scripts/validate-combinations.mjs +0 -439
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: creation-paths
|
|
3
|
+
class: b2
|
|
4
|
+
sourced: 2026-07-12
|
|
5
|
+
source: "b2b-ux-patterns ch.9"
|
|
6
|
+
license: open
|
|
7
|
+
---
|
|
8
|
+
# Pass: creation paths & data entry
|
|
9
|
+
|
|
10
|
+
**Inputs:** per object's birth inventory — `manualCreate`, `bulkOnboarding`, `bornFromTransformation`, `bornFromTemplate`, `recurs`, `externalSourceOfTruth`; per create surface — `creationFrequency` (high | low), `fieldCount` (few | many), `interdependentFields`, `bornComplete`, `sequentialDependencies`, `isGridPrimaryWrite`, `requiredRelationMayBeMissing`, `duplicateProneCreate`, `serverTruthValidation`; per edit surface — `editRegime` (inline | explicit-mode | canvas), `concurrentEditors`, `isConfigObject`.
|
|
11
|
+
**Owns:** `creationPaths`, `requiredMechanics`, `clarifications`.
|
|
12
|
+
**Output artifact:** the per-object creation-path catalog — which of form / import / conversion / clone / recurrence / sync a record is born through, each with its container and shape — plus the edit regime, persistence policy, validation contract, and config draft/publish lifecycle.
|
|
13
|
+
|
|
14
|
+
## The rule
|
|
15
|
+
|
|
16
|
+
**A hand-typed form is one creation path among equals.** The birth inventory declares which paths an object needs, and each is a first-class surface, not an afterthought. *Import* is bulk creation as a flow — upload, map columns to fields, per-row validation preview, a dedupe/upsert key, then a background job whose completion carries a per-row error report, never a blanket success. *Conversion* is born-from transformation (Lead → Account + Contact + Opportunity): it previews what will be created and how fields map, creates several records atomically, and never routes its output through a create form. *Clone* is born-from-existing — templates, duplicate, save-as-template — carrying contextual defaults forward. *Recurrence* materializes instances on a schedule. *Sync ingestion* lands external records carrying their origin provenance. Only when none of these apply is a record hand-typed.
|
|
17
|
+
|
|
18
|
+
**Create container follows creation frequency, field count, and source-context retention** — the same workflow-first logic as detail containers. High-frequency objects created mid-task get a **quick-create** that captures only the required fields and returns the user to their flow, and are **created thin then edited fat** — capture the minimum viable record (often just a name), commit immediately, fill the rest in place over time. Low-frequency, high-ceremony objects with many interdependent required fields get a **full-page create**. Objects with referential-integrity requirements at birth (an invoice line needs an amount, a payment needs a currency) are **born complete** through a gated form — never create-thin. In the grid archetype the table is the write surface, so creation is an **inline row**. And whenever a demoted object is a required or common relation of a promoted one, the create/edit form offers **nested create-in-context** ("+ New Account" inside the Lead form) — the load-bearing mechanism that makes promotion/demotion usable; without it, users are forced back to the create-elsewhere flow the demotion was meant to kill.
|
|
19
|
+
|
|
20
|
+
**Creation shape forks on dependency, not size.** Genuinely sequential, dependent, high-stakes decisions get a **multi-step wizard** with per-step validation gates. Many fields with *no* ordering dependency get a **single long form with sticky section nav** — the anti-wizard, skimmable and non-linear; artificial gating on independent fields is a failure. Accelerate every path with smart defaults and contextual prefill (owner defaults to the current user; a record created from a filtered board inherits the column's status), and add **duplicate detection on create** — fuzzy-match identifying fields and surface "this may already exist" with a link to the existing record — wherever an object has multiple entry points.
|
|
21
|
+
|
|
22
|
+
**Edit regime and persistence are declared together.** Inline edit-in-place and always-editable canvases require **autosave with a saved indicator**; surfaces with an explicit Save button require a **dirty-state guard** that warns on navigation and never silently discards. Assume multiple people touch every record: a save landing on a record that changed underneath surfaces a **concurrent-edit conflict prompt** (show what changed; offer merge / overwrite / discard) — never a silent clobber. Server-truth checks (uniqueness, quota, referential validity) run as **async validation** inline. Configuration-like objects — automations, templates, dashboards, pipelines — get a **draft/publish lifecycle**: an editable draft that does not take effect while the published version keeps running, an explicit publish, and an unpublished-changes indicator; editing live config in place is the failure mode. When a manual-create surface has no frequency reading, its container cannot be chosen: clarify.
|
|
23
|
+
|
|
24
|
+
```json decision-table
|
|
25
|
+
{"pass": "creation-paths", "rows": [
|
|
26
|
+
{"when": {"bulkOnboarding": true}, "then": {"creationPaths": {"mustInclude": ["import"]}, "requiredMechanics": {"mustInclude": ["csv-column-mapping", "per-row-validation-preview", "dedupe-upsert-key", "background-job-partial-failure-report"], "mustNotInclude": ["blanket-success-report"]}}, "reason": "bulk-onboarding-is-import"},
|
|
27
|
+
{"when": {"bornFromTransformation": true}, "then": {"creationPaths": {"mustInclude": ["conversion"]}, "requiredMechanics": {"mustInclude": ["conversion-preview-mapping", "atomic-multi-record-create"], "mustNotInclude": ["conversion-through-create-form"]}}, "reason": "transformation-is-conversion"},
|
|
28
|
+
{"when": {"bornFromTemplate": true}, "then": {"creationPaths": {"mustInclude": ["clone"]}, "requiredMechanics": {"mustInclude": ["template-clone-duplicate", "contextual-defaults-retained"]}}, "reason": "born-from-existing-is-clone"},
|
|
29
|
+
{"when": {"recurs": true}, "then": {"creationPaths": {"mustInclude": ["recurrence"]}, "requiredMechanics": {"mustInclude": ["recurrence-materializes-instances"]}}, "reason": "a-repeating-object-is-a-recurrence-path"},
|
|
30
|
+
{"when": {"externalSourceOfTruth": true}, "then": {"creationPaths": {"mustInclude": ["sync"]}, "requiredMechanics": {"mustInclude": ["sync-ingestion-provenance"]}}, "reason": "external-system-is-a-sync-path"},
|
|
31
|
+
{"when": {"manualCreate": true, "creationFrequency": "high"}, "then": {"creationPaths": {"mustInclude": ["form"]}, "requiredMechanics": {"mustInclude": ["quick-create-modal", "create-thin-then-edit-fat"]}}, "reason": "high-frequency-quick-create-thin"},
|
|
32
|
+
{"when": {"manualCreate": true, "creationFrequency": "low", "interdependentFields": true}, "then": {"creationPaths": {"mustInclude": ["form"]}, "requiredMechanics": {"mustInclude": ["full-page-create"]}}, "reason": "low-frequency-high-ceremony-is-full-page"},
|
|
33
|
+
{"when": {"bornComplete": true}, "then": {"requiredMechanics": {"mustInclude": ["born-complete-gated-form"], "mustNotInclude": ["create-thin-then-edit-fat"]}}, "reason": "referential-integrity-forces-born-complete"},
|
|
34
|
+
{"when": {"isGridPrimaryWrite": true}, "then": {"requiredMechanics": {"mustInclude": ["inline-row-create"]}}, "reason": "grid-writes-in-the-row"},
|
|
35
|
+
{"when": {"requiredRelationMayBeMissing": true}, "then": {"requiredMechanics": {"mustInclude": ["nested-create-in-context"]}}, "reason": "demotion-needs-inline-parent-create"},
|
|
36
|
+
{"when": {"sequentialDependencies": true}, "then": {"requiredMechanics": {"mustInclude": ["multi-step-wizard"]}}, "reason": "dependent-steps-gate"},
|
|
37
|
+
{"when": {"sequentialDependencies": false, "fieldCount": "many"}, "then": {"requiredMechanics": {"mustInclude": ["single-long-form-section-nav"], "mustNotInclude": ["multi-step-wizard"]}}, "reason": "no-dependency-no-wizard"},
|
|
38
|
+
{"when": {"duplicateProneCreate": true}, "then": {"requiredMechanics": {"mustInclude": ["duplicate-detection-on-create"]}}, "reason": "fuzzy-match-before-create"},
|
|
39
|
+
{"when": {"serverTruthValidation": true}, "then": {"requiredMechanics": {"mustInclude": ["async-validation-pending", "inline-blur-validation", "submit-gate-summary", "server-error-field-mapping"]}}, "reason": "server-truth-runs-async-and-maps-to-fields"},
|
|
40
|
+
{"when": {"editRegime": ["inline", "canvas"]}, "then": {"requiredMechanics": {"mustInclude": ["autosave-saved-indicator"]}}, "reason": "inline-and-canvas-autosave"},
|
|
41
|
+
{"when": {"editRegime": "explicit-mode"}, "then": {"requiredMechanics": {"mustInclude": ["explicit-save-dirty-state-guard"], "mustNotInclude": ["silent-discard-on-navigate"]}}, "reason": "deliberate-edits-guard-dirty-state"},
|
|
42
|
+
{"when": {"concurrentEditors": true}, "then": {"requiredMechanics": {"mustInclude": ["concurrent-edit-conflict-prompt"], "mustNotInclude": ["silent-clobber"]}}, "reason": "assume-multiple-editors"},
|
|
43
|
+
{"when": {"isConfigObject": true}, "then": {"requiredMechanics": {"mustInclude": ["draft-publish-lifecycle", "unpublished-changes-indicator"], "mustNotInclude": ["edit-live-config-in-place"]}}, "reason": "config-drafts-then-publishes"},
|
|
44
|
+
{"when": {"manualCreate": true, "creationFrequency": "__absent__"}, "then": {"clarifications": ["creation-frequency-unspecified"]}, "reason": "create-container-needs-a-frequency-reading"}
|
|
45
|
+
]}
|
|
46
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: dashboards
|
|
3
|
+
class: b2
|
|
4
|
+
sourced: 2026-07-12
|
|
5
|
+
source: "b2b-ux-patterns ch.15"
|
|
6
|
+
license: open
|
|
7
|
+
---
|
|
8
|
+
# Pass: dashboards
|
|
9
|
+
|
|
10
|
+
**Inputs:** per canvas — `dashboardJob` (monitoring | narrative | work-router), `multiJobCanvas`, `cachedDecisionData`, `viewerScopedMetrics`, `promotionRole` (manager | operator), `pushDigest`; per tile — `tile`, `monitoringTile`, `thresholdDeclared`, `trendTileRequested`, `sourceHistoryClass` (overwrite | sampled | logged).
|
|
11
|
+
**Owns:** `archetypes`, `requiredStates`, `requiredMechanics`, `clarifications`.
|
|
12
|
+
**Output artifact:** for each surface a product calls a "dashboard," which of the three archetypes it actually is, the five-part contract every tile obeys, and the data properties (Sampled trends, freshness, config-object thresholds) the surface renders.
|
|
13
|
+
|
|
14
|
+
## The rule
|
|
15
|
+
|
|
16
|
+
**"Dashboard" is not one archetype — it is three, with different jobs, metrics, and consumers.** *The monitoring glance* answers "is anything on fire?" in under five seconds and lets the user leave; **success = the user leaves quickly**; it renders **judgment, not data** — green/amber/red against declared thresholds, states instead of precise values, anomaly-first ordering, pre-attentive color-plus-icon (never color alone). A wall of raw numbers on a monitoring surface is an abdication. *The narrative report* tells what happened this period and why, usually to someone other than the operator; **success = the reader trusts and can retell the story**; period comparisons and targets-vs-actuals everywhere, trend context on every number, an explicit as-of timestamp and reporting-timezone declaration, and the house-knowledge corrective behind the significance gate. *The work router in dashboard clothes* is really the Home/work router — my tasks, approvals waiting, the ranked next-best-action queue; **success = click-through, not dwell**; it is a queue and is already specified by that archetype — recognize it and never mix it onto a monitoring or narrative canvas.
|
|
17
|
+
|
|
18
|
+
**The mixing rule: one canvas serves one of the three jobs.** If a page must carry more than one (a home page with a status strip above a worklist), zone them explicitly — separate regions with separate refresh and interaction contracts — rather than interleaving tiles of different species.
|
|
19
|
+
|
|
20
|
+
**Every number is a door — a number alone is decoration.** The full tile contract, required of every tile: (1) **the number**, formatted per its field type, no precision theater; (2) **a comparison** — vs target, prior period, or cohort — without which the reader cannot tell if the number is good; (3) **a trend** — sparkline or delta, shape not just position; (4) **a state** — good/warn/bad, which requires a declared threshold, so no threshold means no state and no place on a monitoring surface; (5) **a door** — clicking lands on the exact filtered record set or analytics view that *produced* the number. A stat tile is a saved view rendered as an aggregate, and the door is a reconciliation requirement: the count behind the door must equal the number on the tile, or trust in the whole surface dies. Browse-index stat cards obey the same five-part contract, scoped to the index's current filter.
|
|
21
|
+
|
|
22
|
+
**Dashboards are where three lifecycle declarations become visible.** Trend tiles are the UI output of the **Sampled** history class — a field declared Overwrite has no trend to show, and an empty trend tile is a history-class declaration failure, not a chart bug. **Freshness is mandatory** — every tile group carries "updated N minutes ago" and degraded tiles fail individually, so one dead query never blanks the board. **Targets and thresholds are config objects** — owned, versioned, auditable — not constants buried in tile definitions. The whole surface renders f(data, viewer): a scope switcher (me / my team / org) rather than separate dashboards per rung, tiles gated by role and plan.
|
|
23
|
+
|
|
24
|
+
**Promotion follows frequency × criticality, not habit** — dashboards go high for managers and low for operators, whose landing surface is the queue or index with the glance strip at most zoned above it; defaulting every sidebar item to a dashboard is the dashboard-first fallacy. The 2026 push inversion turns the monitoring dashboard from the ritually-visited wall into the drill-down destination behind a pushed digest — design the digest → dashboard → door → records chain unbroken, and ship auto-narration only behind the significance gate. A monitoring tile with no declared threshold cannot render a state: clarify. A trend tile over an Overwrite field has no trend to show: clarify.
|
|
25
|
+
|
|
26
|
+
```json decision-table
|
|
27
|
+
{"pass": "dashboards", "rows": [
|
|
28
|
+
{"when": {"dashboardJob": "monitoring"}, "then": {"archetypes": {"mustInclude": ["dashboard"]}, "requiredMechanics": {"mustInclude": ["judgment-not-data", "declared-thresholds", "state-color-plus-icon", "anomaly-first-ordering"], "mustNotInclude": ["wall-of-raw-numbers", "color-alone-encoding"]}}, "reason": "monitoring-renders-judgment"},
|
|
29
|
+
{"when": {"dashboardJob": "narrative"}, "then": {"archetypes": {"mustInclude": ["dashboard"]}, "requiredMechanics": {"mustInclude": ["period-comparison", "targets-vs-actuals", "trend-on-every-number", "as-of-timestamp", "reporting-timezone-declaration"]}}, "reason": "narrative-tells-a-trusted-story"},
|
|
30
|
+
{"when": {"dashboardJob": "work-router"}, "then": {"archetypes": {"mustInclude": ["queue"], "mustNotInclude": ["dashboard"]}, "requiredMechanics": {"mustInclude": ["viewer-scoped-worklist", "click-through-not-dwell"], "mustNotInclude": ["mixed-onto-monitoring-canvas"]}}, "reason": "work-router-is-a-queue-not-a-dashboard"},
|
|
31
|
+
{"when": {"tile": true}, "then": {"requiredMechanics": {"mustInclude": ["tile-number-formatted", "tile-comparison", "tile-trend", "tile-state-threshold", "tile-door-reconciled"], "mustNotInclude": ["number-alone", "unreconciled-door"]}}, "reason": "every-number-is-a-door"},
|
|
32
|
+
{"when": {"multiJobCanvas": true}, "then": {"requiredMechanics": {"mustInclude": ["zone-explicitly-separate-regions"], "mustNotInclude": ["interleave-tile-species"]}}, "reason": "one-canvas-one-job"},
|
|
33
|
+
{"when": {"cachedDecisionData": true}, "then": {"requiredStates": {"mustInclude": ["stale", "degraded"]}, "requiredMechanics": {"mustInclude": ["freshness-updated-n-min", "degraded-tiles-fail-individually"]}}, "reason": "decisions-get-made-on-cached-numbers"},
|
|
34
|
+
{"when": {"viewerScopedMetrics": true}, "then": {"requiredMechanics": {"mustInclude": ["scope-switcher-me-team-org", "role-plan-gated-tiles"]}}, "reason": "dashboard-renders-f-data-viewer"},
|
|
35
|
+
{"when": {"promotionRole": "manager"}, "then": {"requiredMechanics": {"mustInclude": ["dashboard-sidebar-promotion"]}}, "reason": "dashboards-are-high-for-managers"},
|
|
36
|
+
{"when": {"promotionRole": "operator"}, "then": {"requiredMechanics": {"mustInclude": ["glance-strip-zoned-above-queue"], "mustNotInclude": ["dashboard-first-fallacy"]}}, "reason": "operators-land-on-a-queue-not-a-dashboard"},
|
|
37
|
+
{"when": {"pushDigest": true}, "then": {"requiredMechanics": {"mustInclude": ["subscribe-to-metric-digest", "digest-to-dashboard-to-door-chain", "auto-narration-behind-significance-gate"]}}, "reason": "push-inversion-precedes-the-visit"},
|
|
38
|
+
{"when": {"trendTileRequested": true, "sourceHistoryClass": "sampled"}, "then": {"requiredMechanics": {"mustInclude": ["sparkline-from-sampled-class"]}}, "reason": "trend-tiles-render-the-sampled-class"},
|
|
39
|
+
{"when": {"monitoringTile": true, "thresholdDeclared": false}, "then": {"clarifications": ["threshold-unspecified"]}, "reason": "no-threshold-no-state-no-monitoring-tile"},
|
|
40
|
+
{"when": {"trendTileRequested": true, "sourceHistoryClass": "overwrite"}, "then": {"clarifications": ["trend-needs-sampled-class"]}, "reason": "overwrite-field-has-no-trend-to-show"}
|
|
41
|
+
]}
|
|
42
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: modes
|
|
3
|
+
class: b2
|
|
4
|
+
sourced: 2026-07-12
|
|
5
|
+
source: "b2b-ux-patterns ch.5"
|
|
6
|
+
license: open
|
|
7
|
+
---
|
|
8
|
+
# Pass: user modes
|
|
9
|
+
|
|
10
|
+
**Inputs:** per role × dataset — `mode` (monitoring | triage | procedural | exception | approval | investigation | exploration | authoring | reconciliation | comparison | batch-mutation | configuration | collaboration | reporting | learning | supervision), `sameDataMultipleModes`.
|
|
11
|
+
**Owns:** `archetypes`, `requiredMechanics`.
|
|
12
|
+
**Output artifact:** the mode inventory per dataset — which directly selects the page archetype (conformed to the pinned seven-archetype roster: browse, queue, grid, record-detail, dashboard, creation-flow, settings) and the feature requirements per surface.
|
|
13
|
+
|
|
14
|
+
## The rule
|
|
15
|
+
|
|
16
|
+
A mode is a behaviorally distinct way of using the product; it earns a place only if it demands different UI — different layout, affordances, success metric. **Modes are not persona traits:** the same user on the same data switches modes hour to hour (monitoring at 9:00, triage at 9:15, procedural until lunch, an exception at 2:00, approvals at 4:00). Never map persona → mode and design one surface per persona; inventory which modes each role enters per dataset and let one dataset serve several modes — a leads list must support monitoring (stat glance), triage (route verbs, bulk bar), and batch mutation (grid selection) without becoming three pages.
|
|
17
|
+
|
|
18
|
+
**Mode selects archetype — not the object.** When a screen feels wrong despite showing the right object, the usual cause is a mode mismatch: an index built for browsing handed to a team that triages, or a settings *page* given to what is actually a configuration *mode* needing preview and rollback. Distinctions the table encodes: investigation has a fixed question (timeline, trail, drill); exploration has none yet (pivot, segment — the question is the output). Triage routes without resolving; procedural resolves and takes the next. Approval judges someone else's finished output; supervision (the fastest-growing mode of 2025–26) steers an autonomous worker mid-flight — pause, redirect, resume — and is neither monitoring (no intervention), approval (finished artifact), nor exception handling (single-user improvisation after the playbook fails). Exception handling is exactly where UX quality matters most, because the designed flows have run out.
|
|
19
|
+
|
|
20
|
+
Richer surface forms noted in `page-archetype` (conversational inbox, split-pane console, canvas builder, report builder, wizard, log explorer, merge/diff views) are realizations of these roster mappings, not extra archetypes.
|
|
21
|
+
|
|
22
|
+
```json decision-table
|
|
23
|
+
{"pass": "modes", "rows": [
|
|
24
|
+
{"when": {"mode": "monitoring"}, "then": {"archetypes": {"mustInclude": ["dashboard"]}, "requiredMechanics": {"mustInclude": ["glanceable-status", "declared-thresholds-config"]}}, "reason": "nothing-on-fire-glance"},
|
|
25
|
+
{"when": {"mode": "triage"}, "then": {"archetypes": {"mustInclude": ["queue"], "mustNotInclude": ["browse"]}, "requiredMechanics": {"mustInclude": ["route-verbs-on-rows", "bulk-triage-bar", "keyboard-velocity", "unread-new-markers"]}}, "reason": "route-not-resolve"},
|
|
26
|
+
{"when": {"mode": "procedural"}, "then": {"archetypes": {"mustInclude": ["queue", "record-detail"]}, "requiredMechanics": {"mustInclude": ["take-next-auto-advance", "transition-required-fields"]}}, "reason": "assembly-line-to-done"},
|
|
27
|
+
{"when": {"mode": "exception"}, "then": {"archetypes": {"mustInclude": ["record-detail"]}, "requiredMechanics": {"mustInclude": ["reason-capture-required", "logged-history-class", "escalation-path"]}}, "reason": "break-glass-audited"},
|
|
28
|
+
{"when": {"mode": "approval"}, "then": {"archetypes": {"mustInclude": ["queue", "record-detail"]}, "requiredMechanics": {"mustInclude": ["judgment-diff-summary", "approve-reject-rationale"]}}, "reason": "verdict-is-the-work-product"},
|
|
29
|
+
{"when": {"mode": "investigation"}, "then": {"archetypes": {"mustInclude": ["record-detail", "browse"]}, "requiredMechanics": {"mustInclude": ["event-timeline", "drill-through", "cheap-back-navigation"]}}, "reason": "fixed-question-trail"},
|
|
30
|
+
{"when": {"mode": "exploration"}, "then": {"archetypes": {"mustInclude": ["dashboard"]}, "requiredMechanics": {"mustInclude": ["pivot-group-segment", "save-analysis"]}}, "reason": "question-is-the-output"},
|
|
31
|
+
{"when": {"mode": "authoring"}, "then": {"archetypes": {"mustInclude": ["creation-flow"]}, "requiredMechanics": {"mustInclude": ["full-screen-focus", "autosave-indicator", "draft-persistence"]}}, "reason": "chrome-recedes"},
|
|
32
|
+
{"when": {"mode": "reconciliation"}, "then": {"archetypes": {"mustInclude": ["record-detail"]}, "requiredMechanics": {"mustInclude": ["side-by-side-diff", "per-delta-resolve", "field-by-field-picker"]}}, "reason": "difference-oriented"},
|
|
33
|
+
{"when": {"mode": "comparison"}, "then": {"requiredMechanics": {"mustInclude": ["parallel-columns", "period-over-period"]}}, "reason": "choose-a-winner"},
|
|
34
|
+
{"when": {"mode": "batch-mutation"}, "then": {"archetypes": {"mustInclude": ["grid"]}, "requiredMechanics": {"mustInclude": ["multi-select", "bulk-action-bar", "bulk-preview-before-commit", "per-row-partial-failure-report"]}}, "reason": "blast-radius-defines-the-mode"},
|
|
35
|
+
{"when": {"mode": "configuration"}, "then": {"archetypes": {"mustInclude": ["settings"]}, "requiredMechanics": {"mustInclude": ["draft-publish-lifecycle", "impact-preview", "blast-radius-header"]}}, "reason": "rare-consequential-preview-hungry"},
|
|
36
|
+
{"when": {"mode": "collaboration"}, "then": {"archetypes": {"mustInclude": ["record-detail"]}, "requiredMechanics": {"mustInclude": ["activity-composer", "mentions-assignment", "unread-new-markers"]}}, "reason": "conversation-attached-to-data"},
|
|
37
|
+
{"when": {"mode": "reporting"}, "then": {"archetypes": {"mustInclude": ["dashboard"]}, "requiredMechanics": {"mustInclude": ["view-aware-export", "scheduled-delivery", "as-of-timestamp"]}}, "reason": "goal-lives-outside-the-product"},
|
|
38
|
+
{"when": {"mode": "learning"}, "then": {"requiredMechanics": {"mustInclude": ["empty-state-teaching", "sample-data-path", "setup-checklist"]}}, "reason": "scaffolding-experts-never-see"},
|
|
39
|
+
{"when": {"mode": "supervision"}, "then": {"archetypes": {"mustInclude": ["queue", "record-detail"]}, "requiredMechanics": {"mustInclude": ["run-timeline-pause-redirect-resume", "live-plan-visibility", "escalation-to-approval"]}}, "reason": "steering-not-disposal"},
|
|
40
|
+
{"when": {"sameDataMultipleModes": true}, "then": {"requiredMechanics": {"mustInclude": ["multi-mode-single-surface"], "mustNotInclude": ["one-page-per-persona"]}}, "reason": "modes-switch-hourly"}
|
|
41
|
+
]}
|
|
42
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: object-model
|
|
3
|
+
class: b2
|
|
4
|
+
sourced: 2026-07-12
|
|
5
|
+
source: "b2b-ux-patterns ch.1"
|
|
6
|
+
license: open
|
|
7
|
+
---
|
|
8
|
+
# Pass: object model
|
|
9
|
+
|
|
10
|
+
**Inputs:** for each relationship on the object map — `relationshipCardinality`, `childHasOwnLifecycle`, `childMeaningfulAlone`, `editedAtomicallyWithParent`, `associationHasPayload`; plus `collaboration` and `glanceContextNeeded` for the map as a whole.
|
|
11
|
+
**Owns:** `requiredMechanics`, `clarifications`.
|
|
12
|
+
**Output artifact:** the charted object map — every relationship with its assigned UI treatment, junctions promoted where they carry payload, composites flagged for atomic editing, the denormalization list, and a birth inventory per object (the birth inventory's per-path UX is the `creation-paths` pass).
|
|
13
|
+
|
|
14
|
+
## The rule
|
|
15
|
+
|
|
16
|
+
Cardinality deterministically dictates UI treatment — never information size. Two children of identical byte-size get different components based on multiplicity and independence:
|
|
17
|
+
|
|
18
|
+
- **1:1** embeds as fields on the parent detail; no separate surface.
|
|
19
|
+
- **1:few** (bounded, no own lifecycle) is an inline list, fully visible, add/remove in place.
|
|
20
|
+
- **1:many** (unbounded, independently meaningful) is a related list — an embedded mini-index with count, a few columns, row actions, and a "view all" escape to the full filtered index.
|
|
21
|
+
- **M:N** gets a picker (search-select plus create-and-link). **Independence overrides upward:** a 1:few child with its own lifecycle (states, owner, history) earns related-list treatment despite being few.
|
|
22
|
+
|
|
23
|
+
**Junction-as-object:** the moment an M:N association needs any attribute (a role, a label, a date, a status) or its own history, the junction is a first-class object — the picker captures the payload at link time, the related list shows the payload as columns, and editing the association edits the junction, not either endpoint. Pure membership with no payload stays an invisible link table.
|
|
24
|
+
|
|
25
|
+
**Composite / line-item children** (invoice + line items, form + questions) are meaningless alone and edited atomically with the parent: master-detail *form* treatment — an editable grid inside the parent's create/edit surface, saved as one unit. Giving line items related-tab navigation produces absurd flows (navigate away from an unsaved invoice to create its second line).
|
|
26
|
+
|
|
27
|
+
**Denormalization is an explicit pass:** for every relationship ask "which fields from the other side must appear here without a click?" — parent identity fields on child rows (lookups), child aggregates on parents (rollups). Skipping it is why v1 tables show bare foreign-key names.
|
|
28
|
+
|
|
29
|
+
**Users are objects in the model.** There is no separate collaboration layer: ownership, assignment, watching, comments, @mentions, and read/unread are ordinary relationships between User and record. The test of a complete chart: three people touch every record — the model must say who owns it, who watches it, who said what, who has seen it. The User object carries `actor ∈ {human, agent}`; agents are Users, but the fork must be declared because assignment, delegation, audit origin, and access all branch on it.
|
|
30
|
+
|
|
31
|
+
Consult this file once per relationship decision; if cardinality is not yet known, clarify before assigning any treatment.
|
|
32
|
+
|
|
33
|
+
```json decision-table
|
|
34
|
+
{"pass": "object-model", "rows": [
|
|
35
|
+
{"when": {"relationshipCardinality": "one-to-one"}, "then": {"requiredMechanics": {"mustInclude": ["embed-as-fields"], "mustNotInclude": ["related-list-with-view-all"]}}, "reason": "one-to-one-embeds"},
|
|
36
|
+
{"when": {"relationshipCardinality": "one-to-few", "childHasOwnLifecycle": false}, "then": {"requiredMechanics": {"mustInclude": ["inline-list-in-place"], "mustNotInclude": ["related-list-with-view-all"]}}, "reason": "bounded-children-inline"},
|
|
37
|
+
{"when": {"relationshipCardinality": "one-to-few", "childHasOwnLifecycle": true}, "then": {"requiredMechanics": {"mustInclude": ["related-list-with-view-all"]}}, "reason": "independence-overrides-cardinality"},
|
|
38
|
+
{"when": {"relationshipCardinality": "one-to-many", "childMeaningfulAlone": true}, "then": {"requiredMechanics": {"mustInclude": ["related-list-with-view-all", "quick-create-inline"]}}, "reason": "unbounded-children-related-list"},
|
|
39
|
+
{"when": {"relationshipCardinality": "many-to-many", "associationHasPayload": false}, "then": {"requiredMechanics": {"mustInclude": ["association-picker"], "mustNotInclude": ["junction-first-class"]}}, "reason": "pure-membership-invisible-junction"},
|
|
40
|
+
{"when": {"relationshipCardinality": "many-to-many", "associationHasPayload": true}, "then": {"requiredMechanics": {"mustInclude": ["junction-first-class", "payload-at-link-time", "payload-as-columns"]}}, "reason": "junction-carries-payload"},
|
|
41
|
+
{"when": {"childMeaningfulAlone": false, "editedAtomicallyWithParent": true}, "then": {"requiredMechanics": {"mustInclude": ["master-detail-editable-grid", "atomic-parent-child-save"], "mustNotInclude": ["related-list-with-view-all"]}}, "reason": "line-items-edit-atomically"},
|
|
42
|
+
{"when": {"glanceContextNeeded": true}, "then": {"requiredMechanics": {"mustInclude": ["lookup-fields-on-child-rows", "rollup-aggregates-on-parent"]}}, "reason": "denormalize-for-display"},
|
|
43
|
+
{"when": {"collaboration": "concurrent"}, "then": {"requiredMechanics": {"mustInclude": ["users-as-objects", "ownership-assignment-fields", "watcher-junction", "comment-child-objects", "per-viewer-seen-state"]}}, "reason": "three-people-touch-every-record"},
|
|
44
|
+
{"when": {"relationshipCardinality": "__absent__"}, "then": {"clarifications": ["cardinality-unspecified"]}, "reason": "treatment-needs-cardinality"}
|
|
45
|
+
]}
|
|
46
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: page-archetype
|
|
3
|
+
class: b2
|
|
4
|
+
sourced: 2026-07-12
|
|
5
|
+
source: "b2b-ux-patterns ch.7"
|
|
6
|
+
license: open
|
|
7
|
+
---
|
|
8
|
+
# Pass: page archetype
|
|
9
|
+
|
|
10
|
+
**Inputs:** per surface — `primaryJob` (lookup | triage | process | edit-bulk | monitor | narrate-period | route-work | author | configure | approve | investigate | explore | reconcile), `ordering` (priority | sla | age | user-controlled | none), `ownership` (claimable | assigned | individual | shared), `collaboration`, `viewTypeRequested` (table | board | cards | calendar | timeline | map), `hasStatusField`, `hasDateField`, `unitOfWork` (record | machine-proposal | thread), and for existing products `existingArchetype` + `structuralChangeAllowed`.
|
|
11
|
+
**Owns:** `archetypes`, `requiredMechanics`, `requiredStates`, `clarifications`.
|
|
12
|
+
**Output artifact:** one archetype per surface from the pinned seven-archetype roster — **browse, queue, grid, record-detail, dashboard, creation-flow, settings** — plus the projections the view may offer.
|
|
13
|
+
|
|
14
|
+
## The rule
|
|
15
|
+
|
|
16
|
+
**"Index" is three archetypes with opposite success metrics** — collapsing them is the most common structural error in B2B design. *Browse*: read-to-find; success = found it; ordering is the user's convenience; core machinery is sort/filter/search and saved views. *Queue*: process-to-empty; success = the list is empty (celebrate it); ordering is urgency (SLA, age, priority); claim semantics, clocks, and take-next are the archetype, not decorations. *Grid*: edit-in-place; success = data corrected; rows don't open — cells edit. The dominant mode of the primary role on the dataset picks the member; one object may need two members for two roles (a queue for agents, a browse for managers). Prioritized, claimable work is a queue — never a passive browse table. A queue-shaped job with no declared ownership model cannot be laid out: clarify.
|
|
17
|
+
|
|
18
|
+
**View-type is a projection axis, never an archetype.** Board, calendar, timeline, map, cards, and table re-project the *same filtered dataset* on status, time, geography, or identity; a projection is available exactly when the dataset has a field of the projecting type (a board needs a status field, and dragging a card *is* a state transition, subject to the same legality rules as any verb). Filters belong to the view — switching projection never changes which records are present.
|
|
19
|
+
|
|
20
|
+
**Roster conformance for the richer forms:** the home/work router ("My work", approvals waiting, mentions) is a viewer-scoped queue, not a dashboard. The agent-output review queue is a queue ordered by confidence tier whose unit of work is a machine proposal plus its evidence pack. The conversational inbox is a queue whose record is a thread. Composers, canvas builders, wizards, and report builders are creation-flow; log/trace exploration is browse over events with drill into record-detail; merge and reconciliation are record-detail work with side-by-side mechanics.
|
|
21
|
+
|
|
22
|
+
**Existing products:** when the incumbent structure may not change, keep the recorded archetype and layer the needed mechanics onto it (a saved view as a queue lens, claim affordances on the existing table) rather than demanding a new page.
|
|
23
|
+
|
|
24
|
+
```json decision-table
|
|
25
|
+
{"pass": "page-archetype", "rows": [
|
|
26
|
+
{"when": {"primaryJob": "lookup"}, "then": {"archetypes": {"mustInclude": ["browse"], "mustNotInclude": ["queue"]}, "requiredMechanics": {"mustInclude": ["sort-filter-search", "saved-views-first-class"]}}, "reason": "read-to-find"},
|
|
27
|
+
{"when": {"ordering": ["priority", "sla", "age"], "ownership": ["claimable", "assigned"], "structuralChangeAllowed": "__absent__"}, "then": {"archetypes": {"mustInclude": ["queue"], "mustNotInclude": ["browse"]}, "requiredMechanics": {"mustInclude": ["claim-assignment", "sla-age-clock", "take-next-auto-advance", "keyboard-velocity", "bulk-triage-bar"]}, "requiredStates": {"mustInclude": ["empty-cleared"]}}, "reason": "prioritized-claimable-work-is-a-queue"},
|
|
28
|
+
{"when": {"ordering": ["priority", "sla", "age"], "ownership": ["claimable", "assigned"], "structuralChangeAllowed": true}, "then": {"archetypes": {"mustInclude": ["queue"], "mustNotInclude": ["browse"]}, "requiredMechanics": {"mustInclude": ["claim-assignment", "sla-age-clock", "take-next-auto-advance", "keyboard-velocity", "bulk-triage-bar"]}, "requiredStates": {"mustInclude": ["empty-cleared"]}}, "reason": "prioritized-claimable-work-is-a-queue"},
|
|
29
|
+
{"when": {"ordering": ["priority", "sla", "age"], "ownership": "__absent__"}, "then": {"clarifications": ["ownership-model-unspecified"]}, "reason": "queue-needs-an-ownership-model"},
|
|
30
|
+
{"when": {"ownership": "claimable", "collaboration": "concurrent"}, "then": {"requiredStates": {"mustInclude": ["unassigned", "claimed-by-me", "claimed-by-other", "stale"]}, "requiredMechanics": {"mustInclude": ["ownership-conflict"]}}, "reason": "concurrent-claims-need-claim-states"},
|
|
31
|
+
{"when": {"primaryJob": "edit-bulk"}, "then": {"archetypes": {"mustInclude": ["grid"]}, "requiredMechanics": {"mustInclude": ["inline-cell-edit", "type-aware-editors", "fill-down-range-select"]}}, "reason": "edit-in-place-is-its-own-archetype"},
|
|
32
|
+
{"when": {"viewTypeRequested": ["table", "board", "cards", "calendar", "timeline", "map"]}, "then": {"archetypes": {"mustNotInclude": ["table", "board", "cards", "calendar", "timeline", "map"]}, "requiredMechanics": {"mustInclude": ["view-switcher-projection", "filters-stable-across-projections"]}}, "reason": "view-type-is-a-projection"},
|
|
33
|
+
{"when": {"viewTypeRequested": "board", "hasStatusField": true}, "then": {"requiredMechanics": {"mustInclude": ["board-drag-is-transition"]}}, "reason": "drag-is-a-state-transition"},
|
|
34
|
+
{"when": {"viewTypeRequested": "board", "hasStatusField": false}, "then": {"clarifications": ["projection-field-missing"]}, "reason": "board-needs-a-status-field"},
|
|
35
|
+
{"when": {"viewTypeRequested": "calendar", "hasDateField": false}, "then": {"clarifications": ["projection-field-missing"]}, "reason": "calendar-needs-a-date-field"},
|
|
36
|
+
{"when": {"primaryJob": "route-work"}, "then": {"archetypes": {"mustInclude": ["queue"], "mustNotInclude": ["dashboard"]}, "requiredMechanics": {"mustInclude": ["viewer-scoped-work-router", "deep-links-to-records"]}}, "reason": "work-router-is-a-viewer-scoped-queue"},
|
|
37
|
+
{"when": {"unitOfWork": "machine-proposal"}, "then": {"archetypes": {"mustInclude": ["queue"]}, "requiredMechanics": {"mustInclude": ["review-queue-confidence-tiers", "evidence-pack", "batch-approve-within-tier"]}}, "reason": "agent-output-review-queue"},
|
|
38
|
+
{"when": {"unitOfWork": "thread"}, "then": {"archetypes": {"mustInclude": ["queue", "record-detail"]}, "requiredMechanics": {"mustInclude": ["three-pane-inbox", "inline-composer", "audience-split-verbs"]}}, "reason": "conversational-inbox-is-a-thread-queue"},
|
|
39
|
+
{"when": {"primaryJob": "author"}, "then": {"archetypes": {"mustInclude": ["creation-flow"]}}, "reason": "authoring-gets-creation-flow"},
|
|
40
|
+
{"when": {"primaryJob": "configure"}, "then": {"archetypes": {"mustInclude": ["settings"]}}, "reason": "configuration-lands-on-settings"},
|
|
41
|
+
{"when": {"primaryJob": ["monitor", "narrate-period"]}, "then": {"archetypes": {"mustInclude": ["dashboard"]}}, "reason": "glance-and-report-are-dashboard"},
|
|
42
|
+
{"when": {"primaryJob": "investigate"}, "then": {"archetypes": {"mustInclude": ["browse", "record-detail"]}, "requiredMechanics": {"mustInclude": ["event-stream-explorer", "facet-filters", "aggregate-to-event-drill"]}}, "reason": "events-not-records"},
|
|
43
|
+
{"when": {"structuralChangeAllowed": false}, "then": {"requiredMechanics": {"mustInclude": ["layer-mechanics-on-existing-surface"]}}, "reason": "preserve-existing-structure"},
|
|
44
|
+
{"when": {"structuralChangeAllowed": false, "existingArchetype": "browse"}, "then": {"archetypes": {"mustInclude": ["browse"], "mustNotInclude": ["queue", "grid"]}}, "reason": "existing-archetype-retained"},
|
|
45
|
+
{"when": {"structuralChangeAllowed": false, "existingArchetype": "queue"}, "then": {"archetypes": {"mustInclude": ["queue"], "mustNotInclude": ["browse", "grid"]}}, "reason": "existing-archetype-retained"},
|
|
46
|
+
{"when": {"structuralChangeAllowed": false, "existingArchetype": "grid"}, "then": {"archetypes": {"mustInclude": ["grid"], "mustNotInclude": ["browse", "queue"]}}, "reason": "existing-archetype-retained"}
|
|
47
|
+
]}
|
|
48
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: promotion-demotion
|
|
3
|
+
class: b2
|
|
4
|
+
sourced: 2026-07-12
|
|
5
|
+
source: "b2b-ux-patterns ch.6"
|
|
6
|
+
license: open
|
|
7
|
+
---
|
|
8
|
+
# Pass: promotion & demotion
|
|
9
|
+
|
|
10
|
+
**Inputs:** per object × role — `frequency` (high | medium | low: how often this role touches it), `criticality`, `isParent`, `demotionContractMet`, `perRoleVariance`.
|
|
11
|
+
**Owns:** `requiredMechanics`, `clarifications`.
|
|
12
|
+
**Output artifact:** a per-persona sidebar — which objects earn top-level prominence and which are reachable only through other objects — plus a landing type per promoted item (chosen in the `page-archetype` pass). This pass covers exactly one IA decision: promotion/demotion; navigation mechanics are out of scope.
|
|
13
|
+
|
|
14
|
+
## The rule
|
|
15
|
+
|
|
16
|
+
**Prominence = frequency × criticality, computed per role. Parenthood is not the driver.** Parent/child position in the schema is a data-integrity fact; it says nothing about how often a human opens the object. The canonical counterexample: in a CRM, Account is the parent of Leads, Contacts, and Opportunities — and it is demoted; reps live in Leads, Opportunities, and Tasks. If you find yourself promoting an object because "it's the parent," ask instead who opens it, how often, and what breaks if they can't — that answer sets the sidebar. Without a frequency reading per role, prominence cannot be computed: clarify.
|
|
17
|
+
|
|
18
|
+
**Prominence is per persona × plan.** An object demoted for a rep is promoted for the ops admin who lives in it; the same schema yields different sidebars per role. Plan-gated items change what each tenant's sidebar contains (whether locked items render hidden or as upsell is `viewer-context`'s call). Agents and agent surfaces now compete for promoted slots like any object.
|
|
19
|
+
|
|
20
|
+
**The demotion contract** — demotion is only safe when two guarantees hold, or it punishes users:
|
|
21
|
+
1. **Creatable in context** — every demoted object is creatable from inside the flows of promoted objects that reference it (nested create-in-context: "+ New Account" inside the Lead form). If a rep must abandon a half-filled form to create the parent first, the demotion has failed.
|
|
22
|
+
2. **Reachable in context** — every demoted object is readable from the promoted objects it relates to, via related lists and parent links on their detail pages. The demoted object gives up its sidebar entry, not its existence.
|
|
23
|
+
|
|
24
|
+
Test every demotion: *can a user create it and reach it without ever visiting a dedicated page for it?* If yes, demote freely; if no, promote it or fix the contract first.
|
|
25
|
+
|
|
26
|
+
**Anti-patterns encoded below:** the schema-mirror sidebar (promoting every top-level object because it exists — the sidebar is a frequency map, not an ER diagram); parent-first promotion; one static sidebar for all roles; demotion without the contract.
|
|
27
|
+
|
|
28
|
+
```json decision-table
|
|
29
|
+
{"pass": "promotion-demotion", "rows": [
|
|
30
|
+
{"when": {"frequency": "high"}, "then": {"requiredMechanics": {"mustInclude": ["sidebar-promotion"]}}, "reason": "frequency-times-criticality-wins-sidebar"},
|
|
31
|
+
{"when": {"frequency": "low"}, "then": {"requiredMechanics": {"mustInclude": ["demote-reachable-in-context", "nested-create-in-context", "related-list-reachability"], "mustNotInclude": ["sidebar-promotion"]}}, "reason": "low-frequency-demotes-with-contract"},
|
|
32
|
+
{"when": {"frequency": "low", "isParent": true}, "then": {"requiredMechanics": {"mustNotInclude": ["parent-first-promotion"]}}, "reason": "parenthood-is-not-navigational"},
|
|
33
|
+
{"when": {"demotionContractMet": false, "frequency": "low"}, "then": {"requiredMechanics": {"mustInclude": ["nested-create-in-context", "related-list-reachability"]}}, "reason": "demotion-contract-before-demotion"},
|
|
34
|
+
{"when": {"perRoleVariance": true}, "then": {"requiredMechanics": {"mustInclude": ["per-persona-sidebar"], "mustNotInclude": ["single-shared-sidebar"]}}, "reason": "prominence-per-persona-times-plan"},
|
|
35
|
+
{"when": {"frequency": "__absent__"}, "then": {"clarifications": ["role-frequency-unspecified"]}, "reason": "prominence-needs-a-frequency-reading"}
|
|
36
|
+
]}
|
|
37
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: settings
|
|
3
|
+
class: b2
|
|
4
|
+
sourced: 2026-07-12
|
|
5
|
+
source: "b2b-ux-patterns ch.16"
|
|
6
|
+
license: open
|
|
7
|
+
---
|
|
8
|
+
# Pass: settings
|
|
9
|
+
|
|
10
|
+
**Inputs:** per settings surface — `isSettingsPage`, `scope` (personal | workspace | org), `settingKind` (leaf-preference | config-object), `riskClass` (preference | behavior-config | structural-destructive), `subject`, `multiScopeSetting`, `nodeCount` (under-30 | over-30), `governedSurfaceLink`, `buildTimeGeneration`, `productSurfaceInTree`.
|
|
11
|
+
**Owns:** `archetypes`, `requiredStates`, `requiredMechanics`, `clarifications`.
|
|
12
|
+
**Output artifact:** the settings area treated as a **shadow meta-product** — the scope/subject/risk taxonomy, config-objects-not-forms, the interaction tier per risk class, the inheritance cascade, findability, and the AI governance subjects — reusing the whole playbook recursively rather than being hand-designed as a tree of forms.
|
|
13
|
+
|
|
14
|
+
## The rule
|
|
15
|
+
|
|
16
|
+
**Settings is not a page tree — it is the product's shadow meta-product**, used by a different persona (admins/builders), at a different frequency (rare), in a different mode (Configuration: deliberate, consequential, preview-hungry). Most of it should reuse the playbook, not be designed as forms.
|
|
17
|
+
|
|
18
|
+
**Config is objects, not forms.** A large share of "settings" are **config objects with full lifecycles** — webhooks/API keys (an index + detail with delivery logs), roles & permission sets (entity details with related-user lists and an impact surface), pipelines/stages/custom fields (a schema builder — the object model exposed as product), automations (canvas-builder with draft-vs-publish), templates/snippets/brand kits (standing-context assets), notification/SLA policies (config objects with versions and audit). Each has an index, a detail, a create flow, a state machine (draft / enabled / disabled), versioning, and Logged history. **Only leaf preferences — true toggles — are forms.** Designing settings as "a tree of forms" is the root mistake.
|
|
19
|
+
|
|
20
|
+
**Three orthogonal axes, and the navigation rule.** *Scope* — who it affects: personal / workspace / organization. *Subject* — what it configures: identity & access, data model, automation, notifications, integrations, branding, billing & plan, compliance & audit, and AI & agent policy. *Risk class* — how it takes effect: instant toggle, draft-publish config object, or structural migration. **Navigate by scope first, then subject** — scope maps directly to permissions and to the user's mental question, "am I changing this for me, or for everyone?" **Blast radius is declared, not inferred**: every settings page carries a blast-radius declaration in its header ("Affects only you" / "Affects everyone in Acme Corp") — a required element, the settings-land equivalent of the environment banner — paired with distinct per-scope chrome. Configuration belongs on a full surface, never a context-losing modal.
|
|
21
|
+
|
|
22
|
+
**Risk class dictates the interaction tier.** *Preferences* (personal, reversible, instant): autosave silently, no confirm — friction here is pure tax. *Behavior config* (affects others, reversible): explicit save plus a changelog entry, and the setting's own Logged history answers "who changed this and when." *Structural & destructive* (schema changes, role edits, SSO, retention, deletion): the full ceremony — **draft → impact preview → publish**, where the impact preview is the load-bearing step ("this role change affects 34 users"; "changing this field type will truncate 1,204 values"); add maker-checker where policy demands, isolate the irreversible in a type-to-confirm **danger zone**, and log everything to the org audit trail. Tier-3 changes deserve the test-before-live discipline of the AI layer's agent CI (simulate the rule against yesterday's traffic before publishing).
|
|
23
|
+
|
|
24
|
+
**The inheritance cascade — the most underserved settings pattern.** Any setting existing at more than one scope forms a cascade (org default → team override → user override), and the UI must solve the resolved-value problem: show the **effective value** the viewer gets, show **where it came from** ("inherited from Organization" vs "overridden here"), and offer **reset to inherit** as a first-class action distinct from "set to the same value." Once a cascade exists, impersonation/view-as is the only honest debugger. **Findability**: settings search is mandatory past ~30 nodes (admins remember words, not the tree), every setting has a stable deep link, and the in-context gear links bidirectionally between a governed surface and the setting that governs it. **The AI subjects (2026)**: build-time generation compiles NL to an inspectable artifact editable before commit — never a black box; the agent governance console (identities, model-routing, data masking, permission scoping, the AI-action audit view) is a new org-scope subject. Anti-patterns forbidden: the junk drawer, features hiding in settings (saved views, dashboards, templates are product surfaces, not settings), modal settings, and the invisible cascade. A settings page whose scope is undeclared cannot be placed or permissioned: clarify.
|
|
25
|
+
|
|
26
|
+
```json decision-table
|
|
27
|
+
{"pass": "settings", "rows": [
|
|
28
|
+
{"when": {"isSettingsPage": true}, "then": {"archetypes": {"mustInclude": ["settings"]}, "requiredMechanics": {"mustInclude": ["blast-radius-declaration-header", "navigate-scope-first-then-subject", "per-scope-chrome"], "mustNotInclude": ["modal-settings", "settings-as-tree-of-forms"]}}, "reason": "blast-radius-declared-not-inferred"},
|
|
29
|
+
{"when": {"settingKind": "config-object"}, "then": {"requiredMechanics": {"mustInclude": ["config-object-full-surface-set", "config-state-machine", "config-versioning", "config-logged-history"], "mustNotInclude": ["config-as-leaf-form"]}}, "reason": "config-is-objects-not-forms"},
|
|
30
|
+
{"when": {"settingKind": "leaf-preference"}, "then": {"requiredMechanics": {"mustInclude": ["leaf-toggle-form"]}}, "reason": "only-true-toggles-are-forms"},
|
|
31
|
+
{"when": {"riskClass": "preference"}, "then": {"requiredMechanics": {"mustInclude": ["autosave-silent-no-confirm"], "mustNotInclude": ["confirm-on-preference"]}}, "reason": "preference-autosaves-friction-is-tax"},
|
|
32
|
+
{"when": {"riskClass": "behavior-config"}, "then": {"requiredMechanics": {"mustInclude": ["explicit-save", "changelog-entry", "logged-history"]}}, "reason": "behavior-config-logs-who-changed"},
|
|
33
|
+
{"when": {"riskClass": "structural-destructive"}, "then": {"requiredMechanics": {"mustInclude": ["draft-impact-preview-publish", "impact-preview", "danger-zone-type-to-confirm", "org-audit-logged"], "mustNotInclude": ["optimistic-apply", "edit-live-in-place"]}}, "reason": "structural-changes-earn-full-ceremony"},
|
|
34
|
+
{"when": {"multiScopeSetting": true}, "then": {"requiredMechanics": {"mustInclude": ["effective-value-shown", "inherited-from-indicator", "reset-to-inherit"], "mustNotInclude": ["invisible-cascade"]}}, "reason": "a-cascade-must-be-readable"},
|
|
35
|
+
{"when": {"nodeCount": "over-30"}, "then": {"requiredMechanics": {"mustInclude": ["settings-search", "stable-deep-links"]}}, "reason": "search-mandatory-past-thirty-nodes"},
|
|
36
|
+
{"when": {"governedSurfaceLink": true}, "then": {"requiredMechanics": {"mustInclude": ["in-context-gear-bidirectional-link"]}}, "reason": "shadow-product-stays-connected-to-product"},
|
|
37
|
+
{"when": {"subject": "ai-agent-policy"}, "then": {"requiredMechanics": {"mustInclude": ["agent-governance-console", "model-routing-policy", "data-masking-before-llm", "ai-action-audit-view"]}}, "reason": "ai-governance-is-an-org-scope-subject"},
|
|
38
|
+
{"when": {"buildTimeGeneration": true}, "then": {"requiredMechanics": {"mustInclude": ["nl-compiles-to-inspectable-artifact", "edit-before-commit"], "mustNotInclude": ["opaque-black-box"]}}, "reason": "compile-to-the-inspectable-artifact"},
|
|
39
|
+
{"when": {"productSurfaceInTree": true}, "then": {"requiredMechanics": {"mustNotInclude": ["features-hiding-in-settings"]}}, "reason": "product-surfaces-are-not-settings"},
|
|
40
|
+
{"when": {"isSettingsPage": true, "scope": "__absent__"}, "then": {"clarifications": ["setting-scope-unspecified"]}, "reason": "navigate-by-scope-first-so-scope-is-required"}
|
|
41
|
+
]}
|
|
42
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: standard-pages
|
|
3
|
+
class: b2
|
|
4
|
+
sourced: 2026-07-12
|
|
5
|
+
source: "b2b-ux-patterns ch.12"
|
|
6
|
+
license: open
|
|
7
|
+
---
|
|
8
|
+
# Pass: standard pages
|
|
9
|
+
|
|
10
|
+
**Inputs:** per meta-object page — `standardPage` (settings | profile | notifications | audit-object | audit-global | user-management | roles-permissions | seats-licenses | billing | integrations); plus signals — `notificationDelivery`, `ssoScimProvisioning`, `complianceBuyer`, `recordLevelAccess`, `externalSystemMapping`.
|
|
11
|
+
**Owns:** `archetypes`, `requiredMechanics`, `clarifications`.
|
|
12
|
+
**Output artifact:** the settings/profile/notifications/audit/admin/integration pages every B2B product ships regardless of domain — each generated by the earlier passes as an index, detail, or form over a meta-object (users, roles, notifications, audit events, connections), not hand-designed. The full settings scope/subject/risk taxonomy is the `settings` pass; this pass names the pages and their contracts.
|
|
13
|
+
|
|
14
|
+
## The rule
|
|
15
|
+
|
|
16
|
+
**Standard pages are not exempt from the method — they are the method applied to meta-objects.** Each is an index, a detail page, or a form over users, roles, notifications, audit events, or connections, and carries the same archetype, state matrix, and viewer-context obligations as any domain surface.
|
|
17
|
+
|
|
18
|
+
**Profile is a detail page** over the User object where viewer = subject: identity fields, avatar, credentials/security (password, 2FA, sessions), and pointers into personal-scope settings.
|
|
19
|
+
|
|
20
|
+
**The notifications page is a derived index, not a primary object.** Asset-level verbs (watch, subscribe, assign, @mention) combined with the viewer's relationships produce notification records; the page is their index — reverse-chronological, read/unread, filterable by type, each item deep-linking to the record and moment that produced it. For operational products this index doubles as a **work-router** ("what needs me"), so treat its ordering and grouping with index-level seriousness. Beside it lives the **notification preferences matrix** (personal scope): event types × delivery channels, with batching cadence per cell (instant / hourly / daily digest / off) plus a global mute — load-bearing, because getting batching wrong is a top reason users disengage.
|
|
21
|
+
|
|
22
|
+
**Audit has two surfaces, both outputs of the Logged history class at different scopes.** Per-object history is the record-scoped timeline on every detail page. The **global audit log** is an org-scope, append-only index of who-did-what-when across security-relevant actions — logins, permission changes, deletions, exports, setting changes, and every impersonation session (impersonation is always logged, no exceptions) — filterable by actor/action/object/time, searchable, exportable; for SOC2/enterprise buyers it is a purchase criterion, not an afterthought.
|
|
23
|
+
|
|
24
|
+
**Admin pages are indexes and forms over the org's meta-objects.** User management (invite — noting SSO/SCIM may provision users externally, so the invite form is not the only entry point — role assignment, deactivation) must trigger an **ownership-transfer flow** on deactivation: reassign the departing user's records before the account closes, or orphaned records are guaranteed. Roles & permissions is the admin surface for the access layers, paired with **impersonation/view-as** — once record- and field-level access exist, "log in as this user" is the only practical way to debug what a person actually sees. Seats & licenses render "X of Y seats used," pending invites, and reclaim-on-deactivation. Billing is brief here; customer-facing usage/billing surfaces are deferred.
|
|
25
|
+
|
|
26
|
+
**Integrations resolve to objects, never a free-floating layer.** External data always maps to objects and fields: a connect flow (OAuth or keys, workspace scope), a **field-mapping editor** (their "Company" ↔ your "Account," with sync direction and frequency per mapping), and **connection health** (status, last successful sync, error counts, per-connection sync logs as an index of sync events); synced fields carry their origin declaration wherever they render. When a standard-page request omits which meta-object it is over, its contract cannot be derived: clarify.
|
|
27
|
+
|
|
28
|
+
```json decision-table
|
|
29
|
+
{"pass": "standard-pages", "rows": [
|
|
30
|
+
{"when": {"standardPage": "settings"}, "then": {"archetypes": {"mustInclude": ["settings"]}, "requiredMechanics": {"mustInclude": ["three-scope-split", "per-scope-edit-permissions"]}}, "reason": "settings-is-a-scope-tree"},
|
|
31
|
+
{"when": {"standardPage": "profile"}, "then": {"archetypes": {"mustInclude": ["record-detail"]}, "requiredMechanics": {"mustInclude": ["viewer-equals-subject", "credentials-security-section"]}}, "reason": "profile-is-a-detail-page-over-user"},
|
|
32
|
+
{"when": {"standardPage": "notifications"}, "then": {"archetypes": {"mustInclude": ["browse", "queue"]}, "requiredMechanics": {"mustInclude": ["notification-index-deep-links", "read-unread-state", "notification-preferences-matrix", "global-mute"]}}, "reason": "notifications-is-a-derived-index-and-router"},
|
|
33
|
+
{"when": {"notificationDelivery": true}, "then": {"requiredMechanics": {"mustInclude": ["event-type-by-channel-matrix", "per-cell-batching-cadence"]}}, "reason": "batching-matrix-is-load-bearing"},
|
|
34
|
+
{"when": {"standardPage": "audit-global"}, "then": {"archetypes": {"mustInclude": ["browse"]}, "requiredMechanics": {"mustInclude": ["append-only-audit-log", "impersonation-always-logged", "filter-actor-action-object-time", "audit-exportable"]}}, "reason": "global-audit-is-a-compliance-index"},
|
|
35
|
+
{"when": {"standardPage": "audit-object"}, "then": {"archetypes": {"mustInclude": ["record-detail"]}, "requiredMechanics": {"mustInclude": ["record-scoped-history-timeline"]}}, "reason": "per-object-history-is-the-detail-timeline"},
|
|
36
|
+
{"when": {"standardPage": "user-management"}, "then": {"archetypes": {"mustInclude": ["browse", "creation-flow"]}, "requiredMechanics": {"mustInclude": ["ownership-transfer-on-deactivation", "role-assignment"], "mustNotInclude": ["orphaned-records-on-deactivation"]}}, "reason": "deactivation-must-transfer-ownership"},
|
|
37
|
+
{"when": {"ssoScimProvisioning": true}, "then": {"requiredMechanics": {"mustInclude": ["external-provisioning-entry-point"], "mustNotInclude": ["invite-form-only-entry-point"]}}, "reason": "sso-scim-provisions-outside-the-invite-form"},
|
|
38
|
+
{"when": {"standardPage": "roles-permissions"}, "then": {"archetypes": {"mustInclude": ["record-detail"]}, "requiredMechanics": {"mustInclude": ["permission-impact-surface", "impersonation-view-as"]}}, "reason": "roles-need-a-view-as-debugger"},
|
|
39
|
+
{"when": {"recordLevelAccess": true}, "then": {"requiredMechanics": {"mustInclude": ["impersonation-view-as", "impersonation-banner", "impersonation-audit-logged"]}}, "reason": "view-as-is-the-only-honest-access-debugger"},
|
|
40
|
+
{"when": {"standardPage": "seats-licenses"}, "then": {"requiredMechanics": {"mustInclude": ["seats-used-of-total", "pending-invites", "reclaim-on-deactivation"]}}, "reason": "seats-render-as-metered-usage"},
|
|
41
|
+
{"when": {"standardPage": "integrations"}, "then": {"requiredMechanics": {"mustInclude": ["connect-flow", "field-mapping-editor", "connection-health-log"]}}, "reason": "integrations-resolve-to-objects-and-fields"},
|
|
42
|
+
{"when": {"externalSystemMapping": true}, "then": {"requiredMechanics": {"mustInclude": ["field-mapping-editor", "sync-direction-per-mapping", "synced-field-provenance"]}}, "reason": "external-mapping-is-object-mapped"},
|
|
43
|
+
{"when": {"complianceBuyer": true}, "then": {"requiredMechanics": {"mustInclude": ["append-only-audit-log", "audit-exportable"]}}, "reason": "audit-log-is-a-purchase-criterion"},
|
|
44
|
+
{"when": {"standardPage": "__absent__"}, "then": {"clarifications": ["standard-page-subject-unspecified"]}, "reason": "contract-derives-from-the-meta-object"}
|
|
45
|
+
]}
|
|
46
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: state-matrix
|
|
3
|
+
class: b2
|
|
4
|
+
sourced: 2026-07-12
|
|
5
|
+
source: "b2b-ux-patterns ch.11"
|
|
6
|
+
license: open
|
|
7
|
+
---
|
|
8
|
+
# Pass: state matrix & onboarding
|
|
9
|
+
|
|
10
|
+
**Inputs:** per surface — `isListSurface`, `dataFetch`, `fetchLatency`, `compositePage`, `consumesCachedData`, `streamingView`, `optimisticMutation`, `queueSuccessIsEmpty`, `firstRunSurface`; per onboarding technique — `onboardingTechnique`, `onboardingScope` (application-level | empty-state).
|
|
11
|
+
**Owns:** `requiredStates`, `requiredMechanics`, `clarifications`.
|
|
12
|
+
**Output artifact:** the state matrix every page carries **orthogonal to its archetype** — loading, three distinct empties, degraded, stale, recovery — plus optimistic-UI rollback and the two-home classification of every onboarding technique. Archetypes describe pages as if data always arrives; this pass specifies what renders when data hasn't, can't, or shouldn't be trusted.
|
|
13
|
+
|
|
14
|
+
## The rule
|
|
15
|
+
|
|
16
|
+
**Loading is skeletons, not spinners.** Gray placeholder shapes matched to the eventual layout — matched geometry (row height, card size) so the layout doesn't jump when data lands; composite pages skeleton per region, not whole-page. Spinners are acceptable only for actions without a known destination shape.
|
|
17
|
+
|
|
18
|
+
**An empty region means three unrelated things, and each demands different treatment** — collapsing them into one "No results" string is the most common state bug in B2B. **First-run empty** — no data has ever existed here — is an onboarding surface: teach the object's value, offer both a create path and a sample-data path; it is the highest-attention real estate a new account sees. **Filtered-to-zero** — data exists but the filter excludes all of it — is a compact message that restates the active filters with one-click "clear filters"; showing first-run marketing copy to a power user whose saved view returned zero reads as data loss. **Failed-to-load** — the fetch errored — is an honest error with a retry affordance, visually distinct from both empties; silence or a generic empty makes users believe their data is gone. A list surface must carry all three, distinctly.
|
|
19
|
+
|
|
20
|
+
**Degraded and stale are honest surfaces.** On composite pages, each independently-fetched region owns its own loading and error boundary: one failed widget shows an inline "couldn't load — retry" while the rest of the page stays live — the whole page never dies for one bad call. People make decisions on cached numbers, so consumed data carries a **freshness cue** — "updated 2m ago," an as-of timestamp on financial figures, a live/paused indicator on streaming views, and a manual refresh; serve cached instantly, revalidate in the background, and say so. A queue whose success metric is an empty list carries a distinct **cleared-empty** state — celebrated, not a failure.
|
|
21
|
+
|
|
22
|
+
**Optimistic UI makes its rollback visible.** Mutations apply to the UI instantly and reconcile in the background; on failure the rollback is *visible* — a toast naming what failed, the value reverting in view, and a retry that preserves the user's input. Never silently revert (the user believes the edit stuck) and never silently lose the edit. This pairs with the reversible-action undo rule: reversible actions get optimistic-apply + undo; only genuinely irreversible ones get a blocking confirm.
|
|
23
|
+
|
|
24
|
+
**Onboarding has exactly two homes, no third — classify every technique into one.** *Application-level* patterns live in the product's chrome, span sessions, and concern the whole workspace: the setup checklist (persistent, dismissible, progress-tracked, surviving across sessions until completed), product tours/coach-marks (sparing, dismissible, contextually triggered — never a forced first-login gauntlet), and sample/demo data (pre-seeded realistic records with a path to delete or convert). *Empty-state* patterns live inside a specific page's first-run empty: empty-state-as-teacher — the page explaining itself with an inline example or template gallery and both "create real" and "load sample" paths. The classification matters because the lifecycles differ: application-level patterns end when the account activates; empty-state patterns recur forever — every new module, team, or newly permissioned object presents a first-run empty to somebody. An onboarding technique whose home is undeclared cannot be placed: clarify.
|
|
25
|
+
|
|
26
|
+
```json decision-table
|
|
27
|
+
{"pass": "state-matrix", "rows": [
|
|
28
|
+
{"when": {"dataFetch": true}, "then": {"requiredStates": {"mustInclude": ["loading"]}, "requiredMechanics": {"mustInclude": ["skeleton-matched-geometry", "per-region-skeleton"], "mustNotInclude": ["spinner-with-known-shape"]}}, "reason": "loading-is-skeletons-not-spinners"},
|
|
29
|
+
{"when": {"isListSurface": true}, "then": {"requiredStates": {"mustInclude": ["empty-first-run", "empty-filtered", "failed-to-load"]}, "requiredMechanics": {"mustInclude": ["distinct-empty-treatments", "clear-filters-affordance", "retry-on-failed-load"], "mustNotInclude": ["single-no-results-string"]}}, "reason": "three-empties-are-distinct"},
|
|
30
|
+
{"when": {"compositePage": true}, "then": {"requiredStates": {"mustInclude": ["degraded"]}, "requiredMechanics": {"mustInclude": ["per-region-error-boundary", "inline-retry-per-region"], "mustNotInclude": ["whole-page-dies-for-one-call"]}}, "reason": "degraded-isolates-per-region"},
|
|
31
|
+
{"when": {"consumesCachedData": true}, "then": {"requiredStates": {"mustInclude": ["stale"]}, "requiredMechanics": {"mustInclude": ["freshness-cue-as-of-timestamp", "manual-refresh", "revalidate-in-background"]}}, "reason": "decisions-get-made-on-cached-numbers"},
|
|
32
|
+
{"when": {"streamingView": true}, "then": {"requiredMechanics": {"mustInclude": ["live-paused-indicator"]}}, "reason": "streaming-declares-live-or-paused"},
|
|
33
|
+
{"when": {"optimisticMutation": true}, "then": {"requiredMechanics": {"mustInclude": ["optimistic-apply", "visible-rollback-toast", "retry-preserves-input"], "mustNotInclude": ["silent-revert", "silent-edit-loss"]}}, "reason": "rollback-must-be-visible"},
|
|
34
|
+
{"when": {"queueSuccessIsEmpty": true}, "then": {"requiredStates": {"mustInclude": ["empty-cleared"]}}, "reason": "a-cleared-queue-is-celebrated"},
|
|
35
|
+
{"when": {"firstRunSurface": true}, "then": {"requiredStates": {"mustInclude": ["empty-first-run"]}, "requiredMechanics": {"mustInclude": ["empty-state-as-teacher", "create-real-path", "load-sample-path"]}}, "reason": "first-run-is-the-page-teaching-itself"},
|
|
36
|
+
{"when": {"fetchLatency": true}, "then": {"requiredMechanics": {"mustInclude": ["skeleton-matched-geometry"], "mustNotInclude": ["layout-jump-on-load"]}}, "reason": "skeleton-geometry-prevents-jank"},
|
|
37
|
+
{"when": {"onboardingScope": "application-level"}, "then": {"requiredMechanics": {"mustInclude": ["setup-checklist-persistent", "dismissible-contextual-tours", "sample-data-with-convert-or-delete"]}}, "reason": "app-level-onboarding-spans-sessions"},
|
|
38
|
+
{"when": {"onboardingScope": "empty-state"}, "then": {"requiredMechanics": {"mustInclude": ["empty-state-as-teacher"]}}, "reason": "empty-state-onboarding-is-page-scoped"},
|
|
39
|
+
{"when": {"onboardingTechnique": true, "onboardingScope": "__absent__"}, "then": {"clarifications": ["onboarding-home-unspecified"]}, "reason": "every-technique-classifies-into-one-of-two-homes"}
|
|
40
|
+
]}
|
|
41
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: table-mechanics
|
|
3
|
+
class: b2
|
|
4
|
+
sourced: 2026-07-12
|
|
5
|
+
source: "b2b-ux-patterns ch.10"
|
|
6
|
+
license: open
|
|
7
|
+
---
|
|
8
|
+
# Pass: table mechanics
|
|
9
|
+
|
|
10
|
+
**Inputs:** per index surface — `revisitedWithIntent`, `sharedViewScope` (personal | team), `wideObject`, `heavyDailyUse`, `groupBySegment`, `crossCuttingHealthNumbers`, `gridEditable`, `bulkVerbs`, `rowActions`, `hasStatusField`, `viewerRelationships`, `largeDataset`, `listLength` (paginated | infinite | virtualized), `financialRecordKeeping`, `sharedMutableList`, `exportNeeded`.
|
|
11
|
+
**Owns:** `requiredMechanics`, `clarifications`.
|
|
12
|
+
**Output artifact:** the parts list every index-family archetype (browse, queue, grid) assembles — saved views, column management, sticky chrome, grouping, in-table editing, bulk and row affordances, scannability, viewer-relative decoration, list-length strategy, real-time behavior, and export — while the archetype decides which parts appear and the success metric.
|
|
13
|
+
|
|
14
|
+
## The rule
|
|
15
|
+
|
|
16
|
+
Tables render **f(data, viewer)** — the same rows are decorated differently per viewer — and which row actions exist is a function of object state and role, never a fixed toolbar. The machinery below is shared across browse, queue, and grid; each archetype assembles it differently.
|
|
17
|
+
|
|
18
|
+
**View state.** A **saved view** is a named, persistent object — filter + sort + columns + grouping + view-type — with an owner, a sharing scope, pinnability, and an optional default flag, for any index a user visits more than once with the same intent; distinguish personal (private workspace) from team (governed shared lens) from day one, because retrofitting governance onto ungoverned shared views is painful. Wide objects need **column management** (show/hide, drag-reorder, resize, freeze) with the identity column frozen left, and **sticky chrome** (pinned header on vertical scroll, pinned totals footer when grouped). Heavy daily users get a **density toggle** (compact/comfortable, wrap-vs-truncate).
|
|
19
|
+
|
|
20
|
+
**Aggregation lives in the table, not only on analytics pages.** When the natural reading is "by segment" (pipeline by stage, tickets by assignee), use **grouping with per-group and grand-total summary rows**. **Stat cards above the table** are the complement, not a substitute: totals *of the visible segments* belong in the table via grouping; rates, trends, and cross-cutting health numbers belong in stat cards.
|
|
21
|
+
|
|
22
|
+
**Editing and acting on rows.** In the grid archetype the table is the primary write surface: **inline cell editing** with type-aware editors (dropdown, date picker, user picker, checkbox), Tab/Enter/arrow traversal, optimistic commit; and **range operations** (rectangular select, copy/paste, drag-fill). Per-cell editability is decided by field-level access and the field's declarations — the same column is editable for one viewer, static for another. Bulk work gets **row checkboxes with a floating action bar** carrying the legal batch verbs, and keeps two semantics distinct: **select-visible** (this page) versus **select-all-matching** the filter (offered explicitly, "Select all 1,204 matching") — the first must never masquerade as the second — with **per-row partial-failure** reporting, never a blanket success. Rows carry **hover actions** (2–3 highest-frequency verbs) and an **overflow/context menu** (the full legal set for that row's state).
|
|
23
|
+
|
|
24
|
+
**Scannability and viewer decoration.** **Conditional formatting and status chips** are the pre-attentive layer — color-coded badges, priority icons, SLA-countdown colors, progress bars — rendering the state machine consistently everywhere the record appears; never encode with color alone, always pair with text or an icon. The index also carries **viewer-relative decoration** joined from the viewer's own relationships: mine, watched, unread/new, assigned-to-me (the default operational lens).
|
|
25
|
+
|
|
26
|
+
**List length, real-time, and export.** The **list-length strategy** is a deliberate choice that silently dictates selection semantics, exportability, and jump-to-position: pagination (stable, addressable — right for financial/record-keeping lists), infinite scroll (fluid — right for feeds and triage), or virtualization (the grid's default). Whatever the strategy, export-all and select-all operate on the *filtered set*, not the loaded window. Shared lists mutate under the user: never reflow under the cursor — new/changed records arrive behind an **"N new records" pill**, others' edits get a **fading soft highlight**, and scroll position and selection survive updates. **View-aware export** respects active filters, visible columns, and sort, with large exports as background jobs and scheduled recurring delivery — extraction is a security-relevant, audit-logged verb. When a large dataset's list-length strategy is undeclared, selection and export semantics are undecidable: clarify.
|
|
27
|
+
|
|
28
|
+
```json decision-table
|
|
29
|
+
{"pass": "table-mechanics", "rows": [
|
|
30
|
+
{"when": {"revisitedWithIntent": true}, "then": {"requiredMechanics": {"mustInclude": ["saved-views-first-class"]}}, "reason": "revisited-index-earns-saved-views"},
|
|
31
|
+
{"when": {"sharedViewScope": "team"}, "then": {"requiredMechanics": {"mustInclude": ["personal-vs-team-view-scope", "view-sharing-governance"]}}, "reason": "shared-views-are-governed-lenses"},
|
|
32
|
+
{"when": {"wideObject": true}, "then": {"requiredMechanics": {"mustInclude": ["column-management", "frozen-identity-column", "sticky-header-chrome"]}}, "reason": "wide-objects-need-column-control"},
|
|
33
|
+
{"when": {"heavyDailyUse": true}, "then": {"requiredMechanics": {"mustInclude": ["density-toggle"]}}, "reason": "daily-users-trade-whitespace-for-rows"},
|
|
34
|
+
{"when": {"groupBySegment": true}, "then": {"requiredMechanics": {"mustInclude": ["grouping-with-summary-rows"]}}, "reason": "by-segment-reading-groups-in-table"},
|
|
35
|
+
{"when": {"crossCuttingHealthNumbers": true}, "then": {"requiredMechanics": {"mustInclude": ["stat-cards-above-table"]}}, "reason": "rates-and-trends-are-stat-cards"},
|
|
36
|
+
{"when": {"gridEditable": true}, "then": {"requiredMechanics": {"mustInclude": ["inline-cell-edit", "type-aware-editors", "range-operations-fill"]}}, "reason": "grid-is-the-write-surface"},
|
|
37
|
+
{"when": {"bulkVerbs": true}, "then": {"requiredMechanics": {"mustInclude": ["bulk-selection-floating-bar", "select-all-matching-distinct-from-visible", "per-row-partial-failure-report"], "mustNotInclude": ["visible-masquerades-as-all", "blanket-success-report"]}}, "reason": "bulk-keeps-visible-and-all-distinct"},
|
|
38
|
+
{"when": {"rowActions": true}, "then": {"requiredMechanics": {"mustInclude": ["hover-actions", "overflow-context-menu"]}}, "reason": "common-actions-without-a-round-trip"},
|
|
39
|
+
{"when": {"hasStatusField": true}, "then": {"requiredMechanics": {"mustInclude": ["conditional-formatting-status-chips"], "mustNotInclude": ["color-alone-encoding"]}}, "reason": "pre-attentive-never-color-alone"},
|
|
40
|
+
{"when": {"viewerRelationships": true}, "then": {"requiredMechanics": {"mustInclude": ["viewer-relative-decoration", "unread-new-markers"]}}, "reason": "index-renders-f-data-viewer"},
|
|
41
|
+
{"when": {"listLength": "paginated"}, "then": {"requiredMechanics": {"mustInclude": ["addressable-pages", "select-all-on-page"]}}, "reason": "pagination-is-stable-and-addressable"},
|
|
42
|
+
{"when": {"listLength": "virtualized"}, "then": {"requiredMechanics": {"mustInclude": ["windowed-virtualization"]}}, "reason": "virtualization-scrolls-large-sets"},
|
|
43
|
+
{"when": {"financialRecordKeeping": true}, "then": {"requiredMechanics": {"mustInclude": ["addressable-pages"], "mustNotInclude": ["infinite-scroll-for-records"]}}, "reason": "record-keeping-wants-stable-pages"},
|
|
44
|
+
{"when": {"sharedMutableList": true}, "then": {"requiredMechanics": {"mustInclude": ["n-new-records-pill", "others-edit-soft-highlight", "preserve-scroll-and-selection"], "mustNotInclude": ["reflow-under-cursor"]}}, "reason": "never-reflow-a-shared-list-under-the-user"},
|
|
45
|
+
{"when": {"exportNeeded": true}, "then": {"requiredMechanics": {"mustInclude": ["view-aware-export", "export-operates-on-filtered-set", "background-job-large-export", "export-audit-logged"]}}, "reason": "export-is-a-security-relevant-verb"},
|
|
46
|
+
{"when": {"largeDataset": true, "listLength": "__absent__"}, "then": {"clarifications": ["list-length-strategy-unspecified"]}, "reason": "selection-and-export-semantics-need-a-strategy"}
|
|
47
|
+
]}
|
|
48
|
+
```
|