diff --git a/controller/app/build.gradle b/controller/app/build.gradle
index ad18a922..ba1c7736 100644
--- a/controller/app/build.gradle
+++ b/controller/app/build.gradle
@@ -706,6 +706,10 @@ preBuild.dependsOn refreshMapsSizes
// tools/build_kiwix_catalog.py. Unlike the size tasks above it does NOT run on every build
// (the listings are large and the servers throttle bots) — it runs automatically only when
// assembling a RELEASE, and can be invoked manually any time: ./gradlew refreshKiwixCatalog.
+// ADFA-5094: unlike Kolibri, Kiwix is NOT yet pulled from Cloudflare on-device (KiwixCatalog is
+// not overlay-aware — that is Kiwix's phase 2), so release regeneration stays here as its only
+// on-device freshness path until the runtime pull ships. The weekly workflow already publishes
+// the Kiwix catalog to Cloudflare so phase 2 has something to consume.
// Never fails the build: if python3 is missing or the fetch is blocked, the committed CSV
// (last known) is kept.
task refreshKiwixCatalog {
@@ -726,16 +730,18 @@ tasks.matching { it.name == 'assembleRelease' || it.name == 'bundleRelease' }.co
dependsOn refreshKiwixCatalog
}
-// ---- Kolibri channel catalog refresh (release-only) ---------------------------
+// ---- Kolibri channel catalog refresh (manual only) ----------------------------
// Regenerates src/main/assets/kolibri_catalog.jsonl from Kolibri Studio's public API via
// tools/build_kolibri_catalog.py. Bundled rather than fetched on-device because Studio's
// channel endpoint is 97% base64 thumbnails with no way to opt out — 4.1 MB to use 119 KB
-// (ADR-4954 D1). Release-only, like the Kiwix catalog above, and never fails the build:
-// on any error the committed JSONL (last known) is kept.
-// Manual run: ./gradlew refreshKolibriCatalog
+// (ADR-4954 D1). ADFA-5094: this no longer runs on release builds — the weekly publish-catalogs
+// workflow generates the catalog off-device (Studio hit once a week, not per build) and the app
+// pulls it from Cloudflare at runtime. The bundled JSONL is the offline floor; run this by hand
+// only when you want to refresh that floor: ./gradlew refreshKolibriCatalog. Never fails the
+// build: on any error the committed JSONL (last known) is kept.
task refreshKolibriCatalog {
group = 'build setup'
- description = 'Regenerate assets/kolibri_catalog.jsonl from Kolibri Studio (release / manual)'
+ description = 'Regenerate assets/kolibri_catalog.jsonl from Kolibri Studio (manual)'
doLast {
try {
def proc = ['python3', 'tools/build_kolibri_catalog.py'].execute(null, projectDir)
@@ -747,6 +753,3 @@ task refreshKolibriCatalog {
}
}
}
-tasks.matching { it.name == 'assembleRelease' || it.name == 'bundleRelease' }.configureEach {
- dependsOn refreshKolibriCatalog
-}
diff --git a/controller/docs/operation-model-roadmap.svg b/controller/docs/operation-model-roadmap.svg
index 649f80ec..8988cf1e 100644
--- a/controller/docs/operation-model-roadmap.svg
+++ b/controller/docs/operation-model-roadmap.svg
@@ -286,21 +286,21 @@
BLOCKED on a decision: proot alive, services down — kill it,
or start the services without touching it?
-
-
-
-SPLIT OUT
-ADFA-5094 · Kolibri topic display
-Narrowing a channel should not depend on
-reaching Studio over the internet.
-
-Task map learns the metadata-only import
-
-The box serves the tree it imported
-
-The picker prefers the box, falls back
+
+
+
+ADFA-5094 · DONE
+Kolibri topics — offline + fresh
+Narrowing a channel no longer needs
+Studio; the catalog refreshes weekly.
+
+Metadata-only import on device
+
+The box serves the imported tree
+
+Picker prefers the box; weekly pull
-
+
NOT NOW
@@ -348,7 +348,7 @@
ledger row deleted rather than fixed.
A derivable fact is removed, not maintained.
-
+
NO TICKET YET