diff --git a/scripts/render_audit.py b/scripts/render_audit.py index e24a6ea..14bb781 100644 --- a/scripts/render_audit.py +++ b/scripts/render_audit.py @@ -206,6 +206,7 @@ .meter .seg.a { background: var(--meter-a); } .meter .seg.b { background: var(--meter-b); } .meter.mini { height: 8px; max-width: 340px; margin: 6px 0 2px; border-radius: 4px; } +tr.row-migrated td { background: var(--ok-bg); } /* bar list — one measure, single hue, labeled rows */ .barlist { display: grid; grid-template-columns: max-content 1fr max-content; gap: 6px 12px; align-items: center; margin: 14px 0; } .barlist .lbl { font-size: 13px; } @@ -487,29 +488,53 @@ def render_index(audit: dict) -> str: def dataset_status(fname: str, migration: dict) -> tuple[str, str]: - """→ (status, pilot) for any static dataset the audit sees.""" + """→ (status, pilot) for any static dataset the audit sees. A record still + at lifecycle `pending` reads as `queued` — same reader-facing meaning as a + file named in a pending wave.""" rec = (migration.get("datasets") or {}).get(fname) if rec: - return rec.get("status", "pending"), rec.get("pilot", "") + status = rec.get("status", "pending") + return ("queued" if status == "pending" else status), rec.get("pilot", "") for wave in migration.get("pending") or []: if fname in (wave.get("datasets") or []): return "queued", wave.get("pilot", "") return "unscheduled", "" +STATUS_RANK = {"unscheduled": 0, "pending": 1, "queued": 1, "landed": 2, + "repointed": 3, "final": 3} + + def series_manifest(audit: dict) -> str: - """Every static dataset, grouped by the lecture series that owns the bytes - today, with its migration status — the how-far-along view.""" + """Every static dataset with its migration status, grouped by the lecture + series it belongs to — migrated files stay in the series they came FROM + (green rows at the bottom of each group), so each group reads as that + series' progress. A MIGRATED file consumed by two series appears in both + groups; before migration a file has one home — the repo owning the bytes.""" migration = audit["migration"] or {} + manifests = audit["manifests"] groups: dict[str, list] = {} + shared: dict[str, list] = {} for d in audit["datasets"]: - groups.setdefault(repo_of_record(d), []).append(d) + home = repo_of_record(d) + if home == "data-lectures": + # migrated — list it where it was: under each series whose + # lectures consume it (the manifest's consumers) + homes = sorted({c["repo"].split("/")[-1] + for c in manifests.get(d["file"], {}).get("consumers", [])}) \ + or [d["refs"][0]["repo"]] + shared[d["file"]] = homes + for h in homes: + groups.setdefault(h, []).append(d) + else: + groups.setdefault(home, []).append(d) order = ["lecture-python-intro", "lecture-python-programming", - "lecture-python.myst", "lecture-python-advanced.myst", - "data-lectures"] + "lecture-python.myst", "lecture-python-advanced.myst"] rows = "" for repo in [r for r in order if r in groups] + sorted(set(groups) - set(order)): - ds = sorted(groups[repo], key=lambda x: x["file"]) + ds = sorted(groups[repo], + key=lambda x: (STATUS_RANK.get( + dataset_status(x["file"], migration)[0], 0), x["file"])) statuses = [dataset_status(d["file"], migration)[0] for d in ds] n = len(ds) n_done = sum(1 for s in statuses if s in ("repointed", "final")) @@ -529,25 +554,41 @@ def series_manifest(audit: dict) -> str: rows += (f'
Every static file the lectures read today, grouped by the series that owns the -bytes, with its migration status — the how-far-along view. Not scheduled means no -milestone has claimed the file yet; the broad sweep (see the milestones below) eventually -covers them all. Data written by the lectures themselves and live-API reads are not migration -targets and are tracked on the audit page.
+Every static file the lectures read, grouped by the lecture series it belongs +to. Migrated files stay listed in the series they came from — the green rows at the bottom of +each group — so each group reads as that series' progress. A migrated file consumed by two +series appears in both groups (marked shared); the tiles above count distinct files. +Not scheduled means no milestone has claimed the file yet; the broad sweep (see the +milestones below) eventually covers them all. Data written by the lectures themselves and +live-API reads are not migration targets and are tracked on the +audit page.
| File | Contents | Hosting today | Status |
|---|