tenseleyflow/documentlanguagemodel / 93c2712

Browse files

polish: N1 fiction / N11 monkeypatch / N14 mkdocs gate / first-train docs (audit-05)

Authored by espadonne
SHA
93c271239d5d76b20b3edeeae1da5c009860dde6
Parents
601e857
Tree
42182c0

3 changed files

StatusFile+-
M .github/workflows/release.yml 7 1
M docs/getting-started/first-train.md 13 7
M tests/integration/pack/test_round_trip.py 18 17
.github/workflows/release.ymlmodified
@@ -36,7 +36,7 @@ jobs:
3636
           version: ${{ env.UV_VERSION }}
3737
 
3838
       - name: Sync (all groups)
39
-        run: uv sync --all-extras --dev
39
+        run: uv sync --all-extras --dev --group docs
4040
 
4141
       - name: Ruff
4242
         run: uv run ruff check .
@@ -50,6 +50,12 @@ jobs:
5050
       - name: Pytest (non-slow)
5151
         run: uv run pytest -m "not slow and not online and not gpu"
5252
 
53
+      - name: Mkdocs build --strict
54
+        # Audit-05 N14: block release on docs regressions (dead links,
55
+        # missing files in nav, etc.) before the publish step so a broken
56
+        # docs site can't ship alongside a real PyPI tag.
57
+        run: uv run mkdocs build --strict --site-dir /tmp/mkdocs-check
58
+
5359
   build:
5460
     name: build wheel + sdist
5561
     needs: ci-gate
docs/getting-started/first-train.mdmodified
@@ -62,20 +62,26 @@ batch size, grad accumulation), downloads the base model (cached on
6262
 re-runs), and kicks off the SFTTrainer. On a Mac M-series with MPS,
6363
 20 steps of SmolLM2-135M take about two minutes.
6464
 
65
-Output (abbreviated):
65
+Output — the CLI prints the summary lines; per-step metrics go to
66
+a JSONL log for programmatic consumption (Sprint 09's StepLogger):
6667
 
6768
 ```
68
-preflight: 9.6 GB free under ~/.dlm/store/01KC…/
69
-banner:    seed=42 determinism=best-effort plan=fp16/sdpa/bs=1×8
70
-step 5:    loss=3.421  lr=5.00e-04
71
-step 10:   loss=2.887  lr=4.47e-04
72
-step 15:   loss=2.541  lr=3.45e-04
73
-step 20:   loss=2.298  lr=2.08e-04
7469
 trained:   v0001 (20 steps, seed=42, determinism=best-effort)
7570
 adapter:   ~/.dlm/store/01KC…/adapter/versions/v0001
7671
 log:       ~/.dlm/store/01KC…/logs/train-000001-…jsonl
7772
 ```
7873
 
74
+Tail the JSONL log to see per-step loss in the shape:
75
+
76
+```
77
+{"type": "banner", "run_id": 1, "seed": 42, "determinism_class": "best-effort", ...}
78
+{"type": "step", "step": 5, "loss": 3.421, "lr": 0.0005, "grad_norm": 2.14, "timestamp": "..."}
79
+{"type": "step", "step": 10, "loss": 2.887, "lr": 0.000447, ...}
80
+...
81
+```
82
+
83
+A pretty-print `dlm metrics` command lands in Phase 6 (Sprint 26).
84
+
7985
 ## 3. Inspect the store
8086
 
8187
 ```sh
tests/integration/pack/test_round_trip.pymodified
@@ -26,19 +26,25 @@ from typer.testing import CliRunner
2626
 from dlm.cli.app import app
2727
 
2828
 
29
-def _scaffolded_store(tmp_path: Path) -> Path:
30
-    """Init a doc, ensure_layout the store, save a manifest — return the .dlm path."""
29
+def _scaffolded_store(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
30
+    """Init a doc, ensure_layout the store, save a manifest — return the .dlm path.
31
+
32
+    Audit-05 N11: `monkeypatch.setenv` instead of raw `os.environ[...]`
33
+    so the DLM_HOME override auto-reverts at test teardown and can't
34
+    leak into a later test in the same session.
35
+    """
3136
     from dlm.doc.parser import parse_file
32
-    from dlm.store.manifest import Manifest, save_manifest
3337
     from dlm.store.paths import for_dlm
3438
 
39
+    home = tmp_path / "dlm-home"
40
+    monkeypatch.setenv("DLM_HOME", str(home))
3541
     runner = CliRunner()
3642
     doc = tmp_path / "doc.dlm"
3743
     result = runner.invoke(
3844
         app,
3945
         [
4046
             "--home",
41
-            str(tmp_path / "dlm-home"),
47
+            str(home),
4248
             "init",
4349
             str(doc),
4450
             "--base",
@@ -47,17 +53,10 @@ def _scaffolded_store(tmp_path: Path) -> Path:
4753
     )
4854
     assert result.exit_code == 0, result.output
4955
 
50
-    import os
51
-
52
-    os.environ["DLM_HOME"] = str(tmp_path / "dlm-home")
56
+    # Post-B2: `dlm init` already creates the store + manifest. We just
57
+    # drop a marker file so round-trip tests cover non-manifest content.
5358
     parsed = parse_file(doc)
5459
     store = for_dlm(parsed.frontmatter.dlm_id)
55
-    store.ensure_layout()
56
-    save_manifest(
57
-        store.manifest,
58
-        Manifest(dlm_id=parsed.frontmatter.dlm_id, base_model="smollm2-135m"),
59
-    )
60
-    # Drop a marker file in the store so round-trip covers non-manifest content.
6160
     (store.root / "marker.txt").write_text("i survived the round trip\n")
6261
     return doc
6362
 
@@ -69,7 +68,7 @@ class TestRoundTrip:
6968
         from dlm.pack.packer import pack
7069
         from dlm.pack.unpacker import unpack
7170
 
72
-        doc = _scaffolded_store(tmp_path)
71
+        doc = _scaffolded_store(tmp_path, monkeypatch)
7372
         original_dlm = doc.read_bytes()
7473
 
7574
         # Capture pre-pack store state.
@@ -104,11 +103,13 @@ class TestRoundTrip:
104103
         restored_marker = (unpack_result.store_path / "marker.txt").read_bytes()
105104
         assert restored_marker == original_marker
106105
 
107
-    def test_pack_manifest_content_sha256_is_deterministic(self, tmp_path: Path) -> None:
106
+    def test_pack_manifest_content_sha256_is_deterministic(
107
+        self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
108
+    ) -> None:
108109
         """Two packs of identical input produce identical `content_sha256` rollups."""
109110
         from dlm.pack.packer import pack
110111
 
111
-        doc = _scaffolded_store(tmp_path)
112
+        doc = _scaffolded_store(tmp_path, monkeypatch)
112113
         a = pack(doc, out=tmp_path / "a.pack")
113114
         b = pack(doc, out=tmp_path / "b.pack")
114115
 
@@ -136,7 +137,7 @@ class TestForceOverwrite:
136137
         from dlm.pack.packer import pack
137138
         from dlm.pack.unpacker import unpack
138139
 
139
-        doc = _scaffolded_store(tmp_path)
140
+        doc = _scaffolded_store(tmp_path, monkeypatch)
140141
         pack_result = pack(doc, out=tmp_path / "out.pack")
141142
 
142143
         fresh_home = tmp_path / "fresh-home"