@@ -1,302 +0,0 @@ |
| 1 | | -# DocumentLanguageModel — Codex Session Boot Context |
| 2 | | - |
| 3 | | -> This file is read on every session start. Keep it dense, authoritative, and |
| 4 | | -> aligned with the living docs. When anything here conflicts with `.docs/`, |
| 5 | | -> `.docs/` wins and this file must be updated. |
| 6 | | - |
| 7 | | -## One-line |
| 8 | | - |
| 9 | | -A text file with a `.dlm` extension becomes a local, reproducible, trainable |
| 10 | | -LLM. Edit the document, retrain, share. Not a toy — LoRA/QLoRA on a real |
| 11 | | -pretrained base, exportable to Ollama. |
| 12 | | - |
| 13 | | -## Current stage |
| 14 | | - |
| 15 | | -- ✅ Stage 1 — Planning & reference exploration (see `.docs/findings.md`) |
| 16 | | -- ✅ Stage 2 — Revised overview + 29 sprint files across 7 phases |
| 17 | | -- ✅ Stage 3 — this file |
| 18 | | -- ✅ Stage 4 — Audit 01 (YELLOW → patched). Blockers F01–F04 and majors |
| 19 | | - F05–F22 triaged into Sprint 12b + inline sprint amendments. See |
| 20 | | - `.docs/audits/01-initial-plan-audit.md` and the end of this file for |
| 21 | | - the triage summary. |
| 22 | | -- ⏳ Stage 5 — Implementation (begin at Sprint 01) |
| 23 | | - |
| 24 | | -## Where things live |
| 25 | | - |
| 26 | | -``` |
| 27 | | -.docs/overview.md Canonical project description (read this first) |
| 28 | | -.docs/findings.md Stage 1 digest from 8 parallel ref explorations |
| 29 | | -.docs/sprints/00-index.md Master index of the 29 sprints |
| 30 | | -.docs/sprints/phase-*/ Sprint files; each has DoD and risks |
| 31 | | -.docs/audits/ Stage 4+ audit outputs |
| 32 | | -.refs/ Cloned reference repos (gitignored) |
| 33 | | -AGENTS.md You are here. Gitignored. |
| 34 | | -``` |
| 35 | | - |
| 36 | | -`.docs/` and `AGENTS.md` are in `.gitignore` by user choice — planning |
| 37 | | -artifacts stay local. |
| 38 | | - |
| 39 | | -## Crystallized architecture |
| 40 | | - |
| 41 | | -**Training paradigm**: LoRA / QLoRA on a user-selected pretrained base. No |
| 42 | | -from-scratch transformers. The base registry ships with Qwen 2.5 |
| 43 | | -(0.5B–3B + Coder-1.5B), Llama-3.2 (1B, 3B), SmolLM2 (135M–1.7B), and |
| 44 | | -Phi-3.5-mini. Any HF model via `hf:org/name` with compatibility probes. |
| 45 | | - |
| 46 | | -**Document shape**: `mydoc.dlm` is a single UTF-8 text file — YAML |
| 47 | | -frontmatter + markdown body with section fences (`::instruction::`, |
| 48 | | -`::preference::`, default-prose). A stable `dlm_id` in the frontmatter |
| 49 | | -binds the document to a content-addressed store at `~/.dlm/store/<dlm_id>/`. |
| 50 | | - |
| 51 | | -**Retention**: single rolling adapter trained on the current document + |
| 52 | | -recency-weighted sample from a zstd-compressed replay corpus accumulating |
| 53 | | -every prior document version. Rejected alternative: versioned adapters |
| 54 | | -with weighted merge (LoRA-only, SVD cost, harder determinism). |
| 55 | | - |
| 56 | | -**Export**: separate `base.gguf` + `adapter.gguf` + generated Modelfile with |
| 57 | | -`ADAPTER` directive. `--merged` opt-in produces a single file (QLoRA |
| 58 | | -requires explicit `--dequantize`). |
| 59 | | - |
| 60 | | -**Hardware tiers**: |
| 61 | | -- NVIDIA CUDA (SM ≥ 8.0): first-class, bf16 + QLoRA 4-bit + FlashAttention |
| 62 | | -- NVIDIA CUDA (SM < 8.0): second-class, fp16 LoRA |
| 63 | | -- Apple Silicon MPS: first-class training (fp16 LoRA), optional MLX inference in Phase 5 |
| 64 | | -- CPU: inference-only by default, training refused except `--force` on ≤200M bases |
| 65 | | -- AMD ROCm: experimental; Phase 5 promotes to Tier 2 |
| 66 | | - |
| 67 | | -## Stack |
| 68 | | - |
| 69 | | -**In**: Python 3.11+, PyTorch ≥ 2.4, HuggingFace `transformers`/`peft`/`trl`/ |
| 70 | | -`accelerate`/`datasets`, `bitsandbytes` (CUDA-gated), `safetensors`, |
| 71 | | -`zstandard`, llama.cpp (vendored git submodule) for GGUF export, |
| 72 | | -Ollama (user-installed), `typer`, `rich`, `uv`, `pytest`, `mypy --strict`, |
| 73 | | -`ruff`. |
| 74 | | - |
| 75 | | -**Out**: |
| 76 | | -- Unsloth (monkeypatch fragility, transformers-version pinning hell, CUDA-only, Apple Silicon excluded) |
| 77 | | -- MLX for training (adapter `.npz` format is not PEFT-compatible) |
| 78 | | -- From-scratch transformers |
| 79 | | -- DeepSpeed / ZeRO through v1.0 |
| 80 | | -- Windows first-class (best-effort; Linux + macOS are supported tiers) |
| 81 | | - |
| 82 | | -## Pitfalls to always remember |
| 83 | | - |
| 84 | | -1. **Ollama uses Go `text/template`, not Jinja2.** The GGUF's Jinja |
| 85 | | - chat-template is fuzzy-matched by Ollama and fails silently when |
| 86 | | - unmatched. We always emit an explicit `TEMPLATE "..."` in the Modelfile |
| 87 | | - from our per-base-model Go template registry. Round-trip tests assert |
| 88 | | - token-identity with the HF Jinja reference. |
| 89 | | - |
| 90 | | -2. **`peft.save_pretrained` does NOT save optimizer / scheduler / RNG.** We |
| 91 | | - write a separate `training_state.pt` sidecar with optimizer state, |
| 92 | | - scheduler state, AMP scaler, torch/cuda/numpy/python RNGs, step, epoch, |
| 93 | | - pinned versions. Without this, resume is not deterministic. |
| 94 | | - |
| 95 | | -3. **`merge_and_unload` on 4-bit QLoRA base is precision-unsafe.** Refuse |
| 96 | | - the merged export path on QLoRA unless `--dequantize` is explicit; then |
| 97 | | - dequantize to fp16 before merge. |
| 98 | | - |
| 99 | | -4. **Pad token must NOT default to EOS.** Label corruption when EOS |
| 100 | | - appears mid-sequence. Fallback: unk_token → else add `<|pad|>` (and |
| 101 | | - then `modules_to_save=["embed_tokens","lm_head"]` is forced, inflating |
| 102 | | - adapter size; warn loudly). |
| 103 | | - |
| 104 | | -5. **Pre-tokenizer hash table in llama.cpp** is a silent-failure surface. |
| 105 | | - Sprint 06 probes at registry-build time + on `dlm init --base hf:...`; |
| 106 | | - Sprint 11 re-verifies at `dlm export` preflight. Bumping |
| 107 | | - `vendor/llama.cpp` re-runs the registry probe suite via |
| 108 | | - `scripts/bump-llama-cpp.sh`. |
| 109 | | - |
| 110 | | -6. **Sample packing without FlashAttention** causes `position_ids` drift on |
| 111 | | - MPS. Doctor disables packing when FlashAttention is unavailable and |
| 112 | | - packing is otherwise unsafe. |
| 113 | | - |
| 114 | | -7. **`target_modules="all-linear"` on small models** causes memory blowup |
| 115 | | - and instability. Use the per-architecture registry from sprint 06 as |
| 116 | | - the default. |
| 117 | | - |
| 118 | | -8. **Determinism is a contract**: fixed seed, `use_deterministic_algorithms`, |
| 119 | | - `CUBLAS_WORKSPACE_CONFIG=:4096:8`, pinned versions recorded in |
| 120 | | - `dlm.lock`. Any code change that breaks the golden determinism test is |
| 121 | | - a breaking change. |
| 122 | | - |
| 123 | | -Full inventory in `.docs/findings.md#9`. |
| 124 | | - |
| 125 | | -## Contract boundaries (audit F25) |
| 126 | | - |
| 127 | | -Four load-bearing files; keep them distinct when editing. |
| 128 | | - |
| 129 | | -- **`manifest.json`** (per-store): running narrative of training runs, |
| 130 | | - exports, content hashes, adapter version. Mutable on every run. Owned |
| 131 | | - by Sprint 04; extended by Sprints 09, 11, 12, 12b. |
| 132 | | -- **`dlm.lock`** (per-store): version pins + hardware tier + determinism |
| 133 | | - flags + license acceptance fingerprint. Written once per run; stable. |
| 134 | | - Owned by Sprint 15; extended by Sprint 12b (license) and Sprint 23 |
| 135 | | - (world_size + accelerate). |
| 136 | | -- **`training_state.pt`** (per-store, per-adapter-version): optimizer, |
| 137 | | - scheduler, scaler, all RNGs, step/epoch. Required for bit-exact resume. |
| 138 | | - Owned by Sprint 09. Two-phase commit with adapter directory. |
| 139 | | -- **`exports/<quant>/export_manifest.json`** (per-export): checksums, |
| 140 | | - quant level, pinned llama.cpp tag, smoke output. Owned by Sprint 11; |
| 141 | | - appended via Sprint 12. |
| 142 | | - |
| 143 | | -And one repo-level file: |
| 144 | | - |
| 145 | | -- **`dlm.lock`** at the repo root: records which `(torch, transformers, |
| 146 | | - peft, trl, bnb, platform)` tuples have a checked-in determinism golden. |
| 147 | | - Different from the per-store `dlm.lock`. Owned by Sprint 15. |
| 148 | | - |
| 149 | | -## Development guidelines |
| 150 | | - |
| 151 | | -- **Commit often, commit small.** Avoid monolithic commits; maximize commits |
| 152 | | - per feature so the history shows a narrative. One commit per distinct |
| 153 | | - change (a file, a config, a fix), not per day's work. |
| 154 | | -- **Commit message style**: imperative, terse, one line unless a technical |
| 155 | | - choice requires elaboration. **No coauthorship** on any commit. |
| 156 | | -- **Avoid `git add -A`.** Stage specific files by name; it's harder to |
| 157 | | - leak secrets or commit unrelated changes. |
| 158 | | -- **No shortcuts when a robust approach exists.** If you find yourself |
| 159 | | - writing "the simplest approach is…", stop and ask whether this produces |
| 160 | | - a trainable LLM. If not, reapproach. |
| 161 | | -- **Senior AI-engineering discipline.** Write efficient, well-engineered |
| 162 | | - code. Respect the pitfall inventory. |
| 163 | | -- **Strict validation, fail fast.** Axolotl's permissive warnings are the |
| 164 | | - anti-pattern. Our Pydantic schemas reject unknown keys, wrong types, and |
| 165 | | - inconsistent combinations at parse time. |
| 166 | | -- **Determinism is a contract.** See above. |
| 167 | | -- **Tests before implementation** for anything touching training dynamics, |
| 168 | | - tokenization, or GGUF export. The tiny-model fixture (sprint 02) makes |
| 169 | | - end-to-end CI feasible; use it. |
| 170 | | -- **`mypy --strict` from day one.** Never loosen; fix the type at source. |
| 171 | | -- **Per-sprint definition of Done is binary.** A sprint is not Done until |
| 172 | | - every DoD checkbox passes and the sprint file is marked Done. |
| 173 | | - |
| 174 | | -## Workflow inside a sprint |
| 175 | | - |
| 176 | | -1. Read `.docs/sprints/phase-N/NN-*.md` in full. |
| 177 | | -2. Cross-check against `.docs/findings.md` where the sprint references |
| 178 | | - pitfalls or patterns (the sprints do cite sections). |
| 179 | | -3. Implement incrementally. Commit per file / per logical unit. |
| 180 | | -4. Write tests alongside (or before) the code. |
| 181 | | -5. Check every DoD item manually before flipping Status to Done. |
| 182 | | -6. Update `.docs/sprints/00-index.md` status column if we maintain one. |
| 183 | | - |
| 184 | | -## CLI surface by release |
| 185 | | - |
| 186 | | -**v1.0** (Phase 3 end): |
| 187 | | -``` |
| 188 | | -dlm init <path> [--base <key>] [--template <name>] [--i-accept-license] |
| 189 | | -dlm train <path> [--resume|--fresh] [--seed N] [--max-steps N] [--gpus ...] |
| 190 | | - [--strict-lock|--update-lock|--ignore-lock] |
| 191 | | -dlm prompt <path> [query] [--max-tokens N] [--temp F] [--adapter <name,...>] |
| 192 | | -dlm export <path> [--quant Q] [--merged [--dequantize]] [--name N] [--no-smoke] |
| 193 | | - [--adapter-mix name:w,...] |
| 194 | | -dlm pack <path> [--out X] [--include-exports] [--include-base |
| 195 | | - [--i-am-the-licensee <url>]] |
| 196 | | -dlm unpack <path> [--home DIR] [--force] |
| 197 | | -dlm migrate <path> [--dry-run] [--no-backup] |
| 198 | | -dlm doctor [--json] |
| 199 | | -dlm show <path> [--json] |
| 200 | | -``` |
| 201 | | - |
| 202 | | -**v2** (Phases 4–6): |
| 203 | | -``` |
| 204 | | -dlm repl <path> |
| 205 | | -dlm train <path> --watch [--repl] |
| 206 | | -dlm metrics <path> [--json|--csv] |
| 207 | | -dlm metrics watch <path> |
| 208 | | -dlm templates list [--refresh] |
| 209 | | -``` |
| 210 | | - |
| 211 | | -**v2+** (Phase 7): |
| 212 | | -``` |
| 213 | | -dlm push <path> [--to hf:org/name | --to <url>] [--sign] |
| 214 | | -dlm pull <source> |
| 215 | | -dlm serve <path> [--public [--i-know-this-is-public]] |
| 216 | | -``` |
| 217 | | - |
| 218 | | -## Stage gates |
| 219 | | - |
| 220 | | -- Stage 4 — **Patched (YELLOW → triaged)**. New Sprint 12b owns F01–F04. |
| 221 | | - 17 majors amended inline into existing sprints. 9 minors deferred to |
| 222 | | - first touch of their owning sprints. A re-audit pass is recommended |
| 223 | | - before declaring GREEN and entering Stage 5. |
| 224 | | -- Stage 5 — begin Sprint 01 (scaffolding) once Stage 4 is GREEN. |
| 225 | | - |
| 226 | | -## Context for future sessions |
| 227 | | - |
| 228 | | -- Always load `.docs/overview.md`, `.docs/findings.md`, and |
| 229 | | - `.docs/sprints/00-index.md` before working on a sprint. Skim the |
| 230 | | - relevant sprint file in full. |
| 231 | | -- The user prefers concise, direct engineering discussion. Surface |
| 232 | | - tradeoffs; make recommendations with reasoning. |
| 233 | | -- When in doubt about an implementation choice, check findings §10 |
| 234 | | - (adoption matrix per reference repo) — it's the opinionated source of |
| 235 | | - truth for "why are we doing it this way, not that way." |
| 236 | | - |
| 237 | | - |
| 238 | | -<claude-mem-context> |
| 239 | | -# Memory Context |
| 240 | | - |
| 241 | | -# [DocumentLanguageModel] recent context, 2026-04-19 7:40pm EDT |
| 242 | | - |
| 243 | | -Legend: 🎯session 🔴bugfix 🟣feature 🔄refactor ✅change 🔵discovery ⚖️decision |
| 244 | | -Format: ID TIME TYPE TITLE |
| 245 | | -Fetch details: get_observations([IDs]) | Search: mem-search skill |
| 246 | | - |
| 247 | | -Stats: 50 obs (20,314t read) | 1,271,868t work | 98% savings |
| 248 | | - |
| 249 | | -### Apr 18, 2026 |
| 250 | | -92 5:26p 🔵 armfortas/fortsh Build Produces Widespread Ambiguous USE Import Warnings |
| 251 | | -94 5:27p 🔵 fortsh Full Build Succeeds via armfortas — Complete Object Link Map Confirmed |
| 252 | | -98 5:29p 🔵 fortsh Smoke Tests Pass — Parameter Expansion and Pipeline Basics Verified |
| 253 | | -99 " 🔵 fortsh Test Suite Results — read 94%, var-ops 80% with Identified Failure Clusters |
| 254 | | -100 " 🔴 Null Pointer Dereference in afs_compare_char When Empty String Variable Used in Parameter Expansion |
| 255 | | -101 5:32p 🔵 Empty-String Parameter Expansion Bug Isolated to Assignment Side-Effect, Not Expansion Engine |
| 256 | | -105 5:34p 🔵 V="" Assignment Alone Crashes via execute_ast_node — Bug Is in Assignment Executor, Not Compound Commands |
| 257 | | -111 5:36p 🔵 armfortas IR Builder Architecture — FuncBuilder API Surface Mapped |
| 258 | | -113 5:38p 🔵 SIGSEGV Confirmed — Dynamic Substring Index on Zero-Length Allocatable Char Crashes |
| 259 | | -117 5:39p 🔵 fortsh Crash Site Confirmed in ast_executor.f90 — Dynamic Substring on Zero-Length Allocatable |
| 260 | | -120 5:40p 🔴 lower_substring_full — Dynamic Substring Out-of-Bounds GEP Fixed with Safe Clamp |
| 261 | | -121 5:42p 🔴 substring fix validated — 8/8 substring tests pass, repro RC=0, fortsh build proceeding without errors |
| 262 | | -137 5:55p 🔵 armfortas allocate(scalar_derived) Skips Field Default Initializers |
| 263 | | -138 " 🔵 fortsh IFS / read Builtin Architecture Confirmed |
| 264 | | -139 5:56p 🔴 armfortas: allocate(scalar_derived) Now Applies Field Default Initializers |
| 265 | | -142 5:59p 🔵 fortsh Build Completes with Ambiguous USE Import Warnings in readline Module |
| 266 | | -143 6:01p 🔵 fortsh Build Produces Ambiguous USE Import Warnings from Duplicate Module Exports |
| 267 | | -145 " 🔵 armfortas trim/adjustl Branch Produces Correct Value but print '(a)' Adds Leading Space |
| 268 | | -146 6:03p 🔵 armfortas print '(a)' Emits Carriage-Control Space — Confirmed by od Byte Dump |
| 269 | | -147 " 🟣 Regression Test Added: allocatable_shell_default_ifs_follows_trim_branch |
| 270 | | -148 " 🔵 fortsh Builtin Test Results: read 100%, arithmetic 100%, variable_ops 85%, arrays 0% on literal init |
| 271 | | -149 " 🔵 fortsh Array Literal Init Bug — Bounds Check Failure: index 1 outside [1, 0] |
| 272 | | -153 6:06p 🔵 Array Section Argument Descriptor Bug — values(1:count) Passed as Assumed-Shape Gets upper=0 |
| 273 | | -155 6:14p 🔵 armfortas Emits Duplicate Ambiguous-USE Warnings Per Translation Unit |
| 274 | | -156 " 🔵 fortsh Makefile Has Full Native armfortas Profile |
| 275 | | -157 " 🟣 armfortas Rust Test Suite — Array Section Bounds Test Passing |
| 276 | | -158 " 🔵 fortsh Binary Previously Built by armfortas — Incremental Rebuild in Progress |
| 277 | | -159 " 🔵 fortsh test_variables_simple Uses Pooled String API — Not Standard Fortran Variables |
| 278 | | -160 6:15p ✅ armfortas Array Section Fix Staged for Commit — lower.rs and cli_driver.rs |
| 279 | | -161 " 🔴 armfortas Commit 4ec3e9a — Lower Array Section Descriptor Actuals |
| 280 | | -162 6:16p 🔵 fortsh Incremental Rebuild with armfortas Completed Successfully |
| 281 | | -163 6:17p 🔵 armfortas Working Tree — Active afs-as/afs-ld Changes Plus Repro Test Artifacts |
| 282 | | -177 6:24p 🔵 fortsh Build — Mass Ambiguous USE Import Warnings from armfortas |
| 283 | | -179 6:27p 🔵 armfortas Peak RSS ~99 MB Compiling fortsh lexer.f90 |
| 284 | | -182 6:30p 🟣 fortsh Binary Successfully Built with armfortas — /tmp/fortsh_armf_arrayfix/bin/fortsh |
| 285 | | -183 6:31p 🔵 fortsh 1.7.0 Binary Verified Functional — Basic Array and Pipeline Semantics Correct |
| 286 | | -184 " 🔵 Array Test Suite Baseline — 17/31 Pass (54%), 14 Failures Cataloged |
| 287 | | -192 6:34p 🔵 Test Harness Uses Bash 3.2 as Reference — Assoc Array Failures Are Baseline Artifacts |
| 288 | | -193 " 🔵 Three armfortas-Specific Array Regressions Confirmed Against flang-ref Baseline |
| 289 | | -220 6:50p 🔵 armfortas Unset Module Variable — Parity with flang-new Confirmed |
| 290 | | -222 " 🔵 fortsh Array Unset Bugs — Two Distinct Failures in armfortas Build vs Correct flang Reference |
| 291 | | -223 6:53p 🔵 fortsh Null-Assignment Hole (`arr[1]=`) Produces Correct Sparse Indices in armfortas Build |
| 292 | | -224 " 🔵 AST Executor Does Not Dispatch `unset` as Builtin — "command not found" at Runtime |
| 293 | | -228 " 🔵 armfortas `builtin_unset` Direct Call Crashes — "Bounds check failed: index 1026 outside [1, 1025]" |
| 294 | | -231 6:54p 🔵 armfortas `unset foo[N]` on Non-Existent Variable Crashes — Bug Not Array-Existence-Dependent |
| 295 | | -232 " 🔵 fortsh `execute_simple_command` Builtin Dispatch — Routes Through `execute_pipeline`, Not Direct Call |
| 296 | | -234 6:56p 🔵 armfortas `unset` Bug Scope Narrowed — Scalar `unset` Works, Array-Index Form Always Crashes |
| 297 | | -240 7:39p 🔵 armfortas expand_out Token Output Shows Null-Byte Corruption |
| 298 | | -241 " 🔵 flang-new Cannot Compile expand_out Repro — `fill` Not Found in Module `m` |
| 299 | | -242 7:40p 🔵 armfortas .amod Exports `fill` With Fixed-Length Allocatable Character(len=32) Intent(out) |
| 300 | | - |
| 301 | | -Access 1272k tokens of past work via get_observations([IDs]) or mem-search skill. |
| 302 | | -</claude-mem-context> |