new AGENTS.md
ober
f7087d543604a6799655f6df2ae217f7ba278856
--- a/AGENTS.md +++ b/AGENTS.md @@ -1,3 +1,34 @@ +## STOP: Editing `.ss`/`.sls` Files — Mandatory Rules + +These rules exist because local-model sessions have lost **hours** fighting +parenthesis imbalances that these rules would have prevented in seconds. +They override every habit from other editors and languages. + +1. **NEVER use `edit`, `write`, `sed`, `python`, `perl`, or `awk` to modify + `*.ss` or `*.sls` files.** Use the jerboa-mcp tools instead: + - Add a top-level form → `jerboa_balanced_insert` (anchor = one unique + complete form, e.g. the `def` above the insertion point). + - Replace exact text → `jerboa_balanced_replace`. It is **dry-run by + default** — pass `dry_run: false` to actually write. + - Create a whole new file → `jerboa_write_file` (use `verify: true` to + reject unbalanced content before it lands). +2. **After EVERY `.ss` change, run `jerboa_check_balance` before building.** + The balanced tools check automatically; if you bypassed them, check now. +3. **If a file ever becomes unbalanced, STOP.** Do NOT count parens by hand, + do NOT write paren-counting scripts, do NOT poke one character at a time. + Recovery is exactly one of: + - `git checkout -- <file>` and redo the edit with `jerboa_balanced_insert` + (preferred — one command, seconds), or + - `jerboa_repair_balance` (dry-run shows the plan; `apply: true` writes). +4. **Keep closer-runs short.** Never hand-write code that ends in more than + ~4 consecutive closers (`))))]` runs). Flatten deep nesting with helper + `def`s, `let*`, or cond `=>` clauses so no edit ever depends on counting + a long `)` run. +5. **`(def ...)` after an expression in a body is invalid.** Internal defines + must come first in a body, or use `let`/`let*`. The build error + "invalid context for definition" means you violated this — or a missing + paren above glued two top-level forms together (check balance first). + ## The Jerboa Language — Quick Reference Jerboa is a Scheme dialect built on Chez Scheme. It is Gerbil-inspired but its own language. **All user-facing code is `.ss` files. Never write `.sls` files for the user** — those are internal implementation files. @@ -429,6 +460,9 @@ Jerboa is a niche Scheme dialect with limited training data. **Never guess — a | FFI work | `jerboa_ffi_scaffold` / `jerboa_ffi_type_check` / `jerboa_ffi_null_safety` | | Port Gerbil code | `jerboa_migration_check` + `jerboa_translate_scheme` | | Detect paren imbalance | `jerboa_check_balance` — use BEFORE `make build` after deep edits | +| Edit a `.ss` file | `jerboa_balanced_insert` / `jerboa_balanced_replace` — NEVER raw `edit`/`sed`/`python` (see top of file) | +| Create a `.ss` file | `jerboa_write_file` — whole-file atomic write, `verify: true` rejects unbalanced content | +| File already unbalanced | `jerboa_repair_balance` — dry-run repair plan; or `git checkout -- <file>` and redo with `balanced_insert` | | Full project audit | `jerboa_project_health_check` — balance, exports, cycles, duplicates | | Security audit | `jerboa_security_audit` + `jerboa_import_policy_check` | | Static build audit | `jerboa_static_symbol_audit` + `jerboa_boot_library_audit` | @@ -448,7 +482,7 @@ Jerboa is a niche Scheme dialect with limited training data. **Never guess — a ### Code Generation & Refactoring -`jerboa_rename_symbol`, `jerboa_balanced_replace`, `jerboa_wrap_form`, `jerboa_splice_form`, `jerboa_scaffold_test`, `jerboa_generate_module`, `jerboa_translate_scheme`, `jerboa_project_template`, `jerboa_httpd_handler_scaffold`, `jerboa_db_pattern_scaffold`, `jerboa_actor_ensemble_scaffold` +`jerboa_rename_symbol`, `jerboa_balanced_replace`, `jerboa_balanced_insert`, `jerboa_write_file`, `jerboa_repair_balance`, `jerboa_wrap_form`, `jerboa_splice_form`, `jerboa_scaffold_test`, `jerboa_generate_module`, `jerboa_translate_scheme`, `jerboa_project_template`, `jerboa_httpd_handler_scaffold`, `jerboa_db_pattern_scaffold`, `jerboa_actor_ensemble_scaffold` ### Feature Suggestions --- a/no-blinky.md +++ b/no-blinky.md @@ -125,3 +125,23 @@ The fix is successful when: **Implementation time:** ~30 minutes **Testing time:** 10 minutes **Risk level:** Medium (adds state tracking, but tests pass and full redraw still used for mode/resize/first draw) + +## Update: real root cause of persisting flicker (found after this doc) + +The dirty-region logic above was correct but was being defeated by an +unrelated units bug in the periodic self-healing invalidate (added earlier +for `handoff-corruption.md`, unaffiliated with this doc's author). + +`signal/tui/main.ss:398`: `*invalidate-interval-s* = 10`, compared directly +against deltas of `(real-time)`. `real-time` is Chez's builtin and returns +**milliseconds**, not seconds (confirmed by every other use in this file, +e.g. `(cons 'ms (- (real-time) started))`). So the "10 second" interval was +actually 10 *milliseconds* — `tb-invalidate!` (which marks termbox's entire +back buffer dirty) fired on nearly every draw cycle, including every +keystroke. `tb-present!` then re-emitted escape codes for every cell on +screen regardless of how surgical `draw!`'s partial repaint was — full +flicker on every key. + +Fix: renamed to `*invalidate-interval-ms* = 10000`, matching the file's +existing ms-based constant convention (`*idle-poll-ms*`). No other logic +changed. `make binary` and `make test` both pass. --- a/signal/tui/main.ss +++ b/signal/tui/main.ss @@ -395,7 +395,7 @@ (def *idle-poll-ms* 250) (def *max-actor-events-per-tick* 128) - (def *invalidate-interval-s* 10) + (def *invalidate-interval-ms* 10000) (def (event-loop state actor) (let loop ([dirty? #t] [last-invalidate (real-time)]) @@ -403,7 +403,7 @@ [send-dirty? (handle-send-events! state)] [timer-dirty? (expire-typing-indicators! state)] [now (real-time)] - [invalidate? (>= (- now last-invalidate) *invalidate-interval-s*)] + [invalidate? (>= (- now last-invalidate) *invalidate-interval-ms*)] [need-draw? (or dirty? actor-dirty? send-dirty? timer-dirty? invalidate?)]) (when need-draw? (when invalidate? (tb-invalidate!))