docs: add House of Quality diagram

TikZ rendering of the DESIGN.md QFD matrices (goals, functions,
relations, roof, basement weights) for review and slides.
This commit is contained in:
Julien Calixte
2026-05-27 21:58:55 +02:00
parent a304973af6
commit 6606524fc7

320
docs/house-of-quality.md Normal file
View File

@@ -0,0 +1,320 @@
# House of Quality
A TikZ rendering of the QFD matrices in [`DESIGN.md`](../DESIGN.md) §§12, 45, 7:
Goals as WHATs (left + importance), the 10 Functions as HOWs (columns), the §4
relation matrix in the body, the §5 conflicts in the roof, and the basement
carrying each function's target, difficulty, and computed weight.
The `DESIGN.md` tables remain authoritative; this is the picture for a review or
slide. The basement `Rel. wt %` row is the punchline — it collapses the relation
matrix into where the engineering weight sits, confirming the build order:
**F1 (16%)** dominates, then the **F2/F3 filing pair (13% each)** and **F4/F5
weak-point pair (12% each)**, with **F6 (4%) / F10 (5%)** deliberately light.
```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{Our product}
\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]
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}%
}
% =====================================================================
% Andon — House of Quality
% =====================================================================
\def\qfdNW{4} % 4 Goals
\def\qfdNH{10} % 10 Functions
\def\qfdWhatW{4.6}
\def\qfdWhatsTitle{Goals (WHATs)}
\qfdshowcompetitivefalse % no competitor benchmark
\begin{document}
\begin{qfdhouse}
% ---- WHATs (Goals) + Importance % ----
\pgfmathsetmacro{\qfdWhatTextW}{\qfdWhatW - 0.2}
\foreach \r/\t in {%
1/{G1 Flag a board problem in seconds},
2/{G2 Weak points visible at a glance},
3/{G3 Owner notified promptly on phone},
4/{G4 Theodo-only \& attributable}}
\node[anchor=west, font=\scriptsize,
text width=\qfdWhatTextW cm, align=left]
at ({\qfdLeftEdge + 0.1}, {-\r + 0.5}) {\t};
\foreach \r/\imp in {1/31, 2/28, 3/22, 4/19}
\node[font=\scriptsize] at ({-\qfdImpW/2}, {-\r + 0.5}) {\imp};
% ---- HOWs (Functions, rotated) ----
\foreach \c/\t in {%
1/{F1 Board from 1 def},
2/{F2 Time-to-file},
3/{F3 Project suggest},
4/{F4 Dot map},
5/{F5 Verbatim modal},
6/{F6 Dashboard speed},
7/{F7 Push latency},
8/{F8 Subscriptions},
9/{F9 SSO gate},
10/{F10 Durability}}
\node[rotate=90, anchor=west, font=\scriptsize]
at ({\c - 0.5}, 0.15) {\t};
% ---- Relations (Goal x Function) ----
\node[qfdrel/M] at ({1 - 0.5}, {-1 + 0.5}) {}; % F1-G1
\node[qfdrel/S] at ({1 - 0.5}, {-2 + 0.5}) {}; % F1-G2
\node[qfdrel/S] at ({2 - 0.5}, {-1 + 0.5}) {}; % F2-G1
\node[qfdrel/S] at ({3 - 0.5}, {-1 + 0.5}) {}; % F3-G1
\node[qfdrel/S] at ({4 - 0.5}, {-2 + 0.5}) {}; % F4-G2
\node[qfdrel/S] at ({5 - 0.5}, {-2 + 0.5}) {}; % F5-G2
\node[qfdrel/M] at ({6 - 0.5}, {-2 + 0.5}) {}; % F6-G2
\node[qfdrel/S] at ({7 - 0.5}, {-3 + 0.5}) {}; % F7-G3
\node[qfdrel/S] at ({8 - 0.5}, {-3 + 0.5}) {}; % F8-G3
\node[qfdrel/S] at ({9 - 0.5}, {-4 + 0.5}) {}; % F9-G4
\node[qfdrel/M] at ({10 - 0.5}, {-2 + 0.5}) {}; % F10-G2
\node[qfdrel/W] at ({10 - 0.5}, {-4 + 0.5}) {}; % F10-G4
% ---- Roof correlations (Function x Function) ----
\node[font=\scriptsize] at (C-1-2) {$+$}; % F1 reinforces F2
\node[font=\scriptsize] at (C-1-4) {$+\!+$}; % F1 strongly reinforces F4
\node[font=\scriptsize] at (C-2-7) {$-$}; % fast filing vs push
\node[font=\scriptsize] at (C-2-9) {$-$}; % fast filing vs auth gate
\node[font=\scriptsize] at (C-4-6) {$-$}; % rich dot map vs dashboard speed
% ---- Basement: target / difficulty(1-5) / abs weight / rel weight % ----
\foreach \c/\tgt/\diff/\abs/\rel in {%
1/{1 source}/3/345/16,
2/{$\leq$15s}/2/279/13,
3/{0 retype}/2/279/13,
4/{cap $\sim$10}/3/252/12,
5/{modal}/2/252/12,
6/{$\leq$1s}/2/84/4,
7/{$\leq$10s}/3/198/9,
8/{multi-dev}/3/198/9,
9/{100\%}/3/171/8,
10/{0 loss}/2/103/5} {
\node[font=\scriptsize] at ({\c - 0.5}, {-\qfdNW - 0.5}) {\tgt};
\node[font=\scriptsize] at ({\c - 0.5}, {-\qfdNW - 1.5}) {\diff};
\node[font=\scriptsize] at ({\c - 0.5}, {-\qfdNW - 2.5}) {\abs};
\node[font=\scriptsize\bfseries] at ({\c - 0.5}, {-\qfdNW - 3.5}) {\rel};
}
% ---- Basement row labels (to the left of the basement) ----
\foreach \k/\lbl in {0/{Target}, 1/{Difficulty}, 2/{Abs.\ wt}, 3/{Rel.\ wt \%}}
\node[anchor=east, font=\scriptsize\itshape]
at ({\qfdLeftEdge + \qfdWhatW}, {-\qfdNW - 0.5 - \k}) {\lbl};
\end{qfdhouse}
\end{document}
```