A Claude skill that audits experience with the same discipline Mizan applies to claims: evidence tiers, human-locked gates, preregistered thresholds and an append-only registry. Bilingual TR/EN.
Status: v0.2 [H]. One self-validation run has happened: it exercised
the Layer-A scripts and refuted one design decision. The gates, the
walkthrough and every behavioural metric remain untested.
cp -r skill/ux-mizan ~/.claude/skills/ # path must end .../skills/ux-mizan/SKILL.md
pip install -r skill/ux-mizan/scripts/requirements.txt
cp templates/ux-registry.yaml <your-project>/ux-registry.yaml
The usual mistake is a doubly-nested folder. For Claude.ai and desktop,
upload ux-mizan.skill (Settings → Capabilities → Skills) and re-upload
to update.
Triggers: UX audit, usability review, “users get lost”, “the interface is confusing”, “why do they drop off”, IA review, setting up usability measurement, a redesign gated by a diagnosis.
Does not: visual or brand design, copywriting, building a UI from scratch. “What colour should this button be” does not deserve this weight.
Boundary with its siblings: Mizan audits claims, Kıyas generates ideas, İskele structures projects. This one audits experience.
The model proposes a draft; a human locks it. Until then no finding on
that flow can leave [H] (U7). The reason is structural: if the model
infers the purpose and audits against its own inference, the loop closes
and the audit becomes unfalsifiable.
What gets locked: the jobs in the user’s words rather than feature names,
a priority_weight for each, what “done” means, and the route that marks
it (success_screen).
app_type is chosen per flow and decides which metrics are even valid:
| app_type | what it switches OFF |
|---|---|
navigational-multiscreen |
— (the full battery) |
form-heavy-transactional |
lostness (the path is prescribed) |
single-canvas-tool |
lostness, nav_depth (one screen) |
b2b-internal-dashboard |
sus (a captive user; floor-censored) |
content-consumption |
task_success (often no task) |
guided-sequence |
lostness, nav_depth (the server enforces order) |
Volume picks the mode: below ~300 completions per flow per month → lite. At low volume passive telemetry decides nothing for months, while 5–8 moderated sessions give where and why in one afternoon.
python skill/ux-mizan/scripts/structural_checks.py src/ # what is missing
python skill/ux-mizan/scripts/layout_signals.py src/ # how it is arranged
Every count is [KKE]: a place to look, not a defect. layout_signals
prints two tiers per signal — the trace [KKE] and the behavioural claim
[H] — and reporting the [H] line as though the file proved it is
exactly the [Y] the split prevents.
Open the file before writing a finding. Both scripts in this repo have shipped false negatives and false positives, and that rule is what caught every one of them.
Candidates go to the human before they enter the registry. This is where preregistration locks: a threshold written after the data is HARKing.
python skill/ux-mizan/scripts/ux_validate.py --strict ux-registry.yaml
git config core.hooksPath tools/hooks
The registry is the memory, the transcript is not. Append each finding as it settles; batching them for a summary at the end loses them at the next context reset.
The human approves the diagnosis, the priority frame and the direction — not pixels. Showing a mockup and asking whether they like it is approval theatre.
Mandatory self-check per proposal: does this follow from THIS app’s Gate-0 purpose, or is it the generic default? “It is the generic default and that is right here” is a fine answer; not asking is not.
Measure the baseline before any redesign — there is no second chance
to measure the “before”. [K] comes only from real Layer-B data plus a
human decision, and the validator refuses to write it without a resolving
evidence artifact anyway.
L = sqrt( (N/S − 1)² + (R/N − 1)² )
If a flow declares its goal and canonical_path_R in advance, L can be
computed passively from ordinary screen-view telemetry. The advance
declaration is the whole trick — R inferred after the fact is HARKing, and
the script refuses to guess it.
python skill/ux-mizan/scripts/lostness.py events.jsonl --registry ux-registry.yaml
Four caveats print beside every number: navigational app types only; it says where, never why; it is per flow, never global; and Smith’s 0.4/0.5 cut-offs come from hypertext studies and are not validated for your app type — compare against your own baseline.
| rule | what it does |
|---|---|
| U1 | [K] needs a resolving evidence artifact and a non-model source |
| U2 | parent_flow_id mandatory and must resolve — flow primacy |
| U3 | severity recomputed; weight read from the human-locked flow |
| U4 | append-only; [R] entries cannot be moved out |
| U5 | refutation condition and a named instrument required |
| U6 | metric applicability gate (two hops: app_type → flow → finding) |
| U7 | gate provenance; unlocked Gate 0 caps findings at [H] |
| U8 | a measured baseline before any behavioural [K] |
| U9 | a locked min_n and decision rule before [K] |
| U10 | a proposed fix carries a homogenisation self-check — a redesign that never asked whether it is the generic default is the disease this skill diagnoses |
| U11 | a [KKE] names which control is missing; “a control is missing” is not actionable until it says which |
W1–W4 warn without blocking; --strict promotes them. CI runs strict,
local runs do not — a tool that can only block teaches people to write
registries that never trigger it.