From e11759447b1ac00becfb1e979e488f7f9c9cf478 Mon Sep 17 00:00:00 2001
From: soryu <soryu@soryu.co>
Date: Fri, 1 May 2026 23:56:51 +0100
Subject: chore(cleanup): Phase 5 contracts removal + tmp directive + 30-day
 expiry + scroll fix (#118)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Sweeping cleanup across the surface and the wire. Net: -14k LOC of legacy
contracts code, plus the tmp/scroll/UX fixes the user asked for.

## Sidebar/editor independent scroll
Replace `height: calc(100vh - 80px)` (which assumed an 80px masthead and
quietly clipped or pushed the whole page below the fold when the masthead
was taller) with `h-screen + overflow-hidden` on the page root and proper
`flex-1 min-h-0` sizing on `<main>`. Sidebar and editor pane now manage
their own scroll independently; the page itself never scrolls.

Same fix in /tmp/:taskId.

## tmp directive — real backing for orphans/ephemerals

New migration `20260501100000_tmp_directive_and_clear_orphans.sql`:
  * Adds `directives.is_tmp` BOOLEAN NOT NULL DEFAULT false.
  * Partial unique index `(owner_id) WHERE is_tmp` — at most ONE tmp
    directive per owner.
  * Hard-deletes every existing orphan task (`directive_id IS NULL`).
    Per the user spec: "ALSO there are TOO MANY old tasks in tmp, we
    need to remove all of them as well."

New repository helpers:
  * `get_or_create_tmp_directive(pool, owner_id) -> Directive`
    INSERT ON CONFLICT DO NOTHING + fallback SELECT, race-safe.
  * `list_all_tmp_directives` — drives the expiry sweep.
  * `delete_expired_tmp_tasks(tmp_directive_id) -> u64`.
  * `list_tmp_tasks_for_owner` (replaces `list_orphan_tasks_for_owner`).

`mesh::create_task`: every top-level task must have a directive. If a
caller doesn't supply `directive_id` and isn't a subtask, attach to the
caller's tmp directive (auto-creating it on first use).

`list_directives_for_owner` filters out `is_tmp=true` so the scratchpad
directive doesn't pollute the contract list — surfaced via the sidebar's
`tmp/` folder instead.

## 30-day expiry on tmp tasks

New `phase_tmp_expiry` in the directive reconciler. Throttled to once per
hour: enumerates every tmp directive, calls `delete_expired_tmp_tasks`,
logs the count. The actual delete is `WHERE created_at < NOW() - INTERVAL
'30 days'` and is fast on the existing index. Subtasks die via FK cascade.

## Phase 5 — contracts removed

### Frontend
Deleted entire `/contracts` surface:
  * routes: `contracts.tsx`, `contract-file.tsx`
  * components/contracts: ContractList, ContractDetail, ContractCliInput,
    ContractContextMenu, CommandModePanel, PhaseBadge, PhaseHint,
    PhaseDeliverablesPanel, PhaseProgressBar, QuickActionButtons,
    RepositoryPanel, TaskDerivationPreview
  * (Kept `PhaseConfirmationModal` — used outside the contracts surface
    by `TaskOutput` and `PhaseConfirmationNotification`.)
  * Routes deregistered from `main.tsx`; nav entry removed from
    `NavStrip`.

### Backend handlers
Deleted: `contracts.rs` (2.4k LOC), `contract_chat.rs` (3.2k LOC),
`contract_daemon.rs` (~940 LOC), `contract_discuss.rs` (~590 LOC),
`transcript_analysis.rs` (~690 LOC). All `/api/v1/contracts/*` routes
deregistered. OpenAPI entries dropped. Module declarations removed from
`server/handlers/mod.rs`.

### CLI
Removed `makima contract` and `makima supervisor` subcommands. Deleted
`daemon/cli/contract.rs` and `daemon/cli/supervisor.rs`. Bin dispatch
trimmed (~377 LOC).

### Orchestrator
Removed the contract-spawn path from `phase_execution`
(`spawn_step_contract` and its caller). `directive_steps.contract_type`
now logs a warning and falls through to standalone-task spawn. Column
itself stays — old data still reads, just no longer triggers a
contract+supervisor spawn.

### TUI
`Action::PerformCreateContract` is now a no-op that surfaces a status
message: "Contracts have been removed. Use directives instead." The TUI
form is dead code pending a wider refresh.

## Out of scope (deliberately left)

* Contracts DB tables (`contracts`, `contract_repositories`,
  `contract_chat_history`, `contract_events`, `contract_templates`) are
  retained for historical data + because some peripheral code still
  joins to them in TaskSummary queries.
* `mesh_supervisor` handlers are retained — they aren't only used by
  contracts (some mesh-level supervisor behaviour persists), and the
  cross-cutting cleanup is bigger than this PR.
* `directive_steps.contract_type` column itself isn't dropped; just no
  longer functional.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 .../components/contracts/QuickActionButtons.tsx    | 217 ---------------------
 1 file changed, 217 deletions(-)
 delete mode 100644 makima/frontend/src/components/contracts/QuickActionButtons.tsx

(limited to 'makima/frontend/src/components/contracts/QuickActionButtons.tsx')

diff --git a/makima/frontend/src/components/contracts/QuickActionButtons.tsx b/makima/frontend/src/components/contracts/QuickActionButtons.tsx
deleted file mode 100644
index 4dbb90c..0000000
--- a/makima/frontend/src/components/contracts/QuickActionButtons.tsx
+++ /dev/null
@@ -1,217 +0,0 @@
-import { useCallback } from "react";
-
-export type QuickActionType =
-  | "create_file"
-  | "create_task"
-  | "run_task"
-  | "advance_phase"
-  | "derive_tasks"
-  | "update_file";
-
-export interface QuickAction {
-  type: QuickActionType;
-  label: string;
-  description?: string;
-  data?: Record<string, unknown>;
-}
-
-interface QuickActionButtonsProps {
-  actions: QuickAction[];
-  onAction: (action: QuickAction) => void;
-  loading?: boolean;
-}
-
-const ACTION_ICONS: Record<QuickActionType, string> = {
-  create_file: "[+]",
-  create_task: "[T]",
-  run_task: "[>]",
-  advance_phase: "[→]",
-  derive_tasks: "[≡]",
-  update_file: "[*]",
-};
-
-const ACTION_COLORS: Record<QuickActionType, string> = {
-  create_file: "border-blue-400/30 hover:border-blue-400/60 text-blue-400",
-  create_task: "border-green-400/30 hover:border-green-400/60 text-green-400",
-  run_task: "border-yellow-400/30 hover:border-yellow-400/60 text-yellow-400",
-  advance_phase: "border-purple-400/30 hover:border-purple-400/60 text-purple-400",
-  derive_tasks: "border-cyan-400/30 hover:border-cyan-400/60 text-cyan-400",
-  update_file: "border-orange-400/30 hover:border-orange-400/60 text-orange-400",
-};
-
-export function QuickActionButtons({
-  actions,
-  onAction,
-  loading = false,
-}: QuickActionButtonsProps) {
-  const handleClick = useCallback(
-    (action: QuickAction) => {
-      if (!loading) {
-        onAction(action);
-      }
-    },
-    [onAction, loading]
-  );
-
-  if (actions.length === 0) return null;
-
-  return (
-    <div className="flex flex-wrap gap-2 mt-2">
-      {actions.map((action, index) => (
-        <button
-          key={`${action.type}-${index}`}
-          onClick={() => handleClick(action)}
-          disabled={loading}
-          className={`
-            flex items-center gap-1.5 px-2 py-1
-            font-mono text-[10px] uppercase
-            border transition-colors
-            disabled:opacity-50 disabled:cursor-not-allowed
-            ${ACTION_COLORS[action.type]}
-          `}
-          title={action.description}
-        >
-          <span>{ACTION_ICONS[action.type]}</span>
-          <span>{action.label}</span>
-        </button>
-      ))}
-    </div>
-  );
-}
-
-/**
- * Parse tool call results to extract suggested quick actions.
- * This is used by ContractCliInput to detect actionable results.
- */
-export function parseActionsFromToolCalls(
-  toolCalls: { name: string; success: boolean; message: string }[]
-): QuickAction[] {
-  const actions: QuickAction[] = [];
-
-  for (const tc of toolCalls) {
-    if (!tc.success) continue;
-
-    switch (tc.name) {
-      case "derive_tasks_from_file":
-        // When tasks are parsed, offer to create them
-        if (tc.message.includes("task") || tc.message.includes("Found")) {
-          actions.push({
-            type: "derive_tasks",
-            label: "Review & Create Tasks",
-            description: "Review parsed tasks and create them with chaining",
-          });
-        }
-        break;
-
-      case "process_task_completion":
-        // Check for suggested actions in the result
-        if (tc.message.includes("next task")) {
-          actions.push({
-            type: "run_task",
-            label: "Run Next Task",
-            description: "Continue with the next chained task",
-          });
-        }
-        if (tc.message.includes("advance") || tc.message.includes("phase")) {
-          actions.push({
-            type: "advance_phase",
-            label: "Advance Phase",
-            description: "Move to the next contract phase",
-          });
-        }
-        break;
-
-      case "get_phase_checklist":
-        // When checklist shows missing items, offer to create them
-        if (tc.message.includes("missing") || tc.message.includes("not created")) {
-          actions.push({
-            type: "create_file",
-            label: "Create Missing Files",
-            description: "Create files from recommended templates",
-          });
-        }
-        break;
-
-      case "advance_phase":
-        // After phase transition, suggest creating files
-        actions.push({
-          type: "create_file",
-          label: "Create Phase Files",
-          description: "Create recommended files for this phase",
-        });
-        break;
-    }
-  }
-
-  return actions;
-}
-
-/**
- * Parse LLM response text to detect suggested actions.
- * Used as a fallback when structured action data isn't available.
- */
-export function parseActionsFromText(text: string): QuickAction[] {
-  const actions: QuickAction[] = [];
-  const lower = text.toLowerCase();
-
-  // Detect file creation suggestions
-  if (
-    lower.includes("create a file") ||
-    lower.includes("create the file") ||
-    lower.includes("should i create")
-  ) {
-    actions.push({
-      type: "create_file",
-      label: "Create File",
-      description: "Create the suggested file",
-    });
-  }
-
-  // Detect task creation suggestions
-  if (
-    lower.includes("create tasks") ||
-    lower.includes("create these tasks") ||
-    lower.includes("create chained tasks")
-  ) {
-    actions.push({
-      type: "create_task",
-      label: "Create Tasks",
-      description: "Create the suggested tasks",
-    });
-  }
-
-  // Detect phase advancement suggestions
-  if (
-    lower.includes("advance to") ||
-    lower.includes("ready to move to") ||
-    lower.includes("transition to")
-  ) {
-    const phases = ["specify", "plan", "execute", "review"];
-    for (const phase of phases) {
-      if (lower.includes(phase)) {
-        actions.push({
-          type: "advance_phase",
-          label: `Advance to ${phase.charAt(0).toUpperCase() + phase.slice(1)}`,
-          description: `Move to the ${phase} phase`,
-          data: { phase },
-        });
-        break;
-      }
-    }
-  }
-
-  // Detect run task suggestions
-  if (
-    lower.includes("run the task") ||
-    lower.includes("start the task") ||
-    lower.includes("run task")
-  ) {
-    actions.push({
-      type: "run_task",
-      label: "Run Task",
-      description: "Start the suggested task",
-    });
-  }
-
-  return actions;
-}
-- 
cgit v1.2.3

