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>
---
 .../src/components/contracts/CommandModePanel.tsx  | 272 ---------------------
 1 file changed, 272 deletions(-)
 delete mode 100644 makima/frontend/src/components/contracts/CommandModePanel.tsx

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

diff --git a/makima/frontend/src/components/contracts/CommandModePanel.tsx b/makima/frontend/src/components/contracts/CommandModePanel.tsx
deleted file mode 100644
index b39b309..0000000
--- a/makima/frontend/src/components/contracts/CommandModePanel.tsx
+++ /dev/null
@@ -1,272 +0,0 @@
-import { useState, useCallback } from "react";
-import { useNavigate } from "react-router";
-import type { ContractWithRelations } from "../../lib/api";
-import {
-  getSupervisorStatus,
-  startSupervisor,
-  stopSupervisor,
-  resumeSupervisor,
-  updateContract,
-  type SupervisorStatus,
-} from "../../lib/api";
-
-interface CommandModePanelProps {
-  contract: ContractWithRelations;
-  onUpdate: () => void;
-}
-
-const statusConfig: Record<
-  SupervisorStatus["status"],
-  { label: string; color: string; bgColor: string }
-> = {
-  not_configured: {
-    label: "Not Configured",
-    color: "text-[#555]",
-    bgColor: "bg-[#555]/10",
-  },
-  pending: {
-    label: "Ready",
-    color: "text-yellow-400",
-    bgColor: "bg-yellow-400/10",
-  },
-  starting: {
-    label: "Starting...",
-    color: "text-blue-400",
-    bgColor: "bg-blue-400/10",
-  },
-  running: {
-    label: "Running",
-    color: "text-green-400",
-    bgColor: "bg-green-400/10",
-  },
-  paused: {
-    label: "Paused",
-    color: "text-orange-400",
-    bgColor: "bg-orange-400/10",
-  },
-  done: {
-    label: "Completed",
-    color: "text-blue-400",
-    bgColor: "bg-blue-400/10",
-  },
-  failed: {
-    label: "Failed",
-    color: "text-red-400",
-    bgColor: "bg-red-400/10",
-  },
-};
-
-export function CommandModePanel({ contract, onUpdate }: CommandModePanelProps) {
-  const navigate = useNavigate();
-  const [loading, setLoading] = useState(false);
-  const [error, setError] = useState<string | null>(null);
-
-  const supervisorStatus = getSupervisorStatus(contract);
-
-  const handleGoToSupervisor = useCallback(() => {
-    if (supervisorStatus.supervisorTaskId) {
-      navigate(`/exec/${supervisorStatus.supervisorTaskId}`);
-    }
-  }, [supervisorStatus.supervisorTaskId, navigate]);
-  const config = statusConfig[supervisorStatus.status];
-
-  const handleStart = useCallback(async () => {
-    if (!supervisorStatus.supervisorTaskId) return;
-
-    setLoading(true);
-    setError(null);
-
-    try {
-      await startSupervisor(supervisorStatus.supervisorTaskId);
-      onUpdate();
-    } catch (e) {
-      setError(e instanceof Error ? e.message : "Failed to start command mode");
-    } finally {
-      setLoading(false);
-    }
-  }, [supervisorStatus.supervisorTaskId, onUpdate]);
-
-  const handleStop = useCallback(async () => {
-    if (!supervisorStatus.supervisorTaskId) return;
-
-    setLoading(true);
-    setError(null);
-
-    try {
-      await stopSupervisor(supervisorStatus.supervisorTaskId);
-      onUpdate();
-    } catch (e) {
-      setError(e instanceof Error ? e.message : "Failed to stop command mode");
-    } finally {
-      setLoading(false);
-    }
-  }, [supervisorStatus.supervisorTaskId, onUpdate]);
-
-  const handleResume = useCallback(async () => {
-    setLoading(true);
-    setError(null);
-
-    try {
-      await resumeSupervisor(contract.id, { resumeMode: "continue" });
-      // After resuming, we need to start the task
-      if (supervisorStatus.supervisorTaskId) {
-        await startSupervisor(supervisorStatus.supervisorTaskId);
-      }
-      onUpdate();
-    } catch (e) {
-      setError(e instanceof Error ? e.message : "Failed to resume command mode");
-    } finally {
-      setLoading(false);
-    }
-  }, [contract.id, supervisorStatus.supervisorTaskId, onUpdate]);
-
-  const handlePhaseGuardChange = useCallback(async (enabled: boolean) => {
-    setLoading(true);
-    setError(null);
-
-    try {
-      await updateContract(contract.id, {
-        phaseGuard: enabled,
-        version: contract.version,
-      });
-      onUpdate();
-    } catch (e) {
-      setError(e instanceof Error ? e.message : "Failed to update phase guard setting");
-    } finally {
-      setLoading(false);
-    }
-  }, [contract.id, contract.version, onUpdate]);
-
-  return (
-    <div className="space-y-3">
-      <div className="flex items-center justify-between">
-        <h3 className="font-mono text-xs text-[#75aafc] uppercase">
-          Command Mode
-        </h3>
-        <div className="flex items-center gap-2">
-          {supervisorStatus.supervisorTaskId && (
-            <button
-              onClick={handleGoToSupervisor}
-              className="px-2 py-1 font-mono text-xs text-[#9bc3ff] hover:text-[#dbe7ff] hover:bg-[rgba(117,170,252,0.1)] transition-colors flex items-center gap-1"
-            >
-              <span className="text-[#75aafc]">▶</span>
-              Supervisor
-            </button>
-          )}
-          <div
-            className={`px-2 py-1 rounded font-mono text-xs ${config.color} ${config.bgColor}`}
-          >
-            {config.label}
-          </div>
-        </div>
-      </div>
-
-      <p className="font-mono text-xs text-[#555]">
-        {supervisorStatus.status === "not_configured" ? (
-          "This contract does not have a Command Mode supervisor configured."
-        ) : supervisorStatus.status === "running" ? (
-          "Command Mode is actively working on this contract, spawning tasks and managing progress."
-        ) : supervisorStatus.status === "pending" ? (
-          "Command Mode is ready to start. Click 'Enable' to begin autonomous work."
-        ) : supervisorStatus.status === "paused" ? (
-          "Command Mode is paused. Click 'Resume' to continue work."
-        ) : supervisorStatus.status === "failed" ? (
-          "Command Mode encountered an error. You can resume to retry."
-        ) : supervisorStatus.status === "done" ? (
-          "Command Mode has completed its work on this contract."
-        ) : (
-          "Command Mode is initializing..."
-        )}
-      </p>
-
-      {error && (
-        <div className="px-3 py-2 bg-red-500/10 border border-red-400/30 font-mono text-xs text-red-400">
-          {error}
-        </div>
-      )}
-
-      <div className="flex gap-2">
-        {supervisorStatus.canStart && (
-          <button
-            onClick={handleStart}
-            disabled={loading}
-            className="px-4 py-2 font-mono text-xs text-[#dbe7ff] bg-green-600/20 border border-green-400/50 hover:bg-green-600/30 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
-          >
-            {loading ? "Starting..." : "Enable Command Mode"}
-          </button>
-        )}
-
-        {supervisorStatus.canResume && (
-          <button
-            onClick={handleResume}
-            disabled={loading}
-            className="px-4 py-2 font-mono text-xs text-[#dbe7ff] bg-blue-600/20 border border-blue-400/50 hover:bg-blue-600/30 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
-          >
-            {loading ? "Resuming..." : "Resume Command Mode"}
-          </button>
-        )}
-
-        {supervisorStatus.canStop && (
-          <button
-            onClick={handleStop}
-            disabled={loading}
-            className="px-4 py-2 font-mono text-xs text-[#dbe7ff] bg-orange-600/20 border border-orange-400/50 hover:bg-orange-600/30 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
-          >
-            {loading ? "Stopping..." : "Pause Command Mode"}
-          </button>
-        )}
-      </div>
-
-      {/* Phase Guard Toggle */}
-      <div className="pt-3 border-t border-dashed border-[rgba(117,170,252,0.2)]">
-        <label className="flex items-start gap-3 cursor-pointer group">
-          <div className="relative mt-0.5">
-            <input
-              type="checkbox"
-              checked={contract.phaseGuard ?? false}
-              onChange={(e) => handlePhaseGuardChange(e.target.checked)}
-              disabled={loading}
-              className="sr-only peer"
-            />
-            <div className="w-9 h-5 bg-[rgba(117,170,252,0.1)] border border-[rgba(117,170,252,0.3)] rounded-full peer-checked:bg-[rgba(117,170,252,0.3)] transition-colors peer-disabled:opacity-50" />
-            <div className="absolute left-0.5 top-0.5 w-4 h-4 bg-[#555] rounded-full transition-transform peer-checked:translate-x-4 peer-checked:bg-[#75aafc] peer-disabled:opacity-50" />
-          </div>
-          <div className="flex-1">
-            <div className="flex items-center gap-2">
-              <span className="font-mono text-sm text-[#dbe7ff] group-hover:text-white transition-colors">
-                Phase Guard
-              </span>
-              {contract.phaseGuard && (
-                <span className="px-1.5 py-0.5 text-[9px] font-mono uppercase bg-yellow-500/20 text-yellow-400 border border-yellow-400/30 rounded">
-                  active
-                </span>
-              )}
-            </div>
-            <div className="font-mono text-xs text-[#555] mt-0.5">
-              Ask for confirmation before advancing to the next phase
-            </div>
-          </div>
-        </label>
-      </div>
-
-      {/* Show running indicator when active */}
-      {supervisorStatus.status === "running" && (
-        <div className="flex items-center gap-2 pt-2 border-t border-dashed border-[rgba(117,170,252,0.2)]">
-          <div className="w-2 h-2 rounded-full bg-green-400 animate-pulse" />
-          <span className="font-mono text-xs text-green-400">
-            Command Mode is actively working
-          </span>
-        </div>
-      )}
-
-      {supervisorStatus.status === "starting" && (
-        <div className="flex items-center gap-2 pt-2 border-t border-dashed border-[rgba(117,170,252,0.2)]">
-          <div className="w-2 h-2 rounded-full bg-blue-400 animate-pulse" />
-          <span className="font-mono text-xs text-blue-400">
-            Initializing command mode...
-          </span>
-        </div>
-      )}
-    </div>
-  );
-}
-- 
cgit v1.2.3

