From fda983e990e4996bbbed1344cdec1e67bbeb18ae Mon Sep 17 00:00:00 2001
From: soryu <soryu@soryu.co>
Date: Fri, 8 May 2026 13:42:51 +0100
Subject: refactor(frontend): DocumentEditor takes explicit
 body/title/documentId props
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Stops shadowing directive.goal with the contract body via a synthesised
directive object. DocumentEditor now accepts:

  * documentId — scopes the localStorage draft key per contract so
    switching contracts under the same directive doesn't clobber the
    other's unsaved edits.
  * title      — the contract title rendered as the H1.
  * body       — the contract body, used to seed the editor.
  * onUpdateBody (was onUpdateGoal)

The `directive` prop stays for orchestrator state + embedded steps
panel. document-directives.tsx drops the directiveAsDocument synthesis
hack and passes body/title from the contract directly.

This is the prep-work for dropping `directives.goal` from the schema —
once nothing reads it, the column can be dropped in a follow-up
without touching the editor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 makima/frontend/src/routes/document-directives.tsx | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

(limited to 'makima/frontend/src/routes/document-directives.tsx')

diff --git a/makima/frontend/src/routes/document-directives.tsx b/makima/frontend/src/routes/document-directives.tsx
index b89e841..63d0b96 100644
--- a/makima/frontend/src/routes/document-directives.tsx
+++ b/makima/frontend/src/routes/document-directives.tsx
@@ -1391,17 +1391,11 @@ function EditorShell({
       );
     }
 
-    // Synthesise a directive-shaped object whose `goal` is the document body.
-    // DocumentEditor was originally written against DirectiveWithSteps, so we
-    // can keep its shape by overriding `goal` with `doc.body` and `title`
-    // with the document's filename label. The steps panel still draws from
-    // the real directive (passed through StepsBlockContextProvider).
+    // The contract title is the filename label; the contract body is the
+    // editor body. DocumentEditor takes these directly (no more synthesis
+    // hack) — `directive` is still passed for orchestrator state and the
+    // embedded steps panel via StepsBlockContextProvider.
     const docTitle = `${fileLabel(doc, directive)}.md`;
-    const directiveAsDocument = {
-      ...directive,
-      goal: doc.body,
-      title: docTitle,
-    };
 
     return (
       <div className="flex-1 flex flex-col h-full overflow-hidden">
@@ -1420,8 +1414,11 @@ function EditorShell({
           // when the user switches documents, so the previous doc's body
           // doesn't bleed into the new one.
           key={doc.id}
-          directive={directiveAsDocument}
-          onUpdateGoal={onUpdateDocumentBody}
+          directive={directive}
+          documentId={doc.id}
+          title={docTitle}
+          body={doc.body}
+          onUpdateBody={onUpdateDocumentBody}
           onCleanup={async () => {
             await cleanup();
           }}
-- 
cgit v1.2.3

