Improve MCP guidance data and diagnostics
ober
6ce1babf8b2fccc5a18d1528cdfe061ea523a201
--- a/data/anti-patterns.sexp +++ b/data/anti-patterns.sexp @@ -9,280 +9,425 @@ ("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" - . - "Check both lower and upper bounds before computing a vector index or calling `vector-ref`/`vector-set!`. Prefer an `in-bounds?` helper such as `(and (>= x 0) (< x width) (>= y 0) (< y height))`.") - ("avoid" - . - "Do not check only `(< x width)` and `(< y height)` before vector-backed grid access; negative coordinates still pass those checks.") - ("id" . "upper-bound-only-grid-check") - ("kinds" "script" "module" "debug-error" "test") - ("pattern" - . - "vector-ref|vector-set!|not a valid index|grid|neighbor") - ("severity" . "high") - ("tags" "vector" "grid" "bounds" "index" "runtime") - ("title" - . - "Checking only upper bounds before vector grid access") - ("tools" - "jerboa_failure_advisor" - "jerboa_error_fix_lookup" - "jerboa_howto" - "jerboa_verify")) - (("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 `(error 'who \"message\" irritant ...)` for ordinary validation failures, or define `(define (fail msg . xs) (apply error 'script msg xs))`. Look up `bare-string-error-arity` if the verifier reports an incorrect argument count.") - ("avoid" - . - "Do not call `(error \"message\")`, do not switch to `raise` with a bare string, and do not spend turns guessing `make-condition` helpers for simple script validation.") - ("id" . "bare-string-error-call") - ("kinds" "script" "module" "debug-error") - ("pattern" - . - "incorrect argument count in call \\(error \\\"|\\(error \\\"|\\(raise \\\"|make-condition|raise-error") - ("severity" . "medium") - ("tags" "error" "arity" "validation" "script" "raise") - ("title" . "Calling error with only a string") - ("tools" - "jerboa_error_fix_lookup" - "jerboa_howto" - "jerboa_failure_advisor")) - (("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")) - (("advice" - . - "Use `let`, `let*`, or `let-values` for local values inside a function or expression body. Keep `def`/`define` at top level or at the start of a definition body before expressions.") - ("avoid" - . - "Do not introduce local variables with `(def name ...)` or internal `(define name ...)` after expressions such as `when`, `display`, or another `let` body expression.") - ("id" . "local-def-after-expression") - ("kinds" "script" "module" "debug-error") - ("pattern" - . - "invalid context for definition|\\((def|define) [a-zA-Z0-9_?!<>*+-]+ ") - ("severity" . "high") - ("tags" "definition" "let" "local-binding" "invalid-context" - "script") - ("title" . "Using def for local bindings after expressions") - ("tools" - "jerboa_error_fix_lookup" - "jerboa_howto" - "jerboa_failure_advisor" - "jerboa_verify")) - (("advice" - . - "Remember the difference between JSON/tool-call escaping and the text that belongs in the .ss file. In actual Jerboa/Scheme source, character literals use one backslash after `#`: hash is `#\\#` and dot is `#\\.`. After writing through a JSON tool call, read or verify the file and ensure it did not contain doubled source backslashes such as `#\\\\#` or `#\\\\.`.") - ("avoid" - . - "Do not copy JSON-escaped character literals into source files as doubled backslashes, such as writing `#\\\\#` or `#\\\\.` in the actual .ss file.") - ("id" . "overescaped-character-literals") - ("kinds" "script" "module" "debug-error") - ("pattern" . "invalid sharp-sign prefix|#\\\\#|#\\\\.") - ("severity" . "medium") - ("tags" "character-literal" "sharp-sign" "json-escape" - "syntax" "reader") - ("title" - . - "Writing JSON-escaped character literals into source") - ("tools" - "jerboa_error_fix_lookup" - "jerboa_failure_advisor" - "jerboa_verify")) - (("advice" - . - "Inspect the trace for the last provider/tool events, sample the process, and check open file descriptors for duplicate sessions.db-lock handles. If a thread is blocked in flock, serialize same-process session DB opens/transactions with a mutex and add a concurrent session write regression test.") - ("avoid" - . - "Do not assume a jcode UI hang after tool results is provider/model thinking when the trace stops before the next provider stream.") - ("id" . "jcode-session-db-flock-self-deadlock") - ("kinds" "debug-error" "module" "test") - ("pattern" - . - "sessions\\.db-lock|agent: executing-tools|tool-result.*DRAW role=error|flock") - ("severity" . "high") - ("tags" "jcode" "jsqlite" "flock" "sessions-db" "threads" - "hang") - ("title" - . - "Mistaking session DB flock self-deadlock for model thinking") - ("tools" "jerboa_howto" "jerboa_module_exports" - "jerboa_function_signature" "jerboa_check_balance" - "jerboa_run_tests")) - (("advice" - . - "Check trace ordering first: if the provider has returned but tool execution does not begin, inspect session persistence and DB/lock holders. Keep active sessions in small per-session files or another bounded append-oriented store. Treat the legacy global DB as lazy fallback by explicit id only; do not list/search/open it during startup or normal chat turns. Add tests that new sessions do not create/open sessions.db.") - ("avoid" - . - "Do not leave active/new jcode sessions on the legacy global sessions.db hot path, especially when the DB can grow to hundreds of MB. jsqlite may load and rewrite the whole image, so per-turn persistence can look like the model is thinking forever.") - ("id" . "jcode-giant-session-db-hot-path") - ("kinds" "debug-error" "module") - ("pattern" - . - "session-(add-message|list|search|get-messages).*sessions\\.db|sqlite.*active chat|global session db") - ("severity" . "high") - ("tags" "jcode" "session" "jsqlite" "hot-path" "persistence" - "hang") - ("title" - . - "Keeping active chat writes on a giant global jsqlite DB") - ("tools" "jerboa_howto" "jerboa_module_exports" - "jerboa_function_signature" "jerboa_check_balance" - "jerboa_security_scan" "jerboa_make")) - (("advice" - . - "Use SSH access to linux.cons.io for Linux builds and tests. Run the relevant make, jerbuild, or shell commands remotely over ssh linux.cons.io, and copy or sync artifacts as needed instead of relying on containers.") - ("avoid" - . - "Do not use Docker or Podman for Jerboa or jerboa-emacs Linux builds, cross-build verification, or CI-style smoke tests. Do not cite unavailable Docker/Podman as a blocker.") - ("id" . "no-containers-use-linux-cons") - ("kinds" "workflow" "build" "test") - ("pattern" - . - "(?i)\\b(docker|podman)\\b.*\\b(linux|build|cross|jerboa|jerbuild)\\b") - ("severity" . "high") - ("tags" "docker" "podman" "linux.cons.io" "cross-build" - "jerboa" "jerboa-emacs") - ("title" . "Do not use containers for Linux builds") - ("tools" "exec_command")) - (("advice" - . - "Use distinct names for every binding in a `let`, `let*`, `let-values`, or named `let`. In named loops, choose separate names for the counter and the carried state, and update the recursive call in the same order, such as `(let loop ([i 0] [current grid]) ...)`.") - ("avoid" - . - "Do not bind the same identifier twice in one binding list, for example `(let loop ([g 0] [g grid]) ...)`.") - ("id" . "duplicate-let-binding-name") - ("kinds" "script" "module" "debug-error") - ("pattern" - . - "duplicate bound variable|\\(let\\s+[^()]+\\s*\\(\\([^)]*\\b([a-zA-Z0-9!?+\\-*/<>=]+)\\b[^)]*\\b\\1\\b") - ("severity" . "medium") - ("tags" "let" "named-let" "binding" "duplicate" "syntax") - ("title" . "Reusing one name for two let bindings") - ("tools" - "jerboa_error_fix_lookup" - "jerboa_failure_advisor" - "jerboa_verify")) - (("advice" - . - "Call `filter` with exactly two arguments: a one-argument predicate and the list. If the test needs a constant or a second value, close over it in a lambda, such as `(filter (lambda (c) (char=? c #\\#)) chars)`. Use `jerboa_function_signature` when unsure about a list helper's arity.") - ("avoid" - . - "Do not call `filter` with extra predicate arguments or comparison constants, such as `(filter char=? chars #\\#)`. Jerboa's `filter` does not curry or forward extra arguments into the predicate.") - ("id" . "filter-extra-comparison-arguments") - ("kinds" "script" "module" "debug-error") - ("pattern" - . - "incorrect argument count in call \\(filter|possible incorrect argument count in call \\(filter|\\(filter\\s+char=\\?\\s+[^)]*#\\\\") - ("severity" . "medium") - ("tags" "filter" "arity" "list" "predicate" "lambda") - ("title" . "Passing extra comparison arguments to filter") - ("tools" - "jerboa_error_fix_lookup" - "jerboa_function_signature" - "jerboa_failure_advisor" - "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 runnable command or a focused verifier that actually exercises the requested behavior. For CLI scripts that require args or stdin, the configured test command is usually the authority; MCP verify is supporting syntax/expand evidence.") + ("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" + . + "Use `jerboa_verify` as syntax/expand sanity only for executable scripts that require args or stdin. Run the configured verify command or a focused runnable command with the required arguments and input before changing code based on runtime validation output.") + ("avoid" + . + "Do not treat a missing-argument error from `jerboa_verify` on an executable script as proof that the script logic or APIs are wrong when the task requires command-line args or stdin.") + ("id" . "mcp-verify-cli-script-missing-args") + ("kinds" "script" "test" "debug-error") + ("pattern" + . + "expected exactly one argument|missing.*argument|no source location reported") + ("severity" . "medium") + ("tags" "cli" "verify" "stdin" "arguments" "script") + ("title" + . + "Chasing MCP verify missing-argument errors for CLI scripts") + ("tools" + "verify" + "jerboa_verify_plan" + "jerboa_failure_advisor" + "jerboa_error_fix_lookup")) + (("advice" + . + "Check both lower and upper bounds before computing a vector index or calling `vector-ref`/`vector-set!`. Prefer an `in-bounds?` helper such as `(and (>= x 0) (< x width) (>= y 0) (< y height))`.") + ("avoid" + . + "Do not check only `(< x width)` and `(< y height)` before vector-backed grid access; negative coordinates still pass those checks.") + ("id" . "upper-bound-only-grid-check") + ("kinds" "script" "module" "debug-error" "test") + ("pattern" + . + "vector-ref|vector-set!|not a valid index|grid|neighbor") + ("severity" . "high") + ("tags" "vector" "grid" "bounds" "index" "runtime") + ("title" + . + "Checking only upper bounds before vector grid access") + ("tools" + "jerboa_failure_advisor" + "jerboa_error_fix_lookup" + "jerboa_howto" + "jerboa_verify")) + (("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 `(error 'who \"message\" irritant ...)` for ordinary validation failures, or define `(define (fail msg . xs) (apply error 'script msg xs))`. Look up `bare-string-error-arity` if the verifier reports an incorrect argument count.") + ("avoid" + . + "Do not call `(error \"message\")`, do not switch to `raise` with a bare string, and do not spend turns guessing `make-condition` helpers for simple script validation.") + ("id" . "bare-string-error-call") + ("kinds" "script" "module" "debug-error") + ("pattern" + . + "incorrect argument count in call \\(error \\\"|\\(error \\\"|\\(raise \\\"|make-condition|raise-error") + ("severity" . "medium") + ("tags" "error" "arity" "validation" "script" "raise") + ("title" . "Calling error with only a string") + ("tools" + "jerboa_error_fix_lookup" + "jerboa_howto" + "jerboa_failure_advisor")) + (("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")) + (("advice" + . + "Use `let`, `let*`, or `let-values` for local values inside a function or expression body. Keep `def`/`define` at top level or at the start of a definition body before expressions. If the bad binding is inside one named procedure, replace the complete procedure with `replace_def` instead of making repeated tiny text edits.") + ("avoid" + . + "Do not introduce local variables with `(def name ...)` or internal `(define name ...)` after expressions such as `when`, `display`, or another `let` body expression.") + ("id" . "local-def-after-expression") + ("kinds" "script" "module" "debug-error") + ("pattern" + . + "invalid context for definition|\\((def|define) [a-zA-Z0-9_?!<>*+-]+ ") + ("severity" . "high") + ("tags" "definition" "let" "local-binding" "invalid-context" + "script") + ("title" . "Using def for local bindings after expressions") + ("tools" + "jerboa_error_fix_lookup" + "jerboa_howto" + "jerboa_failure_advisor" + "jerboa_verify")) + (("advice" + . + "Remember the difference between JSON/tool-call escaping and the text that belongs in the .ss file. In actual Jerboa/Scheme source, character literals use one backslash after `#`: hash is `#\\#` and dot is `#\\.`. After writing through a JSON tool call, read or verify the file and ensure it did not contain doubled source backslashes such as `#\\\\#` or `#\\\\.`.") + ("avoid" + . + "Do not copy JSON-escaped character literals into source files as doubled backslashes, such as writing `#\\\\#` or `#\\\\.` in the actual .ss file.") + ("id" . "overescaped-character-literals") + ("kinds" "script" "module" "debug-error") + ("pattern" . "invalid sharp-sign prefix|#\\\\#|#\\\\.") + ("severity" . "medium") + ("tags" "character-literal" "sharp-sign" "json-escape" + "syntax" "reader") + ("title" + . + "Writing JSON-escaped character literals into source") + ("tools" + "jerboa_error_fix_lookup" + "jerboa_failure_advisor" + "jerboa_verify")) + (("advice" + . + "Inspect the trace for the last provider/tool events, sample the process, and check open file descriptors for duplicate sessions.db-lock handles. If a thread is blocked in flock, serialize same-process session DB opens/transactions with a mutex and add a concurrent session write regression test.") + ("avoid" + . + "Do not assume a jcode UI hang after tool results is provider/model thinking when the trace stops before the next provider stream.") + ("id" . "jcode-session-db-flock-self-deadlock") + ("kinds" "debug-error" "module" "test") + ("pattern" + . + "sessions\\.db-lock|agent: executing-tools|tool-result.*DRAW role=error|flock") + ("severity" . "high") + ("tags" "jcode" "jsqlite" "flock" "sessions-db" "threads" + "hang") + ("title" + . + "Mistaking session DB flock self-deadlock for model thinking") + ("tools" "jerboa_howto" "jerboa_module_exports" + "jerboa_function_signature" "jerboa_check_balance" + "jerboa_run_tests")) + (("advice" + . + "Check trace ordering first: if the provider has returned but tool execution does not begin, inspect session persistence and DB/lock holders. Keep active sessions in small per-session files or another bounded append-oriented store. Treat the legacy global DB as lazy fallback by explicit id only; do not list/search/open it during startup or normal chat turns. Add tests that new sessions do not create/open sessions.db.") + ("avoid" + . + "Do not leave active/new jcode sessions on the legacy global sessions.db hot path, especially when the DB can grow to hundreds of MB. jsqlite may load and rewrite the whole image, so per-turn persistence can look like the model is thinking forever.") + ("id" . "jcode-giant-session-db-hot-path") + ("kinds" "debug-error" "module") + ("pattern" + . + "session-(add-message|list|search|get-messages).*sessions\\.db|sqlite.*active chat|global session db") + ("severity" . "high") + ("tags" "jcode" "session" "jsqlite" "hot-path" "persistence" + "hang") + ("title" + . + "Keeping active chat writes on a giant global jsqlite DB") + ("tools" "jerboa_howto" "jerboa_module_exports" + "jerboa_function_signature" "jerboa_check_balance" + "jerboa_security_scan" "jerboa_make")) + (("advice" + . + "Use SSH access to linux.cons.io for Linux builds and tests. Run the relevant make, jerbuild, or shell commands remotely over ssh linux.cons.io, and copy or sync artifacts as needed instead of relying on containers.") + ("avoid" + . + "Do not use Docker or Podman for Jerboa or jerboa-emacs Linux builds, cross-build verification, or CI-style smoke tests. Do not cite unavailable Docker/Podman as a blocker.") + ("id" . "no-containers-use-linux-cons") + ("kinds" "workflow" "build" "test") + ("pattern" + . + "(?i)\\b(docker|podman)\\b.*\\b(linux|build|cross|jerboa|jerbuild)\\b") + ("severity" . "high") + ("tags" "docker" "podman" "linux.cons.io" "cross-build" + "jerboa" "jerboa-emacs") + ("title" . "Do not use containers for Linux builds") + ("tools" "exec_command")) + (("advice" + . + "Use distinct names for every binding in a `let`, `let*`, `let-values`, or named `let`. In named loops, choose separate names for the counter and the carried state, and update the recursive call in the same order, such as `(let loop ([i 0] [current grid]) ...)`.") + ("avoid" + . + "Do not bind the same identifier twice in one binding list, for example `(let loop ([g 0] [g grid]) ...)`.") + ("id" . "duplicate-let-binding-name") + ("kinds" "script" "module" "debug-error") + ("pattern" + . + "duplicate bound variable|\\(let\\s+[^()]+\\s*\\(\\([^)]*\\b([a-zA-Z0-9!?+\\-*/<>=]+)\\b[^)]*\\b\\1\\b") + ("severity" . "medium") + ("tags" "let" "named-let" "binding" "duplicate" "syntax") + ("title" . "Reusing one name for two let bindings") + ("tools" + "jerboa_error_fix_lookup" + "jerboa_failure_advisor" + "jerboa_verify")) + (("advice" + . + "Call `filter` with exactly two arguments: a one-argument predicate and the list. If the test needs a constant or a second value, close over it in a lambda, such as `(filter (lambda (c) (char=? c #\\#)) chars)`. Use `jerboa_function_signature` when unsure about a list helper's arity.") + ("avoid" + . + "Do not call `filter` with extra predicate arguments or comparison constants, such as `(filter char=? chars #\\#)`. Jerboa's `filter` does not curry or forward extra arguments into the predicate.") + ("id" . "filter-extra-comparison-arguments") + ("kinds" "script" "module" "debug-error") + ("pattern" + . + "incorrect argument count in call \\(filter|possible incorrect argument count in call \\(filter|\\(filter\\s+char=\\?\\s+[^)]*#\\\\") + ("severity" . "medium") + ("tags" "filter" "arity" "list" "predicate" "lambda") + ("title" . "Passing extra comparison arguments to filter") + ("tools" + "jerboa_error_fix_lookup" + "jerboa_function_signature" + "jerboa_failure_advisor" + "jerboa_verify")) + (("advice" + . + "Use rsync with --exclude patterns for build artifacts (--exclude='*.so' --exclude='*.wpo' --exclude='*.o' --exclude='bin/') or filter through .gitignore rules. Better: clone fresh and only copy source files, or use `git archive` to get a clean source snapshot.") + ("avoid" + . + "Do not blindly copy a working directory with `cp -r` or `rsync` without excluding generated build artifacts (.so, .wpo, .o, bin/). These files often have restrictive permissions, are stale, and cause permission errors when moved between users or machines.") + ("id" . "repo-copy-includes-build-artifacts") + ("kinds" "script" "module" "test") + ("pattern" + . + "(cp\\s+-r|rsync.*--archive|Permission.denied.*\\.so|EACCES.*\\.wpo)") + ("severity" . "medium") + ("tags" "copy" "build-artifacts" "permission" "cp" "rsync" + ".gitignore") + ("title" + . + "Repository copies include build artifacts causing permission errors") + ("tools" "git_status" "glob" "jerboa_make")) + (("advice" + . + "Provide guidance or tool aliases that steer constrained models toward list/read/find-equivalent structured tools or MCP search tools. In the verified prompt, explicitly enumerate available tools. Consider adding lightweight in-process file search (glob+grep) as a structured tool to replace shell grep.") + ("avoid" + . + "Do not let constrained local/jcode models waste turns trying unavailable shell tools (grep, bash, run, shell) when verified mode only exposes structured file/edit/verify tools. Models hallucinate tool availability.") + ("id" . "verified-mode-shell-tool-unavailable") + ("kinds" "script" "module" "debug-error") + ("pattern" . "(grep|bash|run\\b|exec_command|shell)") + ("severity" . "high") + ("tags" "verified" "jcode" "tool-restriction" "grep" "bash" + "shell") + ("title" + . + "Models try grep/bash/run in verified mode where only structured tools exist") + ("tools" + "jerboa_verify_plan" + "jerboa_request_advisor" + "jerboa_howto")) + (("advice" + . + "Before launching any benchmark, validate all model IDs against the provider's models endpoint. For OpenRouter, fetch the models list and check each configured ID is present. Cache the result briefly. Add explicit pre-flight validation that aborts early with a clear error listing which IDs are invalid.") + ("avoid" + . + "Do not launch a benchmark run without first validating that every configured OpenRouter model ID is currently valid. Stale/deprecated model IDs fail immediately with HTTP 400 and waste the entire benchmark run.") + ("id" . "stale-model-id-invalid-api-400") + ("kinds" "script" "module" "test") + ("pattern" + . + "(invalid.*model.*id|model.*not.found|400.*model)") + ("severity" . "high") + ("tags" "benchmark" "model-id" "openrouter" "api-400" + "configuration" "preflight") + ("title" + . + "Stale model IDs cause immediate 400 before benchmark runs") + ("tools" "jerboa_howto" "jerboa_verify")) + (("advice" + . + "Derive per-run ports and paths from a run-id, timestamp, or process identifier. Pass these as arguments or environment variables to each benchmark instance. For ports, use 0 (let the OS assign) and communicate the actual port back, or maintain a port-allocator sidecar.") + ("avoid" + . + "Do not use a fixed REPL port or a single global trace file path when running concurrent benchmark instances. Collisions cause port-bind failures, corrupted trace files, and silently interleaved output.") + ("id" . "concurrent-benchmark-shared-repl-port") + ("kinds" "script" "module" "test") + ("pattern" . "(port\\s*=\\s*[0-9]{4,5}|trace.*path.*=)") + ("severity" . "high") + ("tags" "concurrent" "benchmark" "port" "trace" "isolation" + "race") + ("title" + . + "Concurrent benchmark runs share a fixed REPL port or global trace path") + ("tools" + "jerboa_verify" + "jerboa_run_tests" + "jerboa_security_scan")) + (("advice" + . + "Prefer bounded reads (read with line ranges), search-first workflows (grep/glob to locate relevant spans), and repomap to understand structure before reading. Only read the specific sections needed for the edit. Use lsp_definition and lsp_hover to jump to specific symbols without reading whole files.") + ("avoid" + . + "Do not cat or read entire large source files (>500 lines) before editing. This wastes context budget and can exceed provider context limits entirely, aborting the turn before any edit is made.") + ("id" . "cat-large-file-exceeds-context") ("kinds" "all") + ("pattern" + . + "(context.length.exceeded|maximum.context|token.limit)") + ("severity" . "high") + ("tags" "context-limit" "large-file" "bounded-read" + "search-first" "repomap") + ("title" + . + "Reading entire large source files exceeds provider context limit") + ("tools" "grep" "glob" "repomap" "lsp_definition" + "lsp_hover" "read")) + (("advice" + . + "When an optional feature (REPL port, config flags, etc.) is controlled by an env var that may not be set, do NOT always include the flag in the command with a hardcoded default string. Instead, check whether the env var is nonempty, and conditionally append the flag + value to the command list only when the env var is present. Use (append base (if val (list \\\"--flag\\\" val) '())) or construct the command with list-builder. For port flags, if the env var is absent, simply don't pass --repl-port at all rather than passing a hardcoded \\\"5555\\\".") + ("avoid" + . + "Always including an optional CLI flag with a hardcoded default string (e.g. --repl-port \\\"5555\\\") when the env var controlling it is absent. This bakes in a default that may collide, conflict with another runner, or override a more sensible default in the tool itself. The flag should be absent (not present with a default value) when the env var is unset.") + ("id" . "hardcoded-optional-flag-when-absent") + ("kinds" "module" "script") ("pattern" . "") + ("severity" . "medium") + ("tags" "optional" "env-var" "command-builder" "cli-flags" + "conditional" "append") + ("title" + . + "Always passing optional CLI flags with hardcoded defaults when env var absent") + ("tools" + "jerboa_howto" + "jerboa_function_signature" + "jerboa_verify")) + (("advice" + . + "When two or more modules in the same project need env-nonempty or a similar small helper, either (a) factor it into a shared utility module that both import, or (b) at minimum ensure the implementations match byte-for-byte. Copy-pasting with subtle differences (e.g., one uses string-trim+string=? vs. another using string-null? without trim) creates inconsistencies where one module rejects a blank env var while another accepts it. Shared configuration helpers should live in one importable module when more than one component relies on them.") + ("avoid" + . + "Copy-pasting the same small utility function (like env-nonempty) into multiple modules within the same project. This creates risk of divergence, makes maintenance harder, and often leads to one module having a subtly different check than another.") + ("id" . "copy-paste-duplicate-utility-across-modules") + ("kinds" "module") ("pattern" . "") ("severity" . "low") + ("tags" "copy-paste" "duplicate" "utility" "module" + "refactor" "env-nonempty") + ("title" + . + "Copy-pasting duplicate utility functions across modules in same project") + ("tools" "jerboa_compile_check" "jerboa_verify" "grep"))) --- a/data/cookbooks.sexp +++ b/data/cookbooks.sexp @@ -5616,39 +5616,6 @@ "Prefer the jsh executable when mux SHELL is an fd pseudo-path")) (("code" . - ";;; Contract verifier file. Generated module must export:\n;;; (make-static-board-window paint-count-box) -> values window canvas\n(import (jerboa prelude))\n(import (chezscheme))\n(import (jerboa-qt qt))\n(import (huihui static-board))\n\n(def immediate-exit (foreign-procedure \"_exit\" (int) void))\n\n(def (finish status)\n (flush-output-port (current-output-port))\n (flush-output-port (current-error-port))\n (immediate-exit status))\n\n(def (check expr message)\n (unless expr\n (error 'generated-qt-contract \"~a\" message)))\n\n(def (pump! app n)\n (when (> n 0)\n (qt-app-process-events! app)\n (pump! app (- n 1))))\n\n(def app (qt-app-create))\n(def paint-count-box (vector 0))\n\n(let-values (((win canvas) (make-static-board-window paint-count-box)))\n (check (not (eqv? win 0)) \"window handle should be nonzero\")\n (check (not (eqv? canvas 0)) \"canvas handle should be nonzero\")\n (qt-widget-show! win)\n (qt-paint-widget-update! canvas)\n (pump! app 10)\n (check (> (vector-ref paint-count-box 0) 0)\n \"paint callback did not increment verifier-owned counter\")\n (check (qt-widget-screenshot! win \"/tmp/generated-qt-contract.png\")\n \"screenshot failed\")\n (displayln \"generated Qt contract passed\")\n (finish 0))\n") ("id" . "jerboa-qt-generated-module-contract") - ("imports" - "(jerboa prelude)" - "(chezscheme)" - "(jerboa-qt qt)" - "(huihui static-board)") - ("notes" - . - "Use this when an AI/model should generate a Qt module but the verifier must own QApplication lifecycle, event pumping, screenshots, and assertions. Require the generated module to return handles and increment a verifier-owned `paint-count-box` from its paint callback; this proves the callback actually ran without requiring pixel inspection. Keep `_exit` in the verifier only, not generated app code, because it is a harness workaround for Qt/C++ teardown crashes. The generated module should not call `qt-app-create`, `qt-app-exec!`, `qt-widget-show!`, or `_exit`; the verifier controls those.") - ("tags" "jerboa-qt" "contract" "generated-module" - "offscreen" "paint-widget" "verification") - ("title" - . - "Verifier-owned contract for generated Jerboa Qt modules")) - (("code" - . - ";;; Verifier-owned examples for checking generated Tetris state, controls, and rendering.\n(import (jerboa prelude))\n(import (chezscheme))\n(import (jerboa-qt qt))\n(import (huihui tetris-game))\n\n(def (send-key! app win key)\n (qt-send-key-press! win key QT_MOD_NONE \"\")\n (pump! app 4))\n\n(def (same-cells? a b)\n (equal? (sort cell<? a)\n (sort cell<? b)))\n\n(def (check-piece-rotates! app win state piece)\n (clear-board! state)\n (debug-force-active! state piece 3 0)\n (let ((before-rotation (debug-active-cells state)))\n (send-key! app win QT_KEY_UP)\n (let ((after-rotation (debug-active-cells state)))\n (check (not (same-cells? before-rotation after-rotation))\n (str \"up key should rotate active \" piece \" piece\")))))\n\n;; Every non-square tetromino family should rotate, not only I.\n(for-each (lambda (piece)\n (check-piece-rotates! app win state piece))\n '(I T S Z J L))\n\n;; Rotation legality needs targeted wall/collision cases, not only a happy-path rotate.\n(clear-board! state)\n(debug-force-active! state 'I 3 17)\n(let ((before-rotation (debug-active-cells state)))\n (send-key! app win QT_KEY_UP)\n (check (same-cells? (debug-active-cells state) before-rotation)\n \"up key should not rotate active piece through the bottom wall\"))\n\n;; Timer gravity should lock when blocked, not only move when space is available.\n(qt-timer-set-single-shot! timer #t)\n(clear-board! state)\n(debug-board-set! state 4 19 'X)\n(debug-force-active! state 'O 4 17)\n(qt-timer-start! timer 20)\n(pump-wait! app 5 25)\n(check (debug-board-ref state 4 17)\n \"timer should lock active piece when downward movement is blocked\")\n(qt-timer-set-single-shot! timer #f)\n\n;; Soft drop must also be blocked, not just move on an empty board.\n(clear-board! state)\n(debug-force-active! state 'O 4 18)\n(send-key! app win QT_KEY_DOWN)\n(check (= (debug-active-row state) 18)\n \"down key should not move active piece through the bottom wall\")\n\n;; Hard drop should lock above occupied cells, then spawn the next piece.\n(clear-board! state)\n(debug-board-set! state 4 5 'X)\n(debug-force-active! state 'O 4 0)\n(send-key! app win QT_KEY_SPACE)\n(check (debug-board-ref state 4 3)\n \"space key should hard-drop and lock active piece above occupied cells\")\n(check (= (debug-active-row state) 0)\n \"space key should spawn next active piece after blocked hard drop\")\n\n;; A single lock can clear multiple rows; record baselines because earlier probes may update score/lines.\n(clear-board! state)\n(fill-row-except! state 18 4 5)\n(fill-row-except! state 19 4 5)\n(debug-force-active! state 'O 4 16)\n(let ((lines-before (vector-ref lines-box 0))\n (score-before (vector-ref score-box 0)))\n (debug-step! state)\n (debug-step! state)\n (debug-step! state)\n (check (>= (- (vector-ref lines-box 0) lines-before) 2)\n \"double line clear should increase line count by at least two\")\n (check (> (vector-ref score-box 0) score-before)\n \"double line clear should increase score\"))\n\n;; Repeated hard drops should vary spawned footprints, preferably through a deterministic cycle.\n(let ((spawn-footprints (collect-hard-drop-spawn-footprints! app win state 6)))\n (check (> (length (unique spawn-footprints)) 1)\n \"hard-drop spawn sequence should produce more than one tetromino footprint\"))\n\n;; Before screenshot, force a render state with known pixel coordinates.\n(clear-board! state)\n(debug-board-set! state 7 10 'X)\n(debug-force-active! state 'O 2 3)\n(qt-paint-widget-update! canvas)\n(pump! app 6)\n(check (qt-widget-screenshot! win \"/tmp/jerboa-qt-huihui-tetris-game.png\")\n \"tetris game screenshot failed\")\n\n;; Shell-side follow-up:\n;; scripts/huihui-verify-snapshots pixel \\\n;; /tmp/jerboa-qt-huihui-tetris-game.png 19 19 32 42 56 \"empty cell\" \\\n;; /tmp/jerboa-qt-huihui-tetris-game.png 59 79 64 180 120 \"active piece\" \\\n;; /tmp/jerboa-qt-huihui-tetris-game.png 159 219 190 82 80 \"locked cell\"\n") ("id" . "jerboa-qt-game-debug-contract") - ("imports" - "(jerboa prelude)" - "(chezscheme)" - "(jerboa-qt qt)" - "(huihui tetris-game)") - ("notes" - . - "For generated interactive games, keep the verifier in charge of QApplication, event pumping, synthetic keys, timer start/stop, and screenshots. Require generated code to expose a small debug surface such as `debug-force-active!`, `debug-active-col`, `debug-active-row`, `debug-active-cells`, `debug-board-ref`, `debug-board-set!`, and `debug-step!`. Use public key events plus debug hooks to verify legality: left/right, rotation, and soft drop must not cross board walls or move into occupied cells. Rotation should be checked for every non-square family (`I`, `T`, `S`, `Z`, `J`, and `L`), because checking only `I` allows an I-only rotation implementation to pass. Timer callbacks must exercise the same gravity/lock path as `debug-step!`; use `qt-timer-set-single-shot!` in the verifier for deterministic blocked-timer probes, then restore normal timer mode. For hard drop, add a negative fixture that respects board bounds but ignores occupied cells; this avoids failing earlier bottom/spawn checks and proves the intended blocker case. Include a two-row completion from one active-piece lock and compare `lines-box`/`score-box` against baselines. For screenshots, force a deterministic debug state immediately before `qt-widget-screenshot!` and then run exact RGB pixel checks out-of-process. This catches stale/decorative renderers that pass behavioral state checks and distinct-color screenshot checks but do not paint current active/locked cells. `_exit` and direct `(chezscheme)` imports are harness-only and should not be copied into generated app code; generated-module static audits should forbid them.") - ("tags" "jerboa-qt" "game" "debug-hooks" "contract" - "generated-module" "verification" "tetris" "pixel" - "screenshot" "collision") - ("title" - . - "Verifier debug hooks for generated Jerboa Qt games")) - (("code" - . "#!/usr/bin/env sh\nset -eu\n\n# In a generated-code ladder, keep contract tests fixed in the repo, then prove\n# they can go green by creating temporary reference modules outside the repo.\nrepo_root=$(pwd)\ntmpdir=$(mktemp -d \"${TMPDIR:-/tmp}/contract-reference.XXXXXX\")\ntrap 'rm -rf \"$tmpdir\"' EXIT INT TERM\nmkdir -p \"$tmpdir/src/example\" \"$tmpdir/lib\"\n\ncat > \"$tmpdir/src/example/generated.ss\" <<'EOF'\n(export answer)\n(import (jerboa prelude))\n(def answer 42)\nEOF\n\njerbuild transpile \"$tmpdir/src\" \"$tmpdir/lib\" --force\nJH=$(jerbuild --jerboa-home)\njerbuild exec --libdirs \"$tmpdir/lib:$repo_root/lib:$JH/lib\" tests/generated-contract.ss\n") ("id" . "jerboa-generated-contract-reference-self-test") ("imports" "(jerboa prelude)") ("notes" @@ -5661,147 +5628,6 @@ "Temporary reference modules for generated-code contract self-tests")) (("code" . - "#!/usr/bin/env sh\n# After a Qt offscreen smoke or contract test writes screenshots, decode PNGs and\n# assert dimensions, distinct-color count, and optional exact RGB pixels.\n\nscripts/huihui-verify-snapshots spec \\\n /tmp/jerboa-qt-huihui-tetris-game.png 240 460 3 1000 \"huihui tetris game\"\n\nscripts/huihui-verify-snapshots pixel \\\n /tmp/jerboa-qt-huihui-tetris-game.png 19 19 32 42 56 \"huihui tetris empty cell pixel\" \\\n /tmp/jerboa-qt-huihui-tetris-game.png 59 79 64 180 120 \"huihui tetris active piece pixel\" \\\n /tmp/jerboa-qt-huihui-tetris-game.png 159 219 190 82 80 \"huihui tetris locked cell pixel\"\n\n# Example output:\n# pass: huihui tetris game: 240x460, 4 colors, 1526 bytes\n# huihui snapshot verification passed\n# pass: huihui tetris empty cell pixel: pixel 19,19 RGB 32,42,56\n# pass: huihui tetris active piece pixel: pixel 59,79 RGB 64,180,120\n# pass: huihui tetris locked cell pixel: pixel 159,219 RGB 190,82,80\n# huihui snapshot verification passed\n") ("id" . "jerboa-qt-png-snapshot-content-check") ("imports") - ("notes" - . - "Use this after the Jerboa Qt smoke or contract test has already pumped the event loop and written PNGs with `qt-widget-screenshot!`. A screenshot existence check alone is too weak, and a distinct-color check alone can still pass a stale renderer. The jerboa-qt implementation uses a shell wrapper plus Ruby/Zlib to parse non-interlaced 8-bit PNGs locally, then verifies width, height, byte size, distinct RGB color count, and exact RGB values for selected coordinates. Pair exact-pixel checks with a verifier-forced state so the coordinates are deterministic. Keep this as a verifier-owned guard; generated model code should only create the GUI/screenshot under test.") - ("tags" "jerboa-qt" "screenshot" "png" "verification" - "offscreen" "snapshot" "pixel") - ("title" - . - "Verify Jerboa Qt screenshots by dimensions and exact pixels")) - (("code" - . - "#!/usr/bin/env sh\n# Final saved-log validation requires the runner self-validation section:\nscripts/huihui-verify-run-log docs/runs/20260609T000000Z-00-syntax.md\n\n# Runner-internal validation before appending ## Run Log Verification uses an explicit pre-self mode:\nscripts/huihui-verify-run-log --allow-missing-self docs/runs/20260609T000000Z-00-syntax.md\n\n# Before a live call, capture a no-model readiness checkpoint. This must not invoke jcode or start/stop servers.\nscripts/huihui-readiness-report --with-preflight --output /tmp/huihui-readiness.md\n\n# Live-run timeout defaults should be recorded in command output sections:\nHUIHUI_JCODE_TIMEOUT_SECONDS=900\nHUIHUI_VERIFY_TIMEOUT_SECONDS=300\n\n# Before invoking jcode, prove the requested rung is next using the same provenance dir that will receive the log:\nHUIHUI_STATUS_RUN_DIR=docs/runs HUIHUI_STATUS_CHECK=1 scripts/huihui-status\n\n# Required saved-log evidence order:\n# 1. recognized heading, timestamped filename, and - Time metadata for the same rung\n# 2. exact rung-to-prompt/verifier/source/lib mapping\n# 3. prompt-file digest plus extracted Model Task digest\n# 4. ## Status Gate with selected-rung pending line, exact pre-run summary, Next rung, and exit 0\n# 5. ## Prerequisite Verifier for every dependent rung, including rung 01 when rung 00 is a syntax-smoke prerequisite, with timeout policy and exit 0\n# 6. ## Prompt Text with the exact Model Task body sent to jcode\n# 7. ## Model Environment with no MLX process, no TCP 8000/11434 listener, TCP 8001 present, and Model environment exit: 0\n# 8. ## Command with jcode --provider mlx2 verified ... --cwd matching the repo root\n# 9. ## Output with jcode output and timeout policy\n# 10. ## Final Verifier with runner-owned verifier output, timeout policy, and exit 0\n# 11. ## Generated Artifact Manifest with selected source/library SHA-256 digests and byte counts\n# 12. ## File Guard with File guard: ok\n# 13. ## Generated Module Audit with expected current-rung pass line and summary\n# 14. ## Post-Run Model Environment with no MLX process, no TCP 8000/11434 listener, TCP 8001 present, and Post-run model environment exit: 0\n# 15. ## Exit Status with zero jcode, verifier, artifact, file guard, audit, and post-run model-environment exits\n# 16. ## Run Log Verification naming the same log path and exit 0\n") ("id" . "huihui-jcode-run-log-contract") ("imports") - ("notes" - . - "Use a run-log validator whenever model generation is expensive, risky, or hard to reproduce. The validator should infer the rung from the first markdown heading and require the exact prompt path, prompt digest metadata, verifier target, command text, final verifier command, selected source artifact, and selected generated-library artifact for that rung; otherwise a Frankenstein log can combine evidence from different rungs and still look structurally complete. Require the saved log filename suffix to match the rung heading, require the UTC timestamp filename prefix to match `- Time:`, and bind the recorded `jcode --provider mlx2 verified ... --cwd` to the repository root so copied logs from another checkout are rejected.\n\nBefore any explicit live model call, generate a no-model readiness report that captures model-environment safety, generated audit, ladder status, the single status-allowed live command, dry-run routing, optional preflight, and git status. The live runner should reject any process command line containing `mlx`, not just known server names such as `mlx_lm.server`, `mlx_lm`, or `mlx-lm`; fake-process tests should include a generic spelling such as `python -m mlx.server`. It should also reject listeners on TCP 8000 or 11434 and require the existing 8001 client route.\n\nFor staged ladders, the live runner should ask the status command what rung is next using the same run-log provenance directory it will write to, record the accepted status output under `## Status Gate`, and refuse to invoke jcode unless the requested rung matches that `Next rung` line. The saved-log validator should also require the status gate to contain the selected rung's pending missing-source line and exact pre-run summary, not just a copied `Next rung` line.\n\nScope critical proof text to its owning markdown section and enforce section order outside fenced code blocks. Prompt requirements belong in `## Prompt Text`; pre-call safety and `Model environment exit: 0` belong in `## Model Environment`; artifact digests belong in `## Generated Artifact Manifest`; audit summaries belong in `## Generated Module Audit`; post-run safety and `Post-run model environment exit: 0` belong in `## Post-Run Model Environment`. Close each fenced block before the next `##` heading so later sections are independently parseable.\n\nAfter jcode returns, independently re-run the selected verifier, record the selected generated artifact digests, run a file guard, run the generated-module audit, then run `scripts/huihui-check-model-env` again. This post-run model-environment proof catches a model call that leaves MLX or a listener on TCP 8000/11434 behind. Include the post-run check in the aggregate exit-status line and fail the live run if it exits nonzero. Also fail the live run when jcode exits nonzero even if it wrote artifacts and the final verifier would pass; the saved log should preserve that model output and show a nonzero jcode slot in `## Exit Status`, which the validator rejects.\n\nTests can exercise the whole path with fake ps/lsof/jcode/make binaries so preflight stays non-model and deterministic. Include negative fixtures for bad headers, filename/header rung mismatch, malformed timestamps, mismatched prompt text or prompt digest, malformed artifact digests, mismatched command cwd, missing/nonzero prerequisite proof, missing status-gate evidence, mismatched status run directory, mismatched self-validation log path, reordered section evidence, proof text moved outside its owning section, missing pre-call or post-run environment exit proof, missing timeout policy, mismatched generated-audit summary/pass line, stale prompt/source/library provenance, out-of-sequence requested rungs, generic `mlx` command lines, nonzero jcode exits after writing artifacts, hanging jcode, unexpected file writes, and fake jcode that succeeds but leaves TCP 11434 listening afterward.") - ("tags" "huihui" "jcode" "run-log" "verification" - "prompt-text" "artifact-manifest" "rung-mapping" - "prerequisite" "self-validation" "model-env" - "model-env-exit" "post-run-model-env" - "post-run-env-provenance" "timeout" "readiness-report" - "status-sequencing" "readiness-gate" - "status-pending-provenance" "ordered-evidence" - "section-scoped" "run-dir-provenance" "filename-provenance" - "prompt-provenance" "prompt-text-provenance" - "self-path-provenance" "timestamp-provenance" - "artifact-digest-provenance" "command-cwd-provenance" - "nonzero-exit" "mlx") - ("title" - . - "Verifier-owned run-log contract for Huihui jcode live runs")) - (("code" - . - "#!/usr/bin/env sh\n# Static checks to run before trusting a behavioral contract for AI-generated\n# Jerboa code. These catch common Racket/Gerbil/Clojure, Qt-lifecycle,\n# wrong-dialect API, and verifier-owned output hallucinations seen in generated\n# Tetris code.\n\nfail=0\n\nfail_msg() {\n file=$1\n message=$2\n printf 'FAIL: %s: %s\\n' \"$file\" \"$message\" >&2\n fail=1\n}\n\nforbid_regex() {\n file=$1\n pattern=$2\n message=$3\n if grep -E -- \"$pattern\" \"$file\" >/dev/null; then\n fail_msg \"$file\" \"$message\"\n fi\n}\n\nrequire_text() {\n file=$1\n needle=$2\n message=$3\n if ! grep -F -- \"$needle\" \"$file\" >/dev/null; then\n fail_msg \"$file\" \"$message\"\n fi\n}\n\nrequire_regex() {\n file=$1\n pattern=$2\n message=$3\n if ! grep -E -- \"$pattern\" \"$file\" >/dev/null; then\n fail_msg \"$file\" \"$message\"\n fi\n}\n\ncheck_common() {\n file=$1\n require_text \"$file\" '(jerboa prelude)' 'missing (jerboa prelude) import'\n forbid_regex \"$file\" '(^|[^[:alnum:]_-])defn([^[:alnum:]_-]|$)' 'use def, not defn'\n forbid_regex \"$file\" '(^|[^[:alnum:]_-])set-[[:alnum:]_-]+!' 'Jerboa defstruct setters are field-set!, not set-field!'\n forbid_regex \"$file\" '\\(make-[[:alnum:]_-]+[^)]*[[:space:]][[:alnum:]_-]+:' 'defstruct constructors are positional, not keyword-field calls'\n forbid_regex \"$file\" '#\\{' 'do not use Clojure/hash-literal syntax'\n forbid_regex \"$file\" '\\(library([[:space:]]|\\))' 'user-facing Jerboa files must not use library forms'\n forbid_regex \"$file\" '(^|[^[:alnum:]_-])(every\\?|any\\?)([^[:alnum:]_-]|$)' 'use Jerboa every/any, not Racket-style every?/any?'\n forbid_regex \"$file\" '(^|[^[:alnum:]_-])(symbol<\\?|string-contains\\?|define-struct|environment-bound\\?|time->seconds|thread-sleep!|thread-yield|path-expand|process-status|user-info-home|the-environment|condition/report-string|make-class-type|string-subst|open-fd-pair|make-equal-hashtable|arithmetic-shift|pregexp-match)([^[:alnum:]_-]|$)' 'do not use known non-Jerboa/Gerbil/Racket API names'\n forbid_regex \"$file\" '\\(raise[[:space:]]+\"' 'do not call raise with a string; use error with a who symbol'\n forbid_regex \"$file\" 'write-file|string->path|call-with-output-file|open-output-file|delete-file' 'generated modules should not write files, screenshots, logs, or artifacts; verifier owns outputs'\n forbid_regex \"$file\" 'qt-widget-screenshot!|qt-widget-grab|qt-pixmap-save!' 'generated modules should not capture or save screenshots; verifier owns screenshots and artifacts'\n}\n\ncheck_gui_contract_module() {\n file=$1\n require_text \"$file\" '(jerboa-qt qt)' 'missing (jerboa-qt qt) import'\n forbid_regex \"$file\" 'qt-app-create|qt-app-exec!|qt-app-quit!|qt-app-destroy!|with-qt-app|qt-widget-show!' 'verifier owns Qt app lifecycle and showing'\n forbid_regex \"$file\" 'qt-pixmap-create-blank|qt-painter-create' 'generated GUI rung should paint through the returned paint-widget painter'\n require_text \"$file\" 'qt-paint-widget-create' 'GUI rung should create a paint widget'\n require_text \"$file\" 'qt-on-paint!' 'GUI rung should register a paint callback'\n require_text \"$file\" 'qt-paint-widget-painter' 'GUI rung should draw with the paint-widget painter'\n require_text \"$file\" 'qt-painter-fill-rect!' 'GUI rung should draw visible filled rectangles'\n}\n\ncheck_key_handler() {\n file=$1\n require_text \"$file\" 'qt-on-key-press!' 'GUI rung should register a key handler'\n require_text \"$file\" 'qt-last-key-code' 'key handler should query qt-last-key-code'\n require_text \"$file\" 'QT_KEY_LEFT' 'key handler should reference QT_KEY_LEFT'\n require_text \"$file\" 'QT_KEY_RIGHT' 'key handler should reference QT_KEY_RIGHT'\n}\n\ncheck_tetris_surface() {\n file=$1\n check_common \"$file\"\n check_gui_contract_module \"$file\"\n check_key_handler \"$file\"\n require_text \"$file\" 'QT_KEY_UP' 'Tetris should reference QT_KEY_UP for rotation'\n require_text \"$file\" 'QT_KEY_DOWN' 'Tetris should reference QT_KEY_DOWN for soft drop'\n require_text \"$file\" 'QT_KEY_SPACE' 'Tetris should reference QT_KEY_SPACE for hard drop'\n for piece in I O T S Z J L; do\n require_regex \"$file\" \"(^|[^[:alnum:]_-])${piece}([^[:alnum:]_-]|$)\" \"Tetris should mention ${piece} tetromino family\"\n done\n}\n\ncheck_tetris_surface src/huihui/tetris-game.ss\n[ \"$fail\" -eq 0 ]") ("id" . "jerboa-ai-generated-syntax-tripwire-audit") - ("imports") - ("notes" - . - "Use these tripwires in verifier-owned shell audits for model-generated .ss files. They are intentionally static and cheap: behavioral tests should still compile and run the module afterward. The set-...! rule catches hallucinated setters like set-block-row! while allowing Jerboa names such as board-set!, debug-board-set!, vector-set!, and qt-widget-set-minimum-size! because those do not begin with set-. Keyword-field constructor calls like (make-block row: 0 col: 4) are invalid for Jerboa defstruct constructors, which are positional. Generated rung modules should not write files, screenshots, logs, or artifacts; the runner/verifier owns all output paths, so reject file-output calls before trusting screenshots or run logs. Also reject Qt screenshot/save APIs such as qt-widget-screenshot!, qt-widget-grab, and qt-pixmap-save! inside generated modules: these belong in verifier harnesses, not model-generated code. For generated GUI rungs, the verifier should own QApplication lifecycle and widget showing, so reject with-qt-app, qt-app-exec!, and qt-widget-show!. If the contract expects a returned paint widget, reject pixmap/manual-painter designs and require qt-paint-widget-create, qt-on-paint!, qt-paint-widget-painter, and qt-painter-fill-rect!. For keyboard-driven generated modules, require the source to register qt-on-key-press!, query qt-last-key-code, and mention the required key constants; this catches no-op key callbacks before expensive GUI tests. The wrong-dialect denylist catches high-frequency AI drift from Racket, Gerbil, Gambit, Common Lisp, and R6RS, including symbol<?, string-contains?, define-struct, environment-bound?, time->seconds, thread-sleep!, path-expand, process-status, make-equal-hashtable, arithmetic-shift, and pregexp-match. Also reject (raise \"...\") because Jerboa code should use (error 'who \"message\" irritants ...). For a Tetris rung, also require QT_KEY_UP, QT_KEY_DOWN, QT_KEY_SPACE, and visible mentions of all seven tetromino symbols I/O/T/S/Z/J/L. Static symbol mentions are not a behavioral proof; pair them with contract tests for rotation, collision, hard/soft drop, spawn variety, and line clearing.") - ("tags" "jerboa" "ai-generated" "audit" "syntax" "qt" - "wrong-dialect" "output") - ("title" - . - "Static audit tripwires for AI-generated Jerboa syntax mistakes")) - (("code" - . - "(import (jerboa prelude))\n(import (huihui tetris-board))\n\n(def square-cells\n (list (list 0 0) (list 1 0) (list 0 1) (list 1 1)))\n\n(def t-cells\n (list (list 0 0) (list 1 0) (list 2 0) (list 1 1)))\n\n(def (check expr message)\n (unless expr\n (error 'tetris-board-contract \"~a\" message)))\n\n(def (check-equal got expected message)\n (unless (equal? got expected)\n (error 'tetris-board-contract \"~a: expected ~s, got ~s\" message expected got)))\n\n(def (fill-row! board row value)\n (dotimes (col board-width)\n (board-set! board col row value)))\n\n(def (row-empty? board row)\n (let loop ((col 0))\n (or (= col board-width)\n (and (not (board-ref board col row))\n (loop (+ col 1))))))\n\n;; Core assertions for AI-generated board modules:\n(check-equal board-width 10 \"board width\")\n(check-equal board-height 20 \"board height\")\n(check-equal (board-index 9 19) 199 \"row-major bottom-right\")\n(check (not (in-bounds? 10 0)) \"column past width\")\n\n(def board (make-board))\n(place! board t-cells 2 3 'T)\n(check-equal (board-ref board 2 3) 'T \"translated T left cell\")\n(check-equal (board-ref board 3 4) 'T \"translated T stem cell\")\n(check (not (board-ref board 2 4)) \"adjacent empty cell remains empty\")\n\n(def clear-board (make-board))\n(fill-row! clear-board 15 'A)\n(fill-row! clear-board 18 'B)\n(board-set! clear-board 1 14 'M14)\n(board-set! clear-board 2 16 'M16)\n(board-set! clear-board 3 17 'M17)\n(board-set! clear-board 4 19 'M19)\n(check-equal (clear-full-lines clear-board) 2 \"separated clear count\")\n(check-equal (board-ref clear-board 4 19) 'M19 \"row below clears stays\")\n(check-equal (board-ref clear-board 3 18) 'M17 \"between row shifts once\")\n(check-equal (board-ref clear-board 1 16) 'M14 \"above both clears shifts twice\")\n(check (row-empty? clear-board 0) \"top refill row empty\")\n(displayln \"tetris board contract passed\")\n") ("id" . "jerboa-tetris-board-contract-gate") - ("imports" "(jerboa prelude)") - ("notes" - . - "Use this as a fixed verifier-owned contract before adding Qt. It catches common generated-code mistakes that a shallow board test misses: swapped row/column indexing, translated piece cells written to the wrong coordinates, row-full? behavior, and clear-full-lines implementations that only clear adjacent or bottom rows. Keep the implementation module generated, but keep this contract stable in the repo. Pair it with a temporary reference-module self-test so expected-red failures are known to be caused by the generated module being absent or wrong.") - ("tags" "jerboa" "tetris" "contract" "generated-module" - "board" "verification") - ("title" - . - "Verifier-owned pure Jerboa Tetris board contract gate")) - (("code" - . - "#!/usr/bin/env sh\nset -eu\nrepo_root=$(pwd)\ntmpdir=$(mktemp -d \"${TMPDIR:-/tmp}/negative-contract.XXXXXX\")\ntrap 'rm -rf \"$tmpdir\"' EXIT INT TERM\nJERBUILD=${JERBUILD:-jerbuild}\nJH=$($JERBUILD --jerboa-home)\n\nrun_bad_case() {\n name=$1\n expected=$2\n mkdir -p \"$tmpdir/$name/src/example\" \"$tmpdir/$name/lib\"\n cat > \"$tmpdir/$name/src/example/generated.ss\" <<EOF\n(export answer)\n(import (jerboa prelude))\n(def answer 41)\nEOF\n \"$JERBUILD\" transpile \"$tmpdir/$name/src\" \"$tmpdir/$name/lib\" --force >/tmp/$name.transpile.out 2>&1\n if \"$JERBUILD\" exec --libdirs \"$tmpdir/$name/lib:$repo_root/lib:$JH/lib\" tests/generated-contract.ss >/tmp/$name.contract.out 2>&1; then\n echo \"FAIL: $name unexpectedly passed\" >&2\n exit 1\n fi\n grep -F \"$expected\" /tmp/$name.contract.out >/dev/null || {\n echo \"FAIL: $name did not fail with expected text: $expected\" >&2\n cat /tmp/$name.contract.out >&2\n exit 1\n }\n echo \"pass: contract rejects $name\"\n}\n\nrun_bad_case wrong-answer \"expected 42\"\n") ("id" . "jerboa-generated-contract-negative-fixtures") - ("imports") - ("notes" - . - "Use negative fixtures alongside temporary reference modules for AI-generated-code ladders. The positive reference module proves the verifier can go green. The negative fixtures prove the verifier rejects plausible wrong implementations and that failures are targeted enough to diagnose model mistakes. In jerboa-qt this pattern is used for Tetris board mistakes such as swapped row/column indexing, ignored occupancy, ignored origin offsets, weak row-full?, and bottom-only line clearing.") - ("tags" "jerboa" "contract" "negative-test" - "generated-module" "verification" "jerbuild") - ("title" - . - "Negative fixtures for verifier-owned generated-module contracts")) - (("code" - . - "#!/usr/bin/env sh\n# Production command checks the real repo:\nscripts/huihui-status\n\n# Fixture tests can redirect generated-source presence, generated-library\n# presence, static-audit checks, and run-log provenance while using fake\n# verifier targets from PATH. This avoids creating src/huihui/*.ss in the repo.\ntmpdir=$(mktemp -d)\nroot=$tmpdir/root\nmkdir -p \"$root/src/huihui\" \"$root/lib/huihui\" \"$root/docs/runs\" \"$tmpdir/fake-bin\"\ncat > \"$root/src/huihui/tetris-board.ss\" <<'SRC'\n(export make-board board-width board-height board-index board-ref board-set!\n in-bounds? can-place? place! row-full? clear-full-lines)\n(import (jerboa prelude))\n(def board-width 10)\n(def board-height 20)\n(def (make-board) (make-vector (* board-width board-height) #f))\n(def (board-index col row) (+ col (* row board-width)))\n(def (board-ref board col row) (vector-ref board (board-index col row)))\n(def (board-set! board col row value) (vector-set! board (board-index col row) value))\n(def (in-bounds? col row) (and (>= col 0) (< col board-width) (>= row 0) (< row board-height)))\n(def (can-place? board cells origin-col origin-row) #t)\n(def (place! board cells origin-col origin-row value) #!void)\n(def (row-full? board row) #f)\n(def (clear-full-lines board) 0)\nSRC\ncat > \"$root/lib/huihui/tetris-board.sls\" <<'LIB'\n;; fake generated library artifact for status provenance tests\nLIB\n\nsrc_sha=$(shasum -a 256 \"$root/src/huihui/tetris-board.ss\" | awk '{print $1}')\nsrc_bytes=$(wc -c < \"$root/src/huihui/tetris-board.ss\" | tr -d ' ')\nlib_sha=$(shasum -a 256 \"$root/lib/huihui/tetris-board.sls\" | awk '{print $1}')\nlib_bytes=$(wc -c < \"$root/lib/huihui/tetris-board.sls\" | tr -d ' ')\ncat > \"$root/docs/runs/20260609T000000Z-01-board.md\" <<EOF\n# Huihui Rung 01-board Run\n\n- Prompt: \\`docs/prompts/huihui-rung-01-board.md\\`\n- Provider: \\`mlx2\\`\n- Endpoint policy: existing \\`127.0.0.1:8001\\` route only; this runner did not start a server.\n- Verifier: \\`make huihui-board-contract\\`\n\n## Prompt Text\n\nCreate \\`src/huihui/tetris-board.ss\\`\nDo not modify tests, examples, Makefile, docs, README, or existing Qt modules.\n\n## Model Environment\n\nHuihui model environment check\npass: no MLX process\npass: no listener on TCP 8000\npass: no listener on TCP 11434\npass: listener present on TCP 8001\nSummary: model environment safe for explicit client-only call\n\n## Command\n\njcode --provider mlx2 verified \"<Model Task from docs/prompts/huihui-rung-01-board.md>\" --verify 'make huihui-board-contract' --cwd /repo\n\n## Output\n\nTimeout policy: 900 seconds wall-clock limit for jcode\n\n## Final Verifier\n\n\\$ make huihui-board-contract\nTimeout policy: 300 seconds wall-clock limit for final verifier\nFinal verifier exit: 0\n\n## Generated Artifact Manifest\n\nSelected source: src/huihui/tetris-board.ss\nSelected generated library: lib/huihui/tetris-board.sls\nsource: present src/huihui/tetris-board.ss sha256:$src_sha bytes:$src_bytes\ngenerated library: present lib/huihui/tetris-board.sls sha256:$lib_sha bytes:$lib_bytes\nArtifact manifest: ok\nArtifact manifest exit: 0\n\n## File Guard\n\nFile guard: ok\n\n## Generated Module Audit\n\nHuihui generated module static audit\n\n## Exit Status\n\n\\`0\\` (jcode), \\`0\\` (final verifier), \\`0\\` (artifact manifest), \\`0\\` (file guard), \\`0\\` (generated audit)\n\n## Run Log Verification\n\n\\$ scripts/huihui-verify-run-log --allow-missing-self docs/runs/20260609T000000Z-01-board.md\nhuihui run log verification passed: docs/runs/20260609T000000Z-01-board.md\nRun log verification exit: 0\nEOF\n\ncat > \"$tmpdir/fake-bin/make\" <<'EOF'\n#!/usr/bin/env sh\ncase \"$1\" in\n huihui-board-contract)\n echo \"fake board contract passed\"\n exit 0\n ;;\n huihui-static-board-contract)\n echo \"Exception: library (huihui static-board) not found\"\n exit 1\n ;;\n *)\n echo \"Exception: library for later rung not found\"\n exit 1\n ;;\nesac\nEOF\nchmod +x \"$tmpdir/fake-bin/make\"\n\nPATH=\"$tmpdir/fake-bin:$PATH\" \\\nHUIHUI_STATUS_ROOT=\"$root\" \\\nscripts/huihui-status\n# Expected: rung 01 static audit, contract, and provenance pass; rung 02 is pending.\nrm -rf \"$tmpdir\"\n") ("id" . "generated-ladder-status-fixture-root") ("imports") - ("notes" - . - "For AI-generated capability ladders, status logic should be tested against more than the current workspace state. Add a fixture-root environment variable that redirects generated-source presence, generated-library presence, generated-code static audit checks, and run-log provenance; keep verifier targets running from the repository root so fake `make` commands can model pass, expected missing-library, and broken-contract outcomes. A generated rung should advance only when static audit, behavioral contract, accepted run-log prompt provenance, and accepted run-log artifact provenance all pass. The status command should validate the latest run log with the normal run-log validator, then compare current SHA-256 digests and byte counts for the prompt file, selected source, and generated library against the recorded run log. Test at least seven states: all-pending current state, partial progress that advances to the next rung, generated source with no accepted run log, generated source whose prompt digest changed after the accepted log, generated source whose artifact digest changed after the accepted log, generated source whose verifier fails and blocks continuation, and generated source whose static audit fails even though the fake contract passes. This catches status commands that would incorrectly keep running later model rungs after a broken, prompt-violating, manually edited, or stale generated artifact. When writing shell status scripts, avoid global variable reuse in helper functions; POSIX shell variables are dynamically global unless carefully isolated, and a loop variable in an export checker can corrupt a later printed rung name.") - ("tags" "jerboa" "generated-module" "status" "fixture-root" - "verification" "ladder" "static-audit" "run-log" - "provenance") - ("title" - . - "Test generated-rung ladder status with fixture roots")) - (("code" - . - ";;; Verifier-owned bridge rung before a full seven-piece Tetris game.\n(import (jerboa prelude))\n(import (chezscheme))\n(import (jerboa-qt qt))\n(import (huihui locking-board))\n\n(def (send-key! app win key)\n (qt-send-key-press! win key QT_MOD_NONE \"\")\n (pump! app 4))\n\n;; Generated module API:\n;; (make-locking-board-window paint-count-box score-box lines-box game-over-box)\n;; => win canvas timer state\n;; debug-force-active!, debug-active-col, debug-active-row,\n;; debug-board-ref, debug-board-set!, debug-step!\n\n(clear-board! state)\n(debug-force-active! state 4 0)\n(send-key! app win QT_KEY_SPACE)\n(check (debug-board-ref state 4 18)\n \"space key should hard-drop and lock active square at the bottom\")\n(check (= (debug-active-row state) 0)\n \"space key should spawn the next active square at the top after locking\")\n\n(clear-board! state)\n(debug-board-set! state 4 5 'X)\n(debug-force-active! state 4 0)\n(send-key! app win QT_KEY_SPACE)\n(check (debug-board-ref state 4 3)\n \"space key should hard-drop and lock active square above occupied cells\")\n\n(clear-board! state)\n(fill-row-except! state 19 4 5)\n(debug-force-active! state 4 17)\n(let ((lines-before (vector-ref lines-box 0))\n (score-before (vector-ref score-box 0)))\n (debug-step! state)\n (debug-step! state)\n (check (>= (- (vector-ref lines-box 0) lines-before) 1)\n \"locking into a nearly full row should clear at least one line\")\n (check (> (vector-ref score-box 0) score-before)\n \"line clear should increase score\"))\n\n(clear-board! state)\n(debug-board-set! state 7 10 'X)\n(debug-force-active! state 2 3)\n(qt-paint-widget-update! canvas)\n(pump! app 6)\n(check (qt-widget-screenshot! win \"/tmp/jerboa-qt-huihui-locking-board.png\")\n \"locking board screenshot failed\")\n\n;; Shell-side follow-up:\n;; scripts/huihui-verify-snapshots spec \\\n;; /tmp/jerboa-qt-huihui-locking-board.png 240 460 3 1000 \"locking board\"\n;; scripts/huihui-verify-snapshots pixel \\\n;; /tmp/jerboa-qt-huihui-locking-board.png 19 19 32 42 56 \"empty cell\" \\\n;; /tmp/jerboa-qt-huihui-locking-board.png 59 79 64 180 120 \"active square\" \\\n;; /tmp/jerboa-qt-huihui-locking-board.png 159 219 190 82 80 \"locked cell\"\n") ("id" . "jerboa-qt-locking-board-bridge-contract") - ("imports" - "(jerboa prelude)" - "(chezscheme)" - "(jerboa-qt qt)" - "(huihui locking-board)") - ("notes" - . - "When a generated model struggles with a full Tetris GUI, add a bridge rung that keeps only a 2x2 square active piece but requires the mechanics that make Tetris hard: collision-aware left/right movement, timer gravity, blocked-timer locking, soft drop, hard drop, respawn at row 0, line clear, score/line counters, game-over on blocked spawn, and state-linked rendering. This isolates lock/respawn/line-clear behavior before adding seven tetromino families and rotation. Keep the verifier in charge of QApplication, timer start/stop/destroy, event pumping, and screenshots. Add negative fixtures for no-key, no-horizontal-blocking, no-timeout, no-timer-lock, no-soft-drop, no-soft-drop-blocking, no-hard-drop, no-hard-drop-blocking, no-spawn-after-hard-drop, no-line-clear, no-score, no-game-over, flat render, and stale render. Pair distinct-color screenshot checks with exact RGB pixel checks after forcing a deterministic debug state.") - ("tags" "jerboa-qt" "tetris" "locking" "line-clear" - "contract" "generated-module" "bridge") - ("title" - . - "Bridge full Tetris with a single-square locking Qt board contract")) - (("code" - . - "#!/usr/bin/env sh\n# Report the newest generated-code ladder run without invoking the model.\nscripts/huihui-run-report --run-dir docs/runs\n\n# Report a specific accepted or failed run log.\nscripts/huihui-run-report docs/runs/20260609T000000Z-01-board.md\n\n# Keep the reporter covered by fake accepted and targeted failed logs.\nmake huihui-run-report-test\n") ("id" . "generated-ladder-run-report-triage") ("imports") - ("notes" - . - "A rich saved run log is good provenance, but it is too verbose for quick iteration after a failed AI-generation attempt. Add a separate offline reporter that selects the latest log or accepts an explicit log path, runs the saved-log validator, extracts key section exits, and prints one next action. It should not call jcode, start servers, stop servers, or mutate generated sources.\n\nUseful section summaries include `## Status Gate`, `## Model Environment`, `## Output`, `## Final Verifier`, `## Generated Artifact Manifest`, `## File Guard`, `## Generated Module Audit`, `## Post-Run Model Environment`, `## Exit Status`, and `## Run Log Verification`. If validation passes, the next action can be to run the ladder status command. If validation fails, prioritize nonzero or unsafe sections: pre-call model environment, post-run model environment, status gate, nonzero aggregate `jcode` exit, final verifier, artifact manifest, file guard, generated audit, then generic log validation/provenance failures. Checking the aggregate `jcode` component separately matters because the model client can fail even if stale artifacts allow later runner-owned checks to produce output.\n\nTest this with fake ps/lsof/jcode/make fixtures. Generate one accepted fake log through the real runner, then copy and mutate it into targeted failures such as aggregate ``42`` for `(jcode)`, `Final verifier exit: 42`, and `Post-run model environment exit: 1`. The reporter should still exit successfully for readable failed logs so humans can get triage output, while missing log directories or missing log files should exit nonzero.") - ("tags" "generated-module" "ladder" "run-log" "triage" - "huihui" "jcode" "verification" "next-action") - ("title" - . - "Summarize generated-code ladder run logs for next-action triage")) - (("code" - . - "#!/usr/bin/env sh\n# After an explicit live run, collect the next no-model checkpoint.\nscripts/huihui-post-run-checkpoint --run-dir docs/runs --output /tmp/huihui-post-run.md\n\n# For a specific log, keep the run directory bound to the same provenance set.\nscripts/huihui-post-run-checkpoint \\\n --run-dir docs/runs \\\n --output /tmp/huihui-post-run.md \\\n docs/runs/20260609T000000Z-01-board.md\n\n# Keep the checkpoint covered by fake accepted and failed logs.\nmake huihui-post-run-checkpoint-test\n") ("id" . "generated-ladder-post-run-checkpoint") ("imports") - ("notes" - . - "A staged AI-generated-code ladder benefits from two reports: a pre-run readiness checkpoint and a post-run checkpoint. The post-run checkpoint should never call the model, start servers, stop servers, or edit generated files. It should compose existing gates rather than inventing a second validator: saved-log validation, compact run-report triage, ladder status with the same run-log directory, generated-module static audit, and model-environment safety.\n\nBind the status command to the same provenance directory used by the live run, for example `HUIHUI_STATUS_RUN_DIR=docs/runs HUIHUI_STATUS_CHECK=1 scripts/huihui-status`. This prevents a successful log in one run directory from being mixed with status evidence from another directory and keeps fake status tests deterministic.\n\nThe checkpoint should write its markdown artifact even when a gate fails, then exit nonzero. That behavior preserves useful diagnostics for failed model attempts while preventing automation from continuing to the next rung. Useful sections are `## Run Log Validation`, `## Run Report`, `## Ladder Status`, `## Generated Module Audit`, `## Model Environment`, and a final summary. Tests should include a fake accepted run that advances status to the next rung and a mutated failed log, such as `Final verifier exit: 42`, that makes the checkpoint exit nonzero while retaining the run-report next action.") - ("tags" "generated-module" "ladder" "post-run" "checkpoint" - "run-log" "status" "audit" "model-env" "huihui") - ("title" - . - "Post-run checkpoint for generated-code ladders")) - (("code" - . - "#!/usr/bin/env sh\n# Exercise the real live-run harness through every rung with fake model/verifier tools.\nmake huihui-sequence-test\n\n# The sequence test should prove each saved log validates and final status reaches all-pass:\nscripts/huihui-verify-run-log /tmp/run-dir/20260609T000001Z-01-board.md\nHUIHUI_STATUS_RUN_DIR=/tmp/run-dir HUIHUI_STATUS_CHECK=1 scripts/huihui-status\nscripts/huihui-post-run-checkpoint --run-dir /tmp/run-dir --output /tmp/final-checkpoint.md\n") ("id" . "generated-ladder-fake-sequence-test") ("imports") - ("notes" - . - "Single-rung fake tests prove individual guardrails, but a staged generated-code ladder can still fail at the transitions between rungs. Add a fake full-sequence test that places fake `jcode`, `make`, `ps`, and `lsof` earlier on PATH, runs the real `scripts/huihui-rung --allow-model-call NN` for every rung, and writes logs to a temporary `HUIHUI_RUN_DIR`.\n\nThe fake model should emit static-audit-clean placeholder sources for each rung and the fake verifier should create the corresponding generated-library artifact. The fake status behavior should return missing-library failures until each source exists, then pass the target and let the real status command validate latest accepted run-log provenance. This exercises status-gate sequencing, prerequisite verifier recording, artifact manifests, generated audit summaries, self-validation, and post-run environment proof across the entire ladder.\n\nAfter each rung, run the real status command with `HUIHUI_STATUS_RUN_DIR` bound to the temporary run directory and assert the next rung advanced. After the last rung, require `Summary: 6 passed, 0 pending, 0 failed`, validate all six logs with the saved-log validator, run the real generated audit, and write a post-run checkpoint. This stays fully offline while proving the ladder mechanics are ready for an explicit live model attempt.") - ("tags" "generated-module" "ladder" "sequence" "fake-jcode" - "run-log" "status" "provenance" "huihui") - ("title" - . - "Fake full-sequence test for generated-code ladders")) - (("code" - . - "#!/usr/bin/env sh\n# Run before and after any explicit live model call. This starts and stops\n# nothing; it only verifies the local machine is in the expected client-only\n# state.\n\nfailures=0\n\nfail() {\n printf 'FAIL: %s\\n' \"$*\" >&2\n failures=$((failures + 1))\n}\n\nport_listeners() {\n port=$1\n lsof -nP -iTCP:\"$port\" -sTCP:LISTEN 2>/dev/null || true\n}\n\nprintf 'Model environment check\\n'\n\n# Strict mode: no command line containing mlx is allowed during a client-only run.\nmlx_hits=$(ps -axo pid=,ppid=,command= | awk 'BEGIN{IGNORECASE=1} /[m]lx/ {print}' || true)\nif [ -n \"$mlx_hits\" ]; then\n fail 'MLX process is running'\n printf '%s\\n' \"$mlx_hits\" >&2\nelse\n printf 'pass: no MLX process\\n'\nfi\n\nother_model_hits=$(ps -axo pid=,ppid=,command= | awk 'BEGIN{IGNORECASE=1} /[o]llama|[l]lama-server|[l]lama_server/ {print}' || true)\nif [ -n \"$other_model_hits\" ]; then\n fail 'other local model-server process is running'\n printf '%s\\n' \"$other_model_hits\" >&2\nelse\n printf 'pass: no other local model-server process\\n'\nfi\n\nfor port in 8000 11434; do\n hits=$(port_listeners \"$port\")\n if [ -n \"$hits\" ]; then\n fail \"TCP $port has a listener\"\n printf '%s\\n' \"$hits\" >&2\n else\n printf 'pass: no listener on TCP %s\\n' \"$port\"\n fi\ndone\n\nhits=$(port_listeners 8001)\nif [ -n \"$hits\" ]; then\n printf 'pass: listener present on TCP 8001\\n'\n printf '%s\\n' \"$hits\"\nelse\n fail 'TCP 8001 has no listener'\nfi\n\n[ \"$failures\" -eq 0 ]\n") ("id" . "generated-ladder-model-env-safety-gate") - ("imports") - ("notes" - . - "Use this as a pre-call and post-call safety section in generated-code ladder runners. It is intentionally observational: do not start, stop, unload, or kill processes inside the gate. Reject both process names and ports because failures differ by serving stack. For strict client-only workflows, reject any process command line containing `mlx`, not just known server names such as `mlx_lm.server` or `mlx-lm-server`; fake-process tests should include a generic spelling such as `python -m mlx.server`. Keep the expected client route separate, for example require an existing SSH/OpenAI-compatible listener on TCP 8001 while forbidding local listeners on TCP 8000 and 11434. For saved run logs, record both the command output and an explicit environment-check exit status before and after the model call so copied safety text cannot satisfy validation.") - ("tags" "generated-module" "ladder" "model-env" "safety" - "ports" "jcode" "huihui" "mlx") - ("title" - . - "Model-environment safety gate for generated-code ladders")) - (("code" - . "(export make-counter counter-value counter-step! sum-values classify-cell make-grid grid-index grid-ref grid-set!)\n(import (jerboa prelude))\n\n(def (make-counter initial)\n (vector initial))\n\n(def (counter-value counter)\n (vector-ref counter 0))\n\n(def (counter-step! counter delta)\n (let ((next (+ (counter-value counter) delta)))\n (vector-set! counter 0 next)\n next))\n\n(def (sum-values values)\n (for/fold ((total 0)) ((value values))\n (+ total value)))\n\n(def (classify-cell value)\n (cond\n ((not value) 'empty)\n ((number? value) 'number)\n ((symbol? value) 'symbol)\n (else 'other)))\n\n(def (make-grid width height fill)\n (make-vector (* width height) fill))\n\n(def (grid-index col row width)\n (+ col (* row width)))\n\n(def (grid-ref grid col row width)\n (vector-ref grid (grid-index col row width)))\n\n(def (grid-set! grid col row width value)\n (vector-set! grid (grid-index col row width) value)\n value)\n") ("id" . "generated-ladder-syntax-smoke-rung") ("imports" "(jerboa prelude)") ("notes" @@ -5814,52 +5640,6 @@ "Pre-board syntax-smoke rung for generated Jerboa modules")) (("code" . - "#!/usr/bin/env sh\n# Acquire this only for explicit live model calls, not dry runs.\nrun_dir=${HUIHUI_RUN_DIR:-docs/runs}\nmkdir -p \"$run_dir\"\nrun_lock_dir=$run_dir/.huihui-rung.lock\nrun_lock_acquired=0\n\ncleanup_runner() {\n # Remove temp files here too in the real runner.\n if [ \"$run_lock_acquired\" -eq 1 ]; then\n rmdir \"$run_lock_dir\" 2>/dev/null || true\n fi\n}\ntrap cleanup_runner EXIT INT TERM\n\nif mkdir \"$run_lock_dir\" 2>/dev/null; then\n run_lock_acquired=1\nelse\n printf 'error: another generated-code rung appears to be running; lock exists: %s\\n' \"$run_lock_dir\" >&2\n exit 1\nfi\n\n# After this point it is safe to run status gating, jcode, final verifier,\n# artifact manifest generation, file guard, audit, and run-log validation for\n# this run directory without another runner concurrently mutating the same files.\n") ("id" . "generated-ladder-live-run-lock") ("imports") - ("notes" - . - "Use a per-run-directory lock for generated-code ladders where live model calls mutate fixed generated source paths such as `src/huihui/*.ss` and write provenance logs. Acquire the lock after choosing and creating the run directory and before status gating or invoking the model. Keep dry runs lock-free. Store the lock under the run-log directory so normal source file guards can ignore it with other run artifacts. Tests should cover a pre-existing lock rejecting a live call and successful plus failed live paths removing the lock; otherwise stale locks or overlapping live calls can make prompt/source/library provenance meaningless.") - ("tags" "generated-module" "ladder" "jcode" "run-log" "lock" - "concurrency" "provenance") - ("title" - . - "Serialize generated-code live runs with a run-directory lock")) - (("code" - . - "#!/usr/bin/env sh\n# Compare a pre-call and post-call file manifest, ignoring only the selected\n# generated artifacts for the current rung plus tool-owned run logs.\nsource_file=src/huihui/syntax-smoke.ss\ngenerated_lib_file=lib/huihui/syntax-smoke.sls\nrun_dir=docs/runs\n\nsnapshot_manifest() {\n manifest=$1\n run_dir_rel=${run_dir#./}\n : > \"$manifest\"\n find . -type f ! -path './.git/*' | sort | while IFS= read -r file; do\n case \"$file\" in\n ./\"$run_dir_rel\"/*) continue ;;\n esac\n hash=$(shasum -a 256 \"$file\" | awk '{print $1}')\n printf '%s\\t%s\\n' \"$file\" \"$hash\"\n done > \"$manifest\"\n}\n\nchanged_paths() {\n before=$1\n after=$2\n comm -3 \"$before\" \"$after\" | sed 's/^\\t//' | awk -F '\\t' 'NF >= 2 {print $1}' | sort -u\n}\n\nallowed_changed_path() {\n path=$1\n case \"$path\" in\n ./\"$source_file\" | \\\n ./\"$generated_lib_file\" | \\\n ./src/.jerbuild-hashes)\n return 0\n ;;\n *)\n return 1\n ;;\n esac\n}\n\ncheck_file_guard() {\n before=$1\n after=$2\n bad=$3\n changed_paths \"$before\" \"$after\" | while IFS= read -r path; do\n [ -n \"$path\" ] || continue\n if ! allowed_changed_path \"$path\"; then\n printf '%s\\n' \"$path\"\n fi\n done > \"$bad\"\n\n if [ -s \"$bad\" ]; then\n printf 'File guard: disallowed file changes detected\\n'\n cat \"$bad\"\n return 1\n fi\n\n printf 'File guard: ok\\n'\n}\n") ("id" . "generated-ladder-protected-core-file-guard") - ("imports") - ("notes" - . - "For generated-code ladders, do not broadly allow build outputs such as core binding libraries or shim artifacts. A model can otherwise alter infrastructure to make the selected verifier pass while leaving the rung source looking acceptable. Allow only the selected generated source, the selected generated library artifact, and narrow build metadata such as `src/.jerbuild-hashes`; store run logs outside the manifest comparison. Add a fake-live regression that modifies a protected core file such as `lib/jerboa-qt/qt.sls` and assert the guard rejects it.") - ("tags" "generated-module" "ladder" "jcode" "file-guard" - "provenance" "infrastructure") - ("title" - . - "Protect core infrastructure files in generated-code live runs")) - (("code" - . - "#!/usr/bin/env sh\n# Allow default in-repository run logs under docs/runs, plus out-of-repository\n# temp run directories for tests. Reject broad in-repo dirs such as docs.\nprepare_run_dir() {\n run_dir=$1\n mkdir -p \"$run_dir\"\n\n abs_repo=$(pwd -P)\n abs_run_dir=$(CDPATH= cd -- \"$run_dir\" && pwd -P)\n allowed_repo_run_root=$abs_repo/docs/runs\n\n case \"$abs_run_dir\" in\n \"$abs_repo\" | \"$abs_repo\"/*)\n case \"$abs_run_dir\" in\n \"$allowed_repo_run_root\" | \"$allowed_repo_run_root\"/*)\n ;;\n *)\n printf 'error: HUIHUI_RUN_DIR inside this repository must be docs/runs or a descendant, got: %s\\n' \"$run_dir\" >&2\n exit 1\n ;;\n esac\n ;;\n esac\n}\n\nrun_dir=${HUIHUI_RUN_DIR:-docs/runs}\nprepare_run_dir \"$run_dir\"\n") ("id" . "generated-ladder-run-dir-scope-guard") ("imports") - ("notes" - . - "Manifest-based file guards often exclude the run-log directory from before/after comparisons. If a user or wrapper can set the run directory to a broad in-repo path such as `docs`, generated edits under that path can be hidden from the guard. Validate the run directory before acquiring locks or invoking the model: allow the intended in-repo log root such as `docs/runs` and its descendants, plus out-of-repo temp dirs for fake-run tests. Add a regression with `HUIHUI_RUN_DIR=docs` that fails before the fake model call.") - ("tags" "generated-module" "ladder" "run-log" "file-guard" - "manifest" "provenance") - ("title" - . - "Restrict in-repo run-log directories for manifest-based generated-code guards")) - (("code" - . - "#!/usr/bin/env sh\n# Lightweight static audit helpers for generated Jerboa modules. This is not a\n# full Scheme parser; it catches the common generated-code bypasses before the\n# behavioral verifier is trusted.\ntop_form_count() {\n form=$1\n file=$2\n sed 's/;.*//' \"$file\" |\n grep -E \"^[[:space:]]*\\\\(${form}([[:space:]]|\\\\))\" |\n wc -l |\n tr -d ' '\n}\n\ntop_forms() {\n form=$1\n file=$2\n awk -v form=\"$form\" '\n function paren_delta(s, copy, opens, closes) {\n copy = s\n opens = gsub(/\\(/, \"(\", copy)\n copy = s\n closes = gsub(/\\)/, \")\", copy)\n return opens - closes\n }\n {\n line = $0\n sub(/;.*/, \"\", line)\n }\n !emit && line ~ \"^[[:space:]]*\\\\(\" form \"([[:space:]]|\\\\))\" {\n emit = 1\n depth = 0\n }\n emit {\n print line\n depth += paren_delta(line)\n if (depth <= 0) emit = 0\n }\n ' \"$file\"\n}\n\ncheck_imports() {\n file=$1\n shift\n forms=$(top_forms import \"$file\")\n [ -n \"$forms\" ] || { echo \"missing top-level import form\"; return 1; }\n\n normalized=$(printf '%s\\n' \"$forms\" | tr '\\n' ' ')\n for expected_module in \"$@\"; do\n printf '%s\\n' \"$normalized\" | grep -F \"($expected_module)\" >/dev/null || {\n echo \"missing expected import ($expected_module)\"\n return 1\n }\n normalized=$(printf '%s\\n' \"$normalized\" | sed \"s/($expected_module)//g\")\n done\n\n leftovers=$(printf '%s\\n' \"$normalized\" |\n sed 's/(import//g; s/[()]//g; s/[[:space:]]//g')\n [ -z \"$leftovers\" ] || { echo \"unexpected import module\"; return 1; }\n}\n\ncheck_single_export_form() {\n file=$1\n count=$(top_form_count export \"$file\")\n [ \"$count\" -eq 1 ] || { echo \"must contain exactly one top-level export form\"; return 1; }\n}\n\ncheck_single_export_form src/huihui/static-board.ss\ncheck_imports src/huihui/static-board.ss \"jerboa prelude\" \"jerboa-qt qt\"\n") ("id" . "generated-ladder-exact-import-export-audit") - ("imports") - ("notes" - . - "When generated modules are constrained by prompts, require the static audit to enforce the prompt-owned module boundary too. Behavioral tests may not catch extra imports that perform side effects or a second export form that bypasses an export-token check. Add negative fixtures for `(import (std net request))` in a pure rung and a second top-level `(export rogue-helper)` form. Keep this as a pre-verifier tripwire; use the Jerboa compiler/contracts for full syntax and behavior.") - ("tags" "jerboa" "generated-module" "ladder" "static-audit" - "imports" "exports") - ("title" - . - "Enforce exact imports and a single export form in generated modules")) - (("code" - . "#!/usr/bin/env sh\n# Timeout wrapper that terminates the direct child and any descendants visible\n# by parent PID before escalating to SIGKILL.\nchild_pids() {\n parent=$1\n if [ -x /bin/ps ]; then\n /bin/ps -axo pid=,ppid=\n else\n ps -axo pid=,ppid=\n fi | awk -v parent=\"$parent\" '$2 == parent {print $1}' || true\n}\n\nterminate_process_tree() {\n signal=$1\n pid=$2\n\n for child in $(child_pids \"$pid\"); do\n terminate_process_tree \"$signal\" \"$child\"\n done\n\n kill \"$signal\" \"$pid\" 2>/dev/null || true\n}\n\nrun_with_timeout() {\n label=$1\n seconds=$2\n out=$3\n shift 3\n\n : > \"$out\"\n printf 'Timeout policy: %s seconds wall-clock limit for %s\\n' \"$seconds\" \"$label\" >> \"$out\"\n (\n \"$@\" >> \"$out\" 2>&1 &\n child=$!\n (\n sleep \"$seconds\"\n if kill -0 \"$child\" 2>/dev/null; then\n printf '\\nTIMEOUT: %s exceeded %s seconds; terminating process %s\\n' \"$label\" \"$seconds\" \"$child\" >> \"$out\"\n terminate_process_tree -TERM \"$child\"\n sleep 2\n terminate_process_tree -KILL \"$child\"\n fi\n ) &\n watcher=$!\n wait \"$child\"\n rc=$?\n kill \"$watcher\" 2>/dev/null || true\n wait \"$watcher\" 2>/dev/null || true\n exit \"$rc\"\n )\n}\n") ("id" . "generated-ladder-timeout-process-tree") ("imports") ("notes" @@ -5872,18 +5652,6 @@ "Terminate spawned descendants when generated-code runner timeouts fire")) (("code" . - "#!/usr/bin/env sh\n# After dry-run handling and before process/port checks or jcode lookup:\nallow_model_call=${HUIHUI_ALLOW_MODEL_CALL:-0}\n\nif [ \"$dry_run\" -eq 1 ]; then\n printf 'Dry run only. No model call was made.\\n'\n exit 0\nfi\n\n[ \"$allow_model_call\" = 1 ] || [ \"$allow_model_call\" = true ] || {\n printf 'error: refusing to call jcode without --allow-model-call or HUIHUI_ALLOW_MODEL_CALL=1\\n' >&2\n exit 1\n}\n\n# Only explicit live attempts reach endpoint/process checks.\ncheck_no_mlx_process\ncheck_forbidden_port_clear 11434\ncheck_required_port_present 8001\ncommand -v jcode >/dev/null 2>&1 || exit 1\n") ("id" . "generated-ladder-live-opt-in-before-preflight") - ("imports") - ("notes" - . - "Generated-code runners should make accidental non-dry invocations inert and easy to understand. Check the explicit live-call opt-in immediately after dry-run handling and before endpoint preflight, process scans, `lsof`, timeout parsing, or `jcode` lookup. Keep separate tests for both behaviors: no `--allow-model-call` reports the missing opt-in even when a fake MLX process is visible, while explicit `--allow-model-call` still rejects MLX/forbidden-port environments before invoking the model.") - ("tags" "generated-module" "ladder" "jcode" "safety" - "opt-in" "preflight") - ("title" - . - "Check generated-code live opt-in before endpoint preflight")) - (("code" - . "(import (jerboa prelude))\n\n(def (nonempty-env name)\n (let ([v (getenv name)])\n (and v (> (string-length v) 0) v)))\n\n(def (clear-env-marker! name)\n (putenv name \"\"))\n\n(def (apply-hidden-daemon-markers! args)\n (let ([daemon (nonempty-env \"_MYAPP_DAEMON\")]\n [daemon-name (nonempty-env \"_MYAPP_NAME\")])\n (when daemon\n (hash-put! args 'daemon #t)\n (when daemon-name\n (hash-put! args 'daemon-name daemon-name)))\n (clear-env-marker! \"_MYAPP_DAEMON\")\n (clear-env-marker! \"_MYAPP_NAME\")\n args))\n\n(def parsed-args (make-hash-table))\n(apply-hidden-daemon-markers! parsed-args)\n(displayln (hash-ref parsed-args 'daemon #f))") ("id" . "daemon-hidden-argv-env-marker-dispatch") ("imports" "(jerboa prelude)") ("notes" @@ -5908,33 +5676,6 @@ "Set PTY child as foreground process group after TIOCSCTTY")) (("code" . - "Tooling constraints for this `jcode verified` run:\n\n- Use only the available workflow tools: `read`, `edit`, `verify`, and `done`.\n- Do not call `list`, `run`, `shell`, `bash`, `mkdir`, or any other tool name.\n- If a `read` on the target file says it does not exist, the next tool call must be `edit` for that target file.\n- After editing, call `verify` instead of running shell commands yourself.\n- When `verify` returns `VERIFIED`, immediately call `done`; do not read files, inspect generated libraries, or edit again.\n- The `edit` tool requires a `content` argument; do not use `file_content`.\n- If verification fails, repair using only `read`, `edit`, and `verify`; unknown tools such as `run` still fail this workflow.\n- Prefer replacing the whole target file from a known-good implementation shape instead of making tiny parenthesis edits.\n\nFor fragile Scheme forms, show the exact form separately before the full implementation shape. Example:\n\n```scheme\n(def (clear-row! state row)\n (dotimes (col board-width)\n (debug-board-set! state col row #f)))\n```") ("id" . "jcode-verified-prompt-tool-discipline") - ("imports") - ("notes" - . - "Live Huihui rung work showed that broad prose constraints were not enough after repeated verifier failures: the model attempted unavailable `run` calls and once copied a long Scheme implementation shape with an extra close paren. The successful retry added explicit failure-repair tool discipline, `VERIFIED -> done`, whole-file replacement guidance, and a separately highlighted fragile form.") - ("tags" "jcode" "verified" "generated-module" "prompt" - "tool-discipline" "huihui") - ("title" - . - "Constrain jcode verified prompts to stop after VERIFIED and avoid unavailable tools")) - (("code" - . - ";; In jcode, use a portable skill or prompt to orchestrate strict rungs.\n;; 1. Read-only discovery sub-agent:\n;; task(agent: \"delegate\", write_scope: \"none\",\n;; prompt: \"Inspect the repo/API surface and return exact files/risks.\")\n;;\n;; 2. Scoped blueprint/execute sub-agent without project jcode.json variants:\n;; task(agent: \"implementer\", task_id: \"rung-1\", write_scope: \"src/tetris/,tests/tetris/\",\n;; prompt: \"MODE: BLUEPRINT\\nImplement only the static-board rung...\")\n;; task(task_id: \"rung-1\",\n;; prompt: \"MODE: EXECUTE -- approved\\nImplement exactly the approved blueprint.\")\n;;\n;; 3. Preferred local-model rung runner from a skill:\n;; verified({ task: \"Implement static Qt board only.\",\n;; verify_command: \"make tetris-static-contract\",\n;; cwd: \".\",\n;; best_of: 2,\n;; write_scope: \"src/tetris/,tests/tetris/\" })\n;;\n;; Direct CLI equivalent:\n;; jcode verified \"Implement static Qt board only\" \\\n;; --verify \"make tetris-static-contract\" \\\n;; --bestof 2 \\\n;; --write-scope \"src/tetris/,tests/tetris/\"") ("id" . "jcode-portable-strict-ladder-scopes") - ("imports" - "(jcode tool task)" - "(jcode tool verified)" - "(jcode core agent-defs)") - ("notes" - . - "Use dynamic write_scope for portable strict control instead of adding project-specific agent variants to jcode.json. Runtime scopes can only narrow built-in agent scopes; delegate stays read-only. Resumable task sessions retain the scope across BLUEPRINT -> EXECUTE, preventing accidental widening. The verified tool exposes the ATLAS edit -> verify -> repair gate inside normal jcode skills such as /strict-ladder.") - ("tags" "jcode" "strict-ladder" "write-scope" "verified" - "agents" "atlas") - ("title" - . - "Portable strict ladders with task write_scope and verified tool")) - (("code" - . "(import (jerboa prelude))\n(import (jerboa-qt qt))\n\n(def app (qt-app-create))\n(def win (qt-main-window-create))\n(def state (vector 0))\n\n(def (move-left!)\n (vector-set! state 0 (- (vector-ref state 0) 1))\n #t)\n\n(def (move-right!)\n (vector-set! state 0 (+ (vector-ref state 0) 1))\n #t)\n\n(qt-on-key-press! win\n (lambda ()\n (let ((key (qt-last-key-code)))\n (cond\n ((= key QT_KEY_LEFT) (move-left!))\n ((= key QT_KEY_RIGHT) (move-right!))\n (else #t)))))\n\n(qt-widget-show! win)\n(qt-app-process-events! app)") ("id" . "jerboa-qt-key-code-cond-dispatch") ("imports" "(jerboa prelude)" "(jerboa-qt qt)") ("notes"