diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c10b26..7ad9788 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,15 @@ All notable changes to this project will be documented in this file. ### Changed +* ROADMAP now tracks the `mqobsidian` v0.1.0 single-source-of-truth foundation + as an upstream dependency, while keeping `mqlaunch` read-only or + delegate-only for truth, inbox, ranking, and promotion surfaces. +* Documented the canonical mqobsidian view-manifest keys consumed by `mqlaunch` + and marked that roadmap deliverable done. +* Added a smoke test that locks the MQ Obsidian menu out of memory promotion or + rejection routes, preserving the review-gated ownership boundary. +* Verified the review command delegation boundary through + `tests/mq-agent-routing-smoke.sh` and marked the roadmap item done. * Monolith de-layering (Step 11a): five concerns moved verbatim out of `terminal/launchers/mqlaunch.sh` into dedicated libraries sourced back into the launcher's scope — the network concern (status/diagnostics/connectivity, @@ -33,6 +42,18 @@ All notable changes to this project will be documented in this file. drops ~720 lines and each concern now has a named owner. Guarded by `tests/monolith-delayer-smoke.sh`, a table-driven check that fails if any extracted function is redefined in the monolith or a lib source is dropped. +* `print_header` now has a single owner: `ui/terminal-ui/mq-ui.sh`. The launcher + no longer overrides it; instead it opts the main loop into the dashboard-v7.1 + header via `MQ_USE_DASHBOARD_HEADER=1`. **Behavior change:** the main-loop + header now renders through mq-ui's *cached* dashboard path (bounded by + `MQ_DASHBOARD_CACHE_TTL`, default 5s, and invalidated by the git/release + flows) instead of re-forking the dashboard script uncached on every screen. + This removes a hidden fork in render behavior and aligns the main loop with + the cache and invalidation model the rest of the runtime already used; it also + avoids a dashboard re-fork per screen render. Escape hatch: set + `MQ_DASHBOARD_CACHE_TTL=0` for an uncached, per-screen header while + investigating. The dead `DASHBOARD_V71` launcher variable (only the removed + override used it) is gone. * `semantic-memory-maintainer` renamed to `vector-store-maintainer` to avoid routing collision with mq-mcp's skill of the same name. * `command-template-library` skill moved to mq-ums, where the contracts and diff --git a/ROADMAP.md b/ROADMAP.md index 7c1c245..939e46b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -78,9 +78,9 @@ Goal: make the Obsidian SSOT plan explicit and buildable without expanding | Done | Repo ownership map documented | | Done | `mqlaunch` boundary against direct cognition/memory logic documented | | Done | Existing MQ Obsidian menu kept as read-only/presentation-first surface | -| Todo | Document canonical mqobsidian manifest keys consumed by `mqlaunch` | -| Todo | Add/verify tests that MQ Obsidian menu actions do not promote memory | -| Todo | Add/verify tests that review commands delegate through `mq-agent` | +| Done | Document canonical mqobsidian manifest keys consumed by `mqlaunch` | +| Done | Add/verify tests that MQ Obsidian menu actions do not promote memory | +| Done | Add/verify tests that review commands delegate through `mq-agent` | | Todo | Add `mqlaunch obsidian status` or documented alias for current menu/status | Expected commands: @@ -99,6 +99,10 @@ mqlaunch can show Obsidian readiness and open canonical views, but all scoring, promotion, schema, and cognition logic is owned elsewhere. ``` +Boundary test: `tests/mq-agent-routing-smoke.sh` verifies that review, +risk-review, architecture, repo-health, and mcp-status routes stay delegated +through `mq-agent`. + ## 31-60 Days: Inbox Ranking And Promotion Loop Goal: make repeated Codex/Claude/mqlaunch patterns visible as candidates @@ -181,6 +185,88 @@ The operator can answer "what is true about the MQ stack right now?" from one terminal surface backed by Obsidian truth exports. ``` +## Upstream Dependency: mqobsidian v0.1.0 SSOT Foundation + +`mqobsidian` owns the canonical truth structure for the MQ stack. This repo +depends on that work, but must not implement competing truth, inbox, ranking, +or promotion logic locally. + +Status: Proposed · Priority: P1 · Owner: `mqobsidian` + +Current status: + +* [ ] canonical truth schema is not yet fully locked +* [ ] inbox, ranking, and promotion state are not yet unified under one explicit model +* [ ] consumer repos still risk inventing local truth if exports/contracts stay underdefined +* [ ] moderator workflow risks becoming a bottleneck without clear promotion states and thresholds + +### mqobsidian owns + +* [ ] canonical truth schema +* [ ] inbox structure and promotion queue structure +* [ ] durable memory categories and persistence rules +* [ ] canonical status, views, and manifests consumed by other repos +* [ ] freshness/state markers for truth surfaces +* [ ] promotion state and memory lifecycle states +* [ ] single source of truth rules across the stack + +### macos-scripts relationship + +`mqlaunch` may consume exported status/views/manifests and delegate workflows to +`mq-agent`, but it must not define schema, compute rankings, promote memory, or +invent local lifecycle state. + +Expected consumer contract: + +```text +mqlaunch -> read/open exported truth views +mqlaunch -> delegate inbox/promote workflows to mq-agent +mq-agent -> write/orchestrate through mqobsidian contracts +mqobsidian -> own schema, state, persistence, and durable views +``` + +### Required upstream delivery + +#### A. Canonical schema + +* [ ] define status manifest +* [ ] define inbox manifest +* [ ] define views manifest +* [ ] define learn/review/decision schemas +* [ ] define promotion-state fields +* [ ] define archival/deprecation lifecycle fields + +#### B. Inbox and ranking model + +* [ ] define what enters inbox +* [ ] define recurrence/evidence fields +* [ ] define ranking inputs +* [ ] define review-needed vs auto-promotable states +* [ ] define thresholds and exception paths + +#### C. Durable memory governance + +* [ ] define what qualifies as durable memory +* [ ] define what remains transient or session-local +* [ ] define promotion approvals and guardrails +* [ ] define rollback/deprecation path for bad memory +* [ ] define traceability from source evidence to durable note + +#### D. Consumer contracts + +* [ ] define canonical read surfaces for `mqlaunch` +* [ ] define canonical delegation/contract surfaces for `mq-agent` +* [ ] version exported truth surfaces +* [ ] expose freshness and drift markers + +### Dependency exit criteria + +* [ ] `mqobsidian` is the undisputed truth owner +* [ ] inbox, ranking, promotion, and durable memory have one canonical model +* [ ] consumers read from exported truth surfaces instead of inventing local truth +* [ ] every promoted durable memory item can be traced back to source evidence +* [ ] `mqlaunch` has enough contract detail to stay read-only or delegate-only + ## Phase 12 / v2.0.0 — Runtime Authority And Shell Governance **Status:** Proposed diff --git a/docs/AUTHORITY_MAP.md b/docs/AUTHORITY_MAP.md index 413597a..2d19cf5 100644 --- a/docs/AUTHORITY_MAP.md +++ b/docs/AUTHORITY_MAP.md @@ -60,7 +60,7 @@ Reached through other live paths: | Path | Role | Authority | | --- | --- | --- | -| `ui/terminal-ui/mq-ui.sh` | Shared UI library (rendering, padding, git-status snapshot) | **UI authority** (26 live references) | +| `ui/terminal-ui/mq-ui.sh` | Shared UI library (rendering, padding, git-status snapshot, `print_header`) | **UI authority** (26 live references) — sole owner of `print_header`; the launcher no longer overrides it (Step 11a) | | `ui/ascii/mqlaunch-dashboard-v7.1.sh` | Branded dashboard | **Dashboard authority** | | `ui/dashboards/mq-dashboard.sh` | Status dashboard used by the tools menu / theme manager | secondary, keep until folded into the authority | diff --git a/mqlaunch/docs/mqobsidian-consumer.md b/mqlaunch/docs/mqobsidian-consumer.md index 0f325d4..dd39222 100644 --- a/mqlaunch/docs/mqobsidian-consumer.md +++ b/mqlaunch/docs/mqobsidian-consumer.md @@ -19,6 +19,37 @@ pattern/feedback logic. · `execution` · `mq-agent-hot` · `mq-mcp-hot` · `mq-hal-hot`. Paths are resolved from the manifest, not hardcoded — change the manifest, not the logic. +## Canonical manifest contract + +`mqlaunch` consumes only `mqlaunch/config/mqobsidian/views.json`. The manifest is +an array of view records with these required fields: + +| Field | Allowed values | Consumer behavior | +| --- | --- | --- | +| `key` | stable string identifier | CLI/menu argument; must not be inferred from paths | +| `label` | display string | menu/picker text only | +| `type` | `file` or `folder` | validates whether the target should be a file or folder | +| `relative_path` | vault-relative path | resolved under `MQ_OBSIDIAN_DIR` or the fallback vault | + +Canonical keys currently consumed by `mqlaunch`: + +| Key | Kind | Target | +| --- | --- | --- | +| `dashboard` | file | `systems/mqobsidian/index.md` | +| `roadmaps` | folder | `roadmap` | +| `reviews` | folder | `reviews` | +| `decisions` | folder | `decisions` | +| `execution` | folder | `execution` | +| `mq-agent-hot` | file | `systems/mq-agent/hot.md` | +| `mq-mcp-hot` | file | `systems/mq-mcp/hot.md` | +| `mq-hal-hot` | file | `systems/mq-hal/hot.md` | +| `roadmap-doc` | file | `docs/roadmap-token-reduction.md` | +| `context-budget` | file | `docs/context-budget.md` | + +Ownership rule: adding, removing, renaming, or repointing keys changes the +consumer contract. Keep that change in the manifest and docs; do not duplicate +view paths in shell menu logic. + ## Commands | Command | Does | diff --git a/terminal/launchers/mqlaunch.sh b/terminal/launchers/mqlaunch.sh index 7269399..89ce301 100755 --- a/terminal/launchers/mqlaunch.sh +++ b/terminal/launchers/mqlaunch.sh @@ -82,7 +82,16 @@ MQ_SCRIPT="$BASE_DIR/terminal/launchers/mqlaunch.sh" BACKUP_DIR="$BASE_DIR/backups" BIN_LINK="$HOME/bin/mqlaunch" UI_LIB="$BASE_DIR/ui/terminal-ui/mq-ui.sh" -DASHBOARD_V71="$BASE_DIR/ui/ascii/mqlaunch-dashboard-v7.1.sh" + +# print_header is owned by mq-ui.sh (single header authority). Opt the main loop +# into the dashboard-v7.1 header via mq-ui's cached path — this is a plain +# (non-exported) shell var so it drives this launcher's own print_header calls +# without forcing the dashboard header onto child subprocesses, which set the +# flag themselves where they want it. Cache freshness is bounded by +# MQ_DASHBOARD_CACHE_TTL (default 5s) and invalidated by mutating flows +# (open_git_menu / open_release_menu). Set MQ_DASHBOARD_CACHE_TTL=0 for an +# uncached, per-screen header while investigating. +MQ_USE_DASHBOARD_HEADER=1 TERMINAL_GUIDE_HTML="$BASE_DIR/docs/mac-terminal-guide.html" TERMINAL_GUIDE_URL="https://mcamner.github.io/macos-scripts/" @@ -220,20 +229,10 @@ if [[ -f "$BASE_DIR/terminal/menus/recommendations-menu.sh" ]]; then source "$BASE_DIR/terminal/menus/recommendations-menu.sh" fi -# Prints header. -print_header() { - clear - if [[ -f "$DASHBOARD_V71" ]]; then - bash "$DASHBOARD_V71" "$APP_TITLE" "$APP_SUBTITLE" "ONLINE" - else - echo "$APP_TITLE — $APP_SUBTITLE" - printf '%s -' "----------------------------------------------------------------------------------------" - fi - echo -} - # --- Shared UI ------------------------------------------------ +# print_header is provided by mq-ui.sh (the single header authority); the +# launcher no longer overrides it. With MQ_USE_DASHBOARD_HEADER=1 (set above) +# mq-ui renders the cached dashboard-v7.1 header for the main loop. open_app() { local app_name="$1" open -a "$app_name" >/dev/null 2>&1 || { diff --git a/tests/mq-obsidian-menu-no-promotion-smoke.sh b/tests/mq-obsidian-menu-no-promotion-smoke.sh new file mode 100755 index 0000000..9707934 --- /dev/null +++ b/tests/mq-obsidian-menu-no-promotion-smoke.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +MENU="$ROOT/terminal/menus/mq-obsidian-menu.sh" +DOC="$ROOT/mqlaunch/docs/mqobsidian-consumer.md" +ROADMAP="$ROOT/ROADMAP.md" + +echo "SMOKE: MQ Obsidian menu has no memory promotion path" + +echo "[1/6] files exist" +test -f "$MENU" +test -f "$DOC" +test -f "$ROADMAP" + +echo "[2/6] shell syntax" +bash -n "$MENU" + +echo "[3/6] menu describes presentation/routing ownership" +grep -q "this menu owns presentation and routing only" "$MENU" +grep -q "mqobsidian and mq-agent own memory, context-pack, and learn logic" "$MENU" + +echo "[4/6] triage is read-only and explicitly review-gated" +grep -q "mq_obsidian_triage_learning_inbox()" "$MENU" +grep -q "Learning inbox triage is review-gated" "$MENU" +grep -q "No promote/reject action is run from mqlaunch" "$MENU" +grep -q "mq_obsidian_show_inbox" "$MENU" + +echo "[5/6] menu contains no promotion or rejection command routes" +if grep -Eq '(^|[[:space:];|&])(mq-agent|mqlaunch|python3|bash|zsh)[[:space:]].*(promote|promotion|reject|learn[[:space:]]+promote|promote-from-review|resolve-supersede)' "$MENU"; then + echo "MQ Obsidian menu appears to route promotion/rejection work" >&2 + exit 1 +fi +if grep -Eq '(_run_agent[[:space:]].*(promote|reject)|learn[[:space:]]+promote|promote-from-review|resolve-supersede)' "$MENU"; then + echo "MQ Obsidian menu appears to delegate promotion/rejection work" >&2 + exit 1 +fi + +echo "[6/6] docs and roadmap keep promotion outside mqlaunch" +grep -q "No writes to the vault. No scoring, promotion/downgrade, inbox or feedback-loop" "$DOC" +grep -q "Add/verify tests that MQ Obsidian menu actions do not promote memory" "$ROADMAP" + +echo "OK: MQ Obsidian menu no-promotion smoke test passed"