super-ux 0.66.2 → 0.67.0
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/CHANGELOG.md +67 -0
- package/README.md +5 -4
- package/cursor/rules/super-ux.mdc +14 -10
- package/cursor/rules/ux-flows.mdc +5 -2
- package/cursor/rules/ux-foundation.mdc +9 -1
- package/cursor/rules/ux-scenarios.mdc +5 -2
- package/package.json +1 -1
- package/plugins/super-ux/scripts/ux_doctor.py +35 -3
- package/plugins/super-ux/scripts/ux_lint.py +269 -2
- package/templates/README.md +8 -3
- package/templates/agent-panel.md +40 -0
- package/templates/capabilities.md +29 -0
- package/templates/claude-rule.md +13 -9
- package/templates/flows.md +2 -2
- package/templates/foundation.md +20 -6
- package/templates/scenarios.md +7 -4
- package/templates/screens.md +5 -3
- package/templates/vision.md +8 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,70 @@
|
|
|
1
|
+
## 0.67.0 (2026-11-09): contract v5, agents and capabilities (opt-in)
|
|
2
|
+
|
|
3
|
+
Packet P-SU of the family run `2026-11-09-ai-native` (hub plan and design:
|
|
4
|
+
`docs/evidence/plans/2026-11-09-ai-native.md`,
|
|
5
|
+
`docs/evidence/specs/2026-11-09-ai-native-pipeline.md` in ssheleg/sshlg-skills).
|
|
6
|
+
|
|
7
|
+
- **Contract v5, opt-in by marker.** `scenario-format.md` gains *Contract v5:
|
|
8
|
+
agents and capabilities*, the home of AN-1 (parity by story) and AN-4 (why a
|
|
9
|
+
person: gates and serving reasons, each with evidence): actors `A-NN` under
|
|
10
|
+
`## Actors`, persona `Agent use`, a journey `Performed by` column,
|
|
11
|
+
`docs/ux/capabilities.md` with one `CAP-NN` per effect set (`Traces`,
|
|
12
|
+
`Actors`, `Agent excluded`, `Roles`, `Gate`, `Tools`, `Emits`, `Data`,
|
|
13
|
+
`Automation`, `Human surface`, `Since`, `Status`), scenario `Channel`, screen
|
|
14
|
+
`Fronts` and `Why human`, and `docs/ux/agent-panel.md`. A chain is on v5 when
|
|
15
|
+
its headers carry `ux-contract v5`; the lowest marker decides, so a v4 chain
|
|
16
|
+
with one v5 seed stays on v4. v4 chains lint exactly as before.
|
|
17
|
+
- **Nine lint codes, warnings, v5 only:** `U087` (a CAP field missing), `U088`
|
|
18
|
+
(a v5 value outside its enum), `U089` (a must/should story with no CAP),
|
|
19
|
+
`U090` (an agent CAP with no tools), `U091` (an agent-channel scenario citing
|
|
20
|
+
no CAP), `U092` (agents left out with no evidenced reason, or debt with no
|
|
21
|
+
board row), `U093` (a gate or serving reason with no evidence), `U094` (a
|
|
22
|
+
screen with no `Fronts` or `Why human`, or fronting an unknown CAP), `U095` (a
|
|
23
|
+
no-agent persona's must story served only by agent scenarios). Under v5 a
|
|
24
|
+
chain with no `screens.md` is not asked `U050`. Each code is planted both
|
|
25
|
+
ways in `test/ux_lint_test.py`; `test/fixtures/contract-v4` exits 0 under
|
|
26
|
+
`--strict` and `test/fixtures/contract-v5` is clean too. `validate.py`
|
|
27
|
+
compares the linter's `V5_ENUMS` with the contract's v5 declarations.
|
|
28
|
+
- **Doctor:** `CURRENT = 5`, `HISTORY[5]`; v4 is supported (no problem
|
|
29
|
+
counted) and is offered the v4 to v5 migration: add actors, capabilities and
|
|
30
|
+
channels, then the marker; nothing else is required.
|
|
31
|
+
- **Doctrine:** `system-map.md` carries AN-2 (the design order: stories,
|
|
32
|
+
capabilities, contract, logic, automation, human surfaces) and AN-6
|
|
33
|
+
(automation by default); `ux-design-principles.md` reorders the pipeline
|
|
34
|
+
(jobs, capabilities, contract, then flows and screens for the human lanes)
|
|
35
|
+
and is the home of AN-5 (the attention budget). The agent surface itself is
|
|
36
|
+
cited by raw URL to agent-stack's `agent-surface.md` and `operability.md`,
|
|
37
|
+
not restated.
|
|
38
|
+
- **Templates:** the seeds `/ux init` writes carry `ux-contract v5`;
|
|
39
|
+
`foundation.md` gains `## Actors`, `Agent use` and `Performed by`; new
|
|
40
|
+
`capabilities.md` and `agent-panel.md`; `scenarios.md` gains `Channel`;
|
|
41
|
+
`screens.md` gains `Fronts`, `Why human` and the missing `blocked` status.
|
|
42
|
+
- **Skills:** `ux-foundation` owns the capabilities layer (description 267 to
|
|
43
|
+
264 characters); `ux-scenarios` writes agent-channel steps; `ux-flows` designs
|
|
44
|
+
the human lanes and asks the Figma question at the first human surface;
|
|
45
|
+
`ux-audit` accepts an MCP or CLI call receipt as runtime evidence and checks
|
|
46
|
+
the one-contract proxy; `vision` §4 and §9 guidance ask what an agent can do
|
|
47
|
+
without a screen (nine sections unchanged); `copywriting` separates
|
|
48
|
+
agent-facing text from the `human_steps` a person reads. `/ux` routes agent
|
|
49
|
+
requests to the capabilities layer. The hard rule in `templates/claude-rule.md`
|
|
50
|
+
and `/ux-rule` (byte-equal) becomes foundation, capabilities, contract,
|
|
51
|
+
flows, screens, scenarios for human lanes.
|
|
52
|
+
- **Drift fixed on the way (BN-22):** the screens template lacked `blocked`;
|
|
53
|
+
the linter's no-docs message named only `scenarios.md` although it accepts
|
|
54
|
+
`foundation.md` or `vision.md`.
|
|
55
|
+
|
|
56
|
+
## 0.66.3 (2026-10-27): route misses in Triggers, ux-scenarios names its subject first
|
|
57
|
+
|
|
58
|
+
- **Route misses join ux-flows' `## Triggers`** (hub board row B-267): "users drop off" /
|
|
59
|
+
«пользователи отваливаются», "referral program" / «реферальная программа» and "A/B test" /
|
|
60
|
+
«a/b тест». ux-flows owns them by its own text: funnels and their steps are its flows, the
|
|
61
|
+
growth-loop and referral rows of `practice-selection.md` (BP-147..151) are read in its step 3,
|
|
62
|
+
and every A/B variant needs the mockup this skill draws. Body 4,744 of 4,750 tokens.
|
|
63
|
+
- **ux-scenarios names its subject within the first 57 characters** (hub board row B-285; Hermes
|
|
64
|
+
shows only that many): the head was "Use when starting a new feature, changing user-facing beh"
|
|
65
|
+
and is now "Use when writing UX scenarios (docs/ux/scenarios.md): a n". 295 characters (hub
|
|
66
|
+
measure); triggers, boundary and refusal phrase unchanged.
|
|
67
|
+
|
|
1
68
|
## 0.66.2 (2026-10-25): descriptions within a 300-character budget
|
|
2
69
|
|
|
3
70
|
- **Descriptions within a 300-character budget** (hub board row B-255 (a)): Claude Code lists every
|
package/README.md
CHANGED
|
@@ -184,8 +184,9 @@ Installed into your project's `CLAUDE.md` (and as the always-on Cursor rule):
|
|
|
184
184
|
Code that diverges from a screen's record, or a stale Figma link, is drift
|
|
185
185
|
the audit flags.
|
|
186
186
|
- Any new feature or project **starts** with the chain: which job, which
|
|
187
|
-
journey stage, which story,
|
|
188
|
-
|
|
187
|
+
journey stage, which story, which capability and who performs it (a person,
|
|
188
|
+
an agent, an automation), then flows, screens, and scenarios for the human
|
|
189
|
+
lanes, validated against the existing base and approved.
|
|
189
190
|
- **Do not write interface code until that workflow is done.** Chain designed
|
|
190
191
|
and approved, and (Figma on, the default) the UI mocked up with every screen
|
|
191
192
|
linked to its frame. Building UI before this is the mistake super-ux exists
|
|
@@ -253,13 +254,13 @@ to is a skill nobody runs.
|
|
|
253
254
|
| `/vision` `/ux-init` `/ux-foundation` `/ux-flows` `/ux-update` `/ux-audit` `/ux-rule` `/ux-lint` `/ux-doctor` · `/brand` `/brand-init` `/brand-update` `/brand-lint` `/copy` | Direct controls for when you know exactly what you want; `/ux-rule` installs both hard rules and seeds `lint.py` + `doctor.py`; `/brand-init` seeds `docs/brand/` and its linter |
|
|
254
255
|
| `docs/ux/lint.py` + `/ux-lint` | The deterministic half: missing Figma frames, a screen with no states or no render axes, a built state with no story, more than one onboarding screen before the first value with no reason on file, art direction approved with no critique cited, unresolved SCR/story traces, orphans, built screens without coverage, index desync, ID gaps, broken links. Stdlib-only, exit 1 on problems, so wire it into CI and drift can't merge |
|
|
255
256
|
| `cursor/rules/*.mdc` | The same methodology for Cursor: one always-on hard rule + seven agent-requested rules (vision, foundation, flows, scenarios, audit, brand voice, copywriting) |
|
|
256
|
-
| `templates/` | Seeds for `docs/ux/`: the vision skeleton, foundation, flows, screens, scenario base, the folder README, and the audit-report skeleton. Both hard-rule snippets live here as their single source, `claude-rule.md` (scenario-first) and `vision-rule.md` (vision alignment), and the validator fails if a command's embedded copy drifts from them. Seeds for `docs/brand/`: voice, terminology, facts, channels, the string registry, a locale delta, and its folder README. The tree is mirrored into `plugins/super-ux/templates/` (and the seeds each skill names into that skill's own directory) by `test/sync_references.py`, so installed channels carry the seeds their texts point at; the validator refuses drift between the copies |
|
|
257
|
+
| `templates/` | Seeds for `docs/ux/`: the vision skeleton, foundation, capabilities, flows, screens, scenario base, the agent test panel, the folder README, and the audit-report skeleton. Both hard-rule snippets live here as their single source, `claude-rule.md` (scenario-first) and `vision-rule.md` (vision alignment), and the validator fails if a command's embedded copy drifts from them. Seeds for `docs/brand/`: voice, terminology, facts, channels, the string registry, a locale delta, and its folder README. The tree is mirrored into `plugins/super-ux/templates/` (and the seeds each skill names into that skill's own directory) by `test/sync_references.py`, so installed channels carry the seeds their texts point at; the validator refuses drift between the copies |
|
|
257
258
|
|
|
258
259
|
The contracts every skill reads:
|
|
259
260
|
|
|
260
261
|
| Reference | Holds |
|
|
261
262
|
|---|---|
|
|
262
|
-
| [scenario-format.md](plugins/super-ux/skills/references/scenario-format.md) | **The contract (ux-contract v4).** File layout, every field name, stable IDs (`P` `JTBD` `JRN` `ST` `FLW` `SCR` `SCN`), completeness checklists, the `draft → validated → implemented` lifecycle, audit verdicts and severities, the UX-plan format |
|
|
263
|
+
| [scenario-format.md](plugins/super-ux/skills/references/scenario-format.md) | **The contract (ux-contract v5; v4 chains stay valid).** File layout, every field name, stable IDs (`P` `A` `JTBD` `JRN` `ST` `CAP` `FLW` `SCR` `SCN`), the opt-in v5 layer for agents (actors, capabilities, channels, why a person is needed), completeness checklists, the `draft → validated → implemented` lifecycle, audit verdicts and severities, the UX-plan format |
|
|
263
264
|
| [system-map.md](plugins/super-ux/skills/references/system-map.md) | The whole system on one page: pipeline, files, skills, companions, and the four sync rules; every skill points here |
|
|
264
265
|
| [ux_doctor.py](plugins/super-ux/scripts/ux_doctor.py) | Contract doctor. It reports mixed or stale contract versions across a project's artifacts, files the tooling cannot find under their contract names, and audits produced against a base that is not there. `/ux-lint` checks a chain against itself; this checks it against the contract. Installed as `docs/ux/doctor.py`, read-only unless `--fix` |
|
|
265
266
|
| [best-practices-index.md](plugins/super-ux/skills/references/best-practices-index.md) | Generated tag index over the catalog: tag → ids, id → title. Read it to decide which entries to open; regenerated by `plugins/super-ux/scripts/bp_index.py` and checked for drift by the validator |
|
|
@@ -6,10 +6,11 @@ alwaysApply: true
|
|
|
6
6
|
# UX scenarios — hard rule (super-ux)
|
|
7
7
|
|
|
8
8
|
- `docs/ux/scenarios.md` is the source of truth for all user-facing behavior;
|
|
9
|
-
`docs/ux/foundation.md` (personas, JTBD, journeys, stories)
|
|
10
|
-
`docs/ux/
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
`docs/ux/foundation.md` (personas, actors, JTBD, journeys, stories),
|
|
10
|
+
`docs/ux/capabilities.md` (what people and agents can do, contract v5) and
|
|
11
|
+
`docs/ux/flows.md` (user flows) are the layers scenarios trace to. Above
|
|
12
|
+
them sits `docs/ux/vision.md` (what the product is and refuses to
|
|
13
|
+
become), when the project has written one.
|
|
13
14
|
- Any change that touches user-facing behavior or interface MUST update, in
|
|
14
15
|
the same change: `docs/ux/scenarios.md`; affected flows; the affected
|
|
15
16
|
screens in `docs/ux/screens.md` (the UI map — states, elements, coverage);
|
|
@@ -20,14 +21,17 @@ alwaysApply: true
|
|
|
20
21
|
path must exist and the line range must be inside the file. Seven of this
|
|
21
22
|
pack's own citations were pre-shift ranges nothing re-resolved.
|
|
22
23
|
- Any new feature or project STARTS with the chain: which job does it serve,
|
|
23
|
-
which journey stage, which story
|
|
24
|
+
which journey stage, which story, which capability and who performs it (a
|
|
25
|
+
person, an agent, an automation); then flows and scenarios, validated
|
|
24
26
|
against the existing base, approved. An idea serving no job is challenged,
|
|
25
27
|
not silently accepted.
|
|
26
|
-
- **Do NOT write interface code until the UX workflow is done first:**
|
|
27
|
-
foundation →
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
- **Do NOT write interface code until the UX workflow is done first:**
|
|
29
|
+
foundation → capabilities → contract → flows → screens → scenarios for
|
|
30
|
+
human lanes, designed and approved (capabilities and contract under
|
|
31
|
+
contract v5), and, when Figma is enabled (default), the UI mocked up in
|
|
32
|
+
Figma with every screen linked to its frame. A screen is designed where a
|
|
33
|
+
person is needed; every other capability stays reachable by agents.
|
|
34
|
+
Building UI before this is the exact mistake super-ux exists to prevent.
|
|
31
35
|
- Visual identity is ONE locked style pack, recorded in `docs/ux/screens.md`
|
|
32
36
|
→ Design system and obeyed by every Figma frame and every built screen —
|
|
33
37
|
picked with the **sheleg-design** companion skill when the project has no
|
|
@@ -14,7 +14,7 @@ reused. Any interface change updates `screens.md` (and the Figma frame when
|
|
|
14
14
|
enabled) in the same change — a screen whose code diverges from its record
|
|
15
15
|
is `drifted`.
|
|
16
16
|
|
|
17
|
-
## Flow entry (ux-contract v4)
|
|
17
|
+
## Flow entry (ux-contract v5; a v4 chain stays valid)
|
|
18
18
|
|
|
19
19
|
Fields: `Traces` (story/job IDs), `Goal` (observable end state), `Entry
|
|
20
20
|
points` (ALL of them), `Success exit`, `Task analysis` (numbered
|
|
@@ -29,7 +29,10 @@ Story | Behavior |` — a row per default/loading/empty/error/offline/
|
|
|
29
29
|
long-content/keyboard-up/first-run state that applies), `Axes`
|
|
30
30
|
(viewport; theme; text; locale — or the Design system default),
|
|
31
31
|
`Wireframe`, `Coverage` (file:line), `Scenarios`, `Resources`, `Status`
|
|
32
|
-
(designed|blocked|built|drifted|retired)
|
|
32
|
+
(designed|blocked|built|drifted|retired); under v5 also `Fronts` (the
|
|
33
|
+
`CAP-NN` it fronts, or none) and `Why human` (a serving reason with
|
|
34
|
+
evidence), because flows and screens are drawn for the human lanes only.
|
|
35
|
+
A flow that onboards records
|
|
33
36
|
`Onboarding:` and `First value:`; the budget is one screen before the first
|
|
34
37
|
value unless the director record says why.
|
|
35
38
|
|
|
@@ -10,7 +10,7 @@ alwaysApply: false
|
|
|
10
10
|
stories (ST-NNN)**. IDs sequential, never reused; dropped entries kept, not
|
|
11
11
|
deleted.
|
|
12
12
|
|
|
13
|
-
## Formats (ux-contract v4)
|
|
13
|
+
## Formats (ux-contract v5; a v4 chain stays valid)
|
|
14
14
|
|
|
15
15
|
- **Persona `P-NN`:** 1–3 sentences, grounded in data/observation,
|
|
16
16
|
recognizable by a real user.
|
|
@@ -26,6 +26,14 @@ deleted.
|
|
|
26
26
|
<benefit>` + Traces (JTBD, JRN/stage) + Given/When/Then acceptance
|
|
27
27
|
criteria + priority (must|should|could) + status
|
|
28
28
|
(proposed|validated|delivered|dropped). Quality bar: INVEST.
|
|
29
|
+
- **v5 (opt-in; new projects):** persona `Agent use: none|some|most` with
|
|
30
|
+
evidence; actors `A-NN` under `## Actors` (`Kind: agent|system`, `Acts
|
|
31
|
+
for: P-NN`, `Grant`); a journey `Performed by` column; and
|
|
32
|
+
`docs/ux/capabilities.md`, one `CAP-NN` per must/should story with
|
|
33
|
+
`Traces, Actors, Agent excluded, Roles, Gate, Tools, Emits, Data,
|
|
34
|
+
Automation, Human surface, Since, Status`. A person enters at a gate
|
|
35
|
+
(`body|approval|legal`) or for a serving reason, each with evidence;
|
|
36
|
+
everything else stays reachable by agents.
|
|
29
37
|
|
|
30
38
|
## Workflows
|
|
31
39
|
|
|
@@ -8,7 +8,7 @@ alwaysApply: false
|
|
|
8
8
|
`docs/ux/scenarios.md` describes everything the user can do, see, and hit —
|
|
9
9
|
every feature, button, state, error, result. Keep it true.
|
|
10
10
|
|
|
11
|
-
## File structure (ux-contract v4)
|
|
11
|
+
## File structure (ux-contract v5; a v4 chain stays valid)
|
|
12
12
|
|
|
13
13
|
Title, then header comment, then: **Index** table
|
|
14
14
|
(`| ID | Title | Feature | Persona | Traces | Status | Last audit |`),
|
|
@@ -28,7 +28,10 @@ when none exist), `UI elements` (every button/field/link/dialog/toast involved
|
|
|
28
28
|
this is what audits check), `States covered` (loading|empty|error|success),
|
|
29
29
|
`Errors & recovery` (each failure: what the user sees, how they recover),
|
|
30
30
|
`Status` (draft|validated|implemented|retired), `Coverage` (file:line or
|
|
31
|
-
`none yet`).
|
|
31
|
+
`none yet`). Under v5, `Channel` (human|agent|both; absent reads human): an
|
|
32
|
+
agent step is `A-NN -> tool -> observable response`, the scenario cites the
|
|
33
|
+
`CAP-NN` it exercises, and `UI elements` is required on the human channel
|
|
34
|
+
only.
|
|
32
35
|
|
|
33
36
|
Rules: IDs `SCN-NNN`, sequential, never reused; retired entries are kept,
|
|
34
37
|
never deleted. Lifecycle: draft → validated (human approval) → implemented
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "super-ux",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.67.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"test": "python3 test/validate.py && python3 test/family_gate.py && python3 test/family_gate.py --self-test && python3 test/brand_lint_test.py && python3 test/display_copy_test.py && python3 test/ux_lint_test.py && python3 docs/ux/lint.py && python3 docs/brand/lint.py && node test/installer_test.js && npm run test:audit",
|
|
6
6
|
"test:audit": "for t in test/audit_regressions/*.py; do python3 \"$t\" || exit 1; done"
|
|
@@ -21,7 +21,11 @@ import re
|
|
|
21
21
|
import sys
|
|
22
22
|
from pathlib import Path
|
|
23
23
|
|
|
24
|
-
CURRENT =
|
|
24
|
+
CURRENT = 5
|
|
25
|
+
# The oldest contract still read as current work rather than as debt. v5 is
|
|
26
|
+
# opt-in (agents and capabilities), so a v4 chain is supported, not behind:
|
|
27
|
+
# the doctor names the migration and counts no problem for it.
|
|
28
|
+
SUPPORTED = 4
|
|
25
29
|
|
|
26
30
|
# What each contract version introduced, so a report can say what is missing
|
|
27
31
|
# rather than only that something is old.
|
|
@@ -29,8 +33,19 @@ HISTORY = {
|
|
|
29
33
|
2: "`Traces:` on every scenario + traceability rules; `foundation.md` (personas, JTBD, journeys, stories)",
|
|
30
34
|
3: "scenarios become use cases (`user action -> system response`), `Alt paths`, `Traces` includes `FLW-NN`; `flows.md`; `plans/`",
|
|
31
35
|
4: "`screens.md` — one `SCR-NN` entry per screen with per-state Figma frames; flows reference screens by id instead of respecifying them",
|
|
36
|
+
5: "agents and capabilities, opt-in: actors (`A-NN`) and `Agent use` in `foundation.md`, `capabilities.md` (`CAP-NN`), `Channel` on scenarios, `Fronts` and `Why human` on screens, `agent-panel.md`",
|
|
32
37
|
}
|
|
33
38
|
|
|
39
|
+
# The v4 -> v5 step, named so a v4 chain is told what opting in costs. Nothing
|
|
40
|
+
# else is required: every v5 lint rule is a warning, and only under the marker.
|
|
41
|
+
V5_MIGRATION = (
|
|
42
|
+
"v4 -> v5 is opt-in, best taken on the first capability task: add "
|
|
43
|
+
"`## Actors` (`A-NN`) and `Agent use` to foundation.md, write "
|
|
44
|
+
"capabilities.md with one `CAP-NN` per must/should story, add `Channel` "
|
|
45
|
+
"to scenarios and `Fronts` with `Why human` to screens, then change every "
|
|
46
|
+
"header marker to `ux-contract v5`. Nothing else is required."
|
|
47
|
+
)
|
|
48
|
+
|
|
34
49
|
# Additive since v4 — absence is not a version problem, but it is worth naming.
|
|
35
50
|
ADDITIVE = [
|
|
36
51
|
("foundation.md", "## Product mechanics", "Product mechanics section (personalization, engagement, a11y regime) — 0.26.1"),
|
|
@@ -39,6 +54,8 @@ ADDITIVE = [
|
|
|
39
54
|
]
|
|
40
55
|
|
|
41
56
|
ARTIFACTS = ["vision.md", "foundation.md", "flows.md", "screens.md", "scenarios.md"]
|
|
57
|
+
# v5 files: their markers count, and their absence is reported only on v5.
|
|
58
|
+
V5_ARTIFACTS = ["capabilities.md", "agent-panel.md"]
|
|
42
59
|
|
|
43
60
|
# `screens.md` format 2 (0.58.0): the screen matrix — a state list and render
|
|
44
61
|
# axes per screen, a frame for every declared state, a story per state once
|
|
@@ -82,6 +99,7 @@ def marker(path: Path) -> int | None:
|
|
|
82
99
|
def diagnose(ux: Path) -> dict:
|
|
83
100
|
present = {a: (ux / a).exists() for a in ARTIFACTS}
|
|
84
101
|
markers = {a: marker(ux / a) for a in ARTIFACTS if present[a]}
|
|
102
|
+
markers.update({a: marker(ux / a) for a in V5_ARTIFACTS if (ux / a).exists()})
|
|
85
103
|
known = [v for v in markers.values() if v is not None]
|
|
86
104
|
|
|
87
105
|
misnamed = {
|
|
@@ -135,9 +153,13 @@ def report(ux: Path, d: dict) -> int:
|
|
|
135
153
|
elif eff is None:
|
|
136
154
|
problems += 1
|
|
137
155
|
print(" NO CONTRACT MARKER on any artifact — the chain is unmanaged.")
|
|
138
|
-
elif eff <
|
|
156
|
+
elif eff < SUPPORTED:
|
|
139
157
|
problems += 1
|
|
140
158
|
print(f" BEHIND: contract v{eff}, current v{CURRENT}")
|
|
159
|
+
elif eff < CURRENT:
|
|
160
|
+
print(f" contract v{eff}, supported; current v{CURRENT} is opt-in")
|
|
161
|
+
else:
|
|
162
|
+
print(f" contract v{eff}")
|
|
141
163
|
|
|
142
164
|
if unmarked and not d["mixed"]:
|
|
143
165
|
problems += 1
|
|
@@ -153,6 +175,8 @@ def report(ux: Path, d: dict) -> int:
|
|
|
153
175
|
print(f" MISNAMED: {wrong} -> {right} (the tooling looks for the contract name and finds nothing)")
|
|
154
176
|
|
|
155
177
|
missing_core = [a for a, ok in d["present"].items() if not ok]
|
|
178
|
+
if eff is not None and eff >= 5 and "capabilities.md" not in markers:
|
|
179
|
+
missing_core.append("capabilities.md")
|
|
156
180
|
if missing_core:
|
|
157
181
|
print(f" ABSENT: {', '.join(missing_core)}")
|
|
158
182
|
|
|
@@ -170,7 +194,15 @@ def report(ux: Path, d: dict) -> int:
|
|
|
170
194
|
if d.get("screens_format") == 1:
|
|
171
195
|
print(f" migration offered: {SCREENS_MIGRATION}")
|
|
172
196
|
|
|
173
|
-
|
|
197
|
+
if eff == 4 and not d["mixed"]:
|
|
198
|
+
print(f" migration offered: {V5_MIGRATION}")
|
|
199
|
+
|
|
200
|
+
if problems:
|
|
201
|
+
print(f" {problems} problem(s)")
|
|
202
|
+
elif eff is not None and eff < CURRENT:
|
|
203
|
+
print(" OK: on a supported contract")
|
|
204
|
+
else:
|
|
205
|
+
print(" OK: on the current contract")
|
|
174
206
|
return problems
|
|
175
207
|
|
|
176
208
|
|
|
@@ -1038,6 +1038,265 @@ def check_vision(ux: Path, vision: str) -> None:
|
|
|
1038
1038
|
f"the `vision` skill's step 4, or keep the edit deliberately")
|
|
1039
1039
|
|
|
1040
1040
|
|
|
1041
|
+
# --- Contract v5: agents and capabilities (opt-in) -------------------------
|
|
1042
|
+
#
|
|
1043
|
+
# v5 models who performs a story (a person, an agent acting for one, an
|
|
1044
|
+
# automation), the capabilities a story needs, and why a person is needed
|
|
1045
|
+
# where a screen exists. Every v4 chain stays valid: nothing below runs unless
|
|
1046
|
+
# the chain declares `ux-contract v5`, the marker form `doctor.py` already
|
|
1047
|
+
# reads. The LOWEST marker decides, as the doctor's `effective` does, so one
|
|
1048
|
+
# v5 seed dropped into a v4 chain does not switch it onto rules it never
|
|
1049
|
+
# opted into. Every finding here is a warning: the layer is new, and a gate
|
|
1050
|
+
# that failed builds on day one is the gate that gets switched off.
|
|
1051
|
+
CONTRACT_MARKER = re.compile(r"ux-contract v(\d+)")
|
|
1052
|
+
CONTRACT_FILES = ("vision.md", "foundation.md", "flows.md", "screens.md",
|
|
1053
|
+
"scenarios.md", "capabilities.md", "agent-panel.md")
|
|
1054
|
+
V5 = 5
|
|
1055
|
+
|
|
1056
|
+
# The capability row, in the contract's order. One row is one effect set.
|
|
1057
|
+
CAP_FIELDS = ("Traces", "Actors", "Agent excluded", "Roles", "Gate", "Tools",
|
|
1058
|
+
"Emits", "Data", "Automation", "Human surface", "Since", "Status")
|
|
1059
|
+
|
|
1060
|
+
# Every v5 enum, keyed by (layer, field). `validate.py` compares this table
|
|
1061
|
+
# with the contract's v5 declarations, the same parity `STATUS_ENUMS` has.
|
|
1062
|
+
V5_ENUMS = {
|
|
1063
|
+
("CAP", "Actors"): ("human", "agent", "automation"),
|
|
1064
|
+
("CAP", "Agent excluded"): ("presence", "legal", "debt"),
|
|
1065
|
+
("CAP", "Gate"): ("none", "body", "approval", "legal"),
|
|
1066
|
+
("CAP", "Data"): ("public", "internal", "personal", "payment", "secret"),
|
|
1067
|
+
("CAP", "Status"): ("proposed", "specified", "exposed", "deprecated", "retired"),
|
|
1068
|
+
("A", "Kind"): ("agent", "system"),
|
|
1069
|
+
("P", "Agent use"): ("none", "some", "most"),
|
|
1070
|
+
("SCN", "Channel"): ("agent", "human", "both"),
|
|
1071
|
+
("SCR", "Why human"): ("oversight", "exception-queue", "trust", "presence",
|
|
1072
|
+
"audience", "manual", "taste"),
|
|
1073
|
+
}
|
|
1074
|
+
BOARD_ID = re.compile(r"\b[A-Z][A-Z0-9]*-\d+\b")
|
|
1075
|
+
|
|
1076
|
+
|
|
1077
|
+
def contract_version(ux: Path) -> int | None:
|
|
1078
|
+
"""The lowest `ux-contract vN` among the chain's files, read raw.
|
|
1079
|
+
|
|
1080
|
+
The marker lives in an HTML comment and `read()` strips comments, so the
|
|
1081
|
+
head of each file is read here directly, as `doctor.py` reads it.
|
|
1082
|
+
"""
|
|
1083
|
+
found = []
|
|
1084
|
+
for name in CONTRACT_FILES:
|
|
1085
|
+
try:
|
|
1086
|
+
head = (ux / name).read_text(encoding="utf-8", errors="ignore")[:2000]
|
|
1087
|
+
except OSError:
|
|
1088
|
+
continue
|
|
1089
|
+
m = CONTRACT_MARKER.search(head)
|
|
1090
|
+
if m:
|
|
1091
|
+
found.append(int(m.group(1)))
|
|
1092
|
+
return min(found) if found else None
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
def v5_field(body: str, name: str) -> str | None:
|
|
1096
|
+
"""A v5 field's value on one line; None when the field is absent."""
|
|
1097
|
+
m = re.search(rf"\*\*{re.escape(name)}:\*\*[ \t]*([^\n]*)", body)
|
|
1098
|
+
return None if m is None else m.group(1).strip()
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
def v5_token(value: str) -> tuple[str, str]:
|
|
1102
|
+
"""`(first word, the rest)`: the enum value and the evidence beside it."""
|
|
1103
|
+
m = re.match(r"\s*([A-Za-z][\w-]*)\s*(.*)$", value or "", re.DOTALL)
|
|
1104
|
+
if m is None:
|
|
1105
|
+
return ("", "")
|
|
1106
|
+
return (m.group(1).lower(), m.group(2).strip())
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
def evidenced(rest: str) -> bool:
|
|
1110
|
+
"""Does the text beside an enum value say anything? Brackets and
|
|
1111
|
+
separators alone are not evidence."""
|
|
1112
|
+
return stated(re.sub(r"[()\[\];:,.\s]+", " ", rest or "").strip() or None)
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
def v5_enum(name: str, sid: str, field: str, value: str,
|
|
1116
|
+
allowed: tuple[str, ...]) -> bool:
|
|
1117
|
+
"""Warn U088 on a value outside its enum; True when the value is legal."""
|
|
1118
|
+
if value in allowed:
|
|
1119
|
+
return True
|
|
1120
|
+
warn(f"[U088] {name}: {sid} declares {field} '{value or '(nothing)'}', "
|
|
1121
|
+
f"which is not one of {' | '.join(allowed)}. An unrecognised value "
|
|
1122
|
+
f"reads as no value, and every v5 rule keyed on it stops applying")
|
|
1123
|
+
return False
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
def actors_of(value: str) -> list[str]:
|
|
1127
|
+
"""The actor kinds a CAP names, before any bracketed note."""
|
|
1128
|
+
head = re.split(r"[(;]", value or "", maxsplit=1)[0]
|
|
1129
|
+
return [a.strip().lower() for a in head.split(",") if a.strip()]
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
def check_v5(foundation: str, scenarios: str, screens: str,
|
|
1133
|
+
capabilities: str) -> None:
|
|
1134
|
+
"""The v5 layers: actors, capabilities, channels, and why a person.
|
|
1135
|
+
|
|
1136
|
+
The doctrine of each rule lives in `scenario-format.md`, section
|
|
1137
|
+
"Contract v5: agents and capabilities"; this function only checks it.
|
|
1138
|
+
"""
|
|
1139
|
+
caps = entry_blocks(capabilities, "CAP")
|
|
1140
|
+
cap_ids = set(caps)
|
|
1141
|
+
for prefix, name, text in (("CAP", "capabilities.md", capabilities),
|
|
1142
|
+
("A", "foundation.md/actors", foundation)):
|
|
1143
|
+
entry_ids = ids(text, prefix)
|
|
1144
|
+
if entry_ids:
|
|
1145
|
+
check_unique_and_gaps(entry_ids, name)
|
|
1146
|
+
for sid, colon, title in entry_names(text, prefix):
|
|
1147
|
+
if not (colon and title):
|
|
1148
|
+
err(f"[U073] {name}: `### {sid}` carries no name: the contract's "
|
|
1149
|
+
f"header is `### {sid}: <short name>`")
|
|
1150
|
+
if cap_ids:
|
|
1151
|
+
idx = index_ids(capabilities, "CAP")
|
|
1152
|
+
for missing in sorted(cap_ids - idx):
|
|
1153
|
+
warn(f"[U003] capabilities.md: {missing} has no index row")
|
|
1154
|
+
for ghost in sorted(idx - cap_ids):
|
|
1155
|
+
err(f"[U004] capabilities.md: index lists {ghost} but no entry exists")
|
|
1156
|
+
|
|
1157
|
+
traced_by_caps: set[str] = set()
|
|
1158
|
+
for cid, body in sorted(caps.items()):
|
|
1159
|
+
status, _ = v5_token(v5_field(body, "Status") or "")
|
|
1160
|
+
if status == "retired":
|
|
1161
|
+
continue
|
|
1162
|
+
for field in CAP_FIELDS:
|
|
1163
|
+
if v5_field(body, field) is None:
|
|
1164
|
+
warn(f"[U087] capabilities.md: {cid} is missing **{field}:**. The "
|
|
1165
|
+
f"row is {', '.join(CAP_FIELDS)}; `none` is a value, an "
|
|
1166
|
+
f"absent field is not")
|
|
1167
|
+
traced_by_caps |= refs(v5_field(body, "Traces") or "", "ST")
|
|
1168
|
+
if status:
|
|
1169
|
+
v5_enum("capabilities.md", cid, "Status", status, V5_ENUMS[("CAP", "Status")])
|
|
1170
|
+
actors = actors_of(v5_field(body, "Actors") or "")
|
|
1171
|
+
for actor in actors:
|
|
1172
|
+
v5_enum("capabilities.md", cid, "Actors", actor, V5_ENUMS[("CAP", "Actors")])
|
|
1173
|
+
data, _ = v5_token(v5_field(body, "Data") or "")
|
|
1174
|
+
if data:
|
|
1175
|
+
v5_enum("capabilities.md", cid, "Data", data, V5_ENUMS[("CAP", "Data")])
|
|
1176
|
+
|
|
1177
|
+
tools = v5_field(body, "Tools")
|
|
1178
|
+
if "agent" in actors and (not stated(tools) or v5_token(tools or "")[0] == "none"):
|
|
1179
|
+
warn(f"[U090] capabilities.md: {cid} names agent among its Actors and no "
|
|
1180
|
+
f"**Tools:**. An agent reaches a capability through a tool id, and "
|
|
1181
|
+
f"one with none listed is a capability only a screen can reach")
|
|
1182
|
+
|
|
1183
|
+
excluded, why = v5_token(v5_field(body, "Agent excluded") or "")
|
|
1184
|
+
if actors and "agent" not in actors:
|
|
1185
|
+
if excluded in ("", "none"):
|
|
1186
|
+
warn(f"[U092] capabilities.md: {cid} leaves agents out and names no "
|
|
1187
|
+
f"**Agent excluded:** reason (presence | legal | debt, with "
|
|
1188
|
+
f"evidence). Parity is by story: an exception is named per "
|
|
1189
|
+
f"capability or it is a gap")
|
|
1190
|
+
elif v5_enum("capabilities.md", cid, "Agent excluded", excluded,
|
|
1191
|
+
V5_ENUMS[("CAP", "Agent excluded")]):
|
|
1192
|
+
if excluded == "debt" and not BOARD_ID.search(why):
|
|
1193
|
+
warn(f"[U092] capabilities.md: {cid} records parity debt with "
|
|
1194
|
+
f"no board row. Debt is listed and on the board "
|
|
1195
|
+
f"(`debt (B-nnn)`), never hidden")
|
|
1196
|
+
elif excluded != "debt" and not evidenced(why):
|
|
1197
|
+
warn(f"[U092] capabilities.md: {cid} excludes agents for "
|
|
1198
|
+
f"'{excluded}' and cites no evidence: a JTBD-, ST- or "
|
|
1199
|
+
f"RE- id, a policy or a decision")
|
|
1200
|
+
|
|
1201
|
+
gate, gate_why = v5_token(v5_field(body, "Gate") or "")
|
|
1202
|
+
if gate and v5_enum("capabilities.md", cid, "Gate", gate,
|
|
1203
|
+
V5_ENUMS[("CAP", "Gate")]):
|
|
1204
|
+
if gate != "none" and not evidenced(gate_why):
|
|
1205
|
+
warn(f"[U093] capabilities.md: {cid} is gated '{gate}' and cites no "
|
|
1206
|
+
f"evidence: the policy, the decision or the law that puts a "
|
|
1207
|
+
f"person there. No product-level waiver exists")
|
|
1208
|
+
|
|
1209
|
+
reason_m = re.search(r"Why human:\s*(.*)", v5_field(body, "Human surface") or "")
|
|
1210
|
+
if reason_m:
|
|
1211
|
+
reason, reason_why = v5_token(reason_m.group(1))
|
|
1212
|
+
if v5_enum("capabilities.md", cid, "Why human", reason,
|
|
1213
|
+
V5_ENUMS[("SCR", "Why human")]) and not evidenced(reason_why):
|
|
1214
|
+
warn(f"[U093] capabilities.md: {cid} serves a person for "
|
|
1215
|
+
f"'{reason}' and cites no evidence beside it")
|
|
1216
|
+
|
|
1217
|
+
# AN-1, structurally: every must/should story has a capability tracing to
|
|
1218
|
+
# it, and the capability's row names any exclusion.
|
|
1219
|
+
for sid, body in sorted(entry_blocks(foundation, "ST").items()):
|
|
1220
|
+
if declared_status(body) == "dropped":
|
|
1221
|
+
continue
|
|
1222
|
+
if not re.search(r"\*\*Priority:\*\*\s*(must|should)", body, re.IGNORECASE):
|
|
1223
|
+
continue
|
|
1224
|
+
if sid not in traced_by_caps:
|
|
1225
|
+
warn(f"[U089] foundation.md: {sid} (must/should) has no capability "
|
|
1226
|
+
f"tracing to it in capabilities.md. Parity is by story: name the "
|
|
1227
|
+
f"CAP that serves it, and any exclusion in that CAP's row")
|
|
1228
|
+
|
|
1229
|
+
for aid, body in sorted(entry_blocks(foundation, "A").items()):
|
|
1230
|
+
kind, _ = v5_token(v5_field(body, "Kind") or "")
|
|
1231
|
+
if kind:
|
|
1232
|
+
v5_enum("foundation.md", aid, "Kind", kind, V5_ENUMS[("A", "Kind")])
|
|
1233
|
+
|
|
1234
|
+
# Channel: an absent field reads as `human`, the scenario every v4 chain
|
|
1235
|
+
# already wrote. An agent-channel scenario is the contract's acceptance
|
|
1236
|
+
# test, so it names the capability it accepts.
|
|
1237
|
+
scn_channel: dict[str, str] = {}
|
|
1238
|
+
scn_traces: dict[str, set[str]] = {}
|
|
1239
|
+
for sid, body in sorted(entry_blocks(scenarios, "SCN").items()):
|
|
1240
|
+
channel, _ = v5_token(v5_field(body, "Channel") or "human")
|
|
1241
|
+
scn_traces[sid] = refs(v5_field(body, "Traces") or body, "ST")
|
|
1242
|
+
if not v5_enum("scenarios.md", sid, "Channel", channel,
|
|
1243
|
+
V5_ENUMS[("SCN", "Channel")]):
|
|
1244
|
+
continue
|
|
1245
|
+
scn_channel[sid] = channel
|
|
1246
|
+
if declared_status(body) == "retired":
|
|
1247
|
+
continue
|
|
1248
|
+
if channel in ("agent", "both") and not refs(body, "CAP"):
|
|
1249
|
+
warn(f"[U091] scenarios.md: {sid} is an {channel}-channel scenario and "
|
|
1250
|
+
f"cites no CAP in its Traces. An agent step calls a capability, "
|
|
1251
|
+
f"and the scenario is that capability's acceptance test")
|
|
1252
|
+
|
|
1253
|
+
for sid, body in sorted(screen_blocks(screens).items()):
|
|
1254
|
+
if declared_status(body) == "retired":
|
|
1255
|
+
continue
|
|
1256
|
+
fronts = v5_field(body, "Fronts")
|
|
1257
|
+
why_value = v5_field(body, "Why human")
|
|
1258
|
+
missing = [f for f, v in (("Fronts", fronts), ("Why human", why_value))
|
|
1259
|
+
if not stated(v)]
|
|
1260
|
+
if missing:
|
|
1261
|
+
warn(f"[U094] screens.md: {sid} has no **{':** or **'.join(missing)}:**. "
|
|
1262
|
+
f"A screen fronts capabilities (`Fronts: CAP-NN`, or `none`) and "
|
|
1263
|
+
f"says why a person is needed there")
|
|
1264
|
+
for ghost in sorted(refs(fronts or "", "CAP") - cap_ids):
|
|
1265
|
+
warn(f"[U094] screens.md: {sid} fronts {ghost}, which capabilities.md "
|
|
1266
|
+
f"does not define")
|
|
1267
|
+
if stated(why_value):
|
|
1268
|
+
reason, reason_why = v5_token(why_value)
|
|
1269
|
+
if v5_enum("screens.md", sid, "Why human", reason,
|
|
1270
|
+
V5_ENUMS[("SCR", "Why human")]) and not evidenced(reason_why):
|
|
1271
|
+
warn(f"[U093] screens.md: {sid} serves a person for '{reason}' and "
|
|
1272
|
+
f"cites no evidence beside it: a JTBD-, ST- or RE- id, a "
|
|
1273
|
+
f"policy, a decision or the typed error that routes here")
|
|
1274
|
+
|
|
1275
|
+
# A persona whose people use no agent still gets a whole human path for
|
|
1276
|
+
# every must story: the audience decides the human path's size.
|
|
1277
|
+
jobs = entry_blocks(foundation, "JTBD")
|
|
1278
|
+
for pid, body in sorted(entry_blocks(foundation, "P").items()):
|
|
1279
|
+
use_value = v5_field(body, "Agent use")
|
|
1280
|
+
if use_value is None:
|
|
1281
|
+
continue
|
|
1282
|
+
use, _ = v5_token(use_value)
|
|
1283
|
+
if not v5_enum("foundation.md", pid, "Agent use", use,
|
|
1284
|
+
V5_ENUMS[("P", "Agent use")]) or use != "none":
|
|
1285
|
+
continue
|
|
1286
|
+
for st, sbody in sorted(entry_blocks(foundation, "ST").items()):
|
|
1287
|
+
if not re.search(r"\*\*Priority:\*\*\s*must", sbody, re.IGNORECASE):
|
|
1288
|
+
continue
|
|
1289
|
+
via_jobs = any(pid in refs(v5_field(jobs.get(j, ""), "Personas") or "", "P")
|
|
1290
|
+
for j in refs(sbody, "JTBD"))
|
|
1291
|
+
if pid not in refs(sbody, "P") and not via_jobs:
|
|
1292
|
+
continue
|
|
1293
|
+
serving = [s for s, t in scn_traces.items() if st in t and s in scn_channel]
|
|
1294
|
+
if serving and not any(scn_channel[s] in ("human", "both") for s in serving):
|
|
1295
|
+
warn(f"[U095] foundation.md: {pid} declares Agent use: none and "
|
|
1296
|
+
f"must story {st} has only agent-channel scenarios. People "
|
|
1297
|
+
f"who use no agent need the whole human path for it")
|
|
1298
|
+
|
|
1299
|
+
|
|
1041
1300
|
def check_links(ux: Path) -> None:
|
|
1042
1301
|
link_re = re.compile(r"\[[^\]]*\]\(([^)\s]+)\)")
|
|
1043
1302
|
for md in sorted(ux.rglob("*.md")):
|
|
@@ -1055,7 +1314,8 @@ def main() -> int:
|
|
|
1055
1314
|
strict = "--strict" in sys.argv[1:]
|
|
1056
1315
|
ux = find_ux_dir(args[0] if args else None)
|
|
1057
1316
|
if ux is None:
|
|
1058
|
-
print("no UX docs found (docs/ux/scenarios.md
|
|
1317
|
+
print("no UX docs found (docs/ux/ with scenarios.md, foundation.md or "
|
|
1318
|
+
"vision.md). Run /ux to set up.")
|
|
1059
1319
|
return 2
|
|
1060
1320
|
|
|
1061
1321
|
vision = read(ux / "vision.md")
|
|
@@ -1063,6 +1323,8 @@ def main() -> int:
|
|
|
1063
1323
|
flows = read(ux / "flows.md")
|
|
1064
1324
|
screens = read(ux / "screens.md")
|
|
1065
1325
|
scenarios = read(ux / "scenarios.md")
|
|
1326
|
+
capabilities = read(ux / "capabilities.md")
|
|
1327
|
+
v5 = (contract_version(ux) or 0) >= V5
|
|
1066
1328
|
|
|
1067
1329
|
# Cited paths are project-relative, so they resolve against the tree the
|
|
1068
1330
|
# ux directory sits in — the same derivation `check_links` already uses.
|
|
@@ -1263,9 +1525,14 @@ def main() -> int:
|
|
|
1263
1525
|
check_jobs(foundation, scenarios, flows, screens)
|
|
1264
1526
|
check_journey_owners(foundation)
|
|
1265
1527
|
check_vision(ux, vision)
|
|
1266
|
-
|
|
1528
|
+
# Under v5 a product may have no human surface at all, so a chain with no
|
|
1529
|
+
# `screens.md` has no screen to ask the web question about.
|
|
1530
|
+
if not (v5 and not (ux / "screens.md").exists()):
|
|
1531
|
+
check_web_surface(screens, flows)
|
|
1267
1532
|
check_onboarding(flows, ux, project_root)
|
|
1268
1533
|
check_art_direction(flows, ux, project_root)
|
|
1534
|
+
if v5:
|
|
1535
|
+
check_v5(foundation, scenarios, screens, capabilities)
|
|
1269
1536
|
check_links(ux)
|
|
1270
1537
|
|
|
1271
1538
|
# --- Report ---
|
package/templates/README.md
CHANGED
|
@@ -6,14 +6,19 @@ sync with the code on every interface change.
|
|
|
6
6
|
## The pipeline
|
|
7
7
|
|
|
8
8
|
```
|
|
9
|
-
Vision → Personas · JTBD · Journeys · Stories → Flows → Screens → Scenarios → Audits → Plans
|
|
10
|
-
vision.md foundation.md
|
|
9
|
+
Vision → Personas · Actors · JTBD · Journeys · Stories → Capabilities → Flows → Screens → Scenarios → Audits → Plans
|
|
10
|
+
vision.md foundation.md capabilities.md flows.md screens.md scenarios.md audits/ plans/
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
Flows and screens are drawn for the human lanes: a capability an agent or an
|
|
14
|
+
automation performs needs no screen unless a person is needed there.
|
|
15
|
+
|
|
13
16
|
| File | Holds |
|
|
14
17
|
|------|-------|
|
|
15
18
|
| `vision.md` | WHAT IT IS: essence, core idea, principles, the anti-vision, the alignment test. Optional layer; when present, new features are checked against it before anything is designed |
|
|
16
|
-
| `foundation.md` | WHO & WHY: personas, jobs-to-be-done, journeys, user stories, monetization, Figma on/off + file URL |
|
|
19
|
+
| `foundation.md` | WHO & WHY: personas, actors (the agents and systems acting for them), jobs-to-be-done, journeys, user stories, monetization, Figma on/off + file URL |
|
|
20
|
+
| `capabilities.md` | WHAT PEOPLE AND AGENTS CAN DO: one `CAP-NN` per effect set, with its actors, gate, tools and the human surface that fronts it |
|
|
21
|
+
| `agent-panel.md` | optional: the agents an agent-tester walks the agent-channel scenarios as |
|
|
17
22
|
| `flows.md` | HOW: user-flow diagrams (screens, branches, error paths), referencing screens by `SCR-ID` |
|
|
18
23
|
| `screens.md` | THE UI MAP: every screen and state with its Figma frame link, wireframe, code coverage, scenarios, resources |
|
|
19
24
|
| `scenarios.md` | WHAT IT DOES: use-case scenarios — the source of truth for behavior |
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Agent test panel
|
|
2
|
+
|
|
3
|
+
<!-- Managed with super-ux (ux-contract v5). The agents an agent-tester walks
|
|
4
|
+
the agent-channel scenarios as (task-pipeline reads this file). Separate from
|
|
5
|
+
test-panel.md, the human panel, on purpose. Five agents, each with its grant,
|
|
6
|
+
its model class and the scenarios it walks. A grant here is a test-tenant
|
|
7
|
+
grant: the credential comes from the project's secret store, never this file. -->
|
|
8
|
+
|
|
9
|
+
## Panel
|
|
10
|
+
|
|
11
|
+
<!-- ### AG-01: Full-grant agent
|
|
12
|
+
- **Acts for:** P-01
|
|
13
|
+
- **Grant:** <every scope its principal holds>
|
|
14
|
+
- **Model class:** <the verification model the project uses>
|
|
15
|
+
- **Walks:** <SCN-… agent-channel scenarios>
|
|
16
|
+
|
|
17
|
+
### AG-02: Narrowly delegated agent
|
|
18
|
+
- **Acts for:** P-01
|
|
19
|
+
- **Grant:** <one scope, e.g. read-only billing>
|
|
20
|
+
- **Model class:** <…>
|
|
21
|
+
- **Walks:** <SCN-…: expects a typed refusal where its grant ends>
|
|
22
|
+
|
|
23
|
+
### AG-03: Automation with no conversation
|
|
24
|
+
- **Acts for:** <A-…, Kind: system>
|
|
25
|
+
- **Grant:** <the automation's own scope>
|
|
26
|
+
- **Model class:** none
|
|
27
|
+
- **Walks:** <SCN-… for CAP rows with an Automation trigger>
|
|
28
|
+
|
|
29
|
+
### AG-04: Cheap model
|
|
30
|
+
- **Acts for:** P-01
|
|
31
|
+
- **Grant:** <as AG-01>
|
|
32
|
+
- **Model class:** <a small, inexpensive model; advisory>
|
|
33
|
+
- **Walks:** <SCN-…: can the tool descriptions alone guide it>
|
|
34
|
+
|
|
35
|
+
### AG-05: Adversarial agent
|
|
36
|
+
- **Acts for:** P-01
|
|
37
|
+
- **Grant:** <as AG-02>
|
|
38
|
+
- **Model class:** <…>
|
|
39
|
+
- **Walks:** <SCN-… with injected content in what it reads; owed on a public surface>
|
|
40
|
+
-->
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Capabilities
|
|
2
|
+
|
|
3
|
+
<!-- Managed with super-ux (ux-contract v5). What people and agents can do:
|
|
4
|
+
one CAP-NN per effect set. Between the stories (foundation.md) and the flows
|
|
5
|
+
(flows.md): every must/should story has a capability tracing to it, and a
|
|
6
|
+
capability found while designing a later layer comes back here in the same
|
|
7
|
+
change. Field rules: the contract's "Contract v5: agents and capabilities". -->
|
|
8
|
+
|
|
9
|
+
## Index
|
|
10
|
+
|
|
11
|
+
| ID | Capability | Actors | Gate | Status |
|
|
12
|
+
|----|------------|--------|------|--------|
|
|
13
|
+
|
|
14
|
+
## Capabilities
|
|
15
|
+
|
|
16
|
+
<!-- ### CAP-01: <verb + object, e.g. Cancel a subscription>
|
|
17
|
+
- **Traces:** <ST-…>
|
|
18
|
+
- **Actors:** <human, agent, automation: who performs it>
|
|
19
|
+
- **Agent excluded:** none | presence (<evidence>) | legal (<evidence>) | debt (<board id>)
|
|
20
|
+
- **Roles:** <principal roles allowed to invoke it; an agent never exceeds its principal>
|
|
21
|
+
- **Gate:** none | body | approval | legal (<policy, decision or law>)
|
|
22
|
+
- **Tools:** <tool ids an agent calls, as the contract source names them>
|
|
23
|
+
- **Emits:** <events or notifications an agent can subscribe to, or none>
|
|
24
|
+
- **Data:** public | internal | personal | payment | secret
|
|
25
|
+
- **Automation:** none | <trigger; schedule; kill switch>
|
|
26
|
+
- **Human surface:** none | <SCR-…>; Why human: <serving reason> (<evidence>)
|
|
27
|
+
- **Since:** <contract version that introduced it>
|
|
28
|
+
- **Status:** proposed | specified | exposed | deprecated | retired
|
|
29
|
+
-->
|
package/templates/claude-rule.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
## UX scenarios — hard rule (super-ux)
|
|
2
2
|
|
|
3
3
|
- `docs/ux/scenarios.md` is the source of truth for all user-facing
|
|
4
|
-
behavior; `docs/ux/foundation.md` (personas, JTBD, journeys,
|
|
5
|
-
`docs/ux/
|
|
4
|
+
behavior; `docs/ux/foundation.md` (personas, actors, JTBD, journeys,
|
|
5
|
+
stories), `docs/ux/capabilities.md` (what people and agents can do,
|
|
6
|
+
contract v5) and `docs/ux/flows.md` (user flows) are the layers scenarios
|
|
6
7
|
trace to.
|
|
7
8
|
- Any change that touches user-facing behavior or interface MUST update, in
|
|
8
9
|
the same change: `docs/ux/scenarios.md`; affected flows; the affected
|
|
@@ -11,13 +12,16 @@
|
|
|
11
12
|
links in `screens.md`. A screen whose code diverges from its record, or a
|
|
12
13
|
stale Figma link, is drift — the exact thing this system prevents.
|
|
13
14
|
- Any new feature or project STARTS with the chain: which job does it
|
|
14
|
-
serve, which journey stage, which story
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
serve, which journey stage, which story, which capability and who
|
|
16
|
+
performs it (a person, an agent, an automation); then flows and
|
|
17
|
+
scenarios, validated against the existing base, approved.
|
|
18
|
+
- **Do NOT write interface code until the UX workflow is done first:**
|
|
19
|
+
foundation → capabilities → contract → flows → screens → scenarios for
|
|
20
|
+
human lanes, designed and approved (capabilities and contract under
|
|
21
|
+
contract v5), and, when Figma is enabled (default), the UI mocked up in
|
|
22
|
+
Figma with every screen linked to its frame. A screen is designed where a
|
|
23
|
+
person is needed; every other capability stays reachable by agents.
|
|
24
|
+
Building UI before this is the exact mistake super-ux exists to prevent.
|
|
21
25
|
- Visual identity is ONE locked style pack, recorded in `docs/ux/screens.md`
|
|
22
26
|
→ Design system and obeyed by every Figma frame and every built screen —
|
|
23
27
|
picked with the **sheleg-design** companion skill when the project has no
|
package/templates/flows.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# User Flows
|
|
2
2
|
|
|
3
|
-
<!-- Managed with super-ux (ux-contract
|
|
4
|
-
and user flows. Flows reference screens by SCR-ID (full specs live in
|
|
3
|
+
<!-- Managed with super-ux (ux-contract v5). The HOW layer: task analysis
|
|
4
|
+
and user flows for the human lanes. Flows reference screens by SCR-ID (full specs live in
|
|
5
5
|
screens.md). Scenarios in scenarios.md trace to FLW-IDs and must cover every
|
|
6
6
|
node and edge. -->
|
|
7
7
|
|
package/templates/foundation.md
CHANGED
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
# UX Foundation
|
|
2
2
|
|
|
3
|
-
<!-- Managed with super-ux (ux-contract
|
|
4
|
-
to be done, customer journeys, user stories. Update when the understanding
|
|
5
|
-
of users changes;
|
|
3
|
+
<!-- Managed with super-ux (ux-contract v5). The WHY layer: personas, actors,
|
|
4
|
+
jobs to be done, customer journeys, user stories. Update when the understanding
|
|
5
|
+
of users changes; capabilities.md and scenarios.md trace to the IDs defined
|
|
6
|
+
here. -->
|
|
6
7
|
|
|
7
8
|
## Personas
|
|
8
9
|
|
|
9
10
|
<!-- ### P-01: <name>
|
|
10
11
|
1-3 sentences: who they are, what they know, what they want. Grounded in
|
|
11
|
-
data/observation, recognizable by a real user.
|
|
12
|
+
data/observation, recognizable by a real user.
|
|
13
|
+
- **Agent use:** none | some | most (<evidence: RE-NN, the brief, an interview>)
|
|
14
|
+
-->
|
|
15
|
+
|
|
16
|
+
## Actors
|
|
17
|
+
|
|
18
|
+
<!-- The non-human performers: agents acting for a persona, automations and
|
|
19
|
+
outside systems. People stay in Personas.
|
|
20
|
+
### A-01: <name>
|
|
21
|
+
- **Kind:** agent | system
|
|
22
|
+
- **Acts for:** P-01
|
|
23
|
+
- **Grant:** <the scope it holds; never wider than its principal's role>
|
|
24
|
+
-->
|
|
12
25
|
|
|
13
26
|
## Jobs to Be Done
|
|
14
27
|
|
|
@@ -24,8 +37,9 @@ data/observation, recognizable by a real user. -->
|
|
|
24
37
|
|
|
25
38
|
<!-- ### JRN-01: <persona> — <job> (JTBD-01)
|
|
26
39
|
- **Owner:** unknown
|
|
27
|
-
| # | Stage | User action | Touchpoint | Emotion (1-5) | Pain | Opportunity |
|
|
28
|
-
|
|
40
|
+
| # | Stage | User action | Performed by | Touchpoint | Emotion (1-5) | Pain | Opportunity |
|
|
41
|
+
|---|-------|------------|--------------|------------|---------------|------|-------------|
|
|
42
|
+
Performed by: the P- and A- ids that do this stage.
|
|
29
43
|
-->
|
|
30
44
|
|
|
31
45
|
## Monetization
|
package/templates/scenarios.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# UX Scenarios
|
|
2
2
|
|
|
3
|
-
<!-- Managed with super-ux (ux-contract
|
|
3
|
+
<!-- Managed with super-ux (ux-contract v5). Update in the same change as any user-facing behavior change. -->
|
|
4
4
|
|
|
5
5
|
## Index
|
|
6
6
|
|
|
@@ -16,20 +16,23 @@ know, what they want. -->
|
|
|
16
16
|
## Scenarios
|
|
17
17
|
|
|
18
18
|
<!-- Group scenarios by feature under "## <feature>" headings. Entry shape
|
|
19
|
-
(see ux-contract
|
|
20
|
-
action per step paired with the observable system response
|
|
19
|
+
(see ux-contract v5 for field rules); steps are use-case style: one user
|
|
20
|
+
action per step paired with the observable system response. An agent-channel
|
|
21
|
+
step is `A-NN -> tool -> observable response`, and its scenario cites the
|
|
22
|
+
CAP-NN it exercises in Traces:
|
|
21
23
|
|
|
22
24
|
### SCN-001: <Title>
|
|
23
25
|
- **Persona:** <persona-id>
|
|
24
26
|
- **Feature:** <feature>
|
|
25
27
|
- **Traces:** <ST-…, FLW-… (JTBD-…, JRN-…/#stage) — required when those layers exist>
|
|
28
|
+
- **Channel:** human | agent | both
|
|
26
29
|
- **Entry point:** <where the user starts>
|
|
27
30
|
- **Preconditions:** <state required, or "none">
|
|
28
31
|
- **Steps:**
|
|
29
32
|
1. <user action> -> <observable system response>
|
|
30
33
|
- **Expected result:** <what the user observes on success>
|
|
31
34
|
- **Alt paths:** <meaningful non-error deviations and system responses, or omit>
|
|
32
|
-
- **UI elements:** <every button, field, link, dialog, toast involved>
|
|
35
|
+
- **UI elements:** <every button, field, link, dialog, toast involved; human channel only>
|
|
33
36
|
- **States covered:** <loading | empty | error | success>
|
|
34
37
|
- **Errors & recovery:** <each failure: what the user sees, how they recover>
|
|
35
38
|
- **Telemetry:** <`object_action` event + params, or omit if none>
|
package/templates/screens.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<!-- The line above puts this registry on format 2: the screen matrix
|
|
5
5
|
(states, axes, a frame per state, a story per built state) is a lint gate.
|
|
6
6
|
Keep it. -->
|
|
7
|
-
<!-- Managed with super-ux (ux-contract
|
|
7
|
+
<!-- Managed with super-ux (ux-contract v5). The design map: every screen and
|
|
8
8
|
state with its Figma frame, wireframe, code coverage, and related UX/UI
|
|
9
9
|
resources. Update in the same change as any interface change; when Figma is
|
|
10
10
|
enabled, update the frame and re-verify its link in the same change. A screen
|
|
@@ -44,11 +44,13 @@ the problem it can no longer fix. -->
|
|
|
44
44
|
|
|
45
45
|
## Screens
|
|
46
46
|
|
|
47
|
-
<!-- One entry per screen (see ux-contract
|
|
47
|
+
<!-- One entry per screen (see ux-contract v5 for field rules):
|
|
48
48
|
|
|
49
49
|
### SCR-01: <name>
|
|
50
50
|
- **Used by:** <FLW-… and the step(s)>
|
|
51
51
|
- **Purpose:** <the job step this screen serves>
|
|
52
|
+
- **Fronts:** <CAP-… this screen fronts, or none>
|
|
53
|
+
- **Why human:** <oversight | exception-queue | trust | presence | audience | manual | taste> (<evidence>)
|
|
52
54
|
- **Elements:** <each element; mark the ONE primary action>
|
|
53
55
|
- **States:** (every one that applies: default, loading, empty, error,
|
|
54
56
|
offline, long-content, keyboard-up, first-run, product-specific ones)
|
|
@@ -69,5 +71,5 @@ the problem it can no longer fix. -->
|
|
|
69
71
|
- **Coverage:** <file:line, or "none yet">
|
|
70
72
|
- **Scenarios:** <SCN-… touching this screen>
|
|
71
73
|
- **Resources:** <related components, shared assets, API/data deps, links>
|
|
72
|
-
- **Status:** designed | built | drifted | retired
|
|
74
|
+
- **Status:** designed | blocked | built | drifted | retired
|
|
73
75
|
-->
|
package/templates/vision.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# <Product> — Vision
|
|
2
2
|
|
|
3
|
-
<!-- Managed with super-ux (ux-contract
|
|
3
|
+
<!-- Managed with super-ux (ux-contract v5). The layer above the chain. -->
|
|
4
4
|
|
|
5
5
|
<!--
|
|
6
6
|
Owned by the `vision` skill (super-ux). Nine sections, these headings, in
|
|
@@ -39,8 +39,10 @@
|
|
|
39
39
|
|
|
40
40
|
## 4. The user's role
|
|
41
41
|
|
|
42
|
-
<!-- What the user becomes. Not "the user clicks"
|
|
43
|
-
decides. If it reads like operating any other tool, go deeper.
|
|
42
|
+
<!-- What the user becomes. Not "the user clicks": the user directs, judges,
|
|
43
|
+
decides. If it reads like operating any other tool, go deeper. Say
|
|
44
|
+
which work the person keeps and which their agent or an automation does
|
|
45
|
+
for them; the person is where a gate or a decision needs them. -->
|
|
44
46
|
|
|
45
47
|
## 5. Principles
|
|
46
48
|
|
|
@@ -67,7 +69,9 @@
|
|
|
67
69
|
|
|
68
70
|
<!-- Three to five questions any proposed feature must pass. These are what
|
|
69
71
|
the hard rule in the instruction file actually runs. A stranger should be
|
|
70
|
-
able to reject a plausible feature with them.
|
|
72
|
+
able to reject a plausible feature with them. Include one for agents:
|
|
73
|
+
can an agent do this without a screen, and if a person must, which gate
|
|
74
|
+
or serving reason says so? -->
|
|
71
75
|
|
|
72
76
|
1. <question>
|
|
73
77
|
2. <question>
|