Add MCP advisor knowledge data
ober
5874999de0566df5e3a4f23d9ef46bc590151f6e
new file mode 100644 --- /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"))) --- 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"))) --- 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)))