MCP update_item löscht still den checklist-Render-Hint eines Containers (Datenverlust, vorbestehend) #9
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
mcp updateItemToolbefülltpatch.Rendernie aus dem bestehenden Item. Jedermcp__projax__update_item-Aufruf schreibt das Item also mit leerem Render-Hint zurück — dermetadata.projax.render = "checklist"-Hint eines Containers geht dabei still verloren, auch wenn der Aufruf mit dem Feld überhaupt nichts zu tun hatte (z.B. nurstatussetzen).Gefunden von
apollobeim Umsetzen von #7 (aliases-Write-Path). Nicht dort verursacht — vorbestehend. apollo hat es sauber gemeldet statt es nebenbei mitzufixen, weil es außerhalb des #7-Scopes lag. Richtige Entscheidung.Warum das zählt
Der Checklist-Render-Modus ist Q1 aus dem Phase-7-Entity-Model: m hat sich bewusst gegen einen eigenen
tasklist-Typ und für genau diesen einen Hint entschieden (docs/plans/phase-7-entity-model.md, "ONE container concept + metadata.projax.render=checklist"). Der Hint IST das Feature. Einupdate_itemüber MCP macht aus einer Checkliste also wieder eine gewöhnliche Liste — lautlos, ohne Fehler, ohne dass jemand es merkt, bis m die Seite ansieht.Das ist dieselbe Klasse wie #8: stiller Datenverlust auf einem Write-Pfad, der Erfolg meldet.
Fix
updateItemToolmusspatch.Renderaus dem geladenen Item vorbelegen, bevor es den Patch anwendet — so wie es das mit den anderen erhaltenswerten Feldern tut. Partial-Update heißt: was nicht mitgeschickt wird, bleibt stehen.Beim Aufräumen mitprüfen, ob weitere Felder dieselbe Lücke haben — das Muster "Feld wird beim Partial-Update nicht vorbelegt und damit genullt" ist selten ein Einzelfall. Ein Test, der ein Item mit gesetztem Render-Hint über
update_itemnur imstatusändert und danach den Hint noch vorfindet, pinnt das dauerhaft fest.Refs
docs/plans/phase-7-entity-model.md§Q1 — warum der Hint existiertGefixt — und es war kein Einzelfall
Commit:
a48ef4396aBranch:
mai/hades/issue-9-mcp-update-itemDer gemeldete Bug stimmt exakt wie beschrieben.
store.UpdateInputist full-replace — jedes Feld, das ein Caller nicht aus dem geladenen Item vorbelegt, wird beim Write genullt. Der Auftrag "prüf mit, ob weitere Felder dieselbe Lücke haben" war berechtigt: drei Call-Sites, dasselbe Muster.Was gefunden wurde
mcp/tools.goupdateItemToolRender,StartTime,EndTimeweb/bulk.goupdateInputFromItemRenderweb/server.gohandleDetailWriteStartTime,EndTimeweb/bulk.goist der interessante Fund: die Funktion projiziertStartTime/EndTimesauber durch, aberRenderwurde beim Phase-7-Anbau schlicht vergessen. Ein Bulk-Tag- oder -Status-Update über/admin/bulkhat den Checklist-Hint also genauso still gelöscht wie MCP — derselbe Datenverlust, zweiter Pfad, unabhängig davon ob MCP je aufgerufen wird.Live vs. latent — ehrlich getrennt
Renderist echter, aktiver Datenverlust. Die Web-Edit-Form setzt den Hint (web/server.go:775, Checkboxrender_checklist), also existiert er real inmetadata.projax.renderund beide Write-Pfade haben ihn gefressen.StartTime/EndTimesind heute latent. Kein projax-Pfad setzt sie derzeit (die Create-Pfade führen sie nicht), also ist praktisch überallnil— es ging bisher nichts kaputt. Aber: der mBrian-Reader entpackt sie ausmetadata.projax.start_time, undtimePtrToJSON(nil)→null→ der PATCH-Shallow-Merge löscht sie. Sobald irgendwas außerhalb projax einen Anchor setzt, ist es exakt derselbe Bug. Als Klasse mitgefixt statt als nächste Instanz stehen zu lassen.Zusätzlicher Fund: der Hint war über MCP unsichtbar
itemViewhatte gar keinrender-Feld —get_item/update_itemhaben den Hint nie zurückgegeben. Kein MCP-Client konnte also sehen, ob ein Container eine Checkliste ist, geschweige denn merken, dass der Hint verschwindet. Das erklärt mit, warum der Bug so lange still bleiben konnte. Jetzt wirdrenderim View emittiert — read-only, die Web-Form bleibt der einzige Writer.Tests
Die DB-Tests (
mustDBServer) laufen gegen den Legacy-*store.Store, der fürRenderkeine Spalte hat und das Feld wegwirft — sie können diesen Bug prinzipiell nicht fangen. Deshalb einfakeStore(in-memory Reader+Writer), der den an den Writer übergebenenstore.UpdateInputmitschreibt. Der pinnt den Contract auf der Ebene, die ihn tatsächlich besitzt, und läuft ohne DB.TestUpdateItem_PreservesRenderHint— genau der geforderte Test: nurstatusändern, Hint muss stehen bleibenTestUpdateItem_PreservesUnsentFields— die ganze Klasse (Render/Start/End + Titel/Tags/Aliases/Public/…)TestUpdateItem_ReportsRenderHint— Gegenrichtung: Preserve darf nicht Erfinden werden (ein Item ohne Hint bekommt keinen)TestGetItem_ExposesRenderHint— Read-Seite bleibt ehrlichGegen den ungefixten Code verifiziert — alle Assertions schlagen fehl (
got "", want "checklist";StartTime: got <nil>). Ein Regressionstest, der auch ohne Fix grün ist, pinnt nichts.Testlage
go build ./...undgo vetsauber,mcp/grün. Vorbestehende Failures inweb/(9),store/(3) unddb/(1) sind unverändert — vor und nach dem Change identisch, pergit stashgegengeprüft. Nicht von mir und nicht von mir angefasst.Eine offene Frage für m
renderist jetzt preserve-only + read-only über MCP — die Web-Checkbox bleibt der einzige Writer. Obupdate_itemden Hint auch setzen können soll, ist eine Design-Entscheidung (Q1-Territorium), keine Bug-Fix-Frage — deshalb nicht eigenmächtig entschieden. Sag Bescheid, falls gewünscht; ist ein Einzeiler plus Schema-Feld.Nachtrag zur Meldung: apollo hat richtig gehandelt, den Fund aus #7 rauszuhalten. Der Fix hier berührt drei Dateien und zwei Pfade, die mit Aliases nichts zu tun haben — als Beifang in #7 wäre genau der
web/bulk.go-Fund untergegangen.