diff options
| author | soryu <soryu@soryu.co> | 2026-04-28 21:26:11 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-28 21:26:11 +0100 |
| commit | 5bde7c2d7e099fd9c8b2615602ab1d096bd9b6be (patch) | |
| tree | d605f7c02472f67a88f1c71c9258c1bf0823b44a /makima/src | |
| parent | d1fdfb140cc440664f77a24886172f9976a05a31 (diff) | |
| download | soryu-5bde7c2d7e099fd9c8b2615602ab1d096bd9b6be.tar.gz soryu-5bde7c2d7e099fd9c8b2615602ab1d096bd9b6be.zip | |
revert PRs #93-#98; enforce strict-linear-DAG + mandatory directive verify (#100)
* revert: roll back PRs #93-#98 to pre-Lexical baseline
Reverts the entire chain of directive document UI work and the homepage redesign,
restoring the working tree to the state at 3679ceb (before c8b169d / PR #93).
PRs reverted:
- #93 c8b169d feat: Document UI for directive orchestration with Lexical editor
- #94 d6f01a6 fix: compilation error and warnings already merged via PR #93
- #95 5aa3faf fix: resolve compilation error and warnings in Rust backend
- #97 d513f93 feat: document UI with contract blocks, expandable logs, and interaction controls
- #96 6366941 feat: Redesign homepage with professional PC-98 styling
- #98 d1fdfb1 feat: revert broken directive PRs, re-implement Lexical document orchestrator
The directive Document UI experiments produced fragile output and merge artifacts;
follow-up commits in this PR change orchestration to favor strictly linear DAGs and
add goal/conflict verification so future runs do not require this kind of cleanup.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(directive): strict-linear-DAG planning + mandatory `directive verify`
Tightens directive orchestration so the final PR almost never needs a hand-merge:
1. Planning prompts now strongly bias toward strictly linear DAGs.
Parallel steps are reserved for genuinely independent work (e.g. disjoint
modules); the default for "in doubt" is sequential. Linear chains inherit
each previous step's worktree, so the final merge is typically just a
rebase against the base branch.
2. New CLI command `makima directive verify` does a local in-memory
`git merge-tree` of HEAD against `<remote>/<base>` and exits non-zero
with a list of conflicting files if the PR would not merge cleanly.
Pure-local — no API call, no working-tree mutation.
3. Completion / PR-creation prompts now mandate three pre-push checks:
a. build (`cargo check` and/or `tsc --noEmit`),
b. `makima directive verify --base <base_branch>` must exit 0, and
c. an explicit goal-alignment self-check against the diff.
The orchestrator is told NOT to push, create the PR, or call
`makima directive update` until all three pass. Skipping any of them
is documented as a directive failure.
The combination means that with a linear DAG the final PR-creation task
should almost never see a real conflict — when it does, that is treated as
a planning bug to escalate rather than something to paper over with
`-X theirs`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(frontend): TS errors pre-existing on master
- TaskSlideOutPanel: declare missing `selectedFileDiff` / `selectedFilePath`
state hooks that were referenced everywhere but never created, and
re-balance the JSX so the `<>...</>` fragment in the non-diff branch is
closed (the previous indentation/braces would not parse).
- api.ts: add a `getWorktreeDiff` thin wrapper around `getTaskDiff` so
TaskDetail's per-file click handler type-checks (the per-file slice is a
future improvement; today both return the full task diff).
- WorktreeFilesPanel: remove unused `isClickable` local; the gating already
reads `onFileClick` directly inline.
Run after revert: `npx tsc --noEmit` exits 0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'makima/src')
| -rw-r--r-- | makima/src/bin/makima.rs | 122 | ||||
| -rw-r--r-- | makima/src/daemon/cli/directive.rs | 26 | ||||
| -rw-r--r-- | makima/src/daemon/cli/mod.rs | 7 | ||||
| -rw-r--r-- | makima/src/db/models.rs | 32 | ||||
| -rw-r--r-- | makima/src/db/repository.rs | 85 | ||||
| -rw-r--r-- | makima/src/orchestration/directive.rs | 190 | ||||
| -rw-r--r-- | makima/src/server/mod.rs | 11 |
7 files changed, 317 insertions, 156 deletions
diff --git a/makima/src/bin/makima.rs b/makima/src/bin/makima.rs index c4183f3..df3e8e7 100644 --- a/makima/src/bin/makima.rs +++ b/makima/src/bin/makima.rs @@ -864,6 +864,128 @@ async fn run_directive( let result = client.create_order(&req).await?; println!("{}", serde_json::to_string(&result.0)?); } + DirectiveCommand::Verify(args) => { + run_directive_verify(args).await?; + } + } + + Ok(()) +} + +/// Run `makima directive verify` — checks that the current HEAD merges cleanly +/// into `<remote>/<base>`. Prints a JSON result and exits non-zero on conflict. +/// +/// Implementation uses `git merge-tree --write-tree` (Git ≥ 2.38), which performs +/// the merge in-memory and lists conflicting paths without touching the working +/// tree or creating any commits. +async fn run_directive_verify( + args: makima::daemon::cli::directive::VerifyArgs, +) -> Result<(), Box<dyn std::error::Error + Send + Sync>> { + use std::process::Command; + + fn git(args: &[&str]) -> std::io::Result<std::process::Output> { + Command::new("git").args(args).output() + } + + let head_ref = args.head.as_deref().unwrap_or("HEAD").to_string(); + let base_ref = format!("{}/{}", args.remote, args.base); + + if !args.skip_fetch { + eprintln!("Fetching {} {}...", args.remote, args.base); + let fetch = git(&["fetch", &args.remote, &args.base])?; + if !fetch.status.success() { + return Err(format!( + "git fetch {} {} failed: {}", + args.remote, + args.base, + String::from_utf8_lossy(&fetch.stderr) + ) + .into()); + } + } + + let head_rev = { + let out = git(&["rev-parse", &head_ref])?; + if !out.status.success() { + return Err(format!( + "git rev-parse {} failed: {}", + head_ref, + String::from_utf8_lossy(&out.stderr) + ) + .into()); + } + String::from_utf8_lossy(&out.stdout).trim().to_string() + }; + let base_rev = { + let out = git(&["rev-parse", &base_ref])?; + if !out.status.success() { + return Err(format!( + "git rev-parse {} failed (did you fetch?): {}", + base_ref, + String::from_utf8_lossy(&out.stderr) + ) + .into()); + } + String::from_utf8_lossy(&out.stdout).trim().to_string() + }; + + eprintln!("Verifying merge: {} ({}) <- {} ({})", base_ref, &base_rev[..7.min(base_rev.len())], head_ref, &head_rev[..7.min(head_rev.len())]); + + let merge = Command::new("git") + .args(["merge-tree", "--write-tree", "--name-only", "--no-messages", &base_rev, &head_rev]) + .output()?; + + let stdout = String::from_utf8_lossy(&merge.stdout).to_string(); + let stderr = String::from_utf8_lossy(&merge.stderr).to_string(); + let success = merge.status.success(); + + let conflicting_files: Vec<String> = if success { + Vec::new() + } else { + stdout + .lines() + .skip(1) + .filter(|l| !l.is_empty()) + .map(|l| l.to_string()) + .collect() + }; + + let result = serde_json::json!({ + "ok": success, + "base": base_ref, + "head": head_ref, + "baseSha": base_rev, + "headSha": head_rev, + "conflictingFiles": conflicting_files, + "goal": args.goal, + }); + println!("{}", serde_json::to_string(&result)?); + + if !success { + eprintln!("\n[FAIL] Merge would conflict in {} file(s):", conflicting_files.len()); + for f in &conflicting_files { + eprintln!(" - {}", f); + } + if !stderr.is_empty() { + eprintln!("\ngit stderr:\n{}", stderr); + } + eprintln!( + "\nFix the conflicts before pushing. Typical workflow:\n \ + git fetch {remote} {base}\n \ + git merge {remote}/{base}\n \ + # resolve conflicts, commit, then re-run `makima directive verify`", + remote = args.remote, + base = args.base, + ); + std::process::exit(1); + } + + if let Some(goal) = &args.goal { + eprintln!("\n[OK] No merge conflicts."); + eprintln!("Reminder — directive goal:\n {}\n", goal); + eprintln!("Confirm the diff (`git diff {}...HEAD`) actually delivers this goal before creating the PR.", base_ref); + } else { + eprintln!("[OK] No merge conflicts with {}.", base_ref); } Ok(()) diff --git a/makima/src/daemon/cli/directive.rs b/makima/src/daemon/cli/directive.rs index cc7b224..0f04720 100644 --- a/makima/src/daemon/cli/directive.rs +++ b/makima/src/daemon/cli/directive.rs @@ -177,6 +177,32 @@ pub struct CreateOrderArgs { pub labels: Option<String>, } +/// Arguments for verify command — checks the current worktree can merge into the +/// directive's base branch with no conflicts. Runs entirely locally; no API call. +#[derive(Args, Debug)] +pub struct VerifyArgs { + /// Base branch to attempt merging into (e.g., "master", "main"). + #[arg(long, default_value = "master")] + pub base: String, + + /// Remote name to fetch from (default: "origin"). + #[arg(long, default_value = "origin")] + pub remote: String, + + /// Head ref to verify (default: current HEAD). + #[arg(long)] + pub head: Option<String>, + + /// Skip the `git fetch` step (use already-fetched remote ref). + #[arg(long, default_value = "false")] + pub skip_fetch: bool, + + /// Optional directive goal text. When provided the goal is echoed back as a + /// reminder so the calling orchestrator can self-check goal alignment. + #[arg(long)] + pub goal: Option<String>, +} + /// Arguments for update command. #[derive(Args, Debug)] pub struct UpdateArgs { diff --git a/makima/src/daemon/cli/mod.rs b/makima/src/daemon/cli/mod.rs index af6f885..7affc55 100644 --- a/makima/src/daemon/cli/mod.rs +++ b/makima/src/daemon/cli/mod.rs @@ -255,6 +255,13 @@ pub enum DirectiveCommand { /// Create an order for future work (spike or chore only) CreateOrder(directive::CreateOrderArgs), + + /// Verify the current worktree merges cleanly into the directive's base branch. + /// + /// Mandatory pre-flight before creating or pushing a directive PR — fails + /// with a non-zero exit code (and a list of conflicting files) if the merge + /// would conflict with the base branch. + Verify(directive::VerifyArgs), } impl Cli { diff --git a/makima/src/db/models.rs b/makima/src/db/models.rs index c11150f..97657dc 100644 --- a/makima/src/db/models.rs +++ b/makima/src/db/models.rs @@ -3050,36 +3050,4 @@ pub struct DirectiveOrderGroupListResponse { pub total: i64, } -// ============================================================================= -// User Settings Types -// ============================================================================= - -/// A user setting (feature flag / preference) stored in the database. -#[derive(Debug, Clone, FromRow, Serialize, Deserialize, ToSchema)] -#[serde(rename_all = "camelCase")] -pub struct UserSetting { - pub id: Uuid, - pub owner_id: Uuid, - pub key: String, - #[sqlx(json)] - pub value: serde_json::Value, - pub created_at: DateTime<Utc>, - pub updated_at: DateTime<Utc>, -} - -/// Request to upsert (create or update) a user setting. -#[derive(Debug, Deserialize, ToSchema)] -#[serde(rename_all = "camelCase")] -pub struct UpsertUserSettingRequest { - pub key: String, - pub value: serde_json::Value, -} - -/// Response wrapping a list of user settings. -#[derive(Debug, Serialize, ToSchema)] -#[serde(rename_all = "camelCase")] -pub struct UserSettingsResponse { - pub settings: Vec<UserSetting>, -} - diff --git a/makima/src/db/repository.rs b/makima/src/db/repository.rs index 5a912e4..57e8a78 100644 --- a/makima/src/db/repository.rs +++ b/makima/src/db/repository.rs @@ -6698,88 +6698,3 @@ pub async fn get_available_orders_for_dog_pickup( .await } -// ============================================================================= -// User Settings -// ============================================================================= - -/// Get all settings for a user. -pub async fn get_user_settings( - pool: &PgPool, - owner_id: Uuid, -) -> Result<Vec<UserSetting>, sqlx::Error> { - sqlx::query_as::<_, UserSetting>( - r#" - SELECT id, owner_id, key, value, created_at, updated_at - FROM user_settings - WHERE owner_id = $1 - ORDER BY key ASC - "#, - ) - .bind(owner_id) - .fetch_all(pool) - .await -} - -/// Get a specific setting by key for a user. -pub async fn get_user_setting( - pool: &PgPool, - owner_id: Uuid, - key: &str, -) -> Result<Option<UserSetting>, sqlx::Error> { - sqlx::query_as::<_, UserSetting>( - r#" - SELECT id, owner_id, key, value, created_at, updated_at - FROM user_settings - WHERE owner_id = $1 AND key = $2 - "#, - ) - .bind(owner_id) - .bind(key) - .fetch_optional(pool) - .await -} - -/// Upsert (create or update) a user setting. -pub async fn upsert_user_setting( - pool: &PgPool, - owner_id: Uuid, - key: &str, - value: &serde_json::Value, -) -> Result<UserSetting, sqlx::Error> { - sqlx::query_as::<_, UserSetting>( - r#" - INSERT INTO user_settings (owner_id, key, value) - VALUES ($1, $2, $3) - ON CONFLICT (owner_id, key) DO UPDATE SET - value = EXCLUDED.value, - updated_at = NOW() - RETURNING id, owner_id, key, value, created_at, updated_at - "#, - ) - .bind(owner_id) - .bind(key) - .bind(value) - .fetch_one(pool) - .await -} - -/// Delete a user setting by key. Returns true if a row was deleted. -pub async fn delete_user_setting( - pool: &PgPool, - owner_id: Uuid, - key: &str, -) -> Result<bool, sqlx::Error> { - let result = sqlx::query( - r#" - DELETE FROM user_settings - WHERE owner_id = $1 AND key = $2 - "#, - ) - .bind(owner_id) - .bind(key) - .execute(pool) - .await?; - - Ok(result.rows_affected() > 0) -} - diff --git a/makima/src/orchestration/directive.rs b/makima/src/orchestration/directive.rs index 1e025c8..8b3ae7e 100644 --- a/makima/src/orchestration/directive.rs +++ b/makima/src/orchestration/directive.rs @@ -1604,11 +1604,21 @@ Because of this, you MUST chain steps using dependsOn whenever one step's work b If step B modifies files created/changed by step A, step B MUST list step A in its dependsOn — otherwise step B will start from a blank worktree and won't see step A's changes at all. -Guidelines: -- For sequential work, create a linear chain: step1 → step2 → step3 (each depends on the previous). -- Only omit dependsOn for truly independent steps that can start from a fresh checkout. -- Parallel steps that share no files can omit mutual dependencies, but if they both build on a prior step - they should BOTH list that prior step in dependsOn. +Guidelines (DAG SHAPE — READ CAREFULLY): +- DEFAULT TO STRICTLY LINEAR CHAINS: step1 → step2 → step3 → … each step depends on the previous one. + This is the right shape for almost every directive. A linear chain inherits each previous step's + worktree, so later steps can see and build on earlier work, and the final merge is just a fast-forward + with at most a rebase against the base branch. +- ONLY use parallel steps (same orderIndex, no mutual dependsOn) when the work is GENUINELY independent: + the steps modify completely disjoint files or modules AND neither needs the other's output. + Pure-frontend vs pure-backend work in separate folders is the prototypical example. If you can name + even one shared file or one shared concept, the steps must be sequential. +- WHEN IN DOUBT, MAKE IT SEQUENTIAL. The cost of unnecessary serialization is one extra step run. + The cost of unnecessary parallelism is merge conflicts, lost work, and a final PR that has to be + hand-reconciled — exactly the failure mode this rule exists to prevent. +- A directive with N parallel branches is suspicious; a directive with N+1 sequential steps is the norm. + If you find yourself drawing a diamond (A → {{B, C}} → D), strongly reconsider whether B and C are + actually independent or whether one should follow the other. IMPORTANT: Each step's taskPlan must be self-contained. The executing instance won't have your planning context. @@ -1709,6 +1719,11 @@ Goal: {goal} Steps completed: {step_summary} +NOTE: This directive was planned with the strict-linear-DAG rule, so the step branches +should generally merge cleanly. If a merge produces meaningful conflicts, that is a +signal the plan was wrong, not routine work — prefer asking for help over papering +over conflicts with `-X theirs`. + 1. Clear the old PR URL: ``` makima directive update --pr-url "" @@ -1720,7 +1735,6 @@ git fetch origin NEW_BRANCH="{directive_branch}-v$(date +%s)" git checkout -b "$NEW_BRANCH" origin/{base_branch} {merge_commands} -git push -u origin "$NEW_BRANCH" ``` For each step branch merge above, if a merge fails with conflicts: @@ -1728,7 +1742,47 @@ For each step branch merge above, if a merge fails with conflicts: 2. If that also fails, manually resolve the conflicts, `git add .`, and `git commit --no-edit` 3. Continue with remaining merges -3. Generate a descriptive PR title and create a new PR: +## Step 2.5: MANDATORY pre-push verification + +Before pushing or creating the PR, you MUST run all three of these checks. Skipping any +of them is a directive failure. + +a) Build check — make sure the combined branch compiles: + - Rust backend (if any backend files changed): `cd makima && cargo check` + - Frontend (if any frontend files changed): `cd makima/frontend && npm install && npx tsc --noEmit` + Fix any errors before continuing. Do NOT push broken code. + +b) Merge-conflict check — MANDATORY: +``` +makima directive verify --base {base_branch} +``` + This must exit 0. If it exits non-zero, the branch will not merge cleanly into + `{base_branch}` and the PR is not ready. Resolve by: +``` + git fetch origin {base_branch} + git merge origin/{base_branch} + # resolve any conflicts, then `git add . && git commit --no-edit` + makima directive verify --base {base_branch} +``` + Re-run until verify exits 0. Do NOT push, create a PR, or call `makima directive update` + until verify passes. + +c) Goal-alignment self-check: + Run `git diff origin/{base_branch}...HEAD --stat` and review the file list. Confirm + the diff actually delivers the directive goal: + + {goal} + + If the diff is missing work the goal requires, finish the work or call + `makima directive ask "<question>" --phaseguard` for guidance. Do NOT push a PR that + does not deliver the goal. + +3. Push the branch: +``` +git push -u origin "$NEW_BRANCH" +``` + +4. Generate a descriptive PR title and create a new PR: Based on the steps completed above, generate a descriptive PR title that summarizes the actual changes (not just the directive name "{title}"). The title should: - Be concise (under 72 characters) @@ -1741,13 +1795,13 @@ gh pr create --title "<YOUR_GENERATED_TITLE>" --body "{pr_body}" --head "$NEW_BR ``` Replace <YOUR_GENERATED_TITLE> with the concise descriptive title you generated. -4. Store the new PR URL: +5. Store the new PR URL: ``` makima directive update --pr-url "<URL_FROM_GH_PR_CREATE>" ``` Replace the URL with the actual PR URL from the `gh pr create` output. This step is CRITICAL. -5. Update the directive pr_branch to the new branch name: +6. Update the directive pr_branch to the new branch name: ``` makima directive update --pr-branch "$NEW_BRANCH" ``` @@ -1759,14 +1813,13 @@ The PR is still open. Merge new step branches into the existing PR branch. Steps completed: {step_summary} -Run these commands: +Run these commands to update the branch (note: do NOT push yet — verification comes first): ``` git fetch origin git checkout {directive_branch} git pull origin {directive_branch} git merge origin/{base_branch} --no-edit {merge_commands} -git push origin {directive_branch} ``` Already-merged branches will be a no-op. If a merge fails with conflicts: @@ -1774,6 +1827,33 @@ Already-merged branches will be a no-op. If a merge fails with conflicts: 2. If that also fails, manually resolve the conflicts, `git add .`, and `git commit --no-edit` 3. Continue with remaining merges +## MANDATORY pre-push verification (also applies to PR updates) + +Before `git push`, run all three checks. Skipping any of them is a directive failure. + +a) Build check — Rust: `cd makima && cargo check`. Frontend (if changed): + `cd makima/frontend && npm install && npx tsc --noEmit`. Do NOT push broken code. + +b) Merge-conflict check — MANDATORY: +``` +makima directive verify --base {base_branch} +``` + Must exit 0. If not, merge `origin/{base_branch}` in, resolve, commit, re-verify. + Do NOT push until verify passes. + +c) Goal-alignment self-check — review `git diff origin/{base_branch}...HEAD --stat` + and confirm it still delivers the directive goal: + + {goal} + + If the goal has drifted (e.g., new step branches changed scope), update the PR + description after pushing or call `makima directive ask` for guidance. + +Then push: +``` +git push origin {directive_branch} +``` + If you encounter issues you cannot resolve (e.g., persistent merge conflicts, PR update failures), you can ask for help: makima directive ask "Your question" --phaseguard "#, @@ -1800,17 +1880,65 @@ Goal: {goal} Steps completed: {step_summary} -Run these commands to create a combined branch and PR: +NOTE: This directive was planned with the strict-linear-DAG rule, so the step branches +should generally merge cleanly. If a merge produces meaningful conflicts, that is a +signal the plan was wrong, not routine work — prefer asking for help over papering +over conflicts with `-X theirs`. + +## Step 1: Build the combined branch (do NOT push yet) ``` git fetch origin git checkout -b {directive_branch} origin/{base_branch} {merge_commands} -git push -u origin {directive_branch} ``` -Then generate a descriptive PR title and create the PR: +For each step branch merge, if a merge fails with conflicts: +1. First try: `git merge --abort` then retry with `git merge <the-failing-branch> -X theirs --no-edit` +2. If that also fails, manually resolve the conflicts, `git add .`, and `git commit --no-edit` +3. Continue with remaining merges -Based on the steps completed above, generate a descriptive PR title that summarizes the actual changes (not just the directive name "{title}"). The title should: +## Step 2: MANDATORY pre-push verification + +Before pushing or creating the PR, you MUST run all three of these checks. Skipping any +of them is a directive failure. + +a) Build check — make sure the combined branch compiles: + - Rust backend (if any backend files changed): `cd makima && cargo check` + - Frontend (if any frontend files changed): `cd makima/frontend && npm install && npx tsc --noEmit` + Fix any errors before continuing. Do NOT push broken code. + +b) Merge-conflict check — MANDATORY: +``` +makima directive verify --base {base_branch} +``` + This must exit 0. If it exits non-zero, the branch will not merge cleanly into + `{base_branch}` and the PR is not ready. Resolve by: +``` + git fetch origin {base_branch} + git merge origin/{base_branch} + # resolve any conflicts, then `git add . && git commit --no-edit` + makima directive verify --base {base_branch} +``` + Re-run until verify exits 0. Do NOT push, create a PR, or call `makima directive update` + until verify passes. + +c) Goal-alignment self-check: + Run `git diff origin/{base_branch}...HEAD --stat` and review the file list. Confirm + the diff actually delivers the directive goal: + + {goal} + + If the diff is missing work the goal requires, finish the work or call + `makima directive ask "<question>" --phaseguard` for guidance. Do NOT push a PR that + does not deliver the goal. + +## Step 3: Push and create the PR +``` +git push -u origin {directive_branch} +``` + +Generate a descriptive PR title that summarizes the actual changes (not just the directive +name "{title}"). The title should: - Be concise (under 72 characters) - Describe WHAT was done, not just the project name - Use conventional commit style if appropriate (feat:, fix:, refactor:, etc.) @@ -1821,21 +1949,17 @@ gh pr create --title "<YOUR_GENERATED_TITLE>" --body "{pr_body}" --head {directi ``` Replace <YOUR_GENERATED_TITLE> with the concise descriptive title you generated. -IMPORTANT: After creating the PR, you MUST store the PR URL so the directive system can track it. +## Step 4: Store the PR URL (CRITICAL) + +After creating the PR, you MUST store the PR URL so the directive system can track it. -1. Run `gh pr create` as shown above and capture its output -2. The output will contain the PR URL (e.g., https://github.com/owner/repo/pull/123) -3. Then run this command to store the URL: +1. The `gh pr create` output contains the PR URL (e.g., https://github.com/owner/repo/pull/123) +2. Run: ``` makima directive update --pr-url "https://github.com/..." ``` Replace the URL with the actual PR URL from the `gh pr create` output. This step is CRITICAL — the PR will not be tracked by the directive system without it. -For each step branch merge, if a merge fails with conflicts: -1. First try: `git merge --abort` then retry with `git merge <the-failing-branch> -X theirs --no-edit` -2. If that also fails, manually resolve the conflicts, `git add .`, and `git commit --no-edit` -3. Continue with remaining merges - If you encounter issues you cannot resolve (e.g., persistent merge conflicts, PR creation failures), you can ask for help: makima directive ask "Your question" --phaseguard "#, @@ -2195,11 +2319,19 @@ Because of this, you MUST chain steps using dependsOn whenever one step's work b If step B modifies files created/changed by step A, step B MUST list step A in its dependsOn — otherwise step B will start from a blank worktree and won't see step A's changes at all. -Guidelines: -- For sequential work, create a linear chain: step1 → step2 → step3 (each depends on the previous). -- Only omit dependsOn for truly independent steps that can start from a fresh checkout. -- Parallel steps that share no files can omit mutual dependencies, but if they both build on a prior step - they should BOTH list that prior step in dependsOn. +Guidelines (DAG SHAPE — READ CAREFULLY): +- DEFAULT TO STRICTLY LINEAR CHAINS: step1 → step2 → step3 → … each step depends on the previous one. + This is the right shape for almost every directive. A linear chain inherits each previous step's + worktree, so later steps can see and build on earlier work, and the final merge is just a fast-forward + with at most a rebase against the base branch. +- ONLY use parallel steps (same orderIndex, no mutual dependsOn) when the work is GENUINELY independent: + the steps modify completely disjoint files or modules AND neither needs the other's output. + Pure-frontend vs pure-backend work in separate folders is the prototypical example. If you can name + even one shared file or one shared concept, the steps must be sequential. +- WHEN IN DOUBT, MAKE IT SEQUENTIAL. The cost of unnecessary serialization is one extra step run. + The cost of unnecessary parallelism is merge conflicts, lost work, and a final PR that has to be + hand-reconciled — exactly the failure mode this rule exists to prevent. +- A directive with N parallel branches is suspicious; a directive with N+1 sequential steps is the norm. IMPORTANT: Each step's taskPlan must be self-contained. The executing instance won't have your planning context. diff --git a/makima/src/server/mod.rs b/makima/src/server/mod.rs index 99dc1f3..b382f04 100644 --- a/makima/src/server/mod.rs +++ b/makima/src/server/mod.rs @@ -281,7 +281,7 @@ pub fn make_router(state: SharedState) -> Router { .route("/timeline", get(history::get_timeline)) // Contract type templates (built-in only) .route("/contract-types", get(templates::list_contract_types)) - // Settings endpoints (static routes first to avoid conflict with /settings/{key}) + // Settings endpoints .route( "/settings/repository-history", get(repository_history::list_repository_history), @@ -294,15 +294,6 @@ pub fn make_router(state: SharedState) -> Router { "/settings/repository-history/{id}", axum::routing::delete(repository_history::delete_repository_history), ) - // User settings (feature flags / preferences) - .route( - "/settings", - get(settings::list_settings).put(settings::upsert_setting), - ) - .route( - "/settings/{key}", - get(settings::get_setting).delete(settings::delete_setting), - ) .with_state(state); let swagger = SwaggerUi::new("/swagger-ui") |
