Add MCP advisor knowledge data

ober

5874999de0566df5e3a4f23d9ef46bc590151f6e

diff --git a/data/anti-patterns.sexp b/data/anti-patterns.sexp
new file mode 100644
index 0000000..2fa969a
--- /dev/null
+++ b/data/anti-patterns.sexp
@@ -0,0 +1,104 @@
+((("advice"
+    .
+    "Use one complete .ss script with `(import (jerboa prelude))`, and execute behavior at top level or by calling the entry point.")
+   ("avoid"
+    .
+    "Do not create a `.sls` library or `(library ...)` form for a simple user-facing script.")
+   ("id" . "script-written-as-library")
+   ("kinds" "script")
+   ("pattern" . "\\.sls|\\(library\\b")
+   ("severity" . "high")
+   ("tags" "script" "cli" "library" "sls" "entrypoint")
+   ("title" . "Writing a library for a simple script")
+   ("tools" "jerboa_script_scaffold_verify" "jerboa_verify"))
+ (("advice"
+    .
+    "Make the script run its behavior directly, or explicitly call `(main)` after defining it.")
+   ("avoid"
+    .
+    "Do not only define `main` and then report success without invoking it.")
+   ("id" . "script-main-not-called")
+   ("kinds" "script")
+   ("pattern" . "\\(def \\(main\\b")
+   ("severity" . "high")
+   ("tags" "script" "main" "entrypoint" "output" "cli")
+   ("title" . "Defining main without running it")
+   ("tools" "jerboa_verify" "jerboa_script_scaffold_verify"))
+ (("advice"
+    .
+    "Use Jerboa recipes, `(jerboa prelude)`, and confirmed `(std ...)` modules; check unfamiliar APIs with exports/signature tools.")
+   ("avoid"
+    .
+    "Do not use Gerbil commands, Racket/SRFI assumptions, or guessed imports for Jerboa tasks.")
+   ("id" . "cross-dialect-assumptions")
+   ("kinds" "all")
+   ("pattern" . "gxi|gxc|#lang|srfi-|racket|gerbil")
+   ("severity" . "high")
+   ("tags" "imports" "gerbil" "racket" "srfi" "dialect")
+   ("title" . "Assuming another Scheme dialect")
+   ("tools" "jerboa_howto" "jerboa_module_exports" "jerboa_function_signature"))
+ (("advice"
+    .
+    "Use the recommended shell command or MCP verifier, and make it exercise the requested behavior.")
+   ("avoid"
+    .
+    "Do not verify with `true`, file-existence checks, or load-only commands when the request needs observable output.")
+   ("id" . "weak-verify-command")
+   ("kinds" "all")
+   ("pattern" . "\\btrue\\b|test -f|load-only")
+   ("severity" . "high")
+   ("tags" "verify" "jcode" "success" "tests" "behavior")
+   ("title" . "Using a weak verifier")
+   ("tools" "jerboa_verify_plan" "jerboa_verify" "jerboa_run_tests"))
+ (("advice"
+    .
+    "Run `jerboa_check_balance`, read the enclosing top-level form, and replace the whole broken span.")
+   ("avoid"
+    .
+    "Do not repair unbalanced code with random one-character paren edits.")
+   ("id" . "random-paren-pokes")
+   ("kinds" "debug-error" "script" "module")
+   ("pattern" . "unexpected close|unexpected end|unmatched|invalid syntax")
+   ("severity" . "medium")
+   ("tags" "syntax" "paren" "balance" "repair" "replace-range")
+   ("title" . "Random paren edits on unbalanced code")
+   ("tools" "jerboa_check_balance" "jerboa_read_forms" "jerboa_failure_advisor"))
+ (("advice"
+    .
+    "Patch the named failing span, then re-run the same verifier before reading more unrelated files.")
+   ("avoid"
+    .
+    "Do not keep broad-reading after the verifier has identified a concrete error and file.")
+   ("id" . "broad-reading-after-concrete-failure")
+   ("kinds" "debug-error" "script" "module" "test")
+   ("pattern" . "Exception|error|failed|line [0-9]+")
+   ("severity" . "medium")
+   ("tags" "failure" "repair" "verifier" "focus" "loop")
+   ("title" . "Broad inspection after a concrete verifier failure")
+   ("tools" "jerboa_failure_advisor" "jerboa_explain_error" "jerboa_error_fix_lookup"))
+ (("advice"
+    .
+    "Confirm the symbol with `jerboa_module_exports`, `jerboa_suggest_imports`, or `jerboa_function_signature` before editing.")
+   ("avoid"
+    .
+    "Do not patch unbound or arity errors by guessing names, imports, or argument order.")
+   ("id" . "guessing-after-symbol-error")
+   ("kinds" "debug-error" "script" "module")
+   ("pattern" . "unbound|not bound|wrong number of arguments|arity")
+   ("severity" . "medium")
+   ("tags" "unbound" "arity" "imports" "signature" "symbols")
+   ("title" . "Guessing after symbol or arity errors")
+   ("tools" "jerboa_module_exports" "jerboa_suggest_imports" "jerboa_function_signature"))
+ (("advice"
+    .
+    "Use `jerboa_doc_verify` or `make check-docs` for fenced Scheme/Jerboa examples before claiming the docs are done.")
+   ("avoid"
+    .
+    "Do not mark documentation complete when fenced code blocks have not been compiled.")
+   ("id" . "unverified-doc-code")
+   ("kinds" "docs")
+   ("pattern" . "```scheme|```jerboa")
+   ("severity" . "medium")
+   ("tags" "docs" "markdown" "code-blocks" "verify" "examples")
+   ("title" . "Unverified documentation code blocks")
+   ("tools" "jerboa_doc_verify" "jerboa_doc_status_audit")))
diff --git a/data/cookbooks.sexp b/data/cookbooks.sexp
index 6439645..a6b8585 100644
--- a/data/cookbooks.sexp
+++ b/data/cookbooks.sexp
@@ -6205,14 +6205,52 @@
      "Finalize SQLite native statements and reread oversized columns"))
  (("code"
     .
-    "(import (jerboa prelude))\n(import (chezscheme))\n\n(def (delete-file-if-exists path)\n  (when (file-exists? path)\n    (delete-file path)))\n\n(def (atomic-write-string path contents)\n  ;; Keep the temp file in the same directory so rename-file is atomic.\n  (let ([tmp (string-append path \".tmp.\" (number->string (get-process-id)))])\n    (dynamic-wind\n      (lambda () (void))\n      (lambda ()\n        (delete-file-if-exists tmp)\n        (write-file-string tmp contents)\n        (rename-file tmp path))\n      (lambda ()\n        (when (file-exists? tmp)\n          (delete-file tmp))))))")
-   ("id" . "atomic-write-string-rename-file")
+    "(import (jerboa prelude))\n(import (chezscheme))\n\n(def (delete-file-if-exists path)\n  (when (file-exists? path)\n    (delete-file path)))\n\n(def (atomic-write-string path contents)\n  ;; Keep the temp file in the same directory so rename-file is atomic.\n  (let ([tmp (string-append path \".tmp.\" (number->string (get-process-id)))])\n    (dynamic-wind\n      (lambda () (void))\n      (lambda ()\n        (delete-file-if-exists tmp)\n        (write-file-string tmp contents)\n        (rename-file tmp path))\n      (lambda ()\n        (when (file-exists? tmp)\n          (delete-file tmp))))))") ("id" . "atomic-write-string-rename-file")
    ("imports" "(jerboa prelude)" "(chezscheme)")
    ("notes"
      .
      "Create the temp file next to the destination; cross-directory renames are not guaranteed atomic. Chez/Jerboa `rename-file` replaces the existing target on the tested platforms, so a fully-written temp file can be moved into place without exposing partial contents. Use `dynamic-wind` cleanup so failed writes, failed renames, or exceptions remove the temp file.")
-   ("tags" "file-io" "atomic-write" "rename-file" "dynamic-wind"
-     "cleanup" "temp-file")
+   ("tags" "file-io" "atomic-write" "rename-file"
+     "dynamic-wind" "cleanup" "temp-file")
    ("title"
      .
-     "Atomically replace a text file with rename-file cleanup")))
+     "Atomically replace a text file with rename-file cleanup"))
+ (("code"
+    .
+    "(import (jerboa prelude))\n\n(def status-style \"\\x1B;[37;40m\")\n(def status-reset \"\\x1B;[0m\")\n(def status-session-style \"\\x1B;[37;44m\")\n(def status-load-style \"\\x1B;[32;40m\")\n(def status-time-style \"\\x1B;[33;40m\")\n\n(def (prefix-n s n)\n  (if (<= (string-length s) n)\n      s\n      (substring s 0 (max 0 n))))\n\n(def (right-status-parts load time)\n  (let* ([sep (if (and (> (string-length load) 0)\n                       (> (string-length time) 0))\n                  \" \"\n                  \"\")]\n         [plain (string-append load sep time)]\n         [styled (cond\n                   [(and (> (string-length load) 0)\n                         (> (string-length time) 0))\n                    (string-append status-load-style load status-style \" \"\n                                   status-time-style time status-style)]\n                   [(> (string-length load) 0)\n                    (string-append status-load-style load status-style)]\n                   [(> (string-length time) 0)\n                    (string-append status-time-style time status-style)]\n                   [else \"\"])])\n    (cons styled (string-length plain))))\n\n(def (render-status-bar session windows right-load right-time cols)\n  (let* ([right (right-status-parts right-load right-time)]\n         [right-styled (car right)]\n         [right-len (cdr right)]\n         [session-text (prefix-n session (max 0 (- cols right-len 3)))]\n         [left-plain (string-append session-text \" : \" windows)]\n         [pad-len (max 0 (- cols (string-length left-plain) right-len))]\n         [pad (make-string pad-len #\\space)])\n    (string-append status-style\n                   status-session-style session-text\n                   status-style \" : \" windows pad right-styled\n                   status-reset)))\n\n(displayln (render-status-bar \"default\" \"[0:jsh*] \" \"1.23 0.91 0.75\" \"2026-06-11 15:30:00\" 80))") ("id" . "mux-styled-status-right-segments")
+   ("imports" "(jerboa prelude)")
+   ("notes"
+     .
+     "ANSI SGR bytes must not be counted as visible columns. Build each styled segment together with its plain visible length, reserve right-side width before truncating or budgeting the left side, and pad using the plain visible lengths. For live load/time, expose a narrow FFI helper such as ffi-loadavg-string plus an existing strftime wrapper, then keep the status renderer pure apart from the supplier calls. If the status bar is overlaid below a PTY, combine this with the mux-persistent-status-bar-overlay recipe.")
+   ("tags" "mux" "status-bar" "ansi" "visible-width" "loadavg"
+     "strftime")
+   ("title"
+     .
+     "Render styled mux status segments without breaking visible width"))
+ (("code"
+    .
+    "(def (handle-auth-response ts method)\n  (let loop ()\n    (let ([reply (ssh-transport-recv-packet ts)])\n      (case (bytevector-u8-ref reply 0)\n        [(52) #t]    ;; SSH_MSG_USERAUTH_SUCCESS\n        [(51)        ;; SSH_MSG_USERAUTH_FAILURE\n         (let* ([off 1]\n                [r (ssh-read-name-list reply off)]\n                [methods (car r)])\n           (error 'ssh-auth\n                  (string-append (symbol->string method)\n                                 \" authentication failed; try: \"\n                                 (string-join methods \", \"))))]\n        [(53)        ;; SSH_MSG_USERAUTH_BANNER\n         (loop)]\n        [else\n         (error 'ssh-auth \"unexpected response\"\n                (bytevector-u8-ref reply 0))]))))") ("id" . "jerboa-ssh-userauth-banner-loop")
+   ("imports"
+     "(jerboa prelude)"
+     "(jerboa-ssh wire)"
+     "(jerboa-ssh transport)")
+   ("notes"
+     .
+     "OpenSSH servers may send SSH_MSG_USERAUTH_BANNER (53) after a USERAUTH_REQUEST, especially when a login banner/MOTD policy is configured. Treat it as informational and continue waiting for SUCCESS (52), FAILURE (51), or method-specific packets such as INFO_REQUEST (60). Otherwise publickey auth can fail with an unexpected response 53 even though transport, KEX, and signature verification are working.")
+   ("tags" "ssh" "userauth" "banner" "jerboa-ssh" "rfc4252"
+     "auth")
+   ("title"
+     .
+     "Ignore SSH USERAUTH_BANNER while waiting for auth result"))
+ (("code"
+    .
+    ";; jsh mux dynamic forwarding path:\n;;\n;;   ,mux attach BASTION:PORT -D 1080\n;;   ,proxy start --via-mux BASTION:PORT -p 1080\n;;   ,proxy start --via-mux ROUTER:PORT --mux prod -p 1080\n;;\n;; Both start a local SOCKS5 listener on 127.0.0.1. A SOCKS CONNECT request is\n;; encoded as MSG-FORWARD-OPEN and sent over the mux transport. The mux server\n;; decodes it and performs ffi_stream_connect_tcp from the server/bastion side,\n;; then relays bytes with MSG-FORWARD-DATA. Router mode sends MSG-SELECT-MUX\n;; first, waits for MSG-ROUTE-OK, then handles the backend mux server hello.\n\n(import (chezscheme)\n        (only (jsh mux-proto)\n              MSG-FORWARD-OPEN MSG-FORWARD-OPEN-OK MSG-FORWARD-DATA MSG-FORWARD-CLOSE\n              MSG-SELECT-MUX MSG-ROUTE-OK\n              encode-forward-open decode-forward-open))\n\n(define payload (encode-forward-open 7 \"example.com\" 443))\n(let-values ([(channel-id host port) (decode-forward-open payload)])\n  (list (= MSG-FORWARD-OPEN #x40)\n        channel-id\n        host\n        port\n        (= MSG-FORWARD-OPEN-OK #x41)\n        (= MSG-FORWARD-DATA #x42)\n        (= MSG-FORWARD-CLOSE #x43)\n        (= MSG-SELECT-MUX #x33)\n        (= MSG-ROUTE-OK #x36)))\n;; => (#t 7 \"example.com\" 443 #t #t #t #t #t)") ("id" . "jsh-mux-dynamic-socks-forwarding")
+   ("imports" "(jsh mux-proto)")
+   ("notes"
+     .
+     "For remote egress, reuse the mux forwarding listener and message handlers rather than std/net/socks5-server, because std/net/socks5-server connects locally with ffi_stream_connect_tcp. The headless ,proxy path must complete the normal mux auth/encryption handshake before forwarding. If the endpoint is a mux router, select a backend with MSG-SELECT-MUX and only then wait for the backend server hello. Local SOCKS5 username/password auth is independent from mux/router auth; pass auth-info into the listener and keep ,mux attach -D no-auth by default.")
+   ("tags" "jsh" "mux-client" "mux-server" "socks5"
+     "dynamic-forwarding" "MSG-FORWARD-OPEN")
+   ("title"
+     .
+     "Mux dynamic SOCKS forwarding: local SOCKS, remote egress")))
diff --git a/data/features.sexp b/data/features.sexp
index 1f5ea94..c611f85 100644
--- a/data/features.sexp
+++ b/data/features.sexp
@@ -2780,4 +2780,65 @@
    ("use_case"
      .
      "When mandatory Jerboa MCP verification tools run longer than the client timeout, callers need actionable fallback guidance instead of a generic transport timeout.")
+   ("votes" . 0))
+ (("description"
+    .
+    "Some Jerboa repos intentionally shadow or re-export Chez/prelude identifiers, which can make jerboa_verify fail with duplicate definition errors even when the project build succeeds. Add a mode or project profile hook that mirrors the repository's build/import environment closely enough to avoid false duplicate-export failures, or reports them as non-blocking when known-safe.")
+   ("estimated_token_reduction"
+     .
+     "~400-800 tokens per edit session by avoiding repeated verifier failure analysis and fallback explanation.")
+   ("example_scenario"
+     .
+     "In jerboa-shell, verifying mux-screen.ss failed with duplicate definitions for path-extension and related prelude identifiers, while make jsh-macos-full compiled the changed module successfully.")
+   ("id" . "verify-prelude-duplicate-export-mode")
+   ("impact" . "medium")
+   ("tags"
+     "verify"
+     "prelude"
+     "duplicate-definition"
+     "project-profile")
+   ("title"
+     .
+     "Let jerboa_verify handle prelude duplicate-export projects")
+   ("use_case"
+     .
+     "Use before editing Jerboa modules in repos where the normal project build is authoritative but jerboa_verify currently fails before reaching the changed code.")
+   ("votes" . 0))
+ (("description"
+    .
+    "module_exports should reliably locate generated vendored libraries when project_path and extra_libdirs point at the repository's generated lib roots. In this session, (jerboa-ssh wire) existed under vendor/jerboa-ssh/lib and was compiled by the build, but module_exports reported the library as not found despite explicit extra_libdirs.")
+   ("estimated_token_reduction"
+     .
+     "~300-700 tokens per failed lookup by avoiding fallback rg/sed reads and explanatory detours.")
+   ("example_scenario"
+     .
+     "While fixing static jsh SSH support, the agent needed to confirm that SSH_MSG_USERAUTH_BANNER was exported by (jerboa-ssh wire). The module source and generated .sls existed locally, but module_exports could not resolve it with project_path plus extra_libdirs, forcing a manual source read instead.")
+   ("id" . "module-exports-resolve-project-extra-libdirs")
+   ("impact" . "medium")
+   ("tags" "module_exports" "extra_libdirs" "vendor"
+     "generated-sls" "libdirs")
+   ("title"
+     .
+     "Make module_exports resolve project extra_libdirs consistently")
+   ("use_case"
+     .
+     "Inspecting exports in projects that stage dependency .ss sources into generated .sls lib directories before cross builds.")
+   ("votes" . 0))
+ (("description"
+    .
+    "jerboa_verify on repo source files such as src/jcode/ui/tui.ss fails with 'export form outside of a module or library' when imported dependencies are project .ss files, even though the same files build through jerbuild transpile/compile. The verifier should use the project's module layout or transpiled lib output when project_path/extra_libdirs are supplied.") ("estimated_token_reduction" . "")
+   ("example_scenario" . "")
+   ("id" . "verify-project-source-modules")
+   ("impact"
+     .
+     "Reduces false verifier failures and avoids forcing agents to skip the mandatory verify step for normal project-module edits.")
+   ("status" . "open")
+   ("tags" "verify" "project-path" "source-modules"
+     "export-form" "jerbuild")
+   ("title"
+     .
+     "Make jerboa_verify handle project .ss source modules with top-level export forms")
+   ("use_case"
+     .
+     "Before editing Jerboa project source, agents are required to run jerboa_verify. In this repo, verification of changed TUI modules had to fall back to make build because direct verification could not load exported source modules.")
    ("votes" . 0)))