Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ Task-specific instructions are split into skill files under `skills/`. You MUST
| `skills/version_update.md` | Bumping the daslang version number |
| `skills/jobque_debugging.md` | Channel/LockBox/JobStatus/Feature leaks (`--track-job-status`, `DumpJobQueLeaks`) |
| `skills/make_pr.md` | Creating a pull request (lint, test, AOT, format checklist) |
| `skills/preflight.md` | Pushing a non-trivial branch or reproducing a red CI lane — maps every PR-triggered CI lane to its exact local mirror command (or an honest "not mirrorable") |
| `skills/abi_break_sweep.md` | Changing public C++ API, AST node layout, or daslib generic signatures that external module repos compile against — both-worlds spellings, externals-merge-first ordering, daspkg-index scope |
| `skills/wsl_ci_repro.md` | Reproducing a Linux-only CI failure (sanitizers, POSIX divergence, headless timing) in the WSL CI-mirror distro — verbatim-CI recipe and its traps |
| `skills/pr_review_iteration.md` | Working an open PR through CI failures and Copilot/human review feedback after the PR is created |
| `skills/strudel_port.md` | Porting strudel.cc patterns into daslang |
| `skills/clargs_usage.md` | Writing or editing any tool that parses command-line flags — declarative argv parsing via `daslib/clargs`, plus migration discipline for legacy `get_command_line_arguments()` callers |
Expand Down
11 changes: 10 additions & 1 deletion COVERAGE_GAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,17 @@ Process: per-stage plan → implement → review, same as FIXED_ARRAY_REWORK.md.
lint + clang syntax-only pass on changed C++. `--full` adds interp/AOT/JIT
suites, tests-cpp, all six doc gates, sequence smoke, CI-only-das compile
sweep. Parallelize on big machines.
- **Cross-platform is a requirement, not a nicety**: the same tool must run on
Windows (primary dev box), macOS, and WSL/Linux. Implications: pure `.das` +
clargs + `fio` path helpers (no shell-specific constructs); syntax pass is
`clang-cl /Zs` on Windows and `clang -fsyntax-only` elsewhere behind one
flag; binary/build-dir discovery handles both MSVC multi-config
(`bin/Release/daslang.exe`) and single-config (`build/daslang`) layouts;
gates that need missing host tools (sphinx, clang) degrade to an explicit
SKIP with the install hint, never a silent pass.
- clang syntax-only checker for changed `.cpp`/`.h` (`clang-cl /Zs` with
project includes) — the 80/20 for the MSVC-vs-clang diagnostic gap.
project includes on Windows, `clang -fsyntax-only` on mac/Linux) — the
80/20 for the MSVC-vs-clang diagnostic gap.
- Docs-gate runner mirroring doc.yml steps 1–6 exactly.
- CI-only das surface list (dasOpenGL, sequence, release tooling …) compiled
via `compile_check` with proper mounts.
Expand Down
55 changes: 55 additions & 0 deletions skills/abi_break_sweep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# ABI-break sweep — keeping external modules green

Read this when a PR changes what external module repos compile against:
public C++ API under `include/daScript/`, AST node layout (fields added,
deleted, renamed — e.g. the fixed-array rework deleting `TypeDecl::dim`),
signatures of daslib generics that externals instantiate, or the
`.das_module` / serialization surface.

## Why externals can red YOUR PR

`extended_checks` runs `daspkg install dasImgui --branch master` — it builds
the external repo's **master** against **your branch's** headers, at PR time.
So a breaking change produces a red CI step that looks unrelated
(`no member named 'dim'` inside dasImgui), and the naive fix creates a
deadlock: the daslang PR can't go green until externals are compatible, and an
externals fix that *requires* the new daslang can't merge until the daslang PR
lands.

The scope of "externals" is the [daspkg-index](https://github.com/borisbat/daspkg-index)
package list — that is the universe of repos any user (and the planned nightly
cron) builds against daslang master.

## The checklist

1. **Identify the breaking surface.** List every symbol removed, renamed, or
re-typed. In-repo impact: `cpp_grep_usage` / `grep_usage` MCP tools.
2. **Sweep external usage.** Grep each daspkg-index package (your local
checkouts, or GitHub code search) for those symbols — including
field-access shapes (`->dim`, `.dim`, `dimExpr`), not just call sites.
3. **Pick the compatibility strategy** — in preference order:
1. **Both-worlds spelling** (the `isArray()` precedent). Find a predicate or
accessor that exists with the SAME meaning in both the old and new
world — `TypeDecl::isArray()` meant "is a fixed array" both pre-rework
(`(bool)dim.size()`) and post-rework (`baseType == tFixedArray`).
Rewrite the externals to that spelling: their PRs merge FIRST,
independently, green against both daslang versions. No feature macro,
no lockstep, no red-master window.
2. **Shim in daslang** — keep the old name as a forwarding alias for one
release when no shared spelling exists.
3. **Feature macro / version check** in the external — last resort; it
forces lockstep merges and rots into dead branches.
4. **Land order: externals first.** Because extended_checks pulls externals'
master, the external fix must be MERGED (not just PR'd) before the daslang
PR's CI can go green. Merge externals → re-run the daslang PR's
extended_checks → merge daslang.
5. **Verify locally before pushing** — the external-module junction pattern
(`skills/external_module_debugging.md`), rebuild order **daslang first,
then each module**. Stale-DLL trap: a `.shared_module` built against the
old daslang fails to load *silently* and surfaces as a misleading
`error[20605]: missing prerequisite` — after rebuilding daslang, delete the
external module's `_build/` and rebuild before trusting any 20605.
6. **Post-merge sweep.** Build every remaining daspkg-index package against
the new master and fix drift (unrelated rot surfaces here too — budget for
it). The nightly index cron (`COVERAGE_GAP.md` Stage 4) will turn this
into a standing signal.
42 changes: 27 additions & 15 deletions skills/make_pr.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,15 @@ bin/Release/daslang.exe -jit tests/decs/test_bulk_create.das 2>&1 | grep -iE "ve

**What this catches:** struct-layout drift (i32 vs i64 fields in JIT mirror), mixed-width arithmetic (i64 × i32), missing intrinsic lowering after a runtime-side widening. The two suggested tests cover array indexing + table operations; widen the smoke list to `tests/soa/test_soa_basic.das` and `tests/language/typeAlias.das` if you touched generic-instance lowering or capture frames.

## 2.7. Type-system / daslib-generics changes — sequence smoke + externals sweep

If the PR changes the type system, generic binding rules, AST node layout, or widely-instantiated daslib generics (`builtin.das`, `safe_addr.das`, …), two CI gates have no overlap with the standard test suite:

1. **Sequence smoke** — the only pre-merge lane that compiles GLFW-gated `.das` (dasOpenGL helpers etc.). Build the runtime module targets and run `examples/games/sequence/ci_smoke_test.ps1` (`.sh` on POSIX) — exact commands in `skills/preflight.md`.
2. **Externals sweep** — `extended_checks` installs external dasImgui from ITS master against your branch; an ABI break vs external repos reds CI on an unrelated-looking step. Follow `skills/abi_break_sweep.md` (both-worlds spellings, externals-merge-first ordering, daspkg-index scope).

Skip for changes that can't alter what external/module-gated code sees (tests-only, docs-only, tool-local).

## 3. Build and run AOT tests

**IMPORTANT:** Kill the MCP server and any running daslang processes first — they lock build output files.
Expand Down Expand Up @@ -184,9 +193,12 @@ Use `timeout: 0` (no timeout) for the cmake build — it can take 2-25 minutes.
- Public functions in `daslib/*.das` (added, removed, renamed, or signature changed)
- `//!` doc-comments in `daslib/*.das` files
- C++ bindings in `modules/*/src/*.cpp` or `src/builtin/*.cpp` that add new public functions, types, or struct fields
- **Struct fields or enum values added, REMOVED, or reordered** in any C++ type documented under `doc/source/stdlib/handmade/` — das2rst validates handmade docs **positionally** (line 1 = type description, line N+1 = Nth field/value), so a removed field is just as CI-fatal as an added one
- RST files in `doc/source/` (handwritten tutorials, reference pages, TOCs)
- `doc/reflections/das2rst.das` or `doc/reflections/rst.das`
Comment on lines +196 to 198

Note that CI's doc workflow triggers on **any** `daslib/**` or `src/builtin/**` change and runs six gates (`skills/preflight.md` has the full list); das2rst **stops at the FIRST validation panic**, so a single CI round can hide N−1 further issues — loop step 4b locally until it runs clean.

**Which substeps to run** — match what changed, not "all in order":

| Changed | Run |
Expand Down Expand Up @@ -236,12 +248,13 @@ grep -c Uncategorized doc/source/stdlib/generated/*.rst | grep -v ':0$'

Must return empty. If not, go back to step 4a and add the missing function to a group.

### 4f. Clean Sphinx build
### 4f. Clean Sphinx build — BOTH builders

MUST delete cache — cached builds hide errors:
CI runs `sphinx-build -W` for **latex AND html** — they catch different warning sets (latex chokes on some table/unicode constructs html accepts). MUST delete cache — cached builds hide errors:

```bash
rm -rf doc/sphinx-build site/doc
rm -rf doc/sphinx-build site/doc build/latex
sphinx-build -W --keep-going -b latex -d doc/sphinx-build doc/source build/latex
sphinx-build -b html -d doc/sphinx-build doc/source site/doc 2>&1 | sed 's/\x1b\[[0-9;]*m//g' | tee /tmp/sphinx_out.txt
tail -3 /tmp/sphinx_out.txt
grep -iE "warning:|error:" /tmp/sphinx_out.txt
Comment on lines +256 to 260
Expand All @@ -259,9 +272,13 @@ Common Sphinx issues:
- **Malformed table**: Grid/simple table column widths don't align
- **Unexpected indentation**: Content after directive must be indented consistently

### 4g. Stage doc changes
### 4g. Stage doc changes — including NEW generated files

Add all changed/new files in `doc/` and `doc/reflections/` to the commit. For squashed branches, amend the existing commit.
Add all changed/new files in `doc/` and `doc/reflections/` to the commit. For squashed branches, amend the existing commit. CI fails if das2rst generated files that aren't tracked — verify:

```bash
git ls-files --others --exclude-standard doc/source/stdlib/ # must be empty
```

See `skills/documentation_rst.md` for full details on doc conventions, tutorial RST, and cross-references.

Expand All @@ -273,17 +290,11 @@ Run the MCP `format_file` tool on all changed `.das` files in a single batched c

Do NOT format files you didn't change — only format files that are part of the PR.

### CI `das-fmt` ≠ MCP `format_file` — verify named-arg spacing

CI's `extended_checks` job runs `./bin/Release/daslang ./das-fmt/dasfmt.das -- --path ./ --verify` (plus a compiled `das-fmt.exe` pass). The `das-fmt/dasfmt.das` file is NOT in the repo tree — CI fetches it externally — and it is **stricter** than MCP `format_file` on at least one rule:

| MCP `format_file` accepts | CI `das-fmt` requires |
|---|---|
| `Foo(a=1, b=2)` | `Foo(a = 1, b = 2)` (spaces around `=` in named args) |
### CI formatter = in-tree `utils/das-fmt/dasfmt.das`

`bin/Release/das-fmt.exe` built from `utils/dasFormatter/` is the **v1→v2 syntax converter**, NOT the same formatter — running it locally does not reproduce CI.
CI's `extended_checks` runs `./bin/daslang ./utils/das-fmt/dasfmt.das -- --path ./ --verify` — the script is **in the repo tree** and wraps the same `daslib/das_source_formatter` engine as MCP `format_file`, so the two agree (probe-verified: both rewrite `Foo(a=1)` → `Foo(a = 1)`). The pre-push hook runs the exact CI command on tracked files; if the hook passes, the CI formatter gate passes.

**Before pushing:** mentally format named-arg constructor / call sites with spaces around `=`. If CI `extended_checks` fails on a format diff after MCP said "already formatted", fix the spacing and re-push (or amend, on a squashed branch).
**Name trap:** a locally built `bin/Release/das-fmt.exe` (the CMake `das-fmt` target, from `utils/dasFormatter/`) is the **v1→v2 syntax converter**, not the formatter. CI's `das-fmt.exe` verify pass works because CI first overwrites that binary with an `-exe`-compiled `dasfmt.das`. Locally, always invoke the formatter as `<daslang> utils/das-fmt/dasfmt.das -- ...` (or MCP `format_file`).

## 6. Create the PR

Expand All @@ -302,9 +313,10 @@ Stage, commit, push, and create the PR using GitHub MCP tools or `gh` CLI. Follo
| Workaround audit | `git diff origin/master..HEAD` — read every changed file | Smell (redundant step / synthetic≠real / special-case / copied-hack) → surface fix-vs-workaround and **ask**; never ship a buried workaround |
| Tests | `dastest -- --test tests/` | Must pass. Fix own, fix obvious pre-existing, ask about unclear |
| JIT smoke | `daslang.exe -jit <test>.das 2>&1 \| grep -iE "verifier\|Both operands"` | Empty output = pass. Windows `clang-cl` link fail is local-only, ignore |
| Type-system/generics | sequence smoke (`skills/preflight.md`) + externals sweep (`skills/abi_break_sweep.md`) | Only for type-system / AST-layout / daslib-generics changes |
| AOT build | `cmake --build build --config Release --target test_aot -j 64` | Kill daslang first. Register new test dirs |
| AOT tests | `test_aot.exe -use-aot dastest/dastest.das -- --use-aot --test tests` | Same as regular tests |
| Docs | `das2rst.das` + stubs + Sphinx | Only if daslib/C++ bindings/RST changed |
| Docs | `das2rst.das` (loop until clean) + stubs + Uncategorized + untracked + Sphinx latex AND html | Any daslib/src-builtin/RST change triggers all six gates — `skills/preflight.md` |
| Format | MCP `format_file` with comma-separated list or glob of changed `.das` files (single call) | Only changed files |
| Wrap-up curation | `skills/task_wrap_up.md` | Optional. Add answers for cache misses, edit cached answers this PR invalidated |
| `.md` stop | `git diff --name-only origin/master..HEAD \| grep '\.md$'` | If any match: STOP, list changes, ask user to review BEFORE push |
Expand Down
Loading
Loading