From 6dfb209de4b50a82339f1481bb174c90ebd56f13 Mon Sep 17 00:00:00 2001 From: LLLin000 <809867916@qq.com> Date: Sat, 18 Jul 2026 14:39:37 +0800 Subject: [PATCH] chore: enforce Ask Matt workflow guardrails --- .omp/RULES.md | 11 ++ .omp/hooks/pre/matt-guard.test.ts | 90 +++++++++++++ .omp/hooks/pre/matt-guard.ts | 211 ++++++++++++++++++++++++++++++ PROJECT-MANAGEMENT.md | 25 ++-- 4 files changed, 329 insertions(+), 8 deletions(-) create mode 100644 .omp/RULES.md create mode 100644 .omp/hooks/pre/matt-guard.test.ts create mode 100644 .omp/hooks/pre/matt-guard.ts diff --git a/.omp/RULES.md b/.omp/RULES.md new file mode 100644 index 00000000..fcd849f0 --- /dev/null +++ b/.omp/RULES.md @@ -0,0 +1,11 @@ +# Matt Workflow Guardrails + +- Ask Matt owns the engineering lifecycle: route with `/ask-matt`, implement one agent-ready issue with `/implement`, then run `/review`. Do not introduce a second orchestration workflow. +- One implementation session handles one issue in one authoritative worktree. Start a fresh session before changing issues; use `/handoff` only when context must cross sessions. +- Before editing, pin the issue, parent PRD, issue `updated_at`, base SHA, worktree root, scope, acceptance criteria, and verification commands. If the issue changes, stop and refresh this contract. +- Use one writer. Parallel `task` batches may contain only read-only `scout`, `reviewer`, or `librarian` agents. Never let parallel agents edit shared files or the same worktree. +- Never copy implementation files between the main checkout and a worktree. All reads, writes, tests, reviews, and commits for an issue use its authoritative worktree. +- Follow Matt `/tdd` at pre-agreed seams. Run focused checks while implementing and the issue-specific final gate once after the last mutation; UI work also needs a real-browser smoke test. +- Review exactly once on Matt's two axes. Consolidate findings into one repair pass and one re-review. If an important defect remains, return to the acceptance contract or split the issue; do not create repeated Final/Definitive review loops. +- Commit, merge, push, create/merge a PR, or close an issue only after verification succeeds after the last mutation. Update `PROJECT-MANAGEMENT.md` and the active queue according to project rules before closeout. +- The removed Superpowers workflows are not part of this project. Do not reinstall, invoke, emulate, or delegate through them. diff --git a/.omp/hooks/pre/matt-guard.test.ts b/.omp/hooks/pre/matt-guard.test.ts new file mode 100644 index 00000000..de9a75bc --- /dev/null +++ b/.omp/hooks/pre/matt-guard.test.ts @@ -0,0 +1,90 @@ +import { execFileSync } from "node:child_process"; +import path from "node:path"; +import { describe, expect, test } from "bun:test"; + +import register from "./matt-guard"; + +type Handler = ( + event: Record, + context?: { cwd: string }, +) => unknown | Promise; + +const root = path.resolve(import.meta.dir, "../../.."); + +function handlers() { + const registered: Record = {}; + register({ + on: (event: string, handler: Handler) => { + registered[event] = handler; + }, + } as unknown as Parameters[0]); + return registered; +} + +function foreignWorktree(): string | undefined { + const current = path.normalize(root).toLowerCase(); + return execFileSync("git", ["worktree", "list", "--porcelain"], { + cwd: root, + encoding: "utf8", + }) + .split(/\r?\n/) + .filter((line) => line.startsWith("worktree ")) + .map((line) => path.normalize(line.slice("worktree ".length))) + .find((worktree) => worktree.toLowerCase() !== current); +} + +describe("Matt workflow guard", () => { + test("allows parallel read-only agents and blocks a writer", async () => { + const hook = handlers(); + const context = { cwd: root }; + + expect( + await hook.tool_call( + { + toolName: "task", + input: { tasks: [{ agent: "reviewer" }, { agent: "scout" }] }, + }, + context, + ), + ).toBeUndefined(); + expect( + await hook.tool_call( + { + toolName: "task", + input: { tasks: [{ agent: "reviewer" }, {}] }, + }, + context, + ), + ).toMatchObject({ block: true }); + }); + + test("requires verification after the latest mutation", async () => { + const hook = handlers(); + const context = { cwd: root }; + const commit = { toolName: "bash", input: { command: "git commit --dry-run" } }; + + expect(await hook.tool_call(commit, context)).toMatchObject({ block: true }); + await hook.tool_result({ + toolName: "bash", + input: { command: "npm test" }, + isError: false, + details: { exitCode: 0 }, + }); + expect(await hook.tool_call(commit, context)).toBeUndefined(); + + await hook.tool_call({ toolName: "edit", input: "mutation" }, context); + expect(await hook.tool_call(commit, context)).toMatchObject({ block: true }); + }); + + test.skipIf(!foreignWorktree())("blocks writes into another linked worktree", async () => { + const hook = handlers(); + const target = path.join(foreignWorktree()!, "CONTEXT.md"); + + expect( + await hook.tool_call( + { toolName: "write", input: { path: target } }, + { cwd: root }, + ), + ).toMatchObject({ block: true }); + }); +}); diff --git a/.omp/hooks/pre/matt-guard.ts b/.omp/hooks/pre/matt-guard.ts new file mode 100644 index 00000000..7e156b75 --- /dev/null +++ b/.omp/hooks/pre/matt-guard.ts @@ -0,0 +1,211 @@ +import { execFileSync } from "node:child_process"; +import path from "node:path"; +import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent"; + +const READ_ONLY_AGENTS: Record = { + scout: true, + reviewer: true, + librarian: true, +}; +const RELEASE_COMMAND = + /\bgit(?:\.exe)?\b[^\r\n;&|]*\b(?:commit|merge|push)\b|\bgh(?:\.exe)?\s+(?:issue\s+close|pr\s+(?:create|merge))\b/i; +const VERIFICATION_COMMAND = + /\b(?:pytest|unittest|vitest|jest|ruff|mypy|pyright|tsc)\b|\b(?:npm|pnpm|yarn|bun)\s+(?:test|run\s+(?:test|typecheck|build|lint))\b|\bcargo\s+(?:test|check)\b|\bgo\s+test\b|\bdotnet\s+test\b/i; +const URI = /^[a-z][a-z0-9+.-]*:\/\//i; + +interface GuardState { + verifiedAfterMutation: boolean; +} + +function record(value: unknown): Record { + return value && typeof value === "object" + ? (value as Record) + : {}; +} + +function json(value: unknown): Record { + try { + return record(JSON.parse(String(value ?? ""))); + } catch { + return {}; + } +} + +function runGit(cwd: string, args: string[]): string { + try { + return execFileSync("git", args, { + cwd, + encoding: "utf8", + windowsHide: true, + stdio: ["ignore", "pipe", "ignore"], + }).trim(); + } catch { + return ""; + } +} + +function normalized(value: string): string { + const resolved = path.resolve(value); + return process.platform === "win32" ? resolved.toLowerCase() : resolved; +} + +function isWithin(root: string, candidate: string): boolean { + const relative = path.relative(root, candidate); + return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative)); +} + +function crossesWorktrees(candidate: string, cwd: string): boolean { + if (!candidate || URI.test(candidate)) return false; + + const current = runGit(cwd, ["rev-parse", "--show-toplevel"]); + if (!current) return false; + + const target = normalized(path.resolve(cwd, candidate)); + const currentRoot = normalized(current); + const worktrees = runGit(cwd, ["worktree", "list", "--porcelain"]) + .split(/\r?\n/) + .filter((line) => line.startsWith("worktree ")) + .map((line) => normalized(line.slice("worktree ".length))); + return worktrees.some( + (root) => root !== currentRoot && isWithin(root, target), + ); +} + +function pathsFromCall(toolName: string, input: unknown): string[] { + const fields = record(input); + + if (toolName === "edit") { + const patch = typeof input === "string" ? input : String(fields.input ?? ""); + return [...patch.matchAll(/^\[([^#\r\n]+)#[0-9A-F]{4}\]$/gm)].map( + (match) => match[1], + ); + } + + if (toolName === "ast_edit") { + return Array.isArray(fields.paths) ? fields.paths.map(String) : []; + } + + if (toolName === "lsp") { + return typeof fields.file === "string" ? [fields.file] : []; + } + + if (toolName !== "write") return []; + const target = String(fields.path ?? ""); + if (target === "xd://ast_edit") { + const payload = json(fields.content); + return Array.isArray(payload.paths) ? payload.paths.map(String) : []; + } + if (target === "xd://lsp") { + const payload = json(fields.content); + return typeof payload.file === "string" ? [payload.file] : []; + } + return URI.test(target) ? [] : [target]; +} + +function tasksFromCall(input: unknown): Record[] { + const tasks = record(input).tasks; + return Array.isArray(tasks) ? tasks.map(record) : []; +} + +function hasWriterTask(input: unknown): boolean { + return tasksFromCall(input).some( + (task) => READ_ONLY_AGENTS[String(task.agent ?? "")] !== true, + ); +} + +function isMutatingCall(toolName: string, input: unknown): boolean { + if (toolName === "edit" || toolName === "ast_edit") return true; + if (toolName === "task") return hasWriterTask(input); + if (toolName === "lsp") { + const fields = record(input); + return ( + fields.action === "rename" || + fields.action === "rename_file" || + (fields.action === "code_actions" && fields.apply === true) + ); + } + if (toolName !== "write") return false; + + const fields = record(input); + const target = String(fields.path ?? ""); + if (!URI.test(target)) return true; + if (target === "xd://ast_edit") return true; + if (target !== "xd://lsp") return false; + + const payload = json(fields.content); + return ( + payload.action === "rename" || + payload.action === "rename_file" || + (payload.action === "code_actions" && payload.apply === true) + ); +} + +function releaseAction(toolName: string, input: unknown): boolean { + const fields = record(input); + if (toolName === "bash") return RELEASE_COMMAND.test(String(fields.command ?? "")); + if (toolName === "github") { + return ["pr_create", "pr_push"].includes(String(fields.op ?? "")); + } + if (toolName !== "write" || fields.path !== "xd://github") return false; + return ["pr_create", "pr_push"].includes(String(json(fields.content).op ?? "")); +} + +function successfulVerification(event: Record): boolean { + if (event.toolName !== "bash" || event.isError === true) return false; + const input = record(event.input); + if (!VERIFICATION_COMMAND.test(String(input.command ?? ""))) return false; + + const details = record(event.details); + const exitCode = details.exitCode ?? details.exit_code ?? details.code; + if (typeof exitCode === "number") return exitCode === 0; + + const content = Array.isArray(event.content) ? event.content : []; + const text = content.map((chunk) => String(record(chunk).text ?? "")).join("\n"); + return !/command exited with code\s+[1-9]\d*/i.test(text); +} + +export default function mattGuard(pi: ExtensionAPI): void { + const state: GuardState = { verifiedAfterMutation: false }; + + pi.on("tool_call", async (event, ctx) => { + const toolName = String(event.toolName); + const input = event.input; + + if (toolName === "task") { + const tasks = tasksFromCall(input); + if (tasks.length > 1 && hasWriterTask(input)) { + return { + block: true, + reason: + "Matt guard: parallel task batches may contain only scout, reviewer, or librarian agents. Use one writer.", + }; + } + } + + const crossWorktree = pathsFromCall(toolName, input).find((candidate) => + crossesWorktrees(candidate, ctx.cwd), + ); + if (crossWorktree) { + return { + block: true, + reason: `Matt guard: refusing write into another Git worktree: ${crossWorktree}`, + }; + } + + if (releaseAction(toolName, input) && !state.verifiedAfterMutation) { + return { + block: true, + reason: + "Matt guard: run the issue-specific verification gate after the last mutation before commit, merge, push, PR creation, or issue close.", + }; + } + + if (isMutatingCall(toolName, input)) state.verifiedAfterMutation = false; + }); + + pi.on("tool_result", async (event) => { + if (successfulVerification(event as unknown as Record)) { + state.verifiedAfterMutation = true; + } + }); +} diff --git a/PROJECT-MANAGEMENT.md b/PROJECT-MANAGEMENT.md index 54a22a13..98d567db 100644 --- a/PROJECT-MANAGEMENT.md +++ b/PROJECT-MANAGEMENT.md @@ -1,13 +1,13 @@ -> **Branch:** `feat/ocr-rebuild-ux` | **Last Updated:** 2026-07-15 -> **Active work:** [Control-center PRD #74](https://github.com/LLLin000/PaperForge/issues/74) is split into eight dependency-linked implementation issues (#75–#82). Canonical setup/config migration (#75) and the Installation/Help capability tracer (#76) are implemented; Managed Runtime lifecycle (#77) is the next production slice. +> **Branch:** `master` | **Last Updated:** 2026-07-18 +> **Active work:** [Control-center PRD #74](https://github.com/LLLin000/PaperForge/issues/74) is split into eight dependency-linked implementation issues (#75–#82). Setup/config (#75), capability envelopes (#76), and Managed Runtime/navigation (#77) are implemented; Library/OCR/Memory capability tracers (#78) are next. > > --- > -> **Current state:** Retrieval recovery is merged and live. OCR multi-key rebuild/redo streams progress and refreshes canonical maintenance state. The control plane now has schema-v1 capability envelopes from Python through the Obsidian settings surface: Installation and Help use real probes, stale/malformed cached evidence fails closed, and Library/OCR/Memory/Maintenance remain explicit placeholders for later tracers. +> **Current state:** Retrieval recovery is merged and live. OCR multi-key rebuild/redo streams progress and refreshes canonical maintenance state. The control plane now includes schema-v1 capability envelopes plus a machine-local Managed Runtime with immutable slots, atomic activation, rollback, cancellation, and managed-first command dispatch. > -> #71/#72 prototypes and #73 migration contract are complete. PRD #74 defines the six-module production program; #75 and #76 are implemented. The approved navigation refinement preserves the Wayfinder overview and stages `概览 / 模块详情 / 维护 / 帮助` across #77/#78/#80 instead of creating dead placeholder detail pages. +> #71/#72 prototypes and #73 migration contract are complete. PRD #74 defines the six-module production program; #75–#77 are implemented. The Wayfinder overview and `概览 / 模块详情 / 维护 / 帮助` shell are live; #78 adds real Library/OCR/Memory detail tracers without placeholder pages. > -> Next: implement [#77](https://github.com/LLLin000/PaperForge/issues/77) in a fresh Matt `/implement` session. +> Next: implement [#78](https://github.com/LLLin000/PaperForge/issues/78) in a fresh Matt `/implement` session. ## 1. Architecture ### 1.1 The problem (pre-v2) @@ -60,6 +60,8 @@ raw observations → structural signatures → stable anchors/families → zone | Maintenance regression action model | **19/19 passed** ✅ (per-row canonical action routing, redo confirmation gate, cache manifest preservation) | | Canonical setup/config migration (#75) | **61 passed, 0 failed** ✅ (fresh/v1/v2 config, CLI routing, path forwarding, failure exit, idempotent rerun) | | Installation/Help capability tracer (#76) | **21 backend tests + 169 plugin tests passed; typecheck/build clean; independent review PASS** ✅ | +| Managed Runtime lifecycle + navigation (#77) | **192 focused + 289 full passed; typecheck/build clean** ✅ | +| OMP Matt workflow guard | **Fresh OMP auto-discovery confirmed; 7/7 deterministic guard cases passed** ✅ |

@@ -85,6 +87,8 @@ raw observations → structural signatures → stable anchors/families → zone | **Control-plane contracts** | ✅ Orthogonal capability/activity/attention model and managed-runtime immutable-slot architecture chosen; documented in `docs/research/2026-07-14-capability-state-action-contract.md` and `docs/research/2026-07-14-managed-runtime-architecture.md` | | **Setup/config migration** | ✅ Bare, headless, and modular setup share `SetupPlan`; schema-v2 `vault_config` is authoritative with warned v1 read fallback | | **Capability tracer** | ✅ Installation/Help backend envelopes feed the six-module Overview; malformed/stale persistence fails closed; setup/update actions route to the setup flow | +| **Managed Runtime** | ✅ Immutable machine-local slots, atomic pointer activation, rollback/cancel/retention, managed-first command dispatch | +| **Agent workflow controls** | ✅ `.omp/RULES.md` + `matt-guard.ts` enforce one-writer Matt flow, worktree isolation, and post-mutation verification before release operations | ### 2.3 Fix Status @@ -121,6 +125,7 @@ raw observations → structural signatures → stable anchors/families → zone | 32 | — | OCR rebuild progress + maintenance selection contract | Feature | Added flushed, prefix-separated rebuild/redo streams; full keyed redo; cooperative stop; canonical `needs_derived_rebuild`; All/Recommended filters; selected batch progress UI | `d7b0a527`, `3a516add`, `e556c8ba` | | 33 | — | OCR maintenance canonical per-row action model | Fix | Added `maintenanceActionForRow()` for `display_action`→verb routing, `maintenanceActionRequiresConfirmation()` redo confirmation gate, batch-action filtering by canonical verb, and cache-manifest preservation. Batch actions now follow the canonical backend action instead of raw `can_rebuild`/`can_redo` booleans; destructive redo requires user confirmation; cache refresh preserves the backend manifest. | `d7b0a527` | | 34 | — | Setup/config paths had conflicting precedence, duplicate engines, dropped user paths, and false-success exits | Migration/prefactor | Unified CLI dispatch on `SetupPlan`; v2-only writes with v1 read fallback; complete path forwarding; visible deprecation; non-zero required-step failures | `af849699`, `7b747423`, `906b3caf` | +| 35 | — | Agent sessions could bypass the Matt issue lifecycle, fan out writers, cross worktree boundaries, or release after stale verification | Workflow guard | Added sticky Matt rules plus a project hook that blocks parallel writer batches, cross-worktree mutations, and commit/merge/push/PR/issue-close operations until a recognized verification command succeeds after the latest mutation. | — | ## 3. Remaining Issues — Release-Readiness Layers @@ -150,7 +155,7 @@ raw observations → structural signatures → stable anchors/families → zone [Wayfinder: Restore PaperForge retrieval end to end](https://github.com/LLLin000/PaperForge/issues/45) completed and the resulting retrieval fixes are merged to `master`. The live Literature-hub vault has a healthy 2560-dimensional vec0 index; M and @ search paths are operational. ### Layer 3: Plugin UI -The OCR maintenance slice has a canonical All/Recommended state model, selected batch actions, streaming progress, cooperative stop, and canonical per-row action routing with confirmation gates for destructive operations. Issue #76 now provides the first production capability-envelope tracer: real Installation/Help probes, a six-module Overview, strict persisted-envelope validation, stale fail-closed behavior, and backend-owned actions. Library/OCR/Memory/Maintenance remain explicit placeholders until #78/#80. The approved Wayfinder navigation refinement is recorded on PRD #74 and staged across #77/#78/#80. +The OCR maintenance slice has a canonical All/Recommended state model, selected batch actions, streaming progress, cooperative stop, and canonical per-row action routing with confirmation gates for destructive operations. Issues #76–#77 now provide production capability envelopes, the four-destination navigation shell, and the machine-local Managed Runtime lifecycle. Installation/Help are real probes; Library/OCR/Memory/Maintenance remain explicit placeholders pending #78/#80. Stale or malformed persisted evidence fails closed. ### Layer 4: Downstream Tools `chunker.py` uses hardcoded section regex + fixed 3-paragraph groups. OCR has rich structured output (sections, headings, figures, tables with captions) — chunker should consume this structure directly. Figures/tables should support separate embedding (text + future vision). @@ -158,7 +163,7 @@ The OCR maintenance slice has a canonical All/Recommended state model, selected Remaining legacy OCR issues (carried forward): ## 4. Active Queue -1. 🔴 **[Control-center PRD #74](https://github.com/LLLin000/PaperForge/issues/74)** — published and split into eight native dependency-linked issues (#75–#82). #75 and #76 are implemented; #77 Managed Runtime lifecycle is the next unblocked production tracer. +1. 🔴 **[Control-center PRD #74](https://github.com/LLLin000/PaperForge/issues/74)** — published and split into eight native dependency-linked issues (#75–#82). #75–#77 are implemented; #78 Library/OCR/Memory capability tracers are the next unblocked slice. 2. ✅ **[Capability-state vocabulary](https://github.com/LLLin000/PaperForge/issues/69)** — resolved at `issuecomment-4971161072`. Orthogonal availability/activity/attention axes, 6-state capability ordinal, 12 canonical verbs, backend-owned severity and primary actions, maintenance projection. 3. ✅ **[Managed runtime](https://github.com/LLLin000/PaperForge/issues/70)** — resolved at `issuecomment-4971239398`. Plugin-managed immutable runtime slots, system-Python bootstrap with validated-triplet fallback, single `active-runtime.json` pointer, `ManagedRuntime` class with `current()`/`status()`/`ensure()`, fail-closed command resolution. 4. ✅ **[Control-center prototype](https://github.com/LLLin000/PaperForge/issues/71)** — resolved with independent Critical/Important PASS review and browser verification at 768px. Six-module control-center HTML prototype covers 5 scenarios with plain-button switcher, primary attention zone, responsive layout, and capability-gated actions. Design decisions recorded in `docs/prototypes/2026-07-14-six-module-control-center.html/.md`. No production implementation before #73. @@ -184,7 +189,8 @@ Remaining legacy OCR issues (carried forward): - [x] Publish PRD #74 and eight agent-ready issues (#75–#82) with native dependencies - [x] Canonicalize setup/config migration ([#75](https://github.com/LLLin000/PaperForge/issues/75)) — 61 focused tests; spec PASS; quality APPROVED - [x] Implement Installation/Help capability tracer ([#76](https://github.com/LLLin000/PaperForge/issues/76)) — 21 backend tests; 169 plugin tests; typecheck/build clean; independent review PASS -- [ ] Implement Managed Runtime lifecycle and the approved Installation-detail navigation shell ([#77](https://github.com/LLLin000/PaperForge/issues/77)) +- [x] Implement Managed Runtime lifecycle and the approved Installation-detail navigation shell ([#77](https://github.com/LLLin000/PaperForge/issues/77)) — 192 focused + 289 full tests; typecheck/build clean; merged to `master` +- [ ] Expose Library, OCR, and Memory capabilities end to end ([#78](https://github.com/LLLin000/PaperForge/issues/78)) --- ## 5. Key File Map @@ -341,6 +347,7 @@ Remaining legacy OCR issues (carried forward): | 2026-07-15 | Canonical setup is one `SetupPlan`; configuration writes converge to schema v2 | Duplicate headless/modular/bare engines dropped path inputs and disagreed on success. One engine plus `vault_config`-first reads makes migration observable, idempotent, and reversible through the warned v1 read fallback. | | 2026-07-15 | Capability integration advances by real tracer, never frontend optimism | #76 exposes only Installation and Help as real probes; Library/OCR/Memory/Maintenance remain explicit placeholders until their backend envelopes ship. Persisted malformed or stale evidence becomes unknown/invalid rather than ready. | | 2026-07-15 | Module detail navigation extends Wayfinder instead of replacing it | Preserve the primary-attention zone and concrete backend action. Stage `概览 / 模块详情 / 维护 / 帮助` across #77/#78/#80; use explicit module-title navigation, top ordinary buttons, and no dead placeholder details. | +| 2026-07-18 | Enforce Matt with sticky rules plus a minimal deterministic hook | Prose alone cannot prevent orchestration drift. Keep lifecycle guidance in `.omp/RULES.md`; use the hook only for mechanically provable boundaries: one writer, worktree isolation, and verification-after-last-mutation before release operations. | --- @@ -444,6 +451,8 @@ python -m ruff check paperforge/worker/ocr_*.py | 2026-07-15 | Six-module control-center + maintenance inbox prototypes completed | Closed #71 (six-module HTML prototype, 5 scenarios, plain-button switcher, responsive 768px) with independent Critical/Important PASS review and browser verification. Closed #72 (actionable-only inbox, inline issue-draft review, confirmation-first report) with same review gate. Both prototype pairs passed all review dimensions. No production code changed. | `docs/prototypes/2026-07-14-six-module-control-center.{html,md}`, `docs/prototypes/2026-07-14-maintenance-issue-reporting.{html,md}` | | 2026-07-15 | Control-center PRD split + first production slice | Published PRD #74 and eight native dependency-linked issues (#75–#82). Implemented #75: one SetupPlan for all setup entry points, schema-v2 `vault_config`, warned v1 read fallback, complete path forwarding, visible deprecation, and non-zero required-step failures. Verification: 61/61 focused tests; independent Spec PASS / Quality APPROVED. | [PRD #74](https://github.com/LLLin000/PaperForge/issues/74), [Issue #75](https://github.com/LLLin000/PaperForge/issues/75) | | 2026-07-15 | Installation/Help capability tracer + navigation refinement | Implemented schema-v1 probe envelopes, six-module Overview, setup-complete migration, strict persistence/TTL validation, backend-owned action labels and dispatch, responsive/focus-visible UI, and generated bundle. Verification: 21 backend tests, 169 plugin tests, typecheck/build, live Obsidian stale-cache/action-label smoke test, independent review PASS. Matt flow refined PRD #74 and existing #77/#78/#80 without duplicating issues. | [Issue #76](https://github.com/LLLin000/PaperForge/issues/76), [PRD refinement](https://github.com/LLLin000/PaperForge/issues/74#issuecomment-4980322098) | +| 2026-07-15 | Managed Runtime lifecycle + final navigation shell | Completed #77 with immutable runtime slots, synchronous fail-closed `current`, probed `status`, install/repair/update/rollback/cancel/retention, managed-first dispatch, Release-N fallback, four-destination navigation, Installation detail, Agent integration, and Help focus restoration. Verification: 192 focused + 289 full tests; typecheck/build clean. Merged to `master` in `173a4e8..4ef9e98`. | [Issue #77](https://github.com/LLLin000/PaperForge/issues/77) | +| 2026-07-18 | OMP Matt workflow enforcement | Removed all discoverable Superpowers installations, retained canonical Ask Matt skills, added sticky project rules, and installed an auto-discovered hook for one-writer batches, worktree isolation, and fresh verification gates. Fresh OMP smoke reached the hook; 7/7 deterministic guard cases passed. | `.omp/RULES.md`, `.omp/hooks/pre/matt-guard.ts` | ## 9. Historical Detail Archive