feat: der günstigste Pfad zeigt die offene Front (D46)
Der Pfad rechnete rein aus T-Shirt-Größen — `ownCost()` war `SIZE_RANK[size] + 1`, der Status kam in der Kostenrechnung überhaupt nicht vor (nur `[-]` flog heraus). Folge: Längst Erledigtes wurde voll eingepreist und lag weiter hell auf dem Pfad; im mitgelieferten Werkbaum-Plan zeichnete die Linie damit überwiegend fertige Arbeit nach. Und in einer Alternativgruppe hatte eine bereits realisierte Alternative keinerlei Kostenvorteil — der Pfad empfahl die nominell billigere, obwohl die Wahl längst getroffen und bezahlt ist. Ab jetzt kostet Erledigtes 0. Der Pfad beantwortet damit „was ist als Nächstes am günstigsten?" statt „was hätte der Plan von vorn gekostet?". - Schwelle bei `[x]` fertig: die Beförderung auf `[^]` ist keine Kostenfrage (das tut per D30 ein eigener Commit). - Angefangenes (`[~]`, `[/]`) zählt weiter voll — Bruchteile ordinaler Größen wären erfunden, und `[~]` heißt laut §4 gerade „Risiko hoch". - Maßgeblich ist der intrinsische Status: investiert ist investiert, auch wenn Abhängigkeiten den Knoten effektiv zurückhalten (D39). Verhindert nebenbei doppeltes Zählen — die Abhängigkeit steht mit eigenen Kosten selbst da. - Abgezogen werden nur die eigenen Kosten, nicht der Teilbaum. Darstellung: Erledigte bleiben `cheap` und behalten ihre volle Statusfarbe (grün/blau sagt schon „nichts mehr zu tun"), verlieren aber Stationspunkt und implizites M-Badge — Letzteres macht eine Kostenannahme sichtbar, und an einem erledigten Knoten wird keine getroffen. Station ist der tiefste noch OFFENE Knoten eines Zweigs (`hidesOpenCheap()` fragt den Teilbaum statt nur die direkten Kinder): Sind alle Kinder fertig, wird der offene Elternknoten selbst die Station. Der eingeklappte Knoten (D38) erbt dieselbe Verschärfung. Kein neuer Umschalter — der vorhandene ändert seine Bedeutung. Nachgemessen am Werkbaum-Plan: 110 Knoten auf dem Pfad (unverändert), Stationen 69 -> 24, und die 24 sind exakt die offene Front (Ticket-Referenzen, Öffnen/Speichern, Backend-Gerüst samt REST und Persistenz, Websocket-Transport, Text-CRDT, Mermaid-Layout, IDEA-Plugin). Linie wird weiter gezogen; Export und Druck folgen ohne Zusatzcode, sie lesen dieselbe `.node.cheap-leaf`. 236 Tests grün, davon 14 neue (tests/frontier.test.js). Der Snapshot des kanonischen Beispiels ändert sich um genau zwei Knoten. SPEC §9, llms.md und ROADMAP/TASKS nachgezogen. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
9069955895
commit
c793bf0038
@@ -15,7 +15,7 @@
|
||||
// Diskrepanzen (effectiveStatus() in model.js, D39)
|
||||
} */
|
||||
|
||||
import { gateOf, needsBreakdown, visibleChildren, cheapCls } from './model.js';
|
||||
import { gateOf, needsBreakdown, visibleChildren, cheapCls, isDone } from './model.js';
|
||||
|
||||
/* Zusatzklassen eines Knotens: günstigster Pfad (D18), „neu in Produktion"
|
||||
gegenüber der zuletzt gesehenen Fassung (D28, `freshSet` optional) und
|
||||
@@ -68,7 +68,7 @@ function nodeAria(n, opts, fold){
|
||||
const effKey = opts.effStatus ? opts.effStatus.get(n) : undefined;
|
||||
if(effKey) parts.push(t('a11yEffective', {status: t('st_' + effKey)}));
|
||||
if(n.size) parts.push(t('a11ySize', {size: n.size}));
|
||||
else if(cheapPath) parts.push(t('a11ySizeImplicit'));
|
||||
else if(cheapPath && !isDone(n)) parts.push(t('a11ySizeImplicit'));
|
||||
if(n.tags && n.tags.length) parts.push(t('a11yTags', {names: n.tags.join(', ')}));
|
||||
/* Knoten-ID und Abhängigkeiten (SPEC §1, D36/D37): keine eigene Darstellung
|
||||
im Diagramm — sichtbar nur im Tooltip und hier. */
|
||||
@@ -131,10 +131,13 @@ function nodeHtml(n, extra, opts, fold){
|
||||
const tagsHtml = n.tags && n.tags.length
|
||||
? `<span class="tags" aria-hidden="true">${n.tags.map(tag => `<span class="tag">${esc(tag)}</span>`).join('')}</span>`
|
||||
: '';
|
||||
/* Das implizite M-Badge macht eine KOSTENANNAHME sichtbar (D18). An einem
|
||||
erledigten Knoten wird keine getroffen — er kostet nichts mehr (D46) —,
|
||||
dort bleibt es deshalb weg. */
|
||||
const implicitTip = attr(t('implicitSizeTooltip'));
|
||||
const sizeBadge = n.size
|
||||
? `<span class="size" aria-hidden="true">${n.size}</span>`
|
||||
: (cheapPath ? `<span class="size implicit" aria-hidden="true" title="${implicitTip}">M</span>` : '');
|
||||
: (cheapPath && !isDone(n) ? `<span class="size implicit" aria-hidden="true" title="${implicitTip}">M</span>` : '');
|
||||
/* High-Risk: Warndreieck (⚠, Textpräsentation via VS15) an der oberen linken
|
||||
Ecke. aria-hidden — die Information steckt bereits im Status des aria-label. */
|
||||
const riskMark = n.status && n.status.key === 'highrisk'
|
||||
|
||||
Reference in New Issue
Block a user