diff --git a/docs/quality-house-empty.md b/docs/quality-house-empty.md new file mode 100644 index 0000000..6b6ee12 --- /dev/null +++ b/docs/quality-house-empty.md @@ -0,0 +1,382 @@ +# Quality House — empty (training) + +Same 14 WHATs × 15 HOWs chassis as [`quality-house.md`](quality-house.md), +with the **relations**, **roof correlations**, and basement Σ / Rel % +**deliberately blank**. Fill them in yourself, then compare against the +populated house to check your reading. + +Kept (definitional inputs from `qfd.md`): + +- WHATs + importance weights (§1) +- HOWs + v0.1 targets (§2) + +Blank (training surface): + +- Relation matrix (W × H) +- Roof correlations (H × H) +- Basement Σ abs and Rel % +- Perception zone (hidden, not part of the relation/correlation exercise) + +```tikz +% ===================================================================== +% QFD "House of Quality" preamble +% ===================================================================== +\usetikzlibrary{arrows.meta, positioning, shapes.geometric, shapes.misc, calc, fit, backgrounds} + +\newif\ifqfdshowroof \qfdshowrooftrue +\newif\ifqfdshowbasement \qfdshowbasementtrue +\newif\ifqfdshowcompetitive \qfdshowcompetitivetrue +\newif\ifqfdshowlegend \qfdshowlegendtrue +\newif\ifqfdshowimportance \qfdshowimportancetrue +\newif\ifqfdshowcorrlegend \qfdshowcorrlegendtrue +\newif\ifqfdshowevallegend \qfdshowevallegendtrue + +\def\qfdNW{5} +\def\qfdNH{5} +\def\qfdWhatW{4.0} +\def\qfdImpW{0.9} +\def\qfdCmpW{3} +\def\qfdHdrH{2.6} +\def\qfdBasementN{4} + +\def\qfdWhatsTitle{Customer needs} +\def\qfdImpTitle{Imp.\ \%} +\def\qfdPerceptionTitle{Comparative evaluation} +\def\qfdPoorLabel{poor} +\def\qfdExcellentLabel{excellent} +\def\qfdAltOneLabel{Typoena} +\def\qfdAltTwoLabel{Competitor A} +\def\qfdAltThreeLabel{Competitor B} +\def\qfdRelTitle{Relation} +\def\qfdCorrTitle{Correlation} +\def\qfdEvalTitle{Evaluation} + +\tikzset{ + qfdthin/.style ={line width=0.35pt}, + qfdmed/.style ={line width=0.7pt}, + qfdstrong/.style={circle, draw, fill=black, + minimum size=7pt, inner sep=0pt}, + qfdmod/.style ={circle, draw, + minimum size=7pt, inner sep=0pt, line width=0.8pt}, + qfdweak/.style ={regular polygon, regular polygon sides=3, draw, + minimum size=8.5pt, inner sep=0pt, line width=0.7pt}, + qfdrel/.is choice, + qfdrel/S/.style={qfdstrong}, + qfdrel/M/.style={qfdmod}, + qfdrel/W/.style={qfdweak}, + qfdalt1mk/.style={circle, draw, fill=black, + minimum size=6pt, inner sep=0pt, line width=1pt}, + qfdalt1ln/.style={line width=1.2pt}, + qfdalt2mk/.style={regular polygon, regular polygon sides=3, draw, + fill=black, minimum size=6pt, inner sep=0pt, + line width=0.7pt}, + qfdalt2ln/.style={line width=0.7pt, dashed}, + qfdalt3mk/.style={rectangle, draw, fill=black, + minimum size=5pt, inner sep=0pt, line width=0.7pt}, + qfdalt3ln/.style={line width=0.7pt, dotted}, +} + +\newcommand{\qfdDrawGrid}{% + \foreach \c in {1,...,\qfdNHm} \draw[qfdthin] (\c, 0) -- (\c, -\qfdNW); + \foreach \r in {1,...,\qfdNWm} \draw[qfdthin] (0, -\r) -- (\qfdNH, -\r); + \foreach \r in {1,...,\qfdNWm} + \draw[qfdthin] (\qfdLeftEdge, -\r) -- (0, -\r); + \ifqfdshowroof + \foreach \c in {1,...,\qfdNHm} + \draw[qfdthin] (\c, 0) -- (\c, \qfdHdrH); + \fi + \ifqfdshowcompetitive + \foreach \r in {1,...,\qfdNWm} + \draw[qfdthin] (\qfdNH, -\r) -- (\qfdNH+\qfdCmpW, -\r); + \fi + \ifqfdshowbasement + \foreach \r in {1,...,\qfdBasementN} + \draw[qfdthin] (0, -\qfdNW-\r) -- (\qfdNH, -\qfdNW-\r); + \foreach \c in {1,...,\qfdNHm} + \draw[qfdthin] (\c, -\qfdNW) -- (\c, -\qfdNW-\qfdBasementN); + \fi +} + +\newcommand{\qfdDrawRoof}{% + \ifqfdshowroof + \foreach \k in {1,...,\qfdNHm} {% + \pgfmathsetmacro{\rx}{(\k+\qfdNH)/2} + \pgfmathsetmacro{\ry}{\qfdHdrH + (\qfdNH-\k)/2} + \pgfmathsetmacro{\lx}{\k/2} + \pgfmathsetmacro{\ly}{\qfdHdrH + \k/2} + \draw[qfdthin] (\k, \qfdHdrH) -- (\rx, \ry); + \draw[qfdthin] (\k, \qfdHdrH) -- (\lx, \ly); + }% + \draw[qfdmed] (0, \qfdHdrH) + -- (\qfdNH/2, \qfdApexY) -- (\qfdNH, \qfdHdrH); + \foreach \i in {1,...,\qfdNH} + \foreach \k in {1,...,\qfdNH} {% + \pgfmathtruncatemacro{\jj}{\i+\k} + \ifnum\jj>\qfdNH\relax\else + \pgfmathsetmacro{\xx}{\i + \k/2 - 0.5} + \pgfmathsetmacro{\yy}{\qfdHdrH + \k/2} + \coordinate (C-\i-\jj) at (\xx, \yy); + \fi + }% + \fi +} + +\newcommand{\qfdDrawScale}{% + \ifqfdshowcompetitive + \foreach \tk in {0,1,2,3,4,5} {% + \pgfmathsetmacro{\tx}{\qfdNH + (\tk+0.5)*\qfdCmpW/6} + \node[anchor=south, font=\scriptsize] at (\tx, 0.02) {\tk}; + }% + \node[anchor=south, font=\scriptsize\bfseries, align=center, + text width=\qfdCmpW cm] + at ({\qfdNH + \qfdCmpW/2}, 0.7) {\qfdPerceptionTitle}; + \node[anchor=north, font=\scriptsize\itshape] + at ({\qfdNH + 0.45}, -\qfdNW) {\qfdPoorLabel}; + \node[anchor=north, font=\scriptsize\itshape] + at ({\qfdNH + \qfdCmpW - 0.45}, -\qfdNW) {\qfdExcellentLabel}; + \fi +} + +\newcommand{\qfdDrawZoneTitles}{% + \ifqfdshowimportance + \node[rotate=90, anchor=west, font=\footnotesize\bfseries] + at ({-\qfdImpW/2}, 0.12) {\qfdImpTitle}; + \fi + \node[font=\scriptsize\bfseries, align=center, text width=\qfdWhatW cm] + at ({\qfdLeftEdge + \qfdWhatW/2}, + {\ifqfdshowroof \qfdHdrH/2 \else 0.6 \fi}) {\qfdWhatsTitle}; +} + +\newcommand{\qfdDrawFrames}{% + \begin{scope}[qfdmed] + \draw (\qfdLeftEdge, 0) rectangle (\qfdNH, -\qfdNW); + \ifqfdshowimportance \draw (-\qfdImpW, 0) -- (-\qfdImpW, -\qfdNW); \fi + \draw (0, 0) -- (0, -\qfdNW); + \ifqfdshowroof + \draw (0, 0) rectangle (\qfdNH, \qfdHdrH); \fi + \ifqfdshowbasement + \draw (0, -\qfdNW) rectangle (\qfdNH, -\qfdNW-\qfdBasementN); \fi + \ifqfdshowcompetitive + \draw (\qfdNH, 0) rectangle (\qfdNH+\qfdCmpW, -\qfdNW); \fi + \end{scope} +} + +\newcommand{\qfdDrawLegend}{% + \ifqfdshowlegend + \pgfmathsetmacro{\qfdLegX}{% + \qfdNH + \ifqfdshowcompetitive \qfdCmpW + 0.7 \else 0.7 \fi} + \pgfmathsetmacro{\qfdLegBottom}{% + -2.05 + \ifqfdshowroof \ifqfdshowcorrlegend - 2.55 \fi \fi + \ifqfdshowcompetitive \ifqfdshowevallegend - 2.20 \fi \fi} + \pgfmathsetmacro{\qfdLegY}{\qfdHdrH - 0.4} + \begin{scope}[shift={(\qfdLegX, \qfdLegY)}] + \draw[qfdmed, rounded corners=2pt] + (-0.15, 0.4) rectangle (4.5, \qfdLegBottom); + \node[anchor=west, font=\footnotesize\bfseries] at (0, 0.1) + {\qfdRelTitle}; + \draw[qfdthin] (0, -0.15) -- (4.35, -0.15); + \node[qfdstrong] at (0.22, -0.5) {}; + \node[anchor=west] at (0.5, -0.5) {Strong (9)}; + \node[qfdmod] at (0.22, -0.95) {}; + \node[anchor=west] at (0.5, -0.95) {Medium (3)}; + \node[qfdweak] at (0.22, -1.4) {}; + \node[anchor=west] at (0.5, -1.4) {Weak (1)}; + \ifqfdshowroof \ifqfdshowcorrlegend + \node[anchor=west, font=\footnotesize\bfseries] at (0, -2.10) + {\qfdCorrTitle}; + \draw[qfdthin] (0, -2.35) -- (4.35, -2.35); + \node[anchor=west] at (0, -2.70) {{$+\!+$}\quad very positive}; + \node[anchor=west] at (0, -3.05) {{$+$\phantom{$+$}}\quad positive}; + \node[anchor=west] at (0, -3.40) {{$-$\phantom{$-$}}\quad negative}; + \node[anchor=west] at (0, -3.75) {{$-\!-$}\quad very negative}; + \fi \fi + \ifqfdshowcompetitive \ifqfdshowevallegend + \pgfmathsetmacro{\qfdEvalTop}{% + -2.10 \ifqfdshowroof\ifqfdshowcorrlegend - 2.55 \fi\fi} + \node[anchor=west, font=\footnotesize\bfseries] + at (0, \qfdEvalTop) {\qfdEvalTitle}; + \pgfmathsetmacro{\qfdEvalSep}{\qfdEvalTop - 0.25} + \draw[qfdthin] (0, \qfdEvalSep) -- (4.35, \qfdEvalSep); + \pgfmathsetmacro{\qfdLegA}{\qfdEvalTop - 0.55} + \draw[qfdalt1ln] (0.05, \qfdLegA) -- (0.45, \qfdLegA); + \node[qfdalt1mk] at (0.25, \qfdLegA) {}; + \node[anchor=west, font=\bfseries] at (0.55, \qfdLegA) + {\qfdAltOneLabel}; + \pgfmathsetmacro{\qfdLegB}{\qfdEvalTop - 0.95} + \draw[qfdalt2ln] (0.05, \qfdLegB) -- (0.45, \qfdLegB); + \node[qfdalt2mk] at (0.25, \qfdLegB) {}; + \node[anchor=west] at (0.55, \qfdLegB) {\qfdAltTwoLabel}; + \pgfmathsetmacro{\qfdLegC}{\qfdEvalTop - 1.35} + \draw[qfdalt3ln] (0.05, \qfdLegC) -- (0.45, \qfdLegC); + \node[qfdalt3mk] at (0.25, \qfdLegC) {}; + \node[anchor=west] at (0.55, \qfdLegC) {\qfdAltThreeLabel}; + \fi \fi + \end{scope} + \fi +} + +\newenvironment{qfdhouse}{% + \begin{tikzpicture}[x=1cm, y=1cm, font=\scriptsize, + line cap=round, line join=round] + \ifqfdshowimportance + \pgfmathsetmacro{\qfdLeftEdge}{-\qfdWhatW-\qfdImpW} + \else + \pgfmathsetmacro{\qfdLeftEdge}{-\qfdWhatW} + \fi + \pgfmathsetmacro{\qfdApexY}{\qfdHdrH + \qfdNH/2} + \pgfmathtruncatemacro{\qfdNHm}{\qfdNH - 1} + \pgfmathtruncatemacro{\qfdNWm}{\qfdNW - 1} + \qfdDrawGrid + \qfdDrawRoof + \qfdDrawScale + \qfdDrawZoneTitles +}{% + \qfdDrawFrames + \qfdDrawLegend + \end{tikzpicture}% +} + +% --- Dimensions tuned for the typewriter QFD (14 W x 15 H) --- +\def\qfdNW{14} +\def\qfdNH{15} +\def\qfdWhatW{4.6} +\def\qfdImpW{0.7} +\def\qfdHdrH{5.0} +\def\qfdBasementN{3} + +% Hide the perception zone — not part of the relation/correlation exercise. +\qfdshowcompetitivefalse +\qfdshowevallegendfalse + +\def\qfdWhatsTitle{User-facing requirements (W)} +\def\qfdImpTitle{Weight} + +\begin{document} +\begin{qfdhouse} + + % ---------- WHATs (left column) ---------- + \pgfmathsetmacro{\qfdWhatTextW}{\qfdWhatW - 0.2} + \foreach \r/\t in {% + 1/{W1 Sub-second visible response to typing}, + 2/{W2 Publishing is one deliberate action away}, + 3/{W3 Pulling power never corrupts the file}, + 4/{W4 Provisioning never interrupts a writing session}, + 5/{W5 Quick boot to a writing cursor}, + 6/{W6 Long sessions without crash, lag, drift}, + 7/{W7 Nothing on the device competes with prose}, + 8/{W8 The UI never moves except when I move it}, + 9/{W9 Codebase absorbs the planned roadmap}, + 10/{W10 I can repair or fork it with hobbyist tools}, + 11/{W11 Multi-day battery life (v0.8 onward)}, + 12/{W12 Local-only files coexist with git scope (v0.5+)}, + 13/{W13 Typography sets a writing-tool tone}, + 14/{W14 I can carry the device and write away from a desk}% + } + \node[anchor=west, font=\scriptsize, + text width=\qfdWhatTextW cm, align=left] + at ({\qfdLeftEdge + 0.1}, {-\r + 0.5}) {\t}; + + % ---------- Importance (raw 1-10 weight) ---------- + \foreach \r/\w in {1/10, 2/9, 3/10, 4/7, 5/6, 6/9, 7/8, 8/7, + 9/8, 10/5, 11/4, 12/5, 13/7, 14/8} + \node[font=\scriptsize] at ({-\qfdImpW/2}, {-\r + 0.5}) {\w}; + + % ---------- HOWs (rotated column titles) ---------- + \foreach \c/\t in {% + 1/{H1 Keypress$\to$glyph latency}, + 2/{H2 Refresh area per keystroke}, + 3/{H3 Full-refresh cadence}, + 4/{H4 Cold boot to cursor}, + 5/{H5 Continuous-typing endurance}, + 6/{H6 Push success rate}, + 7/{H7 Push end-to-end time}, + 8/{H8 Save durability vs power loss}, + 9/{H9 PSRAM heap headroom}, + 10/{H10 Firmware binary size}, + 11/{H11 Total stack budget}, + 12/{H12 Wi-Fi reconnect time}, + 13/{H13 Idle / typing / push current}, + 14/{H14 Module / API surface count}, + 15/{H15 Clean release build time}% + } + \node[rotate=90, anchor=west, font=\scriptsize] + at ({\c - 0.5}, 0.15) {\t}; + + % ---------- Relation matrix (fill in: S=9, M=3, W=1) ---------- + % Syntax: \node[qfdrel/S] at ({COL - 0.5}, {-ROW + 0.5}) {}; + % Example for W1 (row 1) × H1 (col 1) strong: + % \node[qfdrel/S] at ({1 - 0.5}, {-1 + 0.5}) {}; + + + % ---------- Roof correlations (fill in) ---------- + % Syntax: \node[font=\scriptsize] at (C-i-j) {SYMBOL}; + % i < j are HOW column indices. + % SYMBOL ∈ {$+\!+$ very positive, $+$ positive, + % $-$ negative, $-\!-$ very negative}. + % Example: \node[font=\scriptsize] at (C-1-2) {$+\!+$}; + + + % ---------- Basement: target / abs / rel% ---------- + % Targets (v0.1, from qfd.md §2) are kept. Σ abs and Rel % are blank — + % compute them from your relations: abs = Σ over WHATs of + % (importance × cell strength), with strength 9 / 3 / 1 / 0. + \foreach \c/\tgt in {% + 1/{$\leq$200\,ms}, + 2/{$\leq$1 line}, + 3/{1 : 20}, + 4/{$\leq$5\,s}, + 5/{$\geq$1\,h}, + 6/{$\geq$95\,\%}, + 7/{$\leq$30\,s}, + 8/{100\,\%}, + 9/{$\geq$1\,MB}, + 10/{$\leq$2\,MB}, + 11/{$\leq$80\,KB}, + 12/{$\leq$30\,s}, + 13/{obs.}, + 14/{$\leq$8}, + 15/{$\leq$7\,min}% + } + \node[font=\scriptsize] at ({\c - 0.5}, {-\qfdNW - 0.5}) {\tgt}; + + % ---------- Basement row labels ---------- + \foreach \k/\lbl in {1/{Target (v0.1)}, 2/{$\Sigma$ abs}, 3/{Rel.\ \%}} + \node[anchor=east, font=\scriptsize\itshape] + at ({-0.1}, {-\qfdNW - \k + 0.5}) {\lbl}; + +\end{qfdhouse} +\end{document} +``` + +## How to fill it in + +1. **Relations (centre).** For each WHAT × HOW cell where the HOW + contributes to the WHAT, drop a marker: + ```tex + \node[qfdrel/S] at ({COL - 0.5}, {-ROW + 0.5}) {}; % strong = 9 + \node[qfdrel/M] at ({COL - 0.5}, {-ROW + 0.5}) {}; % medium = 3 + \node[qfdrel/W] at ({COL - 0.5}, {-ROW + 0.5}) {}; % weak = 1 + ``` + Leave a cell empty for "no relation." +2. **Roof.** For each pair of HOWs that reinforce or conflict: + ```tex + \node[font=\scriptsize] at (C-i-j) {$+\!+$}; % i < j + ``` + Symbols: `$+\!+$` very positive, `$+$` positive, `$-$` negative, + `$-\!-$` very negative. Leave a slot empty for "independent." +3. **Basement Σ abs.** Per HOW column, sum `(importance × cell strength)` + over all WHATs that touch it (strength 9 / 3 / 1 / 0). +4. **Basement Rel %.** Each Σ ÷ total Σ × 100, rounded to integer percent + (should sum to ~100 across HOWs). + +Once filled, diff your numbers against [`quality-house.md`](quality-house.md) +basement and roof to see where your reading agrees or differs — divergences +are usually the most interesting part. + +## Gotchas + +- `<` and `>` render as `¡` `¿` in node text — use `$<$`, `$>$`, `$-$`. +- Row 1 is the top WHAT; column 1 is the leftmost HOW. +- The perception zone is hidden here on purpose. To bring it back, delete + the two `\qfdshow...false` lines near the top of the document. diff --git a/docs/quality-house.md b/docs/quality-house.md index 858db6f..0b24c43 100644 --- a/docs/quality-house.md +++ b/docs/quality-house.md @@ -15,6 +15,10 @@ Out of scope here: §5 component mapping (would need a second house), §6 critical performance budget (already a curated rank), §7 tradeoffs (narrative), §8 inconsistencies (history). +For a blank version of the same chassis (WHATs, HOWs, importance, and +v0.1 targets kept; relations + roof + Σ basement left empty for practice), +see [`quality-house-empty.md`](quality-house-empty.md). + The perception zone scores five products against the WHATs on a 0–5 scale. **These are educated guesses, not measurements** — see the [scoring rationale](#perception-scores-guessed) below for what each cell