make_model_release: --title (the model's title in the entry and the notes; default the file's general.name, as before), and case A with --write needs --min-engine instead of leaving [FILL: minimum engine version] in the entry

This commit is contained in:
Niko1221 committed 2026-11-10 00:02:16 +01:00
1 parent b2f2684035
commit 078b525636
2 files changed
+16 -6

No files matched your search

+6 -3
View File
@@ -231,7 +231,7 @@ def model_entry(s: dict, a) -> dict:
ctx = (geo.get("keys") or {}).get("context_length")
return {
"_status": "DRAFT: made from the intake report by packaging/make_model_release.py; field names follow the Q4-PREP-B brief and are to be checked against strata_control/feed.py",
"id": a.id, "title": g.get("name") or d.get("title"), "by": d.get("by"),
"id": a.id, "title": a.title or g.get("name") or d.get("title"), "by": d.get("by"),
"licence": {"name": g.get("license"), "url": g.get("license.link") or "[FILL: licence URL]"},
"family": entry_family(s, a), "hf": {"repo": a.hf_repo or "[FILL: repository]", "revision": a.revision or "[FILL: pinned commit]"},
"files": [{"name": f["name"], "size": f["size"], "sha256": f.get("sha256")} for f in s["files"]],
@@ -257,7 +257,7 @@ def feed_entry(s: dict, a) -> dict:
files.append(item)
first = s["files"][0]["name"]
quant = a.quant or a.hf_dir or (first.rsplit("/", 1)[0] if "/" in first else "[FILL: quant name]")
e = {"id": a.id, "title": g.get("name") or d.get("title") or a.id, "by": a.by or d.get("by") or "[FILL: who made the model]",
e = {"id": a.id, "title": a.title or g.get("name") or d.get("title") or a.id, "by": a.by or d.get("by") or "[FILL: who made the model]",
"about": a.about or "[FILL: one plain sentence]",
"licence": a.licence or g.get("license") or "[FILL: licence]",
"licence_url": a.licence_url or g.get("license.link") or "[FILL: https licence url]",
@@ -315,7 +315,7 @@ def template_values(s: dict, p: dict, a) -> dict:
g = s.get("general", {})
rows = "\n".join("| %s | %s | %s |" % (f["name"], ("%.1f GB" % (f["size"] / 1e9)), (f.get("sha256") or "[FILL: sha256]")[:16] + ("..." if f.get("sha256") else ""))
for f in s["files"])
return {"model_title": g.get("name") or s["files"][0]["name"], "app_version": a.app_version, "engine_version": a.engine_version or "[FILL: engine version]",
return {"model_title": a.title or g.get("name") or s["files"][0]["name"], "app_version": a.app_version, "engine_version": a.engine_version or "[FILL: engine version]",
"sequence": a.sequence, "case": p["case"], "file_rows": rows, "total_gb": "%.1f" % (s["size_bytes"] / 1e9),
"n_files": len(s["files"]), "licence": g.get("license") or "[FILL: licence]", "licence_url": g.get("license.link") or "[FILL: licence URL]",
"family": s.get("architecture"), "repo": a.hf_repo or "[FILL: repository]", "revision": a.revision or "[FILL: pinned commit]",
@@ -339,6 +339,7 @@ def main(argv=None) -> int:
ap.add_argument("--hf-repo")
ap.add_argument("--hf-dir")
ap.add_argument("--default-context", type=int)
ap.add_argument("--title", help="the model's title in the feed entry and the notes (default: the file's general.name, e.g. 'Qwen3.8-Flash-Next GSQ-RCO')")
ap.add_argument("--by", help="the feed entry's `by` (who made the model)")
ap.add_argument("--about", help="the feed entry's one plain sentence")
ap.add_argument("--licence", help="the licence name (default: the file's general.license)")
@@ -369,6 +370,8 @@ def main(argv=None) -> int:
raise SystemExit("case B: give --shape, the name of the geometry the engines are compiled for (like q4_lite: lower case, digits and _); that engine ships as its own component")
elif a.shape:
raise SystemExit("--shape is for case B (a model of a new shape); case A runs on the engines as they are")
if case == "A" and a.write and not a.min_engine:
raise SystemExit("case A: give --min-engine, the first engine version that runs the model (the entry needs it, and build-feed refuses an entry that still says [FILL])")
prev = scan_upload(a.prev_upload)
if a.prev_upload is None:
print("note: no --prev-upload, so sizes of the files that stay or get rebuilt are unknown", file=sys.stderr)
+10 -3
View File
@@ -173,12 +173,16 @@ class Plan(unittest.TestCase):
(t / "RELEASE-NOTES.md").write_text("# {{model_title}} {{app_version}}\n{{file_rows}}\n[FILL: a number] {{unknown}}\n", encoding="utf-8")
out = Path(self.tmp.name) / "out"
code, _, err = run(self.base(self.a, "--write", str(out), "--templates", str(t), "--revision", "abc"))
self.assertNotEqual(code, 0, "case A with --write needs --min-engine (Q4-READY: it left a [FILL] in the entry)")
self.assertIn("--min-engine", err)
self.assertFalse(out.exists())
code, _, err = run(self.base(self.a, "--write", str(out), "--templates", str(t), "--revision", "abc", "--min-engine", "0.1.58"))
self.assertEqual(code, 0, err)
entry = json.loads((out / "models" / "m1.model.json").read_text())
self.assertIn("DRAFT", entry["_status"])
self.assertEqual(entry["files"][0]["name"], "Qwen3.6-35B-A3B-UD-Q4_K_XL.gguf")
self.assertEqual(entry["drafter"], "mtp")
self.assertEqual(entry["min_engine"], "[FILL: minimum engine version]")
self.assertEqual(entry["min_engine"], "0.1.58")
notes = (out / "RELEASE-NOTES.md").read_text()
self.assertIn("# Qwen3.6-35B-A3B 0.2.12", notes)
self.assertIn("[FILL: a number]", notes)
@@ -192,7 +196,7 @@ class Plan(unittest.TestCase):
from strata_control import feed as feedmod
out = Path(self.tmp.name) / "outfeed"
rev = "a" * 40
code, _, err = run(self.base(self.a, "--write", str(out), "--revision", rev, "--hf-repo", "x/y", "--default-context", "131072"))
code, _, err = run(self.base(self.a, "--write", str(out), "--revision", rev, "--hf-repo", "x/y", "--default-context", "131072", "--min-engine", "0.1.58"))
self.assertEqual(code, 0, err)
path = out / "models" / "m1.entry.json"
entry = json.loads(path.read_text())
@@ -202,9 +206,12 @@ class Plan(unittest.TestCase):
self.assertIn("FILL", str(cm.exception))
out2 = Path(self.tmp.name) / "outfeed2"
code, _, err = run(self.base(self.a, "--write", str(out2), "--revision", rev, "--hf-repo", "x/y", "--default-context", "131072", "--about", "one sentence",
"--licence", "Apache 2.0", "--licence-url", "https://example.org/licence", "--quant", "Q4", "--quant-about", "4-bit", "--ram-gb", "24", "--min-engine", "0.1.58"))
"--licence", "Apache 2.0", "--licence-url", "https://example.org/licence", "--quant", "Q4", "--quant-about", "4-bit", "--ram-gb", "24", "--min-engine", "0.1.58",
"--title", "Qwen4 Test"))
self.assertEqual(code, 0, err)
filled = json.loads((out2 / "models" / "m1.entry.json").read_text())
self.assertEqual(filled["title"], "Qwen4 Test") # --title (Q4-READY); without it the file's general.name, as before
self.assertEqual(json.loads((out / "models" / "m1.entry.json").read_text())["title"], "Qwen3.6-35B-A3B")
self.assertNotIn("[FILL", json.dumps(filled).replace("[FILL: sha256]", ""))
for f in filled["quants"][0]["files"]:
f["sha256"] = f["sha256"] if len(f["sha256"]) == 64 else "0" * 64