@tuned-tensor/local 0.2.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +84 -204
  3. package/dist/artifacts.d.ts +3 -4
  4. package/dist/artifacts.js +55 -33
  5. package/dist/artifacts.js.map +1 -1
  6. package/dist/compare.d.ts +1 -8
  7. package/dist/compare.js +1 -23
  8. package/dist/compare.js.map +1 -1
  9. package/dist/contracts.d.ts +59 -366
  10. package/dist/contracts.js +73 -224
  11. package/dist/contracts.js.map +1 -1
  12. package/dist/dataset.d.ts +2 -4
  13. package/dist/dataset.js +31 -125
  14. package/dist/dataset.js.map +1 -1
  15. package/dist/doctor.d.ts +2 -3
  16. package/dist/doctor.js +23 -161
  17. package/dist/doctor.js.map +1 -1
  18. package/dist/evaluation.d.ts +11 -71
  19. package/dist/evaluation.js +212 -572
  20. package/dist/evaluation.js.map +1 -1
  21. package/dist/huggingface-cache.d.ts +8 -7
  22. package/dist/huggingface-cache.js +16 -8
  23. package/dist/huggingface-cache.js.map +1 -1
  24. package/dist/index.d.ts +0 -10
  25. package/dist/index.js +205 -628
  26. package/dist/index.js.map +1 -1
  27. package/dist/local-project.d.ts +1 -11
  28. package/dist/local-project.js +33 -61
  29. package/dist/local-project.js.map +1 -1
  30. package/dist/model-registry.d.ts +3 -16
  31. package/dist/model-registry.js +76 -292
  32. package/dist/model-registry.js.map +1 -1
  33. package/dist/model-server.d.ts +1 -2
  34. package/dist/model-server.js +9 -18
  35. package/dist/model-server.js.map +1 -1
  36. package/dist/orchestrator.d.ts +11 -25
  37. package/dist/orchestrator.js +246 -566
  38. package/dist/orchestrator.js.map +1 -1
  39. package/dist/prefetch.d.ts +1 -5
  40. package/dist/prefetch.js +14 -19
  41. package/dist/prefetch.js.map +1 -1
  42. package/dist/process-runner.d.ts +10 -29
  43. package/dist/process-runner.js +63 -169
  44. package/dist/process-runner.js.map +1 -1
  45. package/dist/process-training.d.ts +0 -1
  46. package/dist/process-training.js +10 -87
  47. package/dist/process-training.js.map +1 -1
  48. package/dist/store.d.ts +1 -3
  49. package/dist/store.js +92 -290
  50. package/dist/store.js.map +1 -1
  51. package/docs/architecture.md +87 -152
  52. package/docs/spark.md +66 -97
  53. package/examples/dry-runner.json +14 -0
  54. package/examples/local-runner.json +8 -6
  55. package/examples/smoke-spec.json +41 -0
  56. package/package.json +6 -6
  57. package/training/local-runner/pyproject.toml +0 -5
  58. package/training/local-runner/src/evaluate.py +89 -234
  59. package/training/local-runner/src/model_contract.py +47 -0
  60. package/training/local-runner/src/prefetch.py +18 -4
  61. package/training/local-runner/src/serve.py +54 -115
  62. package/training/local-runner/src/sft_data.py +97 -0
  63. package/training/local-runner/src/train.py +146 -346
  64. package/training/local-runner/uv.lock +0 -1197
  65. package/dist/labeling-sanitize.d.ts +0 -31
  66. package/dist/labeling-sanitize.js +0 -158
  67. package/dist/labeling-sanitize.js.map +0 -1
  68. package/dist/labeling.d.ts +0 -155
  69. package/dist/labeling.js +0 -496
  70. package/dist/labeling.js.map +0 -1
  71. package/dist/openrouter.d.ts +0 -29
  72. package/dist/openrouter.js +0 -66
  73. package/dist/openrouter.js.map +0 -1
  74. package/dist/server.d.ts +0 -9
  75. package/dist/server.js +0 -211
  76. package/dist/server.js.map +0 -1
  77. package/docs/local-workflow-remediation-2026-07-13.md +0 -130
  78. package/docs/local-workflow-ux-review-2026-07-13.md +0 -458
  79. package/examples/dpo-preferences.jsonl +0 -2
  80. package/examples/dpo-run-request.json +0 -34
  81. package/examples/smoke-run-request.json +0 -34
  82. package/training/local-runner/src/train_dpo.py +0 -286
@@ -1,458 +0,0 @@
1
- # TT Local end-to-end workflow and UX review
2
-
3
- Date: 2026-07-13
4
- Reviewed release: `@tuned-tensor/local@0.2.7`
5
- Repository commit: `3b18464` (`main`)
6
- Scope: install, init, preflight, validation, base-model download, real fine-tuning,
7
- evaluation, reports, persisted state, recovery, dashboard, and the handoff to model
8
- inference.
9
-
10
- ## Executive summary
11
-
12
- The core training and persistence path works on the DGX Spark once two configuration
13
- workarounds are applied. A real SFT run completed, its PEFT adapter was loaded for
14
- candidate evaluation on CUDA, the model archive was valid, the local store was
15
- internally consistent, and the index could be rebuilt.
16
-
17
- The current first-run UX is not ready to be presented as a smooth default workflow.
18
- The most important blockers are:
19
-
20
- 1. Explicit prefetch and runtime model loading use different Hugging Face cache
21
- layouts, causing a duplicate multi-gigabyte download.
22
- 2. The public no-config quickstart and default evaluator do not select the bundled
23
- uv project, so `doctor` can pass immediately before `run` fails on `import torch`.
24
- 3. Resuming a run can silently reuse a model trained with old hyperparameters or
25
- old runner/evaluation configuration.
26
- 4. An empty model directory can be accepted, reported, and indexed as a completed
27
- model; there is no artifact manifest or verification command.
28
- 5. Subcommand help and unknown-option handling are unsafe: `tt-local run --help`
29
- starts a run.
30
- 6. There is no tested, documented inference-serving handoff for a TT Local adapter.
31
-
32
- These should be addressed before optimizing lower-level polish.
33
-
34
- ## What was tested
35
-
36
- ### Automated and packaged checks
37
-
38
- All existing checks passed:
39
-
40
- - `npm run typecheck`
41
- - `npm test`: 79 passed, 0 failed
42
- - Node test coverage: 91.71% lines, 81.19% branches, 89.39% functions
43
- - `npm pack --dry-run`: 75 files, 115.7 kB package
44
- - fresh-prefix installation of the packed `0.2.7` package
45
- - Python syntax compilation for all bundled runner scripts
46
- - relevant `tuned-tensor-cli` model-serving tests: 29 passed, 0 failed
47
-
48
- The high aggregate coverage does not cover the risky integration boundaries well:
49
-
50
- - `src/index.ts`: 34.97% lines
51
- - `src/doctor.ts`: 30.00% lines
52
- - `src/prefetch.ts`: 75.32% lines, 35.71% branches
53
- - no real Hugging Face download test
54
- - no subprocess-level CLI contract tests
55
- - no Python unit/integration tests
56
- - CI covers Ubuntu x64, not Linux ARM64/DGX Spark or CUDA
57
-
58
- ### Mac dry and command-backed checks
59
-
60
- A new project was initialized, validated, dry-run, listed, reported, served through
61
- the dashboard, and rebuilt from its canonical files. JSON, JSONL, SQLite, spec, run,
62
- event, report, and model records were inspected.
63
-
64
- Additional reproductions:
65
-
66
- - `doctor` returned nonzero on a dry-run/no-inference config only because the Mac
67
- lacks `nvidia-smi`.
68
- - `validate` printed a generated run ID, but the subsequent spec-based `run`
69
- generated a different ID.
70
- - a staged `prepare` invocation printed `"status": "completed"` while persisted
71
- state remained `preparing`.
72
- - changing `n_epochs` from 3 to 9 under the same run ID reused every stage and left
73
- the persisted training hyperparameters at 3.
74
- - a non-dry custom trainer that exited zero and wrote no files completed the run and
75
- registered an empty model directory.
76
- - `tt-local run --help` queued and began a real run path.
77
-
78
- ### DGX Spark real workflow
79
-
80
- Environment and result:
81
-
82
- - audit workspace: `/home/eve/tt-local-audit-20260713-XnkDGt`
83
- - run ID: `f9938d55-1c7d-40f1-9055-de8de5c57ddb`
84
- - model ID: `local-f9938d55-1c7d-40f1-9055-de8de5c57ddb`
85
- - resumed full workflow: 97.42 seconds
86
- - baseline: about 30.9 seconds
87
- - training stage: about 36.1 seconds; actual three-step trainer runtime 1.55 seconds
88
- - candidate evaluation: about 30.1 seconds
89
- - observed GPU memory: 3,760 MiB
90
- - peak RSS: about 4.79 GB
91
-
92
- Persistence checks:
93
-
94
- - model archive: 18,821,402 bytes
95
- - SHA-256: `ad5b329e89d35c271933c484924a056e4d76ad154823ff78df4e2597ab6404b4`
96
- - `gzip -t` passed
97
- - tar inspection passed
98
- - adapter safetensors/config, tokenizer, chat template, and README were present
99
- - the training-output tar and convenience copy had the same hash
100
- - artifact/store request and report copies matched
101
- - SQLite `integrity_check` returned `ok`
102
- - store contained 1 spec, 1 run, 38 events, and 1 model
103
- - `store rebuild-index`, `runs list/get/report/watch`, and `models list/get` passed
104
- - the dashboard health, run, report, model, and spec APIs returned HTTP 200
105
- - no audit process or server remains active
106
-
107
- The successful run required both of these workarounds:
108
-
109
- 1. point `paths.baseModel` directly at the existing cached snapshot;
110
- 2. set `evaluation.inference.project` to `training/local-runner`.
111
-
112
- ## Workflow review
113
-
114
- | Step | Result | UX assessment |
115
- |---|---|---|
116
- | Install package | Pass | Package contains the bundled scripts, but `tt-local --version` is unsupported and the package omits `uv.lock`. |
117
- | `init` | Pass | Creates a runnable three-epoch placeholder and no runner config; accidental placeholder training is possible. |
118
- | `doctor` | Misleading | Checks generic uv/Python and `nvidia-smi`, not the exact training/evaluator environments, Torch/CUDA, disk, cache, credentials, or writability. |
119
- | `validate` | Partial | Schema validation passes, but does not validate placeholder content or runtime prerequisites and prints an ephemeral run ID. |
120
- | `models prefetch` | Fail | Uses a cache layout different from training/evaluation and hides multi-GB progress unless `--verbose`. |
121
- | Baseline | Workaround required | Default evaluator misses the bundled uv project; configured cache is also applied too late in Python. |
122
- | Training | Pass with workaround | Real LoRA training and archive generation worked on Spark. |
123
- | Candidate evaluation | Pass with workaround | Proved that the saved adapter tar can be extracted and loaded with its base model on CUDA. |
124
- | Report and state | Pass with caveats | Reports and canonical copies persist, but stale errors and staged-state inconsistencies remain. |
125
- | Recovery | Pass with caveats | SQLite rebuild works when canonical records exist; a trained artifact is not indexed until the final report completes. |
126
- | Dashboard | Pass | `tt-local serve` is a state/report dashboard, not model inference. |
127
- | Model inference server | Missing | `tt-local models serve` does not exist, and the separate hosted CLI handoff is not tested for TT Local adapters. |
128
-
129
- ## Release-blocking findings
130
-
131
- ### TT-L-001: prefetch and runtime caches are inconsistent
132
-
133
- Severity: critical
134
-
135
- `prefetch.py` calls `snapshot_download(cache_dir=paths.modelCache)`, which stores a
136
- repository directly beneath that directory. Training treats the same value as
137
- `HF_HOME`, whose Hub cache is beneath `<modelCache>/hub`. Evaluation passes the
138
- cache in a JSON payload and changes `HF_HOME` only after importing Transformers and
139
- Hugging Face libraries, so their cached path constants do not change.
140
-
141
- Spark evidence:
142
-
143
- - existing complete cache:
144
- `/home/eve/.cache/huggingface/hub/models--Qwen--Qwen3.5-2B`
145
- - existing size: 4,571,197,824 bytes
146
- - prefetch began a second copy at:
147
- `/home/eve/.cache/huggingface/models--Qwen--Qwen3.5-2B`
148
- - stopped after 101.92 seconds and 291,373,218 bytes of duplicate growth
149
-
150
- Relevant code:
151
-
152
- - `training/local-runner/src/prefetch.py:54-67`
153
- - `src/process-training.ts:224-239`
154
- - `training/local-runner/src/evaluate.py:15-18,303-312`
155
- - `src/evaluation.ts:332-374`
156
-
157
- Required adjustment:
158
-
159
- - define one cache contract (`HF_HOME` or `HF_HUB_CACHE`) and use it identically in
160
- prefetch, training, baseline, candidate, and serving;
161
- - set environment variables before Python imports;
162
- - persist model revision/commit, snapshot path, file count, and byte count;
163
- - add fresh, cached, interrupted, corrupt, gated, unwritable, and low-disk tests.
164
-
165
- ### TT-L-002: the documented/default packaged run does not select its Python project
166
-
167
- Severity: critical
168
-
169
- The homepage advertises `tt-local doctor` followed by `tt-local run` without a
170
- config. Default config does not set the bundled uv project. The first Spark run and
171
- a clean packaged run launched the evaluator as `uv run python .../evaluate.py` and
172
- failed with `ModuleNotFoundError: No module named 'torch'`. `doctor` had passed.
173
-
174
- Relevant code and docs:
175
-
176
- - `src/contracts.ts:294-383`
177
- - `src/process-runner.ts:30-49`
178
- - `src/doctor.ts:43-109`
179
- - sibling web repo `tuned-tensor/src/app/page.tsx:24-30,174-187`
180
-
181
- Required adjustment:
182
-
183
- - make both bundled training and bundled evaluation default to the installed
184
- `training/local-runner` project;
185
- - make `doctor` resolve and execute the exact commands that `run` will use;
186
- - run imports for Torch, Transformers, PEFT, and Hugging Face Hub and assert CUDA
187
- availability/device details when CUDA was requested.
188
-
189
- ### TT-L-003: resume invalidation omits hyperparameters and effective config
190
-
191
- Severity: critical correctness
192
-
193
- The stage source fingerprint includes the spec snapshot and selected dataset/eval
194
- metadata, but not `request.hyperparameters` or most resolved training/evaluation
195
- configuration. Existing baseline, training, and candidate files are then reused by
196
- existence.
197
-
198
- Reproduction: change `n_epochs` from 3 to 9 and rerun the same run ID. The CLI
199
- reported reuse for prepare, baseline, training, and candidate; generated
200
- `hyperparameters.json` still contained 3.
201
-
202
- Relevant code:
203
-
204
- - `src/orchestrator.ts:157-174,397-433`
205
- - `src/orchestrator.ts:454-523,567-624`
206
-
207
- Required adjustment:
208
-
209
- - fingerprint the normalized full request, effective training config, effective
210
- evaluation/generation/scoring config, package/runtime version, model revision,
211
- dataset hashes, and parent artifact manifest;
212
- - record per-stage input fingerprints and explain reuse/invalidation in CLI output;
213
- - add a matrix of resume tests changing one input at a time.
214
-
215
- ### TT-L-004: model completion has no artifact validity contract
216
-
217
- Severity: critical correctness
218
-
219
- Training directories are created before the command runs. Any command that exits
220
- zero can therefore fall back to an empty `training/model` directory. Candidate
221
- evaluation with provider `none` or a permissive custom command does not prove the
222
- artifact is loadable, yet the run and model are marked completed.
223
-
224
- A non-dry `/usr/bin/true` trainer reproduced this: no model files were written, but
225
- the run completed and `models list` registered the empty directory. Dry runs also
226
- register empty simulated models.
227
-
228
- Relevant code:
229
-
230
- - `src/artifacts.ts:63-70`
231
- - `src/process-training.ts:265-305`
232
- - `src/orchestrator.ts:666-740`
233
- - `src/store.ts:605-642`
234
-
235
- Required adjustment:
236
-
237
- - validate expected PEFT/full-model files after training;
238
- - write an atomic `artifact-manifest.json` containing framework, format, base model
239
- and revision, files, sizes, and SHA-256 values;
240
- - add `tt-local models verify <id-or-path>`;
241
- - never register a dry-run model as real/servable;
242
- - reject empty/custom artifacts unless their declared artifact contract passes.
243
-
244
- ### TT-L-005: CLI option parsing can start unintended work
245
-
246
- Severity: critical UX/safety
247
-
248
- Only top-level help is recognized. Unknown options are silently discarded.
249
- Observed behavior:
250
-
251
- ```text
252
- tt-local --version -> Unknown command
253
- tt-local models prefetch --help -> attempts the command
254
- tt-local runs report --help -> looks up run "--help"
255
- tt-local run --help -> queues and starts a run
256
- ```
257
-
258
- A typo such as `--dryrun` can therefore start a real local job.
259
-
260
- Relevant code:
261
-
262
- - `src/index.ts:100-188,305-320,373-439`
263
-
264
- Required adjustment:
265
-
266
- - use a strict command parser with per-command help, `--version`, required-value
267
- validation, mutually exclusive options, and rejection of unknown flags;
268
- - add subprocess-level tests for every command before long-running work begins.
269
-
270
- ### TT-L-006: LLM-judge behavior can silently change metric semantics
271
-
272
- Severity: critical evaluation correctness
273
-
274
- The public real-run example sets `scoring.mode=llm_judge` and exports
275
- `OPENROUTER_API_KEY`, but omits the required `llm` block. The implementation then
276
- silently uses exact match. If `llm` exists but the key is initially absent, the
277
- exact-match baseline is not marked as fallback and may be cached; adding the key
278
- later can compare a cached exact-match baseline with a judge-scored candidate.
279
-
280
- Relevant code and docs:
281
-
282
- - `src/contracts.ts:350-390`
283
- - `src/evaluation.ts:552-582,592-725,775-873`
284
- - sibling web repo `tuned-tensor/src/app/docs/local-training/page.tsx:95-132`
285
-
286
- Required adjustment:
287
-
288
- - fail preflight when judge mode is requested but its model/config/key is absent,
289
- unless the user explicitly opts into fallback;
290
- - record all fallback scoring as fallback and never cache it as a judge baseline;
291
- - include judge availability in the cache key or invalidate on availability change;
292
- - make the documented example assert `judge_scored_count > 0`.
293
-
294
- ## High-priority gaps
295
-
296
- ### Artifact discovery is coupled to successful evaluation/reporting
297
-
298
- `training-report.json` is written after a successful trainer, but the model record is
299
- created only in `completeRun`, after candidate evaluation and report generation. If
300
- evaluation times out or the judge fails, the trained artifact remains on disk but is
301
- absent from `models list`; index rebuild cannot recover a model record that was never
302
- written.
303
-
304
- Register a verified artifact immediately after training. Track training success,
305
- evaluation success, and report success as separate states.
306
-
307
- ### `doctor` and `validate` do not preflight the real job
308
-
309
- Missing checks include:
310
-
311
- - exact installed training and evaluator commands;
312
- - Python imports and CUDA-enabled Torch;
313
- - requested device, GPU memory, and model fit;
314
- - cache/artifact/store writability and free disk headroom;
315
- - model reachability, revision, gated-model token, and partial cache state;
316
- - configured judge/model/key;
317
- - placeholder spec content and dataset readability/shape.
318
-
319
- GPU checks should be conditional: a dry run, CPU command backend, or MPS workflow
320
- should not fail solely because `nvidia-smi` is absent.
321
-
322
- ### No supported TT Local inference-serving endpoint
323
-
324
- `tt-local serve` is the dashboard. `tt-local models serve` is unknown. The separate
325
- `tt models serve` command was not installed on the Spark and has no real integration
326
- test against the exact TT Local adapter tar. Code review also shows a likely mismatch:
327
- TT Local nests archive files beneath `model/`, while the other CLI passes the archive
328
- extraction root directly and its reference runtime is not designed around an explicit
329
- base-model-plus-PEFT-adapter contract.
330
-
331
- Add `tt-local models serve <local-model-id>` or a fully tested documented bridge.
332
- Acceptance requires `/health`, `/v1/models`, and a real `/v1/chat/completions` request
333
- using the saved artifact and its recorded base revision.
334
-
335
- ### Cancellation does not cancel subprocess work
336
-
337
- `runs cancel` writes `cancel.requested` and changes metadata, but the orchestrator and
338
- process runner never read the marker or terminate the child. Work can continue and a
339
- later event can overwrite cancelled state. Cancellation must signal the process group,
340
- wait for exit, and preserve a terminal cancelled state.
341
-
342
- ### Staged commands leave nonterminal persisted state
343
-
344
- An individual stage prints `status: completed`, while the store remains in a running
345
- state such as `preparing` or `training`. `runs watch` only exits for completed, failed,
346
- or cancelled and can hang after a deliberately completed stage. Represent stage
347
- completion explicitly and make watch aware of the requested terminal stage.
348
-
349
- ### Successful resume preserves a stale failure
350
-
351
- The successful Spark resume is `completed`, but `runs get` and the dashboard still
352
- expose the earlier `ModuleNotFoundError` in the `error` field, including after index
353
- rebuild. Clear superseded errors when a run is retried and succeeds, while preserving
354
- them in attempt history/events.
355
-
356
- ### Force/retry can retain stale model-directory files
357
-
358
- Source refresh deletes report JSON files but not training model/output directories.
359
- Stale files can be included in a later archive. Use a new attempt directory or clear
360
- only the stage-owned directory before recomputation, then publish atomically.
361
-
362
- ## Medium-priority UX and documentation gaps
363
-
364
- - `info` does not show the installed version; `--version` is unsupported.
365
- - `init` creates placeholder training data that passes validation and defaults to
366
- three epochs, but creates no runner config.
367
- - `validate` prints an unpersisted run ID different from the eventual spec-based run.
368
- - prefetch progress is hidden by default and its help does not advertise `--verbose`.
369
- - prefetch attempts are not indexed or discoverable through a cache-status command.
370
- - `runs watch` is documented after a blocking foreground run, when it is no longer
371
- useful; document a second terminal, explicit run ID, or detached execution.
372
- - `paths.modelCache`, artifact paths, and store paths need one clear path-resolution
373
- rule; current relative paths resolve from process CWD rather than config location.
374
- - `HF_TOKEN` setup for gated models is not documented.
375
- - “Files and Store” omits the model directory, copied tar, store report copy, and
376
- `models/<id>/model.json`.
377
- - model tar is stored twice; deduplicate or document the durability reason.
378
- - weight-loading progress is mislabeled as training progress; the Spark run reported
379
- 0/320 to 320/320 shard loading before its real 3/3 training steps.
380
- - the default 120-second timeout covers uv startup, model loading/download, and the
381
- whole evaluation batch. A one-example warm-cache Spark evaluation took about 30s.
382
- - the published npm package omits `training/local-runner/uv.lock`, weakening runtime
383
- reproducibility and allowing dependency drift.
384
- - a store-recovered report can retain stale absolute artifact URIs after artifacts
385
- are moved or removed.
386
- - a successful resume updates artifact-side request data but may leave canonical
387
- store request/spec data stale.
388
-
389
- ## Recommended target workflow
390
-
391
- The ideal first-run path should be short, explicit, and self-verifying:
392
-
393
- ```bash
394
- tt-local --version
395
- tt-local init --name "Support Bot" --model Qwen/Qwen3.5-2B --profile spark
396
-
397
- # Edit tunedtensor.json, then:
398
- tt-local doctor tunedtensor.json --config local-runner.json
399
- tt-local models prefetch tunedtensor.json --config local-runner.json
400
- tt-local models verify-base tunedtensor.json --config local-runner.json
401
-
402
- tt-local run tunedtensor.json --config local-runner.json --detach
403
- tt-local runs watch <run-id> --config local-runner.json
404
- tt-local runs report <run-id> --config local-runner.json
405
- tt-local models verify local-<run-id> --config local-runner.json
406
-
407
- tt-local models serve local-<run-id> --spec tunedtensor.json
408
- ```
409
-
410
- Suggested behavior:
411
-
412
- - `init --profile spark` writes both a spec and a safe durable config.
413
- - `doctor` prints an effective-plan summary: exact commands, paths, device, model
414
- revision, cached/download bytes, disk headroom, eval count, scoring mode, and
415
- expected artifact contract.
416
- - prefetch shows byte progress by default and finishes with a verifiable snapshot
417
- manifest.
418
- - `run` emits/persists the run ID before any model work and supports detach/watch.
419
- - completed training makes a verified model discoverable even if evaluation fails.
420
- - final output includes copy-paste report, verify, and serve commands.
421
-
422
- ## Acceptance test plan
423
-
424
- 1. **Clean packaged quickstart:** install the tarball without global ML packages;
425
- init, doctor, prefetch, run, report, verify, and serve with no source checkout.
426
- 2. **Fresh and warm Spark paths:** Linux ARM64/CUDA with empty cache, then cached
427
- retry; assert no duplicate bytes and identical model revision.
428
- 3. **Download resilience:** interrupt/resume, corrupt snapshot, gated model without
429
- token, unwritable cache, insufficient disk, and visible progress.
430
- 4. **Resume correctness:** change each hyperparameter/config/input under one run ID;
431
- assert exactly the dependent stages are invalidated.
432
- 5. **Artifact contract:** empty output, partial adapter, corrupt tar, wrong base model,
433
- and checksum mismatch must fail before model registration.
434
- 6. **Failure after training:** force candidate/judge/report failure and assert the
435
- verified trained model remains listed and servable.
436
- 7. **Dry-run contract:** no real model record, no cache download, terminal dry-run
437
- status, and valid orchestration artifacts.
438
- 8. **Judge correctness:** documented config performs judge calls, records the judge
439
- model, never caches silent fallback, and reports fallback prominently.
440
- 9. **Serving handoff:** exact emitted tar plus recorded base revision passes health,
441
- model listing, and a real chat request.
442
- 10. **CLI contract:** help/version, unknown flags, missing values, JSON mode, exit
443
- codes, staged watch, cancellation, and detached lifecycle.
444
- 11. **Persistence/recovery:** process restart, SQLite rebuild, moved roots, missing or
445
- corrupt canonical files, and stale-error clearing on successful retry.
446
- 12. **Platform matrix:** Ubuntu x64, Linux ARM64, Mac dry run/MPS as supported, plus a
447
- periodic real DGX Spark CUDA job.
448
-
449
- ## Residual audit data
450
-
451
- The Spark audit intentionally did not delete generated data:
452
-
453
- - audit workspace: about 74.7 MB
454
- - interrupted duplicate prefetch data: about 291.2 MB
455
- - total audit-related disk growth: about 366.4 MB
456
-
457
- No existing project, run, or model was overwritten or deleted. Cleanup should be a
458
- separate deliberate action after the cache-location fix is understood.
@@ -1,2 +0,0 @@
1
- {"prompt":"Summarize status: build passed, one flaky test retried successfully.","chosen":"Build passed; one flaky test passed after retry.","rejected":"Everything is broken and the build failed."}
2
- {"prompt":"Reply to customer: refund was issued yesterday.","chosen":"Your refund was issued yesterday and should appear shortly.","rejected":"We cannot help with this request."}
@@ -1,34 +0,0 @@
1
- {
2
- "run_id": "44444444-4444-4444-8444-444444444444",
3
- "user_id": "local-user",
4
- "behavior_spec_id": "55555555-5555-4555-8555-555555555555",
5
- "run_number": 1,
6
- "training_method": "dpo",
7
- "spec_snapshot": {
8
- "name": "Local DPO Assistant",
9
- "description": "Tiny local DPO smoke request.",
10
- "system_prompt": "Answer concisely and accurately.",
11
- "guidelines": [
12
- "Prefer direct, factual replies."
13
- ],
14
- "constraints": [
15
- "Do not invent negative status."
16
- ],
17
- "base_model": "Qwen/Qwen3.5-2B",
18
- "examples": [
19
- {
20
- "input": "Summarize status: build passed, one flaky test retried successfully.",
21
- "output": "Build passed; one flaky test passed after retry."
22
- }
23
- ]
24
- },
25
- "hyperparameters": {
26
- "n_epochs": 1,
27
- "dpo_beta": 0.1,
28
- "save_adapter_only": true
29
- },
30
- "dataset_prebuilt": {
31
- "training": "file://examples/dpo-preferences.jsonl",
32
- "format": "preference_jsonl"
33
- }
34
- }
@@ -1,34 +0,0 @@
1
- {
2
- "run_id": "11111111-1111-4111-8111-111111111111",
3
- "user_id": "local-user",
4
- "behavior_spec_id": "22222222-2222-4222-8222-222222222222",
5
- "run_number": 1,
6
- "spec_snapshot": {
7
- "name": "Local Smoke Assistant",
8
- "description": "Tiny local runner smoke test.",
9
- "system_prompt": "Answer in a concise, literal style.",
10
- "guidelines": [
11
- "Prefer the expected label when the input is a label request."
12
- ],
13
- "constraints": [
14
- "Do not include extra commentary."
15
- ],
16
- "base_model": "Qwen/Qwen3.5-2B",
17
- "examples": [
18
- {
19
- "input": "Classify sentiment: I love this product.",
20
- "output": "positive"
21
- },
22
- {
23
- "input": "Classify sentiment: This was disappointing.",
24
- "output": "negative"
25
- }
26
- ]
27
- },
28
- "hyperparameters": {
29
- "n_epochs": 1,
30
- "augment": false,
31
- "use_llm_judge": false,
32
- "save_adapter_only": true
33
- }
34
- }