lean-path: Angefangenes liegt auf dem Pfad (SPEC §9, D61)
Eine Zugabe (`+`) fällt aus dem günstigsten Pfad — außer sie ist realisiert und noch nicht erledigt (`[~]`/`[/]`). Angefangene Arbeit ist die offene Front, und seit D46 zeigt der Pfad genau die; bisher führte der Von-Station-zu-Station-Knopf nie dorthin, wo gearbeitet wird. Erledigte Zugaben bleiben draußen: dort ist nichts mehr zu tun, und was darunter offen blieb, ist mit ihnen zusammen entbehrlich (§3). Dabei die fehlende Hälfte von D46 gefunden: SPEC §9 sagt seit jeher „eine bereits realisierte Alternative gewinnt", umgesetzt war das aber nur über die Kosten — und die sind allein bei `[x]`/`[^]` null. Ein `[~]`-Zweig verlor damit gegen eine unangetastete billigere, obwohl die XOR-Regel gerade ihn als die realisierte Alternative ausweist. `chosenPool()` schränkt die Wahlmenge auf die realisierten ein; unter mehreren entscheiden wieder die Kosten. Nebengewinn: eine entschiedene Gruppe ist keine freie Variable mehr und verkleinert die Suche (D42). 10 neue Tests; Gegenprobe geführt (jede Regel einzeln herausgenommen lässt genau die nach ihr benannten Zusicherungen fallen). Der mitgelieferte Plan ändert sich nicht — er hat keine angefangene Zugabe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
3018db9f61
commit
36b78efa53
@@ -19,6 +19,8 @@ reverse.
|
||||
|
||||
## 2026-08-24
|
||||
|
||||
- An optional node (`+`) joins the cheapest path while it is being worked on — started work is the open front
|
||||
- Fix: a started alternative lost its `|`/`=` group to an untouched cheaper one, although the choice was already made
|
||||
- A node written as an id alone (`- #US-123`) is now titled by that id, instead of being ignored
|
||||
- A line ending in a space and `\` continues on the next line, so a long node no longer has to fit into one
|
||||
- A star in the header opens What's new: the changes of the last few days, and a link per day that shows the nodes it touched in the diagram
|
||||
|
||||
@@ -4319,3 +4319,100 @@ Knoten.
|
||||
`#`-Umschalter bekommt er **keine** `nid`-Spanne, der Nachbar `#auth: Backend`
|
||||
schon. 337 Tests, davon 6 neue; der eine alte, der die frühere Regel festhielt,
|
||||
ist umgeschrieben und benennt jetzt diese.
|
||||
|
||||
## D61 — Angefangenes liegt auf dem Pfad: Zugaben und Alternativen
|
||||
Gemeldet an einem kleinen Baum:
|
||||
|
||||
```
|
||||
- [ ] #fe
|
||||
+ [~] #fe.rel: Relations bearbeitbar (S)
|
||||
+ [?] #fe.more: weitere Features …
|
||||
```
|
||||
|
||||
Erwartet war, dass der Pfad durch `#fe.rel` läuft — „auch wenn es optional
|
||||
ist, weil das ja nun schon begonnen wurde". Er lief stattdessen durch `#fe`,
|
||||
und die einzige Station war der Elternknoten.
|
||||
|
||||
**Die Regel dahinter stand seit D29 ohne Ausnahme da:** Optionale Knoten sind
|
||||
*nie* nötig. Sie ist aus einem echten Fehler entstanden — der Pfad rechnete
|
||||
jede Zugabe ins Minimum und **überschätzte** sich systematisch. Der umgekehrte
|
||||
Fehler war dabei nie bedacht: angefangene Arbeit zu **unterschlagen**. Seit
|
||||
D46 beantwortet der Pfad ohnehin nicht mehr „was hätte der Plan von vorn
|
||||
gekostet?", sondern „was ist als Nächstes dran?" — und `[~]` ist das
|
||||
Vorderste, was es gibt. Praktisch heißt das, dass der
|
||||
Von-Station-zu-Station-Knopf (D47) einen nie dorthin führt, wo gerade
|
||||
tatsächlich gearbeitet wird.
|
||||
|
||||
`+` ist eine Aussage über den **Plan** („entbehrlich"), der Status eine über
|
||||
die **Tatsachen** („daran wird gearbeitet"). Die beiden Achsen bleiben
|
||||
unabhängig (§3) — der Pfad ist ein Drittes und darf beide lesen.
|
||||
|
||||
**Entschieden: Eine Zugabe liegt auf dem Pfad, sobald sie realisiert (§3),
|
||||
aber noch nicht erledigt (D46) ist** — also bei `[~]` und `[/]`.
|
||||
|
||||
**Die Formulierung ist der eigentliche Fund.** Mein erster Vorschlag war die
|
||||
volle Schwelle „realisiert" (`[~] [/] [x] [^]`), begründet damit, dass §3 das
|
||||
Wort schon führt und keine dritte Schwelle dazukommt. Der Nutzer hat
|
||||
widersprochen: *„Eigentlich sollen fertige oder gar deployed Knoten gar nicht
|
||||
auf den Lean-Path, da gibt es ja nichts mehr zu tun."* Das ist richtig, und
|
||||
mein Argument gegen die engere Fassung fällt weg, sobald man sie aus den
|
||||
**vorhandenen** Begriffen zusammensetzt: *realisiert, aber nicht erledigt*.
|
||||
`isStarted = isRealized && !isDone` — kein neues Vokabular.
|
||||
|
||||
**Was dabei zu klären war: „auf dem Pfad" ist nicht „Station".** Seit D46
|
||||
bekommt ein erledigter Knoten auf dem Pfad **keinen** Stationspunkt, **keine**
|
||||
Pfadlinie und geht mit **0** in die Kosten; übrig bleibt allein, dass er nicht
|
||||
zurücktritt — und das tut er per D46-Nachtrag ohnehin nie. Für den fertigen
|
||||
Knoten **selbst** war der Unterschied zwischen beiden Schwellen also exakt
|
||||
null. Er lag einzig darin, ob der Pfad **in eine fertige Zugabe hineinschaut**
|
||||
und dort liegen gebliebene offene Kinder als Station zeigt. Auch das entfällt
|
||||
jetzt, und zwar mit einem eigenen Argument aus §3: Wer unter einem `+`-Knoten
|
||||
hängt, ist mit ihm zusammen entbehrlich — der Autor hat `[x]` geschrieben, ein
|
||||
offener Rest darunter ist Buchhaltung, keine offene Front.
|
||||
|
||||
**Ehrlich zu benennen ist der Einwand gegen die ganze Regel:** Streng „am
|
||||
günstigsten" wäre es, die angefangene Zugabe **abzubrechen** — Restkosten
|
||||
gespart. Der Pfad zeigt seit D46 aber die offene Front, nicht das theoretische
|
||||
Optimum. Und der Rückweg steht in der Notation schon: Wer die Zugabe wirklich
|
||||
fallen lässt, schreibt `[-]`, und Verworfenes zählt nie.
|
||||
|
||||
**Dabei gefunden: dieselbe Lücke bei Alternativen — und die SPEC hatte recht,
|
||||
der Code nicht.** §9 sagt seit D46 wörtlich: „Eine bereits realisierte
|
||||
Alternative gewinnt, auch wenn eine unangetastete nominell billiger wäre — die
|
||||
Wahl ist getroffen und bezahlt." Umgesetzt war das aber nur **über die
|
||||
Kosten**, und die sind allein bei `[x]`/`[^]` null. Nachgemessen an
|
||||
`= [~] A (L)` / `= [ ] B (S)`: Der Pfad wählte **B** und blasste das
|
||||
angefangene A aus — das Bild widersprach damit der XOR-Regel des Plans, die
|
||||
gerade sagt, dass A die realisierte Alternative ist. Also kein neues Feature,
|
||||
sondern die fehlende Hälfte der Umsetzung: `chosenPool(kids)` schränkt die
|
||||
Wahlmenge auf die realisierten Alternativen ein, sobald es welche gibt; die
|
||||
Kostenregel (kleinste rekursive Kosten, Gleichstand ⇒ erste) gilt darin
|
||||
unverändert.
|
||||
|
||||
**Mehrere realisierte Alternativen** sind in einer `=`-Gruppe schon per
|
||||
`xorConflict` gemeldet, in einer `|`-Gruppe („mindestens eine") aber zulässig.
|
||||
Dort entscheiden unter ihnen wieder die Kosten. Erwogen und **aufgeschoben**:
|
||||
alle realisierten gemeinsam auf den Pfad zu nehmen. Das wäre ein größerer
|
||||
Eingriff — eine any-of-Gruppe trüge dann nicht mehr genau eine Alternative —,
|
||||
und die gewählte Lesart ist für sich verteidigbar: `|` erlaubt das Fallenlassen,
|
||||
also ist „die billigere der begonnenen fertigstellen" ein gültiger günstigster
|
||||
Weg.
|
||||
|
||||
**Nebengewinn bei der Suche (D42):** Eine Gruppe mit genau einer realisierten
|
||||
Alternative ist entschieden und damit **keine freie Variable** mehr — sie
|
||||
koppelt nicht und geht nicht in den Odometer ein. Die erschöpfende Suche wird
|
||||
dadurch kleiner, nie größer.
|
||||
|
||||
**Nachgemessen.** Der gemeldete Baum: `#fe.rel` ist jetzt die Station, `#fe`
|
||||
liegt auf dem Pfad ohne Punkt, `#fe.more` bleibt blass. Eine fertige Zugabe
|
||||
mit offenem Kind bleibt samt Kind draußen. `= [~] A (L)` schlägt
|
||||
`= [ ] B (S)`. Der **mitgelieferte Plan ändert sich nicht** (131 Pfadknoten,
|
||||
27 Stationen, vorher wie nachher) — er hat keine angefangene Zugabe, und seine
|
||||
einzige Gruppe mit realisierten Alternativen trägt zwei `[^]`, die schon
|
||||
vorher beide 0 kosteten.
|
||||
|
||||
346 Tests, davon 10 neue. Gegenprobe: Nimmt man die Zugaben-Ausnahme wieder
|
||||
heraus, fallen genau die fünf danach benannten Zusicherungen; nimmt man
|
||||
`chosenPool` heraus, genau die zwei zu den Alternativen. Die Tests, die das
|
||||
**unveränderte** Verhalten festhalten (unangetastete und erledigte Zugaben
|
||||
bleiben draußen), bleiben in beiden Fällen grün.
|
||||
|
||||
+15
-4
@@ -545,10 +545,21 @@ werden die für die günstigste Realisierung **nötigen** Knoten:
|
||||
- **any of:** nur die **günstigste** Alternative ist nötig. „Günstig" =
|
||||
kleinste rekursive Kosten (eigene T-Shirt-Größe plus — je Gate — Summe bzw.
|
||||
Minimum der Kinder). Bei Gleichstand gewinnt die **erste** Alternative.
|
||||
- **Optionale Knoten (`+`, §3) sind nie nötig** — sie zählen weder zu den
|
||||
Kosten ihres Elternknotens noch liegen sie auf dem Pfad, und der Teilbaum
|
||||
unter ihnen ebenso wenig. Genau dafür gibt es das Zeichen: Ohne `+` rechnet
|
||||
der günstigste Pfad jede Zugabe ins Minimum ein und überschätzt es.
|
||||
**Ist in der Gruppe etwas realisiert** (§3: `[~]`, `[/]`, `[x]`, `[^]`), ist
|
||||
die Wahl damit getroffen — gewählt wird nur noch unter den realisierten
|
||||
Alternativen, auch wenn eine unangetastete nominell billiger wäre. Sind es
|
||||
mehrere (in einer `=`-Gruppe schon per `xorConflict` gemeldet, in einer
|
||||
`|`-Gruppe zulässig), entscheidet unter ihnen wieder die Kostenregel.
|
||||
- **Optionale Knoten (`+`, §3) sind nur nötig, solange an ihnen gearbeitet
|
||||
wird** — also wenn sie realisiert (§3), aber noch nicht erledigt sind:
|
||||
`[~]` und `[/]`. Sonst zählen sie weder zu den Kosten ihres Elternknotens
|
||||
noch liegen sie auf dem Pfad, und der Teilbaum unter ihnen ebenso wenig.
|
||||
Genau dafür gibt es das Zeichen: Ohne `+` rechnet der günstigste Pfad jede
|
||||
Zugabe ins Minimum ein und überschätzt es. Die Ausnahme hält den umgekehrten
|
||||
Fehler heraus — eine angefangene Zugabe ist offene Arbeit, und der Pfad
|
||||
zeigt die offene Front. **Erledigte Zugaben bleiben draußen:** Dort ist
|
||||
nichts mehr zu tun, und was darunter offen blieb, ist mit ihnen zusammen
|
||||
entbehrlich (§3). Siehe D61.
|
||||
- Verworfene Knoten zählen nie mit (unabhängig vom „verworfene einblenden"-
|
||||
Filter).
|
||||
- **Fehlende Größe wird als `M` gewertet** (nur für diese Kostenschätzung; die
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
- [^] #ed.path: Cheapest path (M)
|
||||
- [^] #ed.path.cost: Cost model, missing size counts as M (S)
|
||||
- [^] #ed.path.front: Only the open front: what is done costs nothing (S) %% see D46
|
||||
- [x] #ed.path.started: Started work is on the path, extras included (S) %% see D61
|
||||
- [^] #ed.path.line: Metro-map line through the leaves (S)
|
||||
- [^] #ed.path.step: Step from station to station, one button (S) %% see D47
|
||||
- [^] #ed.closure: Count the whole dependency closure (M)
|
||||
@@ -385,6 +386,11 @@
|
||||
what the plan would have cost from scratch. An alternative already built
|
||||
therefore wins its group even against a cheaper untouched one.
|
||||
|
||||
#ed.path.started
|
||||
An extra (`+`) joins the path while it is being worked on, and a started
|
||||
alternative wins its group. Optionality says the plan can do without it;
|
||||
the status says work has begun, and the front is made of exactly that.
|
||||
|
||||
#ed.path.line
|
||||
A dashed curve threads through the open leaves of the path, with a pale
|
||||
station dot at each. Borrowed from metro maps: the dot is large and faint so
|
||||
|
||||
Reference in New Issue
Block a user