docs: add dantotsu print design document
This commit is contained in:
474
DESIGN.md
Normal file
474
DESIGN.md
Normal file
@@ -0,0 +1,474 @@
|
||||
# Dantotsu Print — Design (QFD)
|
||||
|
||||
This document decomposes the goals of **Dantotsu Print** — a tool that lets a
|
||||
developer put the *actual defective code* onto the **Defect** cell of a physical
|
||||
A3 daily Dantotsu problem-solving board — into functions, approaches,
|
||||
components, and the tradeoffs taken. Vocabulary is defined in
|
||||
[CONTEXT.md](./CONTEXT.md).
|
||||
|
||||
**Scope.** Dantotsu Print owns only the *capture of a code defect onto the
|
||||
Defect cell*. The broader outcome it serves — the daily board becoming the
|
||||
team's living quality ritual, displacing Notion — is the **backdrop it enables
|
||||
but does not own** (that depends on facilitation, huddle discipline, and
|
||||
management buy-in, all outside this tool). The tool must not be judged by
|
||||
whether the huddle happens.
|
||||
|
||||
**Deployment context.** ~400 engineers, 7 floors, **50+ boards by end of 2026**,
|
||||
**per-board** printer unit. Yokoten is ~80% within the board's own team, ~15%
|
||||
floor-level, ~5% company-wide.
|
||||
|
||||
Strength weights used in matrices: **9** strong, **3** medium, **1** weak, blank none.
|
||||
|
||||
---
|
||||
|
||||
## House of Quality
|
||||
|
||||
```tikz
|
||||
\usetikzlibrary{arrows.meta, positioning, shapes.geometric, shapes.misc, calc, fit, backgrounds}
|
||||
|
||||
% Toggles
|
||||
\newif\ifqfdshowroof \qfdshowrooftrue
|
||||
\newif\ifqfdshowbasement \qfdshowbasementtrue
|
||||
\newif\ifqfdshowcompetitive \qfdshowcompetitivetrue
|
||||
\newif\ifqfdshowlegend \qfdshowlegendtrue
|
||||
\newif\ifqfdshowimportance \qfdshowimportancetrue
|
||||
\newif\ifqfdshowcorrlegend \qfdshowcorrlegendtrue
|
||||
\newif\ifqfdshowevallegend \qfdshowevallegendtrue
|
||||
\newif\ifqfdshowtitle \qfdshowtitletrue
|
||||
|
||||
% Dimensions
|
||||
\def\qfdNW{5}
|
||||
\def\qfdNH{5}
|
||||
\def\qfdWhatW{4.0}
|
||||
\def\qfdImpW{0.9}
|
||||
\def\qfdCmpW{3}
|
||||
\def\qfdHdrH{2.6}
|
||||
\def\qfdBasementN{4}
|
||||
|
||||
% Titles & labels
|
||||
\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}
|
||||
|
||||
\def\qfdProjectTitle{}
|
||||
\def\qfdConcept{}
|
||||
|
||||
% Styles
|
||||
\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{\qfdDrawTitle}{%
|
||||
\ifqfdshowtitle
|
||||
\ifx\qfdProjectTitle\empty\else
|
||||
\pgfmathsetmacro{\qfdTitleX}{\qfdNH/2}
|
||||
\pgfmathsetmacro{\qfdTitleY}{\ifqfdshowroof \qfdApexY \else \qfdHdrH \fi + 0.9}
|
||||
\pgfmathsetmacro{\qfdSubW}{\qfdNH + 2}
|
||||
\node[anchor=south, font=\large\bfseries, align=center]
|
||||
at (\qfdTitleX, \qfdTitleY) {\qfdProjectTitle};
|
||||
\ifx\qfdConcept\empty\else
|
||||
\node[anchor=north, font=\footnotesize\itshape, align=center,
|
||||
text width=\qfdSubW cm]
|
||||
at (\qfdTitleX, {\qfdTitleY - 0.1}) {\qfdConcept};
|
||||
\fi
|
||||
\fi
|
||||
\fi
|
||||
}
|
||||
|
||||
\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
|
||||
\qfdDrawTitle
|
||||
}{%
|
||||
\qfdDrawFrames
|
||||
\qfdDrawLegend
|
||||
\end{tikzpicture}%
|
||||
}
|
||||
|
||||
% ---- Overrides for Dantotsu Print ----
|
||||
\def\qfdNW{3}
|
||||
\def\qfdNH{5}
|
||||
\def\qfdWhatW{4.5}
|
||||
\def\qfdHdrH{3.0}
|
||||
\def\qfdImpTitle{Weight}
|
||||
\def\qfdWhatsTitle{Goals (WHATs)}
|
||||
\def\qfdProjectTitle{Dantotsu Print}
|
||||
\def\qfdConcept{One \textbf{keystroke} turns selected code into a \textbf{peel-stick defect card} for the physical \textbf{Dantotsu board}.}
|
||||
\qfdshowcompetitivefalse
|
||||
|
||||
\begin{document}
|
||||
\begin{qfdhouse}
|
||||
% WHATs + weights
|
||||
\pgfmathsetmacro{\qfdWhatTextW}{\qfdWhatW - 0.2}
|
||||
\foreach \r/\t in {1/{Effortless, faithful capture},
|
||||
2/{Deployable at 50+ boards},
|
||||
3/{Traceable to source}}
|
||||
\node[anchor=west, font=\scriptsize, text width=\qfdWhatTextW cm, align=left]
|
||||
at ({\qfdLeftEdge + 0.1}, {-\r + 0.5}) {\t};
|
||||
\foreach \r/\imp in {1/10, 2/8, 3/6}
|
||||
\node[font=\scriptsize] at ({-\qfdImpW/2}, {-\r + 0.5}) {\imp};
|
||||
|
||||
% HOWs
|
||||
\foreach \c/\t in {1/{Capture effort}, 2/{Fidelity \& legibility},
|
||||
3/{Scope to cell}, 4/{Operating burden},
|
||||
5/{Source back-link}}
|
||||
\node[rotate=90, anchor=west, font=\scriptsize] at ({\c - 0.5}, 0.15) {\t};
|
||||
|
||||
% Relations
|
||||
\node[qfdrel/S] at ({1 - 0.5}, {-1 + 0.5}) {};
|
||||
\node[qfdrel/S] at ({2 - 0.5}, {-1 + 0.5}) {};
|
||||
\node[qfdrel/M] at ({3 - 0.5}, {-1 + 0.5}) {};
|
||||
\node[qfdrel/W] at ({4 - 0.5}, {-1 + 0.5}) {};
|
||||
\node[qfdrel/S] at ({4 - 0.5}, {-2 + 0.5}) {};
|
||||
\node[qfdrel/S] at ({5 - 0.5}, {-3 + 0.5}) {};
|
||||
|
||||
% Roof correlations
|
||||
\node[font=\scriptsize] at (C-1-3) {$-$};
|
||||
\node[font=\scriptsize] at (C-1-4) {$+$};
|
||||
\node[font=\scriptsize] at (C-2-3) {$+$};
|
||||
|
||||
% Basement row labels
|
||||
\node[anchor=west, font=\scriptsize] at ({\qfdLeftEdge + 0.1}, {-\qfdNW - 0.5}) {Target};
|
||||
\node[anchor=west, font=\scriptsize] at ({\qfdLeftEdge + 0.1}, {-\qfdNW - 1.5}) {Difficulty (1--5)};
|
||||
\node[anchor=west, font=\scriptsize] at ({\qfdLeftEdge + 0.1}, {-\qfdNW - 2.5}) {Abs.\ weight};
|
||||
\node[anchor=west, font=\scriptsize] at ({\qfdLeftEdge + 0.1}, {-\qfdNW - 3.5}) {Rel.\ weight \%};
|
||||
|
||||
% Basement values
|
||||
\foreach \c/\tgt/\diff/\abs/\rel in
|
||||
{1/{$\leq$10s}/4/90/26,
|
||||
2/{48$\times$19}/3/90/26,
|
||||
3/{preview}/2/30/9,
|
||||
4/{unbox}/4/82/24,
|
||||
5/{@sha}/2/54/16} {
|
||||
\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};
|
||||
}
|
||||
\end{qfdhouse}
|
||||
\end{document}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. Goals — the WHATs
|
||||
|
||||
| ID | Goal | Weight | Source |
|
||||
|-----|-------------------------------------------------------------------------------------------------------------------------------|:------:|--------|
|
||||
| G1 | Getting the **real defective code onto the Defect cell** is effortless and faithful — so filling the sheet is no longer the chore that sends people back to Notion | 10 | walk-with-me 2026-07-01 |
|
||||
| G2 | Deployable to **50+ boards** at low TCO, *without harming adoption* (weight is operational burden, not the modest cash cost) | 8 | walk-with-me 2026-07-01 |
|
||||
| G3 | A defect on the board stays **traceable to its exact source** (commit + line) — earns its keep in the ~20% cross-team yokoten cases | 6 | walk-with-me 2026-07-01 |
|
||||
|
||||
## 2. Functions — the HOWs
|
||||
|
||||
Direction: ↑ higher is better, ↓ lower is better, → hit a fixed target.
|
||||
|
||||
| ID | Function | Dir | Target (now) |
|
||||
|-----|-----------------------------------------------------------------------------------------------------------|:---:|--------------|
|
||||
| F1 | **Minimise capture effort** — gestures & seconds from "I see the defect" to "card in hand" | ↓ | ≤ 1 gesture after selecting code (one keystroke); card in hand ≤ 10 s |
|
||||
| F2 | **Preserve code fidelity & legibility** — verbatim monospaced code inside the 90×85 mm cell | ↑ | exact characters; readable up-close (~0.4 m), card *present* at ~1 m; fits the mono grid budget (~48 cols × ~19 rows at 8 pt); overflow *flagged*, never silently shrunk |
|
||||
| F3 | **Scope the defect to the cell** — developer previews & trims the selection to the essential offending lines | → | live preview of exact print output; adjustable line range; flags (not shrinks) content beyond the legible budget |
|
||||
| F4 | **Minimise per-board operating burden** — consumables, refills, jams, provisioning handled by non-experts, no babysitting | ↓ | consumable swap ≤ monthly & self-serve; per-unit setup ≤ "unbox and pair"; no per-card manual step beyond peel/stick |
|
||||
| F5 | **Embed a durable back-link to source** — every card carries a *computer-native* reference to the exact code | → | printed text `owner/repo · path · Lstart–end · @short-sha` (commit-pinned), read straight into the editor; **optional** QR to the full web permalink for at-the-board phone glances only — never the transfer path |
|
||||
|
||||
_F1–F3 serve G1, F4 serves G2, F5 serves G3 (mapped in §3)._
|
||||
|
||||
_**F5 later upgrade (deferred from v1):** an SSO-backed short-link redirector (`go/dp/AB12` → full permalink) for one-click open on the computer. Cheap to maintain once set up behind existing SSO (auth already solved; a lookup table). Trigger to build: cross-team yokoten (the ~20%) shows the typed `path:line@sha` reference is too slow in practice._
|
||||
|
||||
## 3. Cascade — Goals → Functions → How → Components
|
||||
|
||||
_Pipeline stages resolved so far; printer/transport (F4) and F3's preview mechanism still open._
|
||||
|
||||
- **G1** Effortless & faithful defect capture _W:10_
|
||||
- **F1** Minimise capture effort _↓ ≤1 gesture, ≤10 s_
|
||||
- **How (chosen):** one **CLI engine** invoked by a **per-editor keystroke** that pipes the selection and passes `--file`/`--lines` (Vim map, JetBrains External Tool, VS Code/Cursor keybinding→task). **Xcode:** clipboard-only fallback, no line numbers. _Chosen over a per-editor extension — see T1._
|
||||
- **F2** Fidelity & legibility _↑_
|
||||
- **How (chosen):** CLI renders selection → image via its own tokenizer (tree-sitter / `silicon`-class), sized to the 90×85 mm cell. Monospace makes fit a deterministic **character budget** (~48 cols × ~19 rows at 8 pt after margins + footer); the CLI flags selections that exceed it. Font picked for legibility at the printer's DPI (label ≈ 300 dpi).
|
||||
- **F3** Scope to the cell _→_
|
||||
- **How (chosen):** F3a — CLI renders the real card **at exact cell size (90×85 mm), cell boundary drawn**, and previews it: **inline** in graphics-capable terminals (iTerm2 / Kitty / **Ghostty** / WezTerm / VS Code-Cursor sixel), or as a **text-grid** (code clamped to the ~48-col budget — instant, no graphics needed), or the PNG opened in the OS viewer. Overflow spills past the border → F2's "flag, don't shrink" made visual. Confirm-to-print; `-y` skips. WYSIWYG because the preview *is* the print artifact.
|
||||
- **G3** Traceable to source _W:6_
|
||||
- **F5** Durable back-link _→_
|
||||
- **How (chosen):** CLI derives the introducing commit SHA via `git blame` on the selected lines; prints `repo·path·Lx–y·@sha` + optional QR.
|
||||
- **G2** Deployable at scale _W:8_
|
||||
- **F4** Minimise per-board operating burden _↓_
|
||||
- **How (chosen — peel-stick label):** per-board **monochrome direct-thermal label printer**, wide **networked Brother QL-1110NWB (102 mm)**, ≥300 dpi, **removable** adhesive (peel-on-resolve won't tear the A3). Bonded to the cell → no fall/misfile (G1 trust), zero manual step (F1), no ink (F4). CLI-driven via `brother_ql`. _Rejected: magnet (fall/misfile), receipt+glue (per-card step) — see T3 / §9._
|
||||
- **How (chosen — transport):** **T-B central print service** (thin router) — CLI renders client-side, then POSTs *card image + board-id* to the service, which forwards the raster to that board's **networked Brother QL-1110NWB** by IP. Service owns the board→printer registry, retries, and print/label status. _Over direct (T-A) and corporate CUPS (T-C) — see T4._
|
||||
|
||||
## 4. House — Goals × Functions
|
||||
|
||||
Cells: link strength (9/3/1/blank). Importance row = Σ(weight × strength).
|
||||
|
||||
| | F1 | F2 | F3 | F4 | F5 |
|
||||
|----------|:--:|:--:|:--:|:--:|:--:|
|
||||
| G1 (10) | 9 | 9 | 3 | 1 | |
|
||||
| G2 (8) | | | | 9 | |
|
||||
| G3 (6) | | | | | 9 |
|
||||
| **Σ** | 90 | 90 | 30 | 82 | 54 |
|
||||
|
||||
**Top engineering priorities:** **F1 capture-effort (90) ≈ F2 fidelity (90)** are the heart of G1 — pour engineering there. **F4 operating-burden (82)** is a close third because it is the *sole* driver of the heavy G2. **F5 (54)** is mid. **F3 scope/preview (30)** is the least critical function *and* it conflicts with F1 (see roof) — so build it light; don't gold-plate the preview.
|
||||
|
||||
## 5. Roof — Function × Function
|
||||
|
||||
`◎` strong reinforce · `○` mild reinforce · `×` mild conflict · `⊗` strong conflict.
|
||||
|
||||
| | F1 | F2 | F3 | F4 | F5 |
|
||||
|--------|:--:|:--:|:--:|:--:|:--:|
|
||||
| **F1** | — | | × | ○ | |
|
||||
| **F2** | | — | ○ | | |
|
||||
| **F3** | | | — | | |
|
||||
| **F4** | | | | — | |
|
||||
| **F5** | | | | | — |
|
||||
|
||||
**Conflicts that shape the design:**
|
||||
- **F1 × F3 (×)** — the confirm-preview adds a gesture against F1's ≤1-gesture target. Mitigated per-invocation by `-y`. This is the one live tension (see §8).
|
||||
- **F2 × F3 (○)** — scoping the snippet to the cell *helps* fit and legibility; they reinforce.
|
||||
- **F1 × F4 (○)** — the central service's `--board` routing removes per-print printer-hunting, mildly aiding capture effort.
|
||||
|
||||
## 6. Components & Function → Component map
|
||||
|
||||
The second house: Functions (HOWs) become the WHATs, realised by concrete components.
|
||||
|
||||
| ID | Component | ADR |
|
||||
|-----|---------------------------------------------------------------------------|----------|
|
||||
| C1 | `dp` CLI engine — **Rust, `clap`** (capture stdin+`--file`/`--lines`, render, preview, emit) | ADR-0001, ADR-0003 |
|
||||
| C2 | Per-editor keystroke shims (Vim / JetBrains / VS Code·Cursor; Xcode clipboard) | ADR-0001 |
|
||||
| C3 | Tokenizing renderer — **`syntect`/`silicon`-class → mono PNG at cell size**, `viuer` inline preview | ADR-0003 |
|
||||
| C4 | Central print service — **Python / `brother_ql`** (board→printer registry, queue, status, router) | ADR-0002 |
|
||||
| C5 | Networked label printer — Brother QL-1110NWB, per board | ADR-0002 |
|
||||
| C6 | Board registry / config (`--board`, per-repo/dev default) | ADR-0002 |
|
||||
|
||||
Function → Component strength (9/3/1/blank):
|
||||
|
||||
| | C1 | C2 | C3 | C4 | C5 | C6 |
|
||||
|----|:--:|:--:|:--:|:--:|:--:|:--:|
|
||||
| F1 | 9 | 9 | | | | 3 |
|
||||
| F2 | 3 | | 9 | | | |
|
||||
| F3 | 9 | | 3 | | | |
|
||||
| F4 | | | | 9 | 9 | 3 |
|
||||
| F5 | 9 | | | 1 | | |
|
||||
|
||||
_F5's deferred SSO short-link redirector would later attach to **C4**._
|
||||
|
||||
## 7. Critical performance budget
|
||||
|
||||
Ranked from §4 importance and §5 conflicts. `If we miss it` is mandatory — a target without a fallback is a wish.
|
||||
|
||||
| Rank | Function | Target | Watched on | If we miss it |
|
||||
|------|----------|--------|------------|---------------|
|
||||
| 1 | **F1** capture effort | ≤ 1 gesture, ≤ 10 s | dogfood timing on pilot boards | Notion-relapse risk → default `-y`, tighten keybindings, revisit shims |
|
||||
| 2 | **F2** fidelity/legibility | verbatim; ~48c × 19r @ 8 pt, crisp at 300 dpi | print tests read at the board | drop to 7 pt / widen media / enforce F3 trim |
|
||||
| 3 | **F4** operating burden | unbox+pair; consumable swap ≤ monthly & self-serve; service up | refill cadence + service uptime + jam/label-out incidents across pilot boards | Pi-agent fallback, pre-stock labels, service HA |
|
||||
| 4 | **F5** back-link | resolves to the introducing commit | sample cards resolve to correct SHA | fix blame-vs-HEAD; build the SSO redirector |
|
||||
| 5 | **F3** scope/preview | preview accurate; overflow flagged not shrunk | overflow-flag correctness on oversized snippets | low stakes → fall back to re-select-and-refire |
|
||||
|
||||
## 8. Tradeoffs — Got / Paid / ADR
|
||||
|
||||
| ID | Tradeoff | Got | Paid | ADR |
|
||||
|-----|----------|-----|------|-----|
|
||||
| T1 | One **CLI engine + per-editor keystroke shims**, over a per-editor extension | editor-agnostic across the polyglot fleet (VS Code, Cursor, JetBrains, Vim, Xcode); single engine to maintain (serves F4) | weaker in-editor preview for F3; Xcode degraded to clipboard-only; syntax colors from CLI tokenizer, not the editor's live theme | ADR-0001 |
|
||||
| T2 | **Monochrome print**, over color on paper | no ink/toner refills across 50 boards (F4); high-contrast distance legibility | no syntax *hue* on the card — kept only in the preview + digital permalink | — |
|
||||
| T3 | **Peel-stick label** (wide networked QL-1110NWB, removable), over magnet and over receipt+glue | bonded → no fall/misfile (G1 trust); zero manual step (F1); no ink (F4); CLI-driven via `brother_ql` | ~€9k/50 + recurring label rolls; wide model needed for width | — |
|
||||
| T4 | **T-B central service + networked printers**, over direct (T-A) / corporate CUPS (T-C) | central board→printer registry, retries, print/label status, `--board` routing, home for the F5 redirector; no per-board Pi to patch | a small service to run + maintain; single point of failure if down | ADR-0002 |
|
||||
| T5 | **Rust plain CLI**, over TS/Node and Gleam, no TUI framework | single-binary distribution to the polyglot fleet (F4); best-fit code→PNG ecosystem; no TUI machinery on the fire-and-exit path | Rust-comfortable maintainers required; interactive trim deferred to a scoped ratatui mode | ADR-0003 |
|
||||
|
||||
### Tensions being watched (unresolved by design)
|
||||
|
||||
- **Central print service is a single point of failure.** If it's down, printing stalls. Instead: keep it dead-simple / HA, and let the CLI cache the registry to fall back to direct-print. **Trigger to revisit:** first outage that blocks a daily huddle, or flaky uptime.
|
||||
- **F1 × F3 — preview vs. speed.** The confirm-preview adds a gesture against F1's ≤1-gesture target. Instead: `-y` skips preview per-invocation. **Trigger to revisit:** if devs habitually `-y` everything, drop preview-by-default.
|
||||
|
||||
## 9. Inconsistencies spotted and fixed
|
||||
|
||||
- **Goal overreach — "the board becomes the ritual."** First-draft G1 claimed the tool revives the whole daily practice. Rescoped: the tool owns only *capture onto the Defect cell*; the ritual is backdrop it enables but does not own (see Scope).
|
||||
- **"Defect = the crash."** The switch-missing-a-case example blended the code defect with its consequence (the crash). Resolved: the **Defect** is the code; the crash is only the consequence that made it visible, and is not printed.
|
||||
- **F5 assumed a QR/phone.** Traceability was first specced as a QR — but the audience is developers at computers, and a QR resolves to a phone. Resolved: primary back-link is computer-native `path·lines·@sha` text; QR demoted to an optional at-the-board glance.
|
||||
- **F2 "legible at ~1 m" over-specified.** Dense code is read up-close (~0.4 m); at 1 m only the card's *presence* registers. Target corrected.
|
||||
- **Printer class closed too early, then re-derived correctly.** Originally ruled out thermal receipt on a false premise ("needs glue"). Reopened: Brother QL is itself direct-thermal (the thermal/label split was false; fading is moot at Daily), and the magnetic board suggested magnet attach. Magnet was then eliminated on an **integrity failure mode** — a fallen card re-stuck on the wrong row silently corrupts the defect↔cause/owner link (a G1 trust regression). Landed back on **peel-stick label**, now justified by *bonding/integrity*, not the original hand-wave.
|
||||
|
||||
---
|
||||
|
||||
## How to keep this honest
|
||||
|
||||
- New ADR lands → add its components to §6 and re-score affected rows.
|
||||
- A spike / measurement returns numbers → update §7 `Target` / `Watched on`.
|
||||
- WHATs (§1) change rarely; HOWs (§2) change per release; matrices (§§4–6) are recomputed when either side changes.
|
||||
- If a section becomes empty after edits, delete it — empty sections lie.
|
||||
Reference in New Issue
Block a user