Skip to content

install: ship what the docs promise + close the smoke-test hole that hid it - #3571

Merged
borisbat merged 4 commits into
masterfrom
codex/install-audit-fixes
Jul 26, 2026
Merged

install: ship what the docs promise + close the smoke-test hole that hid it#3571
borisbat merged 4 commits into
masterfrom
codex/install-audit-fixes

Conversation

@borisbat

@borisbat borisbat commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

What

Audited cmake --install coverage against the tree and fixed the gaps. Seven of them broke workflows the shipped docs tell users to follow.

The worst: utils/mcp/setup.das has never been installed, while the installed utils/mcp/README.md (L175-192) and the shipped skills/mcp_tools.md (L73) both document running it. The MCP bootstrap was impossible from a bundle through 0.6.4. Its companion mcp_supervisor.py — which setup.das writes into .mcp.json — was missing too.

Root cause of the whole class: ci/smoke_test_bundle.sh compiled 9 of the 14 installed .das entry points, and setup.das sat in the gap, so nothing ever noticed. All 14 are covered now — 12 checks → 17.

Ship what was missing

Gap Why it mattered
utils/mcp/setup.das + mcp_supervisor.py The documented bootstrap, absent from every bundle
utils/mcp/tests/ non-.das fixtures FILES_MATCHING PATTERN "*.das" dropped _fixture_cpp_outline.h and _pretend_root/.../.das_module, both required by the installed test_tools.das (L2130, L2611)
utils/lint/tests/ (77 files) A bundle could not self-check the linter. Verified: 51 tests, 51 passed via dastest inside the install tree
examples/daStrudel/sfx_lab sounds/*.sfx (27) + .das_package batch_drums.das:19, batch_synth.das:23, export_drums.das:12 read them via get_das_root() — shipping the scripts alone left them broken
examples/graphics per-example .das_package + .gitignore Each subdir is a daspkg -project-root whose release_main points at the shared source one level up; the non-recursive glob dropped the load-bearing manifests
examples/benchmarks/ Documented in the installed examples/README.md:184-193, which also links its README
aot_testing / llvm_tune / perf_lint / style_lint skills Cross-referenced by already-shipped skills, so they dangled in the SDK
tree-sitter-daslang/zed-daslang/ install/README.md points users at it
CHANGELIST.md A versioned bundle shipped with no release notes
integration_cpp_23 in the standalone recipe 23_handle_registry.{cpp,das} shipped with no way to build it; handle_registry.h was already installed

tutorials.md deliberately stays repo-only — shipping it would drag in documentation_rst.md and onward — so the one reference to it (skills/xml.md) is reworded instead.

Decouple tutorial data install from DAS_TUTORIAL_DISABLED

The install rules for all 79 C/C++ integration tutorial sources lived inside the gated include(), so "don't build the tutorial executables" silently also meant "don't ship the tutorial sources." release.yml never sets the flag, so shipping was fine today — but the coupling was a trap. Verified by flipping the flag: 50 integration-source refs survive in the generated install script.

Hygiene

  • Drop FLEX(utils/dasFsormatter/ds_lexer.lpp) — typo'd dir that does not exist, and dasFormatter has no .lpp at all. Inert only because no target consumed the output path (flex is found on some boxes, so this was not protected by FLEX_FOUND).
  • examples/daspkg used a hardcoded DESTINATION instead of DAS_INSTALL_EXAMPLESDIR, and neither it nor examples/games excluded modules/ or build output — a dev tree would ship daspkg junk.
  • file(STRINGS) on install/skills.list now passes ENCODING UTF-8. Without it, non-ASCII bytes act as separators: an em-dash in a comment splits the line and the tail is read as a skill filename, failing the guard with a nonsense path. (Hit this for real while writing the patch.)

dasHV tutorial artifact

tutorials/dasHV/_upload_test/_testfile.txt was committed because the server saves {upload_dir}/_testfile.txt (L279) but cleanup_upload_dir removed {dir}/testfile.txt (L158, no underscore) — the file survived, remove(dir) failed on a non-empty dir, and it landed in git. Fixed the name, untracked the file, gitignored the run dirs. Also corrected the Zed extension path in both READMEs (zed-daslang/, not editors/zed/).

Durable rules recorded

skills/install_instructions.md now carries the shipped-skill closure invariant (a shipped skill may only reference skills/<other>.md when that other ships; repo-only skills stay off the list and referring skills get reworded) with a copy-paste check script, plus the ASCII-only rule for skills.list.

Verification

  • Release-flag bundle (ci/release_modules.txt) built and installed to a scratch prefix, then diffed against the pre-fix bundle: exactly 134 files added, nothing unintended.
  • ci/smoke_test_bundle.sh: 17/17 passing.
  • Shipped lint suite inside the bundle via dastest: 51 tests, 51 passed.
  • Zero dangling skill→skill references across the 33 shipped skills.
  • DAS_TUTORIAL_DISABLED=ON reconfigure: integration sources still install.
  • Lint + format verified on the one changed .das.

Known follow-up (not in this PR)

The 33 shipped skills reference ~90 repo-only paths that can never exist in an SDK bundle — src/*.cpp, tests/**, doc/source/**/*.rst, benchmarks/**, modules/*/src/*.h — plus examples/{fatman,flatten,telegram/dictation,vulkan}, utils/watchdog, utils/dasllama-server. Rewriting those to daslang.io URLs vs. gating the paragraphs vs. accepting them is a product call about whether SDK-facing skills should read repo-internal at all, so it is left out deliberately. The skill→skill half of this class is fixed and guarded here.

Separately, the ten daslang -exe utils (aot, dascov, daspkg, detect-dupe, hygiene, jit, lint, benchctl, mcp, dastest) are built by add_custom_command, so install(TARGETS) cannot reach them and none ship — bundles run them from source. That is by design; this PR only corrects the stale comment in the smoke test that claimed otherwise.


Commit 2 — make the SDK self-contained (9cea6f157)

The audit above found the install rules broken. This second commit fixes the other half: shipped skills sent readers to 70 repo paths a bundle never contains. Two problems were tangled there, needing opposite fixes.

Where the skill relies on the content, the content now ships

One source file, as markdown. Sphinx learns to read markdown (myst-parser==2.0.0, the last line supporting Sphinx 7.2.6) and each .rst becomes a ~13-line pointer that includes the .md. daslang.io and the SDK then read the same bytes — nothing to drift, no generated artifact to keep in sync.

now ships as was
skills/design_philosophy.md reference/design_philosophy.rst
skills/tune.md reference/tune.rst
skills/profiler.md reference/utils/profiler.rst
skills/linq_fold_patterns.md reference/linq_fold_patterns.rst
skills/detect_dupe_reference.md reference/utils/detect_dupe.rst

Two of those RST pages share a stem with an existing shipped skill, because they are the same topic twice — and they are not the same case. memory_leak_detection.md said outright that its RST "covers the same material in docs style", so that pointer is reworded and nothing new ships; four of its five references now resolve to skills/profiler.md, inside the bundle. detect_dupe.rst is genuinely fuller than its skill (541 lines, five flag tables), so it ships under a non-colliding name.

Breadcrumbs in json.md / regex.md / das_macros.md ("RST companion at…", "generated stdlib reference at…" — two of them naming stdlib/generated files that don't exist in a fresh checkout) point at the published page instead.

Where the path is engine internals, the answer is the reverse

src/, tests/, benchmarks/, modules/*/src are never going into a bundle. So the line says so with a repo-only token and the reader skips it, instead of hunting a path that isn't there. 21 refs marked — two heading retitles cover 7 (cpp_integration's "C++ Codebase Notes", jobque_debugging's "Key files"), and 12 one-off prose mentions are marked inline so the sentence stays with the point it supports.

Enforced per-PR by ci/check_shipped_skill_refs.awk, run from ci/smoke_test_bundle.sh — that's build.yml's bundle_smoke job, which triggers on pull_request, so no new CI wiring. Smoke test 17 → 18 checks.

Exemption is section-scoped and resets at each heading. A trailing-marker rule would leak the exemption through the rest of the file, which is wrong for cpp_integration.md, whose internals section sits mid-file. Fenced blocks are exempt because they quote tool output verbatim — including a compiler warning that literally prints a doc/source path.

Verified, not assumed

  • Docs built with CI's exact command (sphinx-build -W --keep-going): zero new warnings, six removed, against a 282-line baseline.
  • The checker negative-tested: clean passes; an unmarked src/ path fails with file:line; the same line marked repo-only passes; a fenced path is ignored.
  • doc/source citations from shipped skills: 9 → 1, and that one is the fenced compiler warning.
  • Bundle reinstalled; 38 skills ship; zero dangling skill→skill references.

Two findings worth recording, both caught the hard way:

  • A MyST (label)= target does not register in Sphinx's std domain when the markdown arrives via .. include:: … :parser:. Page labels therefore live in the .rst stub, and two bare :ref:s needed explicit link text once the title moved into the markdown. Each stub says so.
  • file(STRINGS) treats non-ASCII bytes as separators, so an em-dash in an install/skills.list comment splits the line and the tail is read as a filename. Fixed with ENCODING UTF-8 plus an ASCII-only rule; the guard failing loudly is how it surfaced.

Deliberately not in this PR

tests/53 refs, 24 of them in aot_testing.md. That class needs sorting into inline-the-snippet (where the code sample is the payload) vs quarantine, and it overlaps the question of splitting aot_testing.md / writing_tests.md, which are mixed-audience files. The awk carries a comment saying to add tests/ when it lands.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WiXc1jvihNmEnU7DDQidvt

…hid it

Audited `cmake --install` coverage against the tree. Seven gaps broke workflows
the *shipped* docs tell users to follow; the worst is that `utils/mcp/setup.das`
has never been installed, while the installed `utils/mcp/README.md` and the
shipped `skills/mcp_tools.md` both document running it. The MCP bootstrap was
impossible from a bundle through 0.6.4.

Root cause of the class: ci/smoke_test_bundle.sh compiled 9 of the 14 installed
.das entry points, and setup.das sat in the gap, so nothing ever noticed. All 14
are covered now (12 checks -> 17).

Ship what was missing:
- utils/mcp/setup.das + mcp_supervisor.py (the documented bootstrap).
- utils/mcp/tests/ non-.das fixtures. `FILES_MATCHING PATTERN "*.das"` dropped
  _fixture_cpp_outline.h and _pretend_root/.../.das_module, both required by the
  installed test_tools.das, so the suite shipped unable to run those cases.
- utils/lint/tests/ (77 files), so a bundle can self-check the linter. Verified:
  51 tests, 51 passed via dastest inside the install tree.
- examples/daStrudel/sfx_lab sounds/*.sfx + .das_package. The scripts read these
  via get_das_root(); shipping the scripts alone left them broken.
- examples/graphics per-example .das_package + .gitignore. Each subdir is a
  daspkg -project-root whose release_main points at the shared source one level
  up, so the non-recursive glob dropped the load-bearing manifests.
- examples/benchmarks/, documented in the installed examples/README.md.
- aot_testing / llvm_tune / perf_lint / style_lint skills, cross-referenced by
  already-shipped skills. tutorials.md deliberately stays repo-only and the one
  reference to it (skills/xml.md) is reworded instead, since shipping it would
  drag in documentation_rst.md and onward.
- tree-sitter-daslang/zed-daslang/, which install/README.md points users at.
- CHANGELIST.md: a versioned bundle had no release notes.
- integration_cpp_23 in the standalone tutorial recipe. The source shipped with
  no way to build it; handle_registry.h was already installed.

Decouple tutorial data install from DAS_TUTORIAL_DISABLED. The install rules for
all 79 C/C++ integration tutorial sources lived inside the gated include(), so
"don't build the tutorial executables" silently also meant "don't ship the
tutorial sources". release.yml never sets the flag, so shipping was fine today.
Verified by flipping it: 50 integration-source refs survive in the install script.

Hygiene:
- Drop `FLEX(utils/dasFsormatter/ds_lexer.lpp)`: typo'd dir that does not exist,
  and dasFormatter has no .lpp at all. Inert only because no target consumed the
  output path.
- examples/daspkg used a hardcoded DESTINATION instead of DAS_INSTALL_EXAMPLESDIR,
  and neither it nor examples/games excluded modules/ or build output, so a dev
  tree would ship daspkg junk.
- file(STRINGS) on install/skills.list now passes ENCODING UTF-8. Without it,
  non-ASCII bytes act as separators: an em-dash in a comment splits the line and
  the tail is read as a skill filename, failing the guard with a nonsense path.

Also fix the dasHV tutorial artifact that got committed: the server saves
{upload_dir}/_testfile.txt but cleanup_upload_dir removed {dir}/testfile.txt (no
underscore), so the file survived, remove(dir) failed on a non-empty dir, and
_upload_test/_testfile.txt landed in git. Fix the name, untrack the file,
gitignore the run dirs. Correct the Zed extension path in both READMEs
(zed-daslang/, not editors/zed/).

Record the durable rules in skills/install_instructions.md: the shipped-skill
closure invariant with a check script, and the ASCII-only rule for skills.list.

Verified end to end: release-flag bundle installed to a scratch prefix and diffed
against the pre-fix bundle -- exactly 134 files added, nothing unintended;
smoke test 17/17; zero dangling skill-to-skill references across 33 shipped skills.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WiXc1jvihNmEnU7DDQidvt
Copilot AI review requested due to automatic review settings July 26, 2026 05:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens the SDK/bundle install surface so cmake --install actually ships the files and fixtures that the shipped documentation and examples reference, and extends the bundle smoke test to compile every installed .das entry point to catch future install gaps.

Changes:

  • Move C/C++ integration tutorial source installation out of DAS_TUTORIAL_DISABLED-gated CMake includes so tutorial sources always ship, and extend the standalone tutorial recipe to include tutorial 23.
  • Expand installed content for MCP + lint tooling and examples (fixtures/tests, Strudel sfx_lab data, benchmarks, tree-sitter Zed extension), and update docs to match shipped paths.
  • Strengthen smoke-test coverage and clean up accidental tutorial artifacts via corrected cleanup + .gitignore rules.

Reviewed changes

Copilot reviewed 15 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tutorials/integration/cpp/CMakeLists.txt Removes local install rules and documents that tutorial-source installs live in tutorials/CMakeLists.txt.
tutorials/integration/cpp/CMakeLists.standalone.cmake Adds standalone build recipe entry for integration_cpp_23.
tutorials/integration/c/CMakeLists.txt Removes local install rules and explains why installs must be unconditional.
tutorials/dasHV/05_cookies_and_forms.das Fixes cleanup to remove the correct uploaded test filename, preventing leftover artifacts.
tutorials/dasHV/_upload_test/_testfile.txt Removes an accidentally committed runtime artifact.
tutorials/CMakeLists.txt Adds unconditional install rules for C/C++ integration tutorial sources + standalone CMakeLists.
skills/xml.md Rewords tutorial-data install guidance to avoid referencing a repo-only skill and to point at the actual globbing behavior.
skills/install_instructions.md Documents shipped-skill closure and skills.list encoding constraints + a check script.
README.md Fixes Zed extension path under tree-sitter-daslang/.
modules/dasAudio/CMakeLists.txt Installs .sfx and .das_package for Strudel sfx_lab so shipped scripts can run.
install/skills.list Adds shipped-skill closure invariant notes and ships additional cross-referenced skills.
install/README.md Fixes Zed extension path under tree-sitter-daslang/.
install/CLAUDE.md Adds entries for newly shipped skills in the SDK-facing skill table.
CMakeLists.txt Adds missing installed files (e.g., MCP setup + supervisor, lint tests, examples/benchmarks, zed extension, CHANGELIST) and improves install hygiene/excludes.
ci/smoke_test_bundle.sh Expands compile-only coverage to all installed .das entry points and clarifies bundle executable expectations.
.gitignore Ignores tutorial runtime artifacts (dasHV upload/static dirs and dasAudio tutorial WAVs) to prevent re-commits.
Comments suppressed due to low confidence (2)

tutorials/CMakeLists.txt:144

  • Same as above: add CONFIGURE_DEPENDS so newly added/removed C/C++ integration tutorial sources are picked up without requiring a manual CMake reconfigure, which helps keep install coverage correct over time.
file(GLOB CPP_INTEGRATION_TUTORIAL_SOURCES

CMakeLists.txt:2127

  • Same concern as the graphics install: if the source tree contains daspkg/runtime artifacts (lock/log/tmp dirs, shared_module outputs, jitted_scripts, etc.), they will be copied into the installed SDK because they are not excluded here.
install(DIRECTORY ${PROJECT_SOURCE_DIR}/examples/benchmarks/
    DESTINATION ${DAS_INSTALL_EXAMPLESDIR}/benchmarks
    FILES_MATCHING
        PATTERN "*.das"
        PATTERN "*.md"
        PATTERN ".das_package"

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tutorials/CMakeLists.txt
# These are UNCONDITIONAL on purpose: DAS_TUTORIAL_DISABLED means "don't build the
# tutorial executables", not "don't ship the tutorial sources". The rules used to
# live inside the two include()d files below, which coupled the two.
file(GLOB C_INTEGRATION_TUTORIAL_SOURCES
Comment thread CMakeLists.txt
Comment on lines +2105 to +2116
install(DIRECTORY ${PROJECT_SOURCE_DIR}/examples/graphics/
DESTINATION ${DAS_INSTALL_EXAMPLESDIR}/graphics
FILES_MATCHING
PATTERN "*.das"
PATTERN ".das_package"
PATTERN ".gitignore"
PATTERN "README.md"
PATTERN "modules" EXCLUDE
PATTERN ".daspkg_cache" EXCLUDE
PATTERN ".jitted_scripts" EXCLUDE
PATTERN "_aot_generated" EXCLUDE
)
…at can't ship

Follow-up to the install audit in this PR. The shipped skills sent readers to 70
repo paths that a bundle never contains. Two problems were tangled together there,
and they need opposite fixes.

Where the skill relies on the content, the content now SHIPS, as markdown, with
exactly one source file. Teach Sphinx to read markdown (myst-parser==2.0.0, the
last line supporting sphinx 7.2.6) and each .rst becomes a ~13-line pointer that
includes the .md via `.. include:: ... :parser: myst_parser.sphinx_`. daslang.io
and the SDK then read the same bytes, so they cannot drift, and there is no
generated artifact to keep in sync. Converted this way, and added to
install/skills.list:

  skills/design_philosophy.md      (was reference/design_philosophy.rst)
  skills/tune.md                   (was reference/tune.rst)
  skills/profiler.md               (was reference/utils/profiler.rst)
  skills/linq_fold_patterns.md     (was reference/linq_fold_patterns.rst)
  skills/detect_dupe_reference.md  (was reference/utils/detect_dupe.rst)

Two of those RST pages share a stem with an existing shipped skill, because they
are the same topic twice. They are NOT the same case. memory_leak_detection.md
said outright that its RST "covers the same material in docs style", so that
pointer is simply reworded and nothing new ships — four of its five references now
resolve to skills/profiler.md, inside the bundle. detect_dupe.rst is genuinely
fuller than its skill (541 lines, five flag tables), so it ships under a
non-colliding name. Breadcrumb pointers in json.md / regex.md / das_macros.md
("RST companion at", "generated stdlib reference at" — two of them naming
stdlib/generated files that do not exist in a fresh checkout) point at the
published page instead.

Where the path is engine internals, the answer is the reverse of shipping it.
src/, tests/, benchmarks/ and modules/*/src are never going into a bundle, so the
line now says so with a repo-only token, and the reader skips it instead of
hunting a path that is not there. 21 refs marked: two heading retitles cover 7
(cpp_integration's "C++ Codebase Notes", jobque_debugging's "Key files"), and 12
one-off prose mentions are marked inline so the sentence stays with the point it
supports.

Enforced per-PR by ci/check_shipped_skill_refs.awk, run from
ci/smoke_test_bundle.sh (build.yml's bundle_smoke job, which triggers on
pull_request) — no new CI wiring. Smoke test 17 -> 18 checks. Exemption is
SECTION-scoped and resets at each heading: a trailing-marker rule would leak the
exemption through the rest of the file, which is wrong for cpp_integration.md
where the internals section sits mid-file. Fenced blocks are exempt because they
quote tool output verbatim, including a compiler warning that literally prints a
doc/source path. tests/ is deliberately not in the pattern yet (53 refs, 24 of
them in aot_testing.md) — that class still needs sorting into inline-the-snippet
vs quarantine, and the awk says so.

Verified, not assumed:
  * docs built with CI's exact command (sphinx-build -W --keep-going): ZERO new
    warnings, six removed, against a 282-line baseline. Page labels had to move
    into the .rst stubs, because a MyST (label)= target does NOT register in
    Sphinx's std domain when the markdown arrives through an include with
    :parser:; and two bare :ref: uses needed explicit link text once the title
    moved into the markdown.
  * the checker negative-tested: clean passes; an unmarked src/ path fails with
    file:line; the same line marked repo-only passes; a fenced path is ignored.
  * doc/source citations from shipped skills: 9 -> 1, and that one is a compiler
    warning quoted inside a fence, which must stay verbatim.
  * bundle reinstalled; 38 skills ship; zero dangling skill-to-skill references.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WiXc1jvihNmEnU7DDQidvt
Copilot AI review requested due to automatic review settings July 26, 2026 08:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 45 out of 46 changed files in this pull request and generated 1 comment.

Comment on lines 160 to 167
install(DIRECTORY ${PROJECT_SOURCE_DIR}/examples/daStrudel/
DESTINATION ${DAS_INSTALL_EXAMPLESDIR}/daStrudel
FILES_MATCHING
PATTERN "*.das"
PATTERN "*.md"
PATTERN "*.sfx"
PATTERN ".das_package"
)
…ow to write a skill

Three pieces: a per-PR gate for what a script can check, a review skill for what it
can't, and a CLAUDE.md section so the decision gets made before the writing.

ci/check_shipped_skills.py replaces the awk from the previous commit. The link check
needs to tell a missing file from a directory, which awk cannot do portably, so this is
Python — invoked from ci/smoke_test_bundle.sh and skipped (not failed) when no
interpreter is present, so the script stays runnable on a bare box. Five classes, all in
a SHIPPED skill:

  * src/, doc/source/, benchmarks/, modules/*/{src,tests,tutorial,harness}
  * bin/Release|Debug/... -- the Windows repo layout; a bundle has bin/daslang
  * daslang.exe <script> -- .exe is Windows-only
  * C:\Users\..., /home/<name>/..., AppData -- someone's machine in a doc
  * a relative link whose target is absent from the bundle
  * skills/<other>.md where <other> is not shipped (the closure invariant, ported over)

It found 34 real hits, all now fixed. 14 were bin/Release/daslang.exe -- including the
first three lines of das_formatting.md, i.e. instructions that are wrong on two of three
platforms. 8 were dead links, 3 named generated .rst that exists nowhere, 9 were .exe
invocations.

Narrowness was the hard part, and two of my own patterns were wrong before they were
right. A naive absolute-path regex matched every http:// URL (77 false hits) and the
\\-UNC branch matched \\d and \\s in regex prose; that check is now scoped to
machine-local paths only, so the 17 deliberate C:/DummyRoot examples in
external_module_debugging.md stay quiet. The link resolver joined against the bundle root
while links are authored relative to skills/, which made 19 live links look dead. And the
.exe check flagged prose ("shared across `daslang.exe` and every module DLL") until it
required the next token to be a flag or a real file. A gate that cries wolf gets muted,
and then it is worse than no gate — so all 21 shapes are negative-tested: 9 must-fail, 10
false-positive shapes that must stay quiet, plus a check that a section-scoped repo-only
marker RESETS at the next heading instead of leaking down the file.

Also fixed while wiring it up: `command -v python3` finds the Windows Store shim, which
is on PATH but exits "Permission denied". The probe now executes the interpreter.

Split writing_tests.md, which was two audiences in one file. The universal dastest
guidance stays and ships; the repo's own harness — AOT registration for a new tests/ dir,
the tests/.das_test gating filter and its root-path caveat, per-folder sweep gating,
deep-engine model-test rules — moves to skills/tests_in_repo.md, deliberately NOT shipped.
The shipped half also now points at dastest/tests, which ships and doubles as a worked
example, instead of tests/linq, which does not. My first draft of the shipped file
referenced skills/tests_in_repo.md — the exact closure violation documented one commit
earlier — which is why the closure check is now enforced by the script rather than living
as a shell snippet in a doc.

New skills/writing_skills.md (repo-only) covers what no script can: pick the audience
BEFORE writing, because a mixed file serves neither and splitting it afterwards is a
reorganization rather than a cut (aot_testing.md is the standing example, still unsplit);
check whether an existing skill or doc/source page already owns the topic, since two
documents drifting apart beats one imperfect one; verify syntax claims by probe rather
than recall; and never silence the gate with a marker when the honest answer is a split.
CLAUDE.md gains a short "Writing a new skill" section pointing at it, plus a table row.

Verified: smoke test 18 checks green; gate exits 0 against the reinstalled bundle;
38 skills ship; tests_in_repo.md and writing_skills.md correctly absent from it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WiXc1jvihNmEnU7DDQidvt
Copilot AI review requested due to automatic review settings July 26, 2026 09:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 57 out of 58 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

skills/profiler.md:60

  • For SDK users running from the bundle root, this command should use bin/daslang (not daslang on PATH). Also consider changing the code fence language to bash since this is a shell invocation.

Comment thread skills/mcp_tools.md
**`shutdown` tool.** Shuts down the MCP server process. Claude Code auto-restarts it, picking up code changes to `.das` tool files. Tool registration changes (adding/removing tools) still require a manual MCP restart.

**Configuration.** Configure `.mcp.json` with `"command"` pointing at the daslang binary (`bin/Release/daslang.exe` on Windows MSVC, `build/daslang` on Linux/macOS, `bin/daslang` for the installed SDK), `"args": ["utils/mcp/main.das"]`. See `utils/mcp/README.md` for details and Claude Code permissions.
**Configuration.** Configure `.mcp.json` with `"command"` pointing at the daslang binary (`bin/daslang` on Windows MSVC, `build/daslang` on Linux/macOS, `bin/daslang` for the installed SDK), `"args": ["utils/mcp/main.das"]`. See `utils/mcp/README.md` for details and Claude Code permissions.
Comment thread skills/profiler.md
Run any daslang script with `--das-profiler` and optionally a log-file path:

```das
daslang --das-profiler --das-profiler-log-file /tmp/trace.json path/to/script.das
…eeds it

aot_testing.md is the daslang repo's AOT test harness -- the test_aot binary, tests/aot
registration, libDaScriptAot regeneration, CI wiring. An SDK user has no way to act on any
of it, so it is not their skill and it no longer ships. That is simpler and more honest
than the split I was heading for, and it reverts churn: the six edits I had made to that
file were all gate-appeasement, including turning bin/Release/daslang.exe into bin/daslang,
which is a REGRESSION for Windows repo devs whose layout really is bin/Release. The file is
now byte-identical to master again.

The only shipped skill that referenced it was cpp_integration.md. Rather than drop the
pointer, that section now carries the actionable part inline -- generate stubs with
`bin/daslang -aot in.das out.cpp`, add -aot-macros for macros, regenerate on
error[50101] -- and names aot_testing.md as repo-only for the harness itself. install/
CLAUDE.md loses its row; install/skills.list explains WHY the file is absent, so the next
person does not re-add it to satisfy the closure invariant.

With aot_testing.md out and writing_tests.md already split, tests/ can finally join the
gate pattern. That surfaced 10 more refs in shipped skills, all worked-example pointers
into the repo test corpus (das_macros, dashv, daslib_modules, llvm_tune, xml, plus two in
my own new prose) -- each now marked rather than deleted, since they are useful to a repo
reader and simply absent for an SDK one.

The marker is now PARAGRAPH-scoped, not line-scoped. Two of those last ten hits were text
I had just written, where the marker landed one line away from the path because the
sentence wrapped -- twice. Scoping per-line means an author has to reflow prose to satisfy
the gate, which is exactly how a gate earns being muted. A marker anywhere in a paragraph
now covers it; the exemption still does not leak across a blank line, and heading-scoped
and line-scoped markers are unchanged. Verified both directions.

Two process traps hit while doing this, both worth knowing:
  * `cmake --install` is ADDITIVE. Un-shipping a file leaves the old copy in the prefix, so
    the gate ran green against a bundle that still contained aot_testing.md. Removing the
    prefix first is the only way to see the real shipped set.
  * install/skills.list is read at CONFIGURE time via file(STRINGS). Editing it and running
    only `cmake --install` installs the OLD list. Reconfigure first.

Verified: fresh install ships 37 skills with aot_testing.md absent; gate exits 0; smoke
test 18 checks green; the full negative-test suite still passes (9 must-fail classes, 10
false-positive shapes that must stay quiet, section-marker reset, and the two new
paragraph-scope cases).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WiXc1jvihNmEnU7DDQidvt

Also adds ci/reinstall_bundle.sh: reconfigure + wipe prefix + install + verify in one
command, so the loop is a single reviewable invocation instead of an ad-hoc `rm -rf`. It
guards the delete -- refuses anything that is not absent or recognizably an installed
bundle, and refuses a source checkout outright -- and its comments encode the two traps
above so the next person does not rediscover them.
Copilot AI review requested due to automatic review settings July 26, 2026 10:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 59 out of 60 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (3)

skills/daslang_live.md:34

  • The code block now uses the cross-platform bin/daslang-live naming, but this comment still says daslang.exe. Since the goal here is bundle-friendly docs, it should refer to daslang (or bin/daslang) rather than a Windows-only filename.
# Standalone mode (same as daslang.exe — if script only has main())
bin/daslang-live path/to/main.das

skills/daslang_live.md:37

  • This sentence says scripts can be run with bin/daslang ... but then refers to the non-live host as daslang.exe. For consistency (and to avoid implying a Windows-only binary), this should say bin/daslang.
Scripts can also run standalone with `bin/daslang path/to/main.das` — the same `main.das` works in both hosts. Under `daslang.exe`, `is_live_mode()` returns `false`, the REST API does not start, and `[before_reload]`/`[after_reload]` annotations are ignored.

skills/install_instructions.md:41

  • This enforcement note is stale: it still points at the old awk checker and claims tests/ is not in the pattern. The new Python gate includes tests/ and is what ci/smoke_test_bundle.sh actually runs, so the instructions should match reality.

Comment thread skills/mcp_tools.md
**`shutdown` tool.** Shuts down the MCP server process. Claude Code auto-restarts it, picking up code changes to `.das` tool files. Tool registration changes (adding/removing tools) still require a manual MCP restart.

**Configuration.** Configure `.mcp.json` with `"command"` pointing at the daslang binary (`bin/Release/daslang.exe` on Windows MSVC, `build/daslang` on Linux/macOS, `bin/daslang` for the installed SDK), `"args": ["utils/mcp/main.das"]`. See `utils/mcp/README.md` for details and Claude Code permissions.
**Configuration.** Configure `.mcp.json` with `"command"` pointing at the daslang binary (`bin/daslang` on Windows MSVC, `build/daslang` on Linux/macOS, `bin/daslang` for the installed SDK), `"args": ["utils/mcp/main.das"]`. See `utils/mcp/README.md` for details and Claude Code permissions.

The CMake install rule (in root `CMakeLists.txt`) reads the manifest with `file(STRINGS ...)` and `install(FILES ...)` for each named basename. Missing files trigger `FATAL_ERROR` at configure time, so a typo in `install/skills.list` fails loudly.

**Closure invariant.** A shipped skill may only reference `skills/<other>.md` when that other skill also ships — otherwise the SDK carries a dead link. The rule cuts both ways: a genuinely repo-only skill (`tests_in_repo.md`, `tutorials.md`, `documentation_rst.md`, `preflight.md`, `make_pr.md`, …) stays **off** the list, and a shipped skill pointing at one either gets reworded or marks the line `repo-only` (see below) rather than dragging it in. Enforced per-PR by the same `ci/check_shipped_skill_refs.awk` as the path rule — it takes the ship list via `-v shipped=`, so a skill sitting on disk but absent from `install/skills.list` is still caught.
Comment on lines +10 to +16
Five checks. Each is deliberately narrow: a gate that cries wolf gets muted, and then it
is worse than no gate. Two escape hatches, both spelled `repo-only`:
* in a HEADING -> exempts that section, resetting at the next heading of any level.
(Not "everything after the marker": cpp_integration.md has a repo-internals section
in the MIDDLE, and a trailing rule would exempt the rest of the file.)
* on a LINE -> exempts that line, for one-off mentions in prose.

Comment thread skills/daslang_live.md
Comment on lines 20 to +22
`daslang-live.exe` is a live-reloading application host. It compiles and runs a daScript file, then watches for file changes and hot-reloads the script without restarting the process. It also exposes a REST API for remote control.

**Binary:** `bin/Release/daslang-live.exe`
**Binary:** `bin/daslang-live`
@borisbat
borisbat merged commit b4258ee into master Jul 26, 2026
38 checks passed
pull Bot pushed a commit to forksnd/daScript that referenced this pull request Jul 27, 2026
…, and lens rails

Everything the cm2 production twin needs underneath it, landed green before
the kernel itself:

- KqFmt.q8n (= 6): the same q8 weights as gguf-native 34B interleaved blocks
  ({f16 d; int8 qs[32]}, ONE plane) — a GPU-tier tag, never a disk format.
  Schema gains Q8N_BPB; the tier's arena/stack math grows the q8n arm
  (single plane, ws = 0, 32-elem blocks via vk_fmt_b32).
- Device + mode: has_coopmat2 probe, DASLLAMA_COOPMAT=cm2 -> mode 4 (guarded
  on the extension, downgrades to mm without it), the cm2 device chain via
  #77's creator. cm2 stays OPT-IN until it beats mm in the bench — the
  fastest-path default is measurement-driven.
- dasllama_layout: moe_gpu_gather_stack_q8n — prepared planes (grp<mr> or
  row-major, wbias XOR) -> interleaved 34B blocks; hook chain extended
  (GatherStackQ8nFn, register_model_layout arity +1).
- Kernel-access lens: the cm2 tensor intrinsics modeled (coopmatStoreTensor
  writes arg 1; coopmatLoadTensor/Decode plain reads) on top of the merged
  GaijinEntertainment#3570 analyzer.

Gates: full chain compiles, lint 0 across 5 files, test_vulkan_tier 34/34.
Branch rebased onto master (post-GaijinEntertainment#3570/GaijinEntertainment#3571) with a full C++ rebuild and a
fresh dasVulkan shared_module.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G1Qe2TFnnxaLv4TyQm9Xeh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants