@nurix/etna 0.19.66 → 0.19.67
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/bin/etna.js +10 -1
- package/data/harness-index.json +1 -5
- package/data/harnesses/code/CLAUDE.md +2 -0
- package/data/harnesses/code/agents/maintenance.md +3 -1
- package/data/harnesses/code/harness.json +7 -2
- package/data/harnesses/code/hooks/compliance.mjs +1 -0
- package/data/harnesses/code/hooks/lib/frozen.mjs +3 -0
- package/data/harnesses/code/hooks/lib/ownership.mjs +3 -1
- package/data/harnesses/code/skills/documentation/scripts/doc-lint.mjs +1 -1
- package/data/harnesses/delivery/agents/maintenance.md +3 -1
- package/data/harnesses/delivery/harness.json +2 -2
- package/data/harnesses/delivery/skills/documentation/scripts/doc-lint.mjs +1 -1
- package/data/harnesses/etna/agents/maintenance.md +3 -1
- package/data/harnesses/etna/harness.json +2 -2
- package/data/harnesses/etna/skills/documentation/scripts/doc-lint.mjs +1 -1
- package/lib/install/materialize.mjs +51 -57
- package/package.json +2 -2
- package/data/harnesses/apollo/.mcp.json +0 -8
- package/data/harnesses/apollo/.prettierignore +0 -29
- package/data/harnesses/apollo/.prettierrc.json +0 -3
- package/data/harnesses/apollo/.vscode/settings.json +0 -19
- package/data/harnesses/apollo/CLAUDE.md +0 -162
- package/data/harnesses/apollo/agents/bookkeeper.md +0 -28
- package/data/harnesses/apollo/agents/brainstorm.md +0 -144
- package/data/harnesses/apollo/agents/change-review.md +0 -251
- package/data/harnesses/apollo/agents/lld-mode.md +0 -58
- package/data/harnesses/apollo/agents/maintenance.md +0 -234
- package/data/harnesses/apollo/agents/performance-review.md +0 -223
- package/data/harnesses/apollo/agents/retro.md +0 -46
- package/data/harnesses/apollo/codex/agents/bookkeeper.toml +0 -26
- package/data/harnesses/apollo/codex/agents/brainstorm.toml +0 -142
- package/data/harnesses/apollo/codex/agents/change-review.toml +0 -249
- package/data/harnesses/apollo/codex/agents/lld-mode.toml +0 -52
- package/data/harnesses/apollo/codex/agents/maintenance.toml +0 -228
- package/data/harnesses/apollo/codex/agents/performance-review.toml +0 -222
- package/data/harnesses/apollo/codex/agents/retro.toml +0 -45
- package/data/harnesses/apollo/harness.json +0 -19
- package/data/harnesses/apollo/hooks/approved-packages.md +0 -44
- package/data/harnesses/apollo/hooks/awareness.mjs +0 -405
- package/data/harnesses/apollo/hooks/check-bookkeeping-clean.mjs +0 -19
- package/data/harnesses/apollo/hooks/check-changelog-presence.mjs +0 -57
- package/data/harnesses/apollo/hooks/check-completion-integrity.mjs +0 -71
- package/data/harnesses/apollo/hooks/check-ownership.mjs +0 -22
- package/data/harnesses/apollo/hooks/compliance.mjs +0 -457
- package/data/harnesses/apollo/hooks/hooks.json +0 -23
- package/data/harnesses/apollo/hooks/lib/frozen.mjs +0 -58
- package/data/harnesses/apollo/hooks/lib/ownership.mjs +0 -242
- package/data/harnesses/apollo/hooks/lib/state.mjs +0 -170
- package/data/harnesses/apollo/rules/changelog.md +0 -27
- package/data/harnesses/apollo/rules/database.md +0 -34
- package/data/harnesses/apollo/rules/frontend.md +0 -30
- package/data/harnesses/apollo/rules/general.md +0 -40
- package/data/harnesses/apollo/rules/nomenclature.md +0 -30
- package/data/harnesses/apollo/rules/pnpm.md +0 -57
- package/data/harnesses/apollo/rules/testing.md +0 -64
- package/data/harnesses/apollo/skills/boundary/SKILL.md +0 -75
- package/data/harnesses/apollo/skills/boundary/references/index.md +0 -16
- package/data/harnesses/apollo/skills/boundary/references/mechanisms.md +0 -99
- package/data/harnesses/apollo/skills/boundary/references/packs/async-messaging.md +0 -81
- package/data/harnesses/apollo/skills/boundary/references/packs/auth.md +0 -93
- package/data/harnesses/apollo/skills/boundary/references/packs/build-config-runtime.md +0 -93
- package/data/harnesses/apollo/skills/boundary/references/packs/cloudflare.md +0 -93
- package/data/harnesses/apollo/skills/boundary/references/packs/frontend.md +0 -93
- package/data/harnesses/apollo/skills/boundary/references/packs/generic-tail.md +0 -55
- package/data/harnesses/apollo/skills/boundary/references/packs/persistence.md +0 -93
- package/data/harnesses/apollo/skills/boundary/references/packs/wire-api.md +0 -87
- package/data/harnesses/apollo/skills/brainstorm/README.md +0 -56
- package/data/harnesses/apollo/skills/brainstorm/SKILL.md +0 -173
- package/data/harnesses/apollo/skills/brainstorm/references/doctrine.md +0 -98
- package/data/harnesses/apollo/skills/brainstorm/references/harvest.md +0 -86
- package/data/harnesses/apollo/skills/brainstorm/references/session-schema.md +0 -186
- package/data/harnesses/apollo/skills/brainstorm/scripts/detector.mjs +0 -460
- package/data/harnesses/apollo/skills/design/SKILL.md +0 -121
- package/data/harnesses/apollo/skills/design/components/charts.md +0 -76
- package/data/harnesses/apollo/skills/design/components/collections.md +0 -132
- package/data/harnesses/apollo/skills/design/components/feedback.md +0 -47
- package/data/harnesses/apollo/skills/design/components/hooks.md +0 -35
- package/data/harnesses/apollo/skills/design/components/index.md +0 -143
- package/data/harnesses/apollo/skills/design/components/inputs.md +0 -327
- package/data/harnesses/apollo/skills/design/components/layout.md +0 -52
- package/data/harnesses/apollo/skills/design/components/media.md +0 -66
- package/data/harnesses/apollo/skills/design/components/motion.md +0 -82
- package/data/harnesses/apollo/skills/design/components/navigation.md +0 -29
- package/data/harnesses/apollo/skills/design/components/overlays.md +0 -72
- package/data/harnesses/apollo/skills/design/components/setup.md +0 -40
- package/data/harnesses/apollo/skills/design/components/typography.md +0 -46
- package/data/harnesses/apollo/skills/design/components/utils.md +0 -37
- package/data/harnesses/apollo/skills/design/data/blueprints/browse.md +0 -38
- package/data/harnesses/apollo/skills/design/data/blueprints/creation-flow.md +0 -38
- package/data/harnesses/apollo/skills/design/data/blueprints/dashboard.md +0 -38
- package/data/harnesses/apollo/skills/design/data/blueprints/grid.md +0 -38
- package/data/harnesses/apollo/skills/design/data/blueprints/queue.md +0 -38
- package/data/harnesses/apollo/skills/design/data/blueprints/record-detail.md +0 -38
- package/data/harnesses/apollo/skills/design/data/blueprints/settings.md +0 -38
- package/data/harnesses/apollo/skills/design/data/charts/census.csv +0 -58
- package/data/harnesses/apollo/skills/design/data/checklists/browse.md +0 -21
- package/data/harnesses/apollo/skills/design/data/checklists/creation-flow.md +0 -20
- package/data/harnesses/apollo/skills/design/data/checklists/dashboard.md +0 -21
- package/data/harnesses/apollo/skills/design/data/checklists/grid.md +0 -21
- package/data/harnesses/apollo/skills/design/data/checklists/queue.md +0 -21
- package/data/harnesses/apollo/skills/design/data/checklists/record-detail.md +0 -21
- package/data/harnesses/apollo/skills/design/data/checklists/settings.md +0 -21
- package/data/harnesses/apollo/skills/design/data/chrome/board-column.md +0 -68
- package/data/harnesses/apollo/skills/design/data/chrome/data-table.md +0 -63
- package/data/harnesses/apollo/skills/design/data/chrome/side-panel.md +0 -60
- package/data/harnesses/apollo/skills/design/data/chrome/sidebar.md +0 -78
- package/data/harnesses/apollo/skills/design/data/chrome/stat-cards.md +0 -62
- package/data/harnesses/apollo/skills/design/data/chrome/topbar.md +0 -65
- package/data/harnesses/apollo/skills/design/data/elevation/ant-design-directional-shadow.md +0 -19
- package/data/harnesses/apollo/skills/design/data/elevation/apple-liquid-glass-material.md +0 -18
- package/data/harnesses/apollo/skills/design/data/elevation/atlassian-surface-shadow-pairing.md +0 -20
- package/data/harnesses/apollo/skills/design/data/elevation/fluent-2-key-ambient-ramp.md +0 -20
- package/data/harnesses/apollo/skills/design/data/elevation/github-primer-sparing-shadow.md +0 -19
- package/data/harnesses/apollo/skills/design/data/elevation/ibm-carbon-layer-and-border.md +0 -19
- package/data/harnesses/apollo/skills/design/data/elevation/linear-dark-surface-ladder.md +0 -17
- package/data/harnesses/apollo/skills/design/data/elevation/material-2-key-ambient-dp-ramp.md +0 -19
- package/data/harnesses/apollo/skills/design/data/elevation/material-3-tonal-elevation.md +0 -21
- package/data/harnesses/apollo/skills/design/data/elevation/neobrutalist-hard-offset.md +0 -19
- package/data/harnesses/apollo/skills/design/data/elevation/neumorphic-soft-dual-shadow.md +0 -18
- package/data/harnesses/apollo/skills/design/data/elevation/notion-warm-minimal-hairline.md +0 -17
- package/data/harnesses/apollo/skills/design/data/elevation/polaris-elevation-inset-bevel.md +0 -21
- package/data/harnesses/apollo/skills/design/data/elevation/radix-themes-alpha-ring-scale.md +0 -19
- package/data/harnesses/apollo/skills/design/data/elevation/shadcn-neutral-derived-radius.md +0 -19
- package/data/harnesses/apollo/skills/design/data/elevation/stripe-brand-tinted-dual-shadow.md +0 -18
- package/data/harnesses/apollo/skills/design/data/elevation/tailwind-default-utility-scale.md +0 -19
- package/data/harnesses/apollo/skills/design/data/elevation/vercel-geist-shadow-as-border.md +0 -20
- package/data/harnesses/apollo/skills/design/data/iconography.md +0 -199
- package/data/harnesses/apollo/skills/design/data/motion/accordion-expand.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/destructive-hold-confirm.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/drag-dismiss-momentum.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/empty-state-arrive.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/hover-lift.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/modal-center-arrive.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/number-ticker-roll.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/onboarding-bounce.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/panel-slide.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/press-feedback.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/progress-linear-loop.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/route-crossfade.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/rubber-band-overscroll.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/skeleton-shimmer.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/stagger-arrive.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/toast-enter-stack.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/tooltip-chain-instant.md +0 -18
- package/data/harnesses/apollo/skills/design/data/motion/trigger-anchored-reveal.md +0 -18
- package/data/harnesses/apollo/skills/design/data/tells.csv +0 -34
- package/data/harnesses/apollo/skills/design/data/voices/bright-collaborator.md +0 -29
- package/data/harnesses/apollo/skills/design/data/voices/direct-operator.md +0 -29
- package/data/harnesses/apollo/skills/design/data/voices/earnest-helper.md +0 -29
- package/data/harnesses/apollo/skills/design/data/voices/editorial-composed.md +0 -29
- package/data/harnesses/apollo/skills/design/data/voices/quiet-concierge.md +0 -29
- package/data/harnesses/apollo/skills/design/data/voices/warm-guide.md +0 -29
- package/data/harnesses/apollo/skills/design/references/compose.md +0 -23
- package/data/harnesses/apollo/skills/design/references/content.md +0 -28
- package/data/harnesses/apollo/skills/design/references/emission.md +0 -21
- package/data/harnesses/apollo/skills/design/references/existing-apps.md +0 -27
- package/data/harnesses/apollo/skills/design/references/foundations.md +0 -57
- package/data/harnesses/apollo/skills/design/references/intake.md +0 -40
- package/data/harnesses/apollo/skills/design/references/object-pass.md +0 -24
- package/data/harnesses/apollo/skills/design/references/ship-gate.md +0 -29
- package/data/harnesses/apollo/skills/design/references/ux-patterns/Readme.md +0 -195
- package/data/harnesses/apollo/skills/design/references/ux-patterns/ai-layer.md +0 -49
- package/data/harnesses/apollo/skills/design/references/ux-patterns/attributes-lifecycle.md +0 -43
- package/data/harnesses/apollo/skills/design/references/ux-patterns/container-choice.md +0 -44
- package/data/harnesses/apollo/skills/design/references/ux-patterns/creation-paths.md +0 -46
- package/data/harnesses/apollo/skills/design/references/ux-patterns/dashboards.md +0 -42
- package/data/harnesses/apollo/skills/design/references/ux-patterns/modes.md +0 -42
- package/data/harnesses/apollo/skills/design/references/ux-patterns/object-model.md +0 -46
- package/data/harnesses/apollo/skills/design/references/ux-patterns/page-archetype.md +0 -48
- package/data/harnesses/apollo/skills/design/references/ux-patterns/promotion-demotion.md +0 -37
- package/data/harnesses/apollo/skills/design/references/ux-patterns/settings.md +0 -42
- package/data/harnesses/apollo/skills/design/references/ux-patterns/standard-pages.md +0 -46
- package/data/harnesses/apollo/skills/design/references/ux-patterns/state-matrix.md +0 -41
- package/data/harnesses/apollo/skills/design/references/ux-patterns/table-mechanics.md +0 -48
- package/data/harnesses/apollo/skills/design/references/ux-patterns/verbs.md +0 -45
- package/data/harnesses/apollo/skills/design/references/ux-patterns/viewer-context.md +0 -40
- package/data/harnesses/apollo/skills/design/scripts/README-validator.md +0 -27
- package/data/harnesses/apollo/skills/design/scripts/select-chart.mjs +0 -622
- package/data/harnesses/apollo/skills/design/scripts/validate-design-md.mjs +0 -1198
- package/data/harnesses/apollo/skills/documentation/SKILL.md +0 -135
- package/data/harnesses/apollo/skills/documentation/references/examples.md +0 -279
- package/data/harnesses/apollo/skills/documentation/references/frontmatter.md +0 -44
- package/data/harnesses/apollo/skills/documentation/references/instruction-style.md +0 -50
- package/data/harnesses/apollo/skills/documentation/references/style-guide.md +0 -384
- package/data/harnesses/apollo/skills/documentation/references/untemplated.md +0 -38
- package/data/harnesses/apollo/skills/documentation/scripts/doc-lint.mjs +0 -140
- package/data/harnesses/apollo/skills/documentation/templates/Readme.md +0 -35
- package/data/harnesses/apollo/skills/documentation/templates/api-reference.md +0 -20
- package/data/harnesses/apollo/skills/documentation/templates/architecture-decision.md +0 -121
- package/data/harnesses/apollo/skills/documentation/templates/backlog.md +0 -33
- package/data/harnesses/apollo/skills/documentation/templates/behavioral-checklist.md +0 -81
- package/data/harnesses/apollo/skills/documentation/templates/bookkeeping.md +0 -18
- package/data/harnesses/apollo/skills/documentation/templates/changelog-entry.md +0 -57
- package/data/harnesses/apollo/skills/documentation/templates/changelog-index.md +0 -41
- package/data/harnesses/apollo/skills/documentation/templates/docs-readme.md +0 -72
- package/data/harnesses/apollo/skills/documentation/templates/domain-model.md +0 -30
- package/data/harnesses/apollo/skills/documentation/templates/environment-registry.md +0 -15
- package/data/harnesses/apollo/skills/documentation/templates/feature.md +0 -150
- package/data/harnesses/apollo/skills/documentation/templates/glossary.md +0 -11
- package/data/harnesses/apollo/skills/documentation/templates/implementation-map.md +0 -42
- package/data/harnesses/apollo/skills/documentation/templates/journal.md +0 -13
- package/data/harnesses/apollo/skills/documentation/templates/memory-main.md +0 -25
- package/data/harnesses/apollo/skills/documentation/templates/migration-runbook.md +0 -34
- package/data/harnesses/apollo/skills/documentation/templates/non-goals.md +0 -11
- package/data/harnesses/apollo/skills/documentation/templates/operations-procedure.md +0 -36
- package/data/harnesses/apollo/skills/documentation/templates/plan.md +0 -88
- package/data/harnesses/apollo/skills/documentation/templates/protected-files.md +0 -37
- package/data/harnesses/apollo/skills/documentation/templates/root-readme.md +0 -104
- package/data/harnesses/apollo/skills/documentation/templates/security-overview.md +0 -27
- package/data/harnesses/apollo/skills/documentation/templates/structure.md +0 -65
- package/data/harnesses/apollo/skills/documentation/templates/system-overview.md +0 -32
- package/data/harnesses/apollo/skills/documentation/templates/testing-strategy.md +0 -29
- package/data/harnesses/apollo/skills/schema-design/SKILL.md +0 -141
- package/data/harnesses/apollo/skills/test/SKILL.md +0 -104
- package/data/harnesses/apollo/skills/testing/SKILL.md +0 -166
- package/data/harnesses/apollo/skills/workflow-mapper/SKILL.md +0 -451
- package/data/harnesses/apollo/skills/workflow-mapper/references/patterns.md +0 -214
- /package/data/harnesses/{apollo → code}/docs/README.md +0 -0
- /package/data/harnesses/{apollo → code}/docs/history/CHANGELOG.md +0 -0
- /package/data/harnesses/{apollo → code}/docs/history/backlog.md +0 -0
- /package/data/harnesses/{apollo → code}/docs/memory/main.md +0 -0
- /package/data/harnesses/{apollo → code}/docs/structure.md +0 -0
- /package/data/harnesses/{apollo → code}/rules/cloudflare.md +0 -0
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Step 5 — The ship gate
|
|
2
|
-
|
|
3
|
-
The project ships with its project-local artifacts — `design.md` (the resolved fork, with provenance line, brief bindings, recorded deviations), its derived `design.tokens.css`, and `product.md` — and its memory server-side. The gate has two tiers, both objective: this is the only runtime check the skill performs, permitted precisely because it is automated and needs no judgment. Nothing here grades taste — anything that needs grading was the build-time harness's burden, not the run's.
|
|
4
|
-
|
|
5
|
-
## Tier 1 — fails closed
|
|
6
|
-
|
|
7
|
-
Every check a binary predicate. Run the validator (`node scripts/validate-design-md.mjs <project design.md> --mode ship`) plus the build itself; all of these must hold:
|
|
8
|
-
|
|
9
|
-
- **No placeholder text or scaffold stubs** anywhere (lorem, TODO, "Coming soon", empty `href="#"` walls).
|
|
10
|
-
- **Data plausibility** against the corpus's declared invariants: aggregates reconcile with their visible rows; legal ranges hold; no degenerate repetition in visible rows (surname clusters, identical amounts).
|
|
11
|
-
- **Accessibility floor, mechanical**: contrast computed on the emitted token pairs in *both* themes; focus visible on every interactive element; `prefers-reduced-motion` respected.
|
|
12
|
-
- **Every declared surface reachable** — each surface in the structure doc has a live route/nav path.
|
|
13
|
-
- **`design.md` present at the repo base** and the token artifact recompiles from it to a byte-match (the validator's drift check).
|
|
14
|
-
- **The pipe checks**:
|
|
15
|
-
- the token artifact carries 100% coverage and components consume tokens — no raw color/size literals in component code;
|
|
16
|
-
- fonts bound to installed packages under registered family names (a family that never resolves is a fail);
|
|
17
|
-
- every authored token group reaches a named consumer — an emitted ramp nobody consumes is a fail;
|
|
18
|
-
- the emitted CSS actually compiles;
|
|
19
|
-
- charts and status surfaces consume the package's tokens (a dark dashboard with hardcoded light charts fails here).
|
|
20
|
-
|
|
21
|
-
A Tier-1 failure blocks the ship; fix and re-run. Binary phrasing is the contract — anything that would need "use sparingly" grading does not belong in this tier.
|
|
22
|
-
|
|
23
|
-
## Tier 2 — flags, never gates
|
|
24
|
-
|
|
25
|
-
Sweep `data/tells.csv` (the operator tell list), at this step only, plus the motion tells (`transition: all`; `ease-in` on an entrance; animation attached to a keyboard-triggered action). Flags cannot fail the build and trigger no in-run judging: each is **fixed or dismissed with one recorded line** through `record`, and every flag appears in the ship report for the human's eyes — numbers point eyes; they do not replace them. The validator may run this sweep warn-only after compose-step edits; nothing new ever fails the build mid-composition.
|
|
26
|
-
|
|
27
|
-
## The ship report
|
|
28
|
-
|
|
29
|
-
Close the run with a compact report: surfaces shipped, the recorded choices, Tier-1 results, every Tier-2 flag with its disposition, and the validator's warn list. No scores, no self-grades. Write it to memory — `record` with `report: { kind: "gate", summary }` — and, if the run's surviving edits changed the project's `design.md`, push the new text in the same `record` so the server canonical stays current.
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: ux-patterns-index
|
|
3
|
-
class: b2
|
|
4
|
-
sourced: 2026-07-12
|
|
5
|
-
source: "b2b-ux-patterns playbook (16 chapters) — distilled"
|
|
6
|
-
license: open
|
|
7
|
-
---
|
|
8
|
-
# B2 — the B2B UX-pattern decision layer
|
|
9
|
-
|
|
10
|
-
What-to-use-when for every structural UI decision, distilled from the ratified 16-chapter B2B UX playbook. **One decision file per pass**, each carrying its rule twice in one body: prose for the model, then an embedded machine-readable `json decision-table` that is the executable core — the contract runner ([`../../../../evals/design/run-decision-contracts.mjs`](../../../../evals/design/run-decision-contracts.mjs)) parses and evaluates these tables directly, so the tested rule and the followed rule are the same bytes.
|
|
11
|
-
|
|
12
|
-
The pinned **seven-archetype roster** every pass conforms to: `browse`, `queue`, `grid`, `record-detail`, `dashboard`, `creation-flow`, `settings`. View-types (table, board, cards, calendar, timeline, map) are **projections** of an archetype, never archetypes themselves.
|
|
13
|
-
|
|
14
|
-
## The 15 passes
|
|
15
|
-
|
|
16
|
-
Run each at the step of the method that needs it — the order below is the method's order.
|
|
17
|
-
|
|
18
|
-
| # | Pass | Source | Owns |
|
|
19
|
-
| --- | --- | --- | --- |
|
|
20
|
-
| 1 | [object-model](object-model.md) | ch.1 | `requiredMechanics`, `clarifications` |
|
|
21
|
-
| 2 | [attributes-lifecycle](attributes-lifecycle.md) | ch.2 | `requiredMechanics`, `requiredStates`, `clarifications` |
|
|
22
|
-
| 3 | [verbs](verbs.md) | ch.3 | `requiredMechanics`, `requiredStates`, `containers`, `clarifications` |
|
|
23
|
-
| 4 | [viewer-context](viewer-context.md) | ch.4 | `requiredMechanics`, `clarifications` |
|
|
24
|
-
| 5 | [modes](modes.md) | ch.5 | `archetypes`, `requiredMechanics` |
|
|
25
|
-
| 6 | [promotion-demotion](promotion-demotion.md) | ch.6 | `requiredMechanics`, `clarifications` |
|
|
26
|
-
| 7 | [page-archetype](page-archetype.md) | ch.7 | `archetypes`, `requiredMechanics`, `requiredStates`, `clarifications` |
|
|
27
|
-
| 8 | [container-choice](container-choice.md) | ch.8 | `containers`, `requiredMechanics`, `clarifications` |
|
|
28
|
-
| 9 | [creation-paths](creation-paths.md) | ch.9 | `creationPaths`, `requiredMechanics`, `clarifications` |
|
|
29
|
-
| 10 | [table-mechanics](table-mechanics.md) | ch.10 | `requiredMechanics`, `clarifications` |
|
|
30
|
-
| 11 | [state-matrix](state-matrix.md) | ch.11 | `requiredStates`, `requiredMechanics`, `clarifications` |
|
|
31
|
-
| 12 | [standard-pages](standard-pages.md) | ch.12 | `archetypes`, `requiredMechanics`, `clarifications` |
|
|
32
|
-
| 13 | [ai-layer](ai-layer.md) | ch.13 | `archetypes`, `requiredStates`, `requiredMechanics`, `clarifications` |
|
|
33
|
-
| 14 | [dashboards](dashboards.md) | ch.15 | `archetypes`, `requiredStates`, `requiredMechanics`, `clarifications` |
|
|
34
|
-
| 15 | [settings](settings.md) | ch.16 | `archetypes`, `requiredStates`, `requiredMechanics`, `clarifications` |
|
|
35
|
-
|
|
36
|
-
(Playbook chapter 14 — the agentic pattern catalog — is consideration material behind pass 13, not a pass of its own.)
|
|
37
|
-
|
|
38
|
-
## The decision-table contract
|
|
39
|
-
|
|
40
|
-
Every pass file ends with one fenced `json decision-table` block: `{"pass": "<id>", "rows": [{"when": {...}, "then": {...}, "reason": "<kebab-code>"}]}`.
|
|
41
|
-
|
|
42
|
-
**Matching semantics (canonical).** A row matches when **every** key in its `when` matches the input: a literal value matches by equality, an array value matches by membership (input ∈ array), and `"__absent__"` matches when the key is missing or null. The engine unions the `then` of every matched row.
|
|
43
|
-
|
|
44
|
-
**`then` fields.** `archetypes` / `containers` / `creationPaths` / `requiredStates` / `requiredMechanics` each take `{"mustInclude": [...], "mustNotInclude": [...]}` (`containers` may use `"acceptable"` / `"forbidden"`); `clarifications` takes a flat list of missing-input codes.
|
|
45
|
-
|
|
46
|
-
## Shared input vocabulary
|
|
47
|
-
|
|
48
|
-
Every `when` key used across the 15 passes, with its legal values. **Any key may also be `"__absent__"`** (the input omits it) — that is how clarification rows fire. Boolean keys take `true` / `false`.
|
|
49
|
-
|
|
50
|
-
| Key | Legal values | Used by |
|
|
51
|
-
| --- | --- | --- |
|
|
52
|
-
| `relationshipCardinality` | one-to-one · one-to-few · one-to-many · many-to-many | object-model |
|
|
53
|
-
| `childHasOwnLifecycle` | boolean | object-model |
|
|
54
|
-
| `childMeaningfulAlone` | boolean | object-model |
|
|
55
|
-
| `editedAtomicallyWithParent` | boolean | object-model |
|
|
56
|
-
| `associationHasPayload` | boolean | object-model |
|
|
57
|
-
| `glanceContextNeeded` | boolean | object-model |
|
|
58
|
-
| `collaboration` | concurrent · single-writer | object-model, viewer-context, page-archetype |
|
|
59
|
-
| `historySignal` | none · trajectory · compliance · derived-high-frequency | attributes-lifecycle |
|
|
60
|
-
| `disputeLikely` | boolean | attributes-lifecycle |
|
|
61
|
-
| `fieldOrigin` | manual · computed · synced · imported · ai-generated | attributes-lifecycle |
|
|
62
|
-
| `objectHasLifecycle` | boolean | attributes-lifecycle |
|
|
63
|
-
| `transitionRequirements` | boolean | attributes-lifecycle |
|
|
64
|
-
| `timeProperty` | sla · due-escalation · recurrence · snooze · none | attributes-lifecycle |
|
|
65
|
-
| `endOfLife` | reference-after-completion · user-data-deletion · compliance-erasure | attributes-lifecycle |
|
|
66
|
-
| `multipleEntryPoints` | boolean | attributes-lifecycle |
|
|
67
|
-
| `verbKind` | transition · edit · association · collaboration · communication · conversion · break-glass · approval-gated | verbs |
|
|
68
|
-
| `reversible` | boolean | verbs, ai-layer |
|
|
69
|
-
| `outwardFacing` | boolean | verbs, ai-layer |
|
|
70
|
-
| `bulk` | boolean | verbs |
|
|
71
|
-
| `thresholdVariant` | boolean | verbs |
|
|
72
|
-
| `denialKind` | role · plan | viewer-context |
|
|
73
|
-
| `entitlementKind` | boolean · metered | viewer-context |
|
|
74
|
-
| `fieldLevelSecurity` | boolean | viewer-context |
|
|
75
|
-
| `requiredFieldHidden` | boolean | viewer-context |
|
|
76
|
-
| `existenceLeakRisk` | boolean | viewer-context |
|
|
77
|
-
| `viewerKind` | human · agent | viewer-context |
|
|
78
|
-
| `concurrentViewers` | boolean | viewer-context |
|
|
79
|
-
| `environmentSeparation` | boolean | viewer-context |
|
|
80
|
-
| `mode` | monitoring · triage · procedural · exception · approval · investigation · exploration · authoring · reconciliation · comparison · batch-mutation · configuration · collaboration · reporting · learning · supervision | modes |
|
|
81
|
-
| `sameDataMultipleModes` | boolean | modes |
|
|
82
|
-
| `frequency` | high · medium · low | promotion-demotion |
|
|
83
|
-
| `isParent` | boolean | promotion-demotion |
|
|
84
|
-
| `demotionContractMet` | boolean | promotion-demotion |
|
|
85
|
-
| `perRoleVariance` | boolean | promotion-demotion |
|
|
86
|
-
| `primaryJob` | lookup · triage · process · edit-bulk · monitor · narrate-period · route-work · author · configure · approve · investigate · explore · reconcile | page-archetype |
|
|
87
|
-
| `ordering` | priority · sla · age · user-controlled · none | page-archetype |
|
|
88
|
-
| `ownership` | claimable · assigned · individual · shared | page-archetype |
|
|
89
|
-
| `viewTypeRequested` | table · board · cards · calendar · timeline · map | page-archetype |
|
|
90
|
-
| `hasStatusField` | boolean | page-archetype, table-mechanics |
|
|
91
|
-
| `hasDateField` | boolean | page-archetype |
|
|
92
|
-
| `unitOfWork` | record · machine-proposal · thread | page-archetype |
|
|
93
|
-
| `structuralChangeAllowed` | boolean | page-archetype |
|
|
94
|
-
| `existingArchetype` | browse · queue · grid · record-detail · dashboard · creation-flow · settings | page-archetype |
|
|
95
|
-
| `opensRecord` | boolean | container-choice |
|
|
96
|
-
| `contextRetentionNeeded` | boolean | container-choice |
|
|
97
|
-
| `interactionDepth` | quick-read · deep-edit | container-choice |
|
|
98
|
-
| `sharing` | stable-url · sent-outward · none | container-choice |
|
|
99
|
-
| `traversal` | boolean | container-choice |
|
|
100
|
-
| `interruption` | interrupt · continue | container-choice |
|
|
101
|
-
| `contentSize` | small · large | container-choice |
|
|
102
|
-
| `recordReference` | boolean | container-choice |
|
|
103
|
-
| `opensInOverlay` | boolean | container-choice |
|
|
104
|
-
| `isDetailSurface` | boolean | container-choice |
|
|
105
|
-
| `detailBody` | large-independent · modest-cross-skim | container-choice |
|
|
106
|
-
| `longSessionStream` | boolean | container-choice |
|
|
107
|
-
| `customerFacingComposer` | boolean | container-choice |
|
|
108
|
-
| `manualCreate` | boolean | creation-paths |
|
|
109
|
-
| `bulkOnboarding` | boolean | creation-paths |
|
|
110
|
-
| `bornFromTransformation` | boolean | creation-paths |
|
|
111
|
-
| `bornFromTemplate` | boolean | creation-paths |
|
|
112
|
-
| `recurs` | boolean | creation-paths |
|
|
113
|
-
| `externalSourceOfTruth` | boolean | creation-paths |
|
|
114
|
-
| `creationFrequency` | high · low | creation-paths |
|
|
115
|
-
| `fieldCount` | few · many | creation-paths |
|
|
116
|
-
| `interdependentFields` | boolean | creation-paths |
|
|
117
|
-
| `bornComplete` | boolean | creation-paths |
|
|
118
|
-
| `sequentialDependencies` | boolean | creation-paths |
|
|
119
|
-
| `isGridPrimaryWrite` | boolean | creation-paths |
|
|
120
|
-
| `requiredRelationMayBeMissing` | boolean | creation-paths |
|
|
121
|
-
| `duplicateProneCreate` | boolean | creation-paths |
|
|
122
|
-
| `serverTruthValidation` | boolean | creation-paths |
|
|
123
|
-
| `editRegime` | inline · explicit-mode · canvas | creation-paths |
|
|
124
|
-
| `concurrentEditors` | boolean | creation-paths |
|
|
125
|
-
| `isConfigObject` | boolean | creation-paths |
|
|
126
|
-
| `revisitedWithIntent` | boolean | table-mechanics |
|
|
127
|
-
| `sharedViewScope` | personal · team | table-mechanics |
|
|
128
|
-
| `wideObject` | boolean | table-mechanics |
|
|
129
|
-
| `heavyDailyUse` | boolean | table-mechanics |
|
|
130
|
-
| `groupBySegment` | boolean | table-mechanics |
|
|
131
|
-
| `crossCuttingHealthNumbers` | boolean | table-mechanics |
|
|
132
|
-
| `gridEditable` | boolean | table-mechanics |
|
|
133
|
-
| `bulkVerbs` | boolean | table-mechanics |
|
|
134
|
-
| `rowActions` | boolean | table-mechanics |
|
|
135
|
-
| `viewerRelationships` | boolean | table-mechanics |
|
|
136
|
-
| `largeDataset` | boolean | table-mechanics |
|
|
137
|
-
| `listLength` | paginated · infinite · virtualized | table-mechanics |
|
|
138
|
-
| `financialRecordKeeping` | boolean | table-mechanics |
|
|
139
|
-
| `sharedMutableList` | boolean | table-mechanics |
|
|
140
|
-
| `exportNeeded` | boolean | table-mechanics |
|
|
141
|
-
| `isListSurface` | boolean | state-matrix |
|
|
142
|
-
| `dataFetch` | boolean | state-matrix |
|
|
143
|
-
| `fetchLatency` | boolean | state-matrix |
|
|
144
|
-
| `compositePage` | boolean | state-matrix |
|
|
145
|
-
| `consumesCachedData` | boolean | state-matrix |
|
|
146
|
-
| `streamingView` | boolean | state-matrix |
|
|
147
|
-
| `optimisticMutation` | boolean | state-matrix |
|
|
148
|
-
| `queueSuccessIsEmpty` | boolean | state-matrix |
|
|
149
|
-
| `firstRunSurface` | boolean | state-matrix |
|
|
150
|
-
| `onboardingTechnique` | boolean | state-matrix |
|
|
151
|
-
| `onboardingScope` | application-level · empty-state | state-matrix |
|
|
152
|
-
| `standardPage` | settings · profile · notifications · audit-object · audit-global · user-management · roles-permissions · seats-licenses · billing · integrations | standard-pages |
|
|
153
|
-
| `notificationDelivery` | boolean | standard-pages |
|
|
154
|
-
| `ssoScimProvisioning` | boolean | standard-pages |
|
|
155
|
-
| `complianceBuyer` | boolean | standard-pages |
|
|
156
|
-
| `recordLevelAccess` | boolean | standard-pages |
|
|
157
|
-
| `externalSystemMapping` | boolean | standard-pages |
|
|
158
|
-
| `intelligenceTime` | build-time · run-time | ai-layer |
|
|
159
|
-
| `aiWrites` | boolean | ai-layer |
|
|
160
|
-
| `blastRadius` | single-record · many-records · external-fanout | ai-layer |
|
|
161
|
-
| `initiative` | invoked · suggested · initiated | ai-layer |
|
|
162
|
-
| `latency` | live · just-in-time · per-row · scheduled · ambient | ai-layer |
|
|
163
|
-
| `confidenceGateable` | boolean | ai-layer |
|
|
164
|
-
| `correctsHumanOrThirdParty` | boolean | ai-layer |
|
|
165
|
-
| `autonomousAgent` | boolean | ai-layer |
|
|
166
|
-
| `agentPrincipal` | boolean | ai-layer |
|
|
167
|
-
| `durableWait` | boolean | ai-layer |
|
|
168
|
-
| `copilotOutput` | inspectable-reversible · externally-committing | ai-layer |
|
|
169
|
-
| `accumulatedMemory` | boolean | ai-layer |
|
|
170
|
-
| `inputBoundaryTransduction` | boolean | ai-layer |
|
|
171
|
-
| `dashboardJob` | monitoring · narrative · work-router | dashboards |
|
|
172
|
-
| `multiJobCanvas` | boolean | dashboards |
|
|
173
|
-
| `cachedDecisionData` | boolean | dashboards |
|
|
174
|
-
| `viewerScopedMetrics` | boolean | dashboards |
|
|
175
|
-
| `promotionRole` | manager · operator | dashboards |
|
|
176
|
-
| `pushDigest` | boolean | dashboards |
|
|
177
|
-
| `tile` | boolean | dashboards |
|
|
178
|
-
| `monitoringTile` | boolean | dashboards |
|
|
179
|
-
| `thresholdDeclared` | boolean | dashboards |
|
|
180
|
-
| `trendTileRequested` | boolean | dashboards |
|
|
181
|
-
| `sourceHistoryClass` | overwrite · sampled · logged | dashboards |
|
|
182
|
-
| `isSettingsPage` | boolean | settings |
|
|
183
|
-
| `scope` | personal · workspace · org | settings |
|
|
184
|
-
| `settingKind` | leaf-preference · config-object | settings |
|
|
185
|
-
| `riskClass` | preference · behavior-config · structural-destructive | settings |
|
|
186
|
-
| `subject` | identity-access · data-model · automation · notifications · integrations · branding · billing · compliance-audit · ai-agent-policy | settings |
|
|
187
|
-
| `multiScopeSetting` | boolean | settings |
|
|
188
|
-
| `nodeCount` | under-30 · over-30 | settings |
|
|
189
|
-
| `governedSurfaceLink` | boolean | settings |
|
|
190
|
-
| `buildTimeGeneration` | boolean | settings |
|
|
191
|
-
| `productSurfaceInTree` | boolean | settings |
|
|
192
|
-
|
|
193
|
-
## The load rule
|
|
194
|
-
|
|
195
|
-
**One pass file per step, never all at once.** The load contract ([09 §Load contracts](../../../../docs/features/design-skill/09-database-structures.md)) is explicit: B2 enters context as *the one pass file the current step needs*; loading all passes at once is forbidden. Consult this Readme to route to the right file, then load only that file at the step that needs it. Clarification codes are surfaced, never guessed around — a `then.clarifications` firing means an input the pass needs is missing, and the step pauses to obtain it rather than proceeding on a default.
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: ai-layer
|
|
3
|
-
class: b2
|
|
4
|
-
sourced: 2026-07-12
|
|
5
|
-
source: "b2b-ux-patterns ch.13"
|
|
6
|
-
license: open
|
|
7
|
-
---
|
|
8
|
-
# Pass: the AI layer
|
|
9
|
-
|
|
10
|
-
**Inputs:** per intelligent capability — `intelligenceTime` (build-time | run-time), `aiWrites`, `blastRadius` (single-record | many-records | external-fanout), `reversible`, `outwardFacing`, `initiative` (invoked | suggested | initiated), `latency` (live | just-in-time | per-row | scheduled | ambient), `confidenceGateable`, `correctsHumanOrThirdParty`, `autonomousAgent`, `agentPrincipal`, `durableWait`, `copilotOutput` (inspectable-reversible | externally-committing), `accumulatedMemory`, `inputBoundaryTransduction`.
|
|
11
|
-
**Owns:** `archetypes`, `requiredStates`, `requiredMechanics`, `clarifications`.
|
|
12
|
-
**Output artifact:** for every AI capability, its decision-rights stance (who holds the write), the guardrail envelope (prevention + recovery + glass box), and the write-path bindings that connect it to the lifecycle, verbs, and access passes. Every AI pattern is a transfer of a slice of cognition from human to system; this pass governs the transfer.
|
|
13
|
-
|
|
14
|
-
## The rule
|
|
15
|
-
|
|
16
|
-
**Divide first by when the intelligence runs.** *Run-time* intelligence operates within a built system (fills fields, routes rows, drafts text, resolves) and transfers the operator's cognition. *Build-time* intelligence constructs the system itself (NL → tables, views, automations) and transfers the builder's cognition — its guardrail shape is **preview-the-generated-artifact and edit-before-commit**, never per-row confidence, and its compilation target must be inspectable (a node graph, a field list), never an opaque box.
|
|
17
|
-
|
|
18
|
-
**The three-actor write model is the spine, and the stance is set by blast radius and reversibility — not by model confidence alone.** *System proposes, human disposes* — output lands in a *proposed* state and waits for accept/edit/reject; the default for external, irreversible, or fan-out writes (a customer email, a bulk send). *System acts, human audits after* — the write commits, with the audit trail, rollback, and exception queue as the control; correct for internal, reversible, single-record writes. *System acts silently* — auto-classification, continuous re-enrichment; governance lives in configuration, sampling, and dashboards. The clean formulation: *AI proposes the signal, deterministic rules dispose the record.* Two axes cross the spine: **initiative** (invoked → suggested → initiated) separates next-best-action from anticipation; the **latency ladder** (live → just-in-time → per-row → scheduled → ambient) dictates the affordance — live cue cards streamed mid-call can never be a modal; scheduled jobs surface as a review queue on completion.
|
|
19
|
-
|
|
20
|
-
**Non-deterministic in, deterministic out.** Free-form material (dictated text, an email thread, a PDF, a receipt) is matched to the declared object model and lands as typed fields — the input-boundary transducer, "parse, don't type," applied at every scope (field, record, row-stream, table, ambient stream). Output generation is grounded in declared assets and post-filtered by deterministic rulebooks. Every AI write carries **origin = ai-generated** with provenance, rides the standard *proposed* state and approval verbs, and is **Logged with dual attribution** (the agent, and the human who accepted or the policy that authorized).
|
|
21
|
-
|
|
22
|
-
**Guardrails are one orthogonal layer, factored once.** *Prevention*: confidence gating with a numeric threshold where the domain is mature (high-confidence posts through, sub-threshold queues for review); **statistical-significance gating** where the system corrects a human or third-party claim (never assert on a small sample — the reputation guardrail, and the home of the house-knowledge corrective); simulation/eval gating before an agent version deploys. *Recovery*: the undo/rollback backstop under every agent action; the **escalation floor** — no serious autonomous agent ships without a mandatory hand-to-human boundary, and the handoff carries what was already tried so the human resumes mid-stream. *Glass box*: citations, the source anchor stored beside every transduced value, and the **AI-action audit log as a surface distinct from record edit history** (actor = AI, what changed, and what data informed it).
|
|
23
|
-
|
|
24
|
-
**The agent is a governed actor and the checkpoint is how the flow waits.** An agent principal gets its own identity in the directory, scoped least-privilege permissions, a human sponsor, and a lifecycle — never a borrowed human credential; its effective access is the intersection of its grants and its delegating subject's (see viewer-context). The **durable checkpoint** (axiom 21) — pause, persist, notify, resume — is the portable guardrail node: decision rights choose *when* the human enters; the checkpoint is *how* the flow waits, with state persisting across days and the notification carrying the evidence pack. Design against this primitive, not against inline blocking prompts. Chat is the **home surface** when its output is inspectable and reversible (conversational BI — expose the compiled query as the escape to determinism) and the **escape hatch** when output is externally committing (the human ratifies). Accumulated memory (system-auto-written, cross-session) is audited after and demands its own management surface and memory-provenance show-which. When an AI capability writes but its blast radius is undeclared, the decision-rights stance cannot be set: clarify.
|
|
25
|
-
|
|
26
|
-
```json decision-table
|
|
27
|
-
{"pass": "ai-layer", "rows": [
|
|
28
|
-
{"when": {"intelligenceTime": "build-time"}, "then": {"requiredMechanics": {"mustInclude": ["preview-generated-artifact", "edit-before-commit", "inspectable-compilation-target"], "mustNotInclude": ["opaque-black-box", "per-row-confidence-on-build"]}}, "reason": "build-time-previews-the-artifact"},
|
|
29
|
-
{"when": {"aiWrites": true, "blastRadius": "single-record", "reversible": true, "outwardFacing": false}, "then": {"requiredMechanics": {"mustInclude": ["ai-acts-human-audits-after", "audit-trail", "rollback-backstop", "exception-queue"]}}, "reason": "internal-reversible-single-record-acts"},
|
|
30
|
-
{"when": {"outwardFacing": true}, "then": {"requiredMechanics": {"mustInclude": ["ai-proposes-human-disposes", "approval-verbs"], "mustNotInclude": ["ai-acts-silently"]}, "requiredStates": {"mustInclude": ["proposed"]}}, "reason": "external-facing-writes-propose"},
|
|
31
|
-
{"when": {"blastRadius": "external-fanout"}, "then": {"requiredMechanics": {"mustInclude": ["ai-proposes-human-disposes", "approval-verbs"], "mustNotInclude": ["ai-acts-silently"]}, "requiredStates": {"mustInclude": ["proposed"]}}, "reason": "fan-out-writes-propose"},
|
|
32
|
-
{"when": {"aiWrites": true, "reversible": false}, "then": {"requiredMechanics": {"mustInclude": ["ai-proposes-human-disposes"], "mustNotInclude": ["ai-acts-silently"]}, "requiredStates": {"mustInclude": ["proposed"]}}, "reason": "irreversible-writes-propose"},
|
|
33
|
-
{"when": {"initiative": "initiated"}, "then": {"requiredMechanics": {"mustInclude": ["anticipation-system-initiated", "statistical-significance-gate"]}}, "reason": "system-initiated-needs-the-significance-gate-most"},
|
|
34
|
-
{"when": {"initiative": "suggested"}, "then": {"requiredMechanics": {"mustInclude": ["next-best-action-same-recommendation-multi-surface"]}}, "reason": "suggested-is-next-best-action"},
|
|
35
|
-
{"when": {"latency": "live"}, "then": {"requiredMechanics": {"mustInclude": ["streamed-cue-cards"], "mustNotInclude": ["live-output-in-a-modal"]}}, "reason": "sub-second-cannot-be-a-modal"},
|
|
36
|
-
{"when": {"latency": "scheduled"}, "then": {"archetypes": {"mustInclude": ["queue"]}, "requiredMechanics": {"mustInclude": ["review-queue-on-completion", "evidence-pack"]}}, "reason": "scheduled-jobs-surface-a-review-queue"},
|
|
37
|
-
{"when": {"confidenceGateable": true}, "then": {"requiredMechanics": {"mustInclude": ["confidence-threshold-gate", "sub-threshold-review-queue"]}}, "reason": "mature-domain-gates-on-confidence"},
|
|
38
|
-
{"when": {"correctsHumanOrThirdParty": true}, "then": {"requiredMechanics": {"mustInclude": ["statistical-significance-gate", "house-knowledge-corrective"], "mustNotInclude": ["assert-on-small-sample"]}}, "reason": "reputation-guardrail-never-asserts-on-a-small-sample"},
|
|
39
|
-
{"when": {"inputBoundaryTransduction": true}, "then": {"requiredMechanics": {"mustInclude": ["parse-dont-type-transducer", "source-anchor-per-value", "typed-fields-out"]}}, "reason": "non-deterministic-in-deterministic-out"},
|
|
40
|
-
{"when": {"aiWrites": true}, "then": {"requiredMechanics": {"mustInclude": ["origin-ai-generated-provenance", "dual-attribution-logged", "ai-action-audit-log-distinct"]}}, "reason": "ai-writes-carry-provenance-and-dual-attribution"},
|
|
41
|
-
{"when": {"autonomousAgent": true}, "then": {"requiredMechanics": {"mustInclude": ["escalation-floor-hand-to-human", "handoff-carries-context", "supervisor-layer", "undo-rollback-backstop"], "mustNotInclude": ["no-escalation-boundary"]}}, "reason": "no-autonomous-agent-without-an-escalation-floor"},
|
|
42
|
-
{"when": {"agentPrincipal": true}, "then": {"requiredMechanics": {"mustInclude": ["agent-own-directory-identity", "scoped-least-privilege", "human-sponsor", "delegated-subject-intersection"], "mustNotInclude": ["borrowed-human-credential"]}}, "reason": "agent-is-a-governed-principal"},
|
|
43
|
-
{"when": {"durableWait": true}, "then": {"requiredMechanics": {"mustInclude": ["durable-checkpoint-pause-persist-notify-resume", "notification-carries-evidence-pack"], "mustNotInclude": ["inline-blocking-prompt"]}}, "reason": "design-against-the-checkpoint-primitive"},
|
|
44
|
-
{"when": {"copilotOutput": "inspectable-reversible"}, "then": {"requiredMechanics": {"mustInclude": ["chat-as-home-surface", "expose-compiled-query", "promote-answer-to-artifact"]}}, "reason": "inspectable-reversible-output-lives-in-chat"},
|
|
45
|
-
{"when": {"copilotOutput": "externally-committing"}, "then": {"requiredMechanics": {"mustInclude": ["chat-as-escape-hatch", "human-ratifies-before-commit", "propose-then-confirm"], "mustNotInclude": ["chat-commits-externally-unratified"]}}, "reason": "externally-committing-output-is-ratified"},
|
|
46
|
-
{"when": {"accumulatedMemory": true}, "then": {"requiredMechanics": {"mustInclude": ["memory-management-surface", "memory-provenance-show-which", "identity-scoped-memory"]}}, "reason": "auto-written-memory-is-audited-after"},
|
|
47
|
-
{"when": {"aiWrites": true, "blastRadius": "__absent__"}, "then": {"clarifications": ["ai-write-blast-radius-unspecified"]}, "reason": "decision-rights-stance-needs-blast-radius"}
|
|
48
|
-
]}
|
|
49
|
-
```
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: attributes-lifecycle
|
|
3
|
-
class: b2
|
|
4
|
-
sourced: 2026-07-12
|
|
5
|
-
source: "b2b-ux-patterns ch.2"
|
|
6
|
-
license: open
|
|
7
|
-
---
|
|
8
|
-
# Pass: attributes, lifecycle & history
|
|
9
|
-
|
|
10
|
-
**Inputs:** per field — `historySignal` (none | trajectory | compliance | derived-high-frequency), `fieldOrigin` (manual | computed | synced | imported | ai-generated), `disputeLikely`; per object — `objectHasLifecycle`, `transitionRequirements`, `timeProperty` (sla | due-escalation | recurrence | snooze | none), `endOfLife` (reference-after-completion | user-data-deletion | compliance-erasure), `multipleEntryPoints`.
|
|
11
|
-
**Owns:** `requiredMechanics`, `requiredStates`, `clarifications`.
|
|
12
|
-
**Output artifact:** per-field declarations (type, history class, origin) and per-object declarations (state machine, time properties, end-of-life tier) that every later pass derives from mechanically — chips, timelines, trends, boards, gated buttons, countdowns, trash, and merge are renders of these declarations, never inventions.
|
|
13
|
-
|
|
14
|
-
## The rule
|
|
15
|
-
|
|
16
|
-
**Every field declares one of three history classes.** *Overwrite* (the default — update in place, no history; paying history cost on every descriptive field is how products drown their own timelines). *Logged* (every change attributed: old value, new value, actor, timestamp) for fields where the trajectory is the meaning — stage, status, owner, amount — and anything with compliance weight or dispute risk; Logged fields are what make a detail page's history tab worth opening. *Sampled* (sparse snapshots or rollups) for high-frequency derived values — scores, metrics, queue depths; a Sampled field renders as a number with a trace (sparkline, as-of view), never as a change log. An empty timeline is a history-class declaration failure, not a UI failure.
|
|
17
|
-
|
|
18
|
-
**Origin decides editability and provenance.** Computed fields are never directly editable. Synced fields render their source and last-sync ("Enriched by Clearbit, 3 days ago") and need a conflict resolution when the sync wants to overwrite a human edit. Field types drive four renders at once — cell, input, filter, sort — declared once, derived everywhere; enums declare semantic color and icon here, never color alone.
|
|
19
|
-
|
|
20
|
-
**The state machine is data:** a status enum, legal transitions, terminal states. The UI derives gated verbs (Refund exists only on succeeded payments), status chips rendered identically everywhere, spatial board projection (a drag is a transition), and per-transition requirements (required fields, approvals, permissions) declared on the transition, not in form code. The status field itself is almost always Logged.
|
|
21
|
-
|
|
22
|
-
**Time properties mutate records with no user action** — SLA countdowns that re-sort queues, escalation on due-date breach, recurrence materializing instances, snooze as a time-scoped visibility state. Lists holding such objects are not stable; queues sort on the clock.
|
|
23
|
-
|
|
24
|
-
**Every object declares how it dies**, in order of preference: archive (restorable, filter-exposed) for completed referenceable work; soft-delete with a trash retention window — the data property that permits undo-toast instead of a confirm dialog; hard delete reserved for compliance erasure. Any object with multiple entry points will accumulate duplicates and needs a merge flow whose survivor keeps the Logged history — a merge that discards a Logged trail breaks the audit chain.
|
|
25
|
-
|
|
26
|
-
```json decision-table
|
|
27
|
-
{"pass": "attributes-lifecycle", "rows": [
|
|
28
|
-
{"when": {"historySignal": "none"}, "then": {"requiredMechanics": {"mustInclude": ["overwrite-in-place"], "mustNotInclude": ["activity-timeline-entries"]}}, "reason": "descriptive-fields-overwrite"},
|
|
29
|
-
{"when": {"historySignal": ["trajectory", "compliance"]}, "then": {"requiredMechanics": {"mustInclude": ["logged-field-history", "activity-timeline-entries", "changed-by-attribution"]}}, "reason": "trajectory-is-the-meaning"},
|
|
30
|
-
{"when": {"historySignal": "derived-high-frequency"}, "then": {"requiredMechanics": {"mustInclude": ["sampled-snapshots", "sparkline-trend"], "mustNotInclude": ["activity-timeline-entries"]}}, "reason": "high-frequency-sampled-not-logged"},
|
|
31
|
-
{"when": {"disputeLikely": true, "historySignal": "__absent__"}, "then": {"clarifications": ["history-class-unspecified"]}, "reason": "disputes-need-declared-history"},
|
|
32
|
-
{"when": {"fieldOrigin": "computed"}, "then": {"requiredMechanics": {"mustInclude": ["read-only-derived-render"], "mustNotInclude": ["editable-input"]}}, "reason": "computed-never-editable"},
|
|
33
|
-
{"when": {"fieldOrigin": "synced"}, "then": {"requiredMechanics": {"mustInclude": ["provenance-render", "sync-conflict-resolution"]}}, "reason": "synced-origin-carries-provenance"},
|
|
34
|
-
{"when": {"objectHasLifecycle": true}, "then": {"requiredMechanics": {"mustInclude": ["status-enum-semantic-colors", "transition-graph-legal-only", "state-gated-verbs"]}}, "reason": "state-machine-is-data"},
|
|
35
|
-
{"when": {"transitionRequirements": true}, "then": {"requiredMechanics": {"mustInclude": ["transition-required-fields"]}}, "reason": "requirements-on-transition-not-form"},
|
|
36
|
-
{"when": {"timeProperty": ["sla", "due-escalation"]}, "then": {"requiredMechanics": {"mustInclude": ["sla-countdown-render", "breach-state-resort"]}, "requiredStates": {"mustInclude": ["stale"]}}, "reason": "clock-mutates-the-record"},
|
|
37
|
-
{"when": {"timeProperty": "snooze"}, "then": {"requiredMechanics": {"mustInclude": ["snooze-until-resurface"]}}, "reason": "snooze-is-visibility-not-deletion"},
|
|
38
|
-
{"when": {"endOfLife": "reference-after-completion"}, "then": {"requiredMechanics": {"mustInclude": ["archive-restorable"], "mustNotInclude": ["hard-delete"]}}, "reason": "archive-completed-work"},
|
|
39
|
-
{"when": {"endOfLife": "user-data-deletion"}, "then": {"requiredMechanics": {"mustInclude": ["soft-delete-trash-retention"], "mustNotInclude": ["hard-delete"]}}, "reason": "soft-delete-enables-undo"},
|
|
40
|
-
{"when": {"endOfLife": "compliance-erasure"}, "then": {"requiredMechanics": {"mustInclude": ["hard-delete-typed-confirmation"]}}, "reason": "hard-delete-compliance-only"},
|
|
41
|
-
{"when": {"multipleEntryPoints": true}, "then": {"requiredMechanics": {"mustInclude": ["merge-duplicates-flow", "survivor-history-preserved"]}}, "reason": "multiple-entry-points-guarantee-duplicates"}
|
|
42
|
-
]}
|
|
43
|
-
```
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: container-choice
|
|
3
|
-
class: b2
|
|
4
|
-
sourced: 2026-07-12
|
|
5
|
-
source: "b2b-ux-patterns ch.8"
|
|
6
|
-
license: open
|
|
7
|
-
---
|
|
8
|
-
# Pass: detail surface & container choice
|
|
9
|
-
|
|
10
|
-
**Inputs:** per record-opening — `opensRecord`, `contextRetentionNeeded`, `interactionDepth` (quick-read | deep-edit), `sharing` (stable-url | sent-outward | none), `traversal`, `interruption` (interrupt | continue), `contentSize` (small | large), `recordReference`, `opensInOverlay`; per detail surface — `isDetailSurface`, `detailBody` (large-independent | modest-cross-skim), `longSessionStream`, `customerFacingComposer`.
|
|
11
|
-
**Owns:** `containers`, `requiredMechanics`, `clarifications`.
|
|
12
|
-
**Output artifact:** the record-detail anatomy (sticky header, body organization, related lists, timeline, composer, context rail) and, for every place a record opens, the container rung it opens at — chosen by workflow, never by information size.
|
|
13
|
-
|
|
14
|
-
## The rule
|
|
15
|
-
|
|
16
|
-
**A detail page is a workstation, not a read-only profile.** Every detail surface carries a *sticky record header* — identity, state chip, and the 1–3 highest-frequency legal verbs for the record's current state and this viewer (from the verbs pass), the rest in overflow — pinned so identity never scrolls away. Fields *edit in place* by default (optimistic save with saving/saved/failed feedback); an explicit whole-record edit mode is reserved for interdependent fields that must commit atomically. Related lists are *action surfaces* — inline create, inline edit, row verbs, and a "view all" escape — and they are how demoted objects honor the reachability half of the demotion contract. The activity timeline is *derived*, never designed: Logged fields contribute attributed change entries, Sampled fields contribute trends, comments and notes are ordinary child objects; you declare history classes and the feed renders. A customer-facing composer carries **audience safety** — an internal note and a customer-facing send are different verbs with distinct affordance and color, never a toggle buried in one composer; sending to the wrong audience is a severity-1 failure.
|
|
17
|
-
|
|
18
|
-
**Body organization forks two ways.** *Tabs* (lazy-loaded, per-section linkable) when sections are large, independently loaded, and rarely needed together — the record is "several pages sharing a header." *Single-scroll with a sticky anchor rail* when the job needs cross-section skimming in one pass and sections are modest. Objects worked in long sessions over a streaming main column (conversation, timeline) earn a persistent **360 / context rail** — the parent summary and key attributes stay put while the narrative moves; the rail is denormalization-for-display doing its job.
|
|
19
|
-
|
|
20
|
-
**The container ladder — `hovercard → inline-popover → center-modal → side-peek → full-page`.** Information size does not pick the rung; five workflow axes do, size only breaks ties. (1) **Context retention** — if the originating list must stay live behind the opened record (open, close, open the next, compare), it is a **side peek**, however small the record; a modal dims and blocks the hub, a peek keeps it alive. (2) **Read-vs-edit depth** — a quick read wants a peek; deep, multi-field, interdependent editing wants center focus or a full page, because accidental dismissal becomes expensive. (3) **Shareability** — a record that needs a stable, shareable URL can now live in a URL-addressable peek or split pane; a record **sent outward** (an invoice) still defaults to a **full page** despite tiny size. (4) **Traversal** — processing or comparing many records in a row needs next/prev through the *exact filtered, sorted set*, which means a peek or split pane, never a modal and never a full-page round-trip per record. (5) **Interruption** — a center modal *blocks* (correct for confirmations and irreversible commits); a peek *continues* (work proceeds around it). Size is the tiebreaker only when the axes are indifferent: a leaf datum in a popover, a modest record in a peek.
|
|
21
|
-
|
|
22
|
-
**Container requirements.** Every peek and modal carries an **"open as full page"** escape hatch — users promote up the ladder themselves, so picking the lighter rung costs one click. Closing a peek or modal honors the **return contract**: the originating surface restores *exactly as left* — same scroll, filters, selection. The same object opens at the same rung from the same kind of origin, product-wide — container choice is per-object-per-origin, not per-screen improvisation. When a record must open but no workflow axis is declared, the rung cannot be chosen from size alone: clarify.
|
|
23
|
-
|
|
24
|
-
```json decision-table
|
|
25
|
-
{"pass": "container-choice", "rows": [
|
|
26
|
-
{"when": {"contextRetentionNeeded": true}, "then": {"containers": {"acceptable": ["side-peek", "split-pane"], "forbidden": ["center-modal"]}}, "reason": "hub-stays-live-is-a-peek"},
|
|
27
|
-
{"when": {"interactionDepth": "deep-edit"}, "then": {"containers": {"acceptable": ["full-page", "center-modal"], "forbidden": ["side-peek"]}}, "reason": "deep-edit-wants-committed-focus"},
|
|
28
|
-
{"when": {"interactionDepth": "quick-read", "contextRetentionNeeded": false, "traversal": false}, "then": {"containers": {"acceptable": ["side-peek", "inline-popover"]}}, "reason": "quick-read-is-a-peek"},
|
|
29
|
-
{"when": {"sharing": "sent-outward"}, "then": {"containers": {"acceptable": ["full-page"], "forbidden": ["center-modal", "side-peek"]}}, "reason": "sent-records-get-a-page"},
|
|
30
|
-
{"when": {"sharing": "stable-url"}, "then": {"requiredMechanics": {"mustInclude": ["stable-shareable-url"]}}, "reason": "url-addressable-rungs-are-fine"},
|
|
31
|
-
{"when": {"traversal": true}, "then": {"containers": {"acceptable": ["side-peek", "split-pane"], "forbidden": ["center-modal", "full-page"]}, "requiredMechanics": {"mustInclude": ["next-prev-through-filtered-set"]}}, "reason": "traverse-the-filtered-set-needs-a-peek"},
|
|
32
|
-
{"when": {"interruption": "interrupt"}, "then": {"containers": {"acceptable": ["center-modal"]}}, "reason": "blocking-is-the-point"},
|
|
33
|
-
{"when": {"interruption": "continue"}, "then": {"containers": {"forbidden": ["center-modal"]}}, "reason": "work-continues-around-a-peek"},
|
|
34
|
-
{"when": {"recordReference": true}, "then": {"containers": {"acceptable": ["hovercard"]}, "requiredMechanics": {"mustInclude": ["hovercard-read-only-no-actions"]}}, "reason": "fk-resolution-is-a-hovercard"},
|
|
35
|
-
{"when": {"contentSize": "small", "interactionDepth": "quick-read"}, "then": {"containers": {"acceptable": ["inline-popover", "hovercard", "side-peek"]}}, "reason": "smaller-content-sits-lower"},
|
|
36
|
-
{"when": {"opensInOverlay": true}, "then": {"requiredMechanics": {"mustInclude": ["escape-hatch-open-as-full-page", "return-contract-restore-state", "consistent-rungs-per-object"]}}, "reason": "peek-and-modal-carry-escape-and-return"},
|
|
37
|
-
{"when": {"isDetailSurface": true}, "then": {"requiredMechanics": {"mustInclude": ["sticky-record-header", "inline-edit-in-place-default", "related-lists-action-surface", "activity-timeline-derived"]}}, "reason": "detail-is-a-workstation"},
|
|
38
|
-
{"when": {"detailBody": "large-independent"}, "then": {"requiredMechanics": {"mustInclude": ["tabs-lazy-panels"], "mustNotInclude": ["single-scroll-anchor-rail"]}}, "reason": "independent-sections-tab"},
|
|
39
|
-
{"when": {"detailBody": "modest-cross-skim"}, "then": {"requiredMechanics": {"mustInclude": ["single-scroll-anchor-rail"], "mustNotInclude": ["tabs-lazy-panels"]}}, "reason": "cross-skim-single-scroll"},
|
|
40
|
-
{"when": {"longSessionStream": true}, "then": {"requiredMechanics": {"mustInclude": ["context-rail-360", "denormalized-parent-summary"]}}, "reason": "durable-context-beside-a-moving-stream"},
|
|
41
|
-
{"when": {"customerFacingComposer": true}, "then": {"requiredMechanics": {"mustInclude": ["activity-composer-audience-safety"], "mustNotInclude": ["audience-toggle-single-composer"]}}, "reason": "internal-note-and-send-are-different-verbs"},
|
|
42
|
-
{"when": {"opensRecord": true, "interactionDepth": "__absent__", "contextRetentionNeeded": "__absent__", "sharing": "__absent__", "traversal": "__absent__", "interruption": "__absent__"}, "then": {"clarifications": ["container-workflow-unspecified"]}, "reason": "container-picked-by-workflow-not-size"}
|
|
43
|
-
]}
|
|
44
|
-
```
|
|
@@ -1,46 +0,0 @@
|
|
|
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
|
-
```
|
|
@@ -1,42 +0,0 @@
|
|
|
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
|
-
```
|
|
@@ -1,42 +0,0 @@
|
|
|
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
|
-
```
|