Skip to content

Commit e5df034

Browse files
committed
feat(getter): use provider-backed update checks
1 parent 0bb0c77 commit e5df034

6 files changed

Lines changed: 26 additions & 14 deletions

File tree

CONTEXT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ A getter-owned notification boundary used by native/Flutter UI to learn that run
112112

113113
### Provider host API
114114

115-
A getter-owned API exposed to package Lua for requesting provider/source data. Lua packages should call getter host APIs rather than using any Lua-native network library or Flutter/Kotlin HTTP path. Getter-shipped standard provider modules use provider-specific host functions under `getter.provider.*`, such as `getter.provider.fdroid.update_candidates(...)` and `getter.provider.github.release_candidates(...)`, so Rust owns provider parsing, cache consistency, diagnostics, and candidate normalization. Generic/custom HTTP remains exposed as a getter-managed host function such as `http_get(url, { headers = ..., cache = true|false })`; `cache` defaults to `false`, and Lua actively opts a generic request into HTTP/source caching with `cache = true`. Getter owns execution, cache key construction, persistence, revalidation, stale diagnostics, permissions, secret redaction, and output validation. For package scripts without `allow_free_network`, provider host calls must not bypass package `Manifest`: refreshed source response bodies must match Manifest SHA-512 entries, and parsed provider cache hits are usable only when their provider cache provenance records source response digest(s) and a compatible provenance schema proving Manifest compatibility. Getter-shipped provider modules such as `luaclass.fdroid_android` and `luaclass.github_android_apk` are built-in fallback modules over this host API, not independent provider implementations. The provider executor behind the host API can be fake during early runtime development and live later.
115+
A getter-owned API exposed to package Lua for requesting provider/source data. Lua packages should call getter host APIs rather than using any Lua-native network library or Flutter/Kotlin HTTP path. Getter-shipped standard provider modules use provider-specific host functions under `getter.provider.*`, such as `getter.provider.fdroid.update_candidates(...)` and `getter.provider.github.release_candidates(...)`, so Rust owns provider parsing, cache consistency, diagnostics, and candidate normalization. Generic/custom HTTP remains exposed as a getter-managed host function such as `http_get(url, { headers = ..., cache = true|false })`; `cache` defaults to `false`, and Lua actively opts a generic request into HTTP/source caching with `cache = true`. Getter owns execution, cache key construction, persistence, revalidation, stale diagnostics, permissions, secret redaction, and output validation. For package scripts without `allow_free_network`, provider host calls must not bypass package `Manifest`: refreshed source response bodies must match Manifest SHA-512 entries, and parsed provider cache hits are usable only when their provider cache provenance records source response digest(s) and a compatible provenance schema proving Manifest compatibility. Getter-shipped provider modules such as `luaclass.fdroid_android` and `luaclass.github_android_apk` are built-in fallback modules over this host API, not independent provider implementations. Plain read-model package evaluation does not install this host API, but the product runtime update-check operation does: `update_check_package_issue_action` installs the stable provider host and runtime hooks, evaluates package Lua, then compares normalized candidates and issues getter-owned opaque actions. The bridge request remains package/update oriented (`package_id`, optional `repository_id`, `installed_version`, and `pin_version`); provider fixture bodies, cache mode, endpoint URLs, and live transport controls are not Flutter/native payload fields. Until live provider transport is accepted and implemented, runtime update-check provider calls use existing provider cache rows and fail on cache miss or Manifest-incompatible provenance. The provider executor behind the host API can be fake during early runtime development and live later.
116116

117117
### Provider cache provenance
118118

PLAN/provider-host-api-v1.md

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# PLAN: Stable Lua provider host API v1
22

3-
> Status: implementation plan with stable host, provenance, and provider module promotion slices validated; generated-output migration pending
3+
> Status: stable host, provenance, provider module promotion, and cache-backed product runtime update-check slices validated; generated-output migration pending
44
> Scope: ADR-0012 provider-host API design for F-Droid and GitHub standard Lua modules
5-
> Current boundary: provider modules are promoted to built-in fallbacks; generated F-Droid output has not yet been migrated to require them
5+
> Current boundary: provider modules are promoted to built-in fallbacks, and `update_check_package_issue_action` can evaluate provider-backed packages against Manifest-compatible provider cache entries; generated F-Droid output has not yet been migrated to require them
66
77
## Progress
88

@@ -15,7 +15,8 @@
1515
- [x] Implement and validate Slice 2 provider cache provenance storage and Manifest-compatible cache hits.
1616
- [x] Implement and validate Slice 4 standard provider module promotion tests.
1717
- [x] Add pre-adoption regression coverage locking generated F-Droid output as self-contained/plain-evaluable.
18-
- [ ] Next slice: product provider-backed package evaluation/update-check operation before generated F-Droid provider-module adoption.
18+
- [x] Add product provider-backed package evaluation/update-check operation before generated F-Droid provider-module adoption.
19+
- [ ] Next slice: generated F-Droid provider-module adoption, keeping generated packages usable through the provider-backed update-check path.
1920

2021
## Current evidence and constraints
2122

@@ -26,6 +27,8 @@
2627
- Runtime hooks live under `<data-dir>/rc/hook/*.lua`, load after host functions are installed in the current operation harness, and call originals through `getter_builtin.*`.
2728
- Package `Manifest` constrains external network/dynamic response bodies for scripts without `allow_free_network`; missing `Manifest` means an empty allow-list. Hooks and cache must not bypass this.
2829
- Current provider-named modules `luaclass.fdroid_android` and `luaclass.github_android_apk` are always-on getter-shipped built-in fallback modules that call operation-installed `getter.provider.*` host functions. Plain package evaluation still does not install provider APIs and fails with a stable host-unavailable error if a package calls a provider module there.
30+
- Product runtime update checks deliberately install the stable provider host and runtime hooks before package evaluation. The bridge request shape remains narrow (`package_id`, optional `repository_id`, `installed_version`, and `pin_version`); provider fixture bodies, cache mode, endpoint URLs, and live transport controls are not Flutter/native request fields in this slice.
31+
- Until live provider transport is accepted and implemented, the product runtime path is cache-backed: provider-backed packages can use existing provider cache rows only when Manifest-compatible provenance permits them, while cache miss/refresh remains a later provider operation concern.
2932
- Repository-local `luaclass/` modules must continue to override getter-shipped built-ins; cross-repository `luaclass` lookup stays unsupported.
3033

3134
## Design goals
@@ -340,7 +343,7 @@ The operation evaluating package Lua decides the cache mode:
340343
- normal update/read: use cached provider facts when valid, refresh on cache miss or stale according to provider policy;
341344
- forced refresh: bypass cached reads for the requested provider/package scope, replace cache on success, and use stale cache only with explicit diagnostics on refresh failure.
342345

343-
Lua package authors do not pass `mode = "force_refresh"` to stable provider host functions.
346+
Lua package authors do not pass `mode = "force_refresh"` to stable provider host functions. The first product runtime slice keeps `update_check_package_issue_action` in normal cache-backed mode only and does not add provider fixture/cache-mode fields to the Flutter/native bridge payload. Live refresh and user-triggered force-refresh semantics remain separate provider-operation work.
344347

345348
### Provider cache contents
346349

@@ -467,11 +470,18 @@ Done in the implementation branch:
467470
- Plain package evaluation resolves the built-in provider modules, but calling them without operation-installed provider host functions fails with a stable host-unavailable diagnostic.
468471
- Provider modules are always-on built-in fallback modules; `getter_dev.*` remains only a private compatibility shim in operation tests.
469472

470-
### Slice 5: docs and generated output migration
473+
### Slice 5: product runtime adoption and generated output migration
474+
475+
Done in the implementation branch:
476+
477+
- Updated ADR-0012, `CONTEXT.md`, and this plan with stable provider module/product runtime status.
478+
- Added pre-adoption regression coverage that generated F-Droid output remains self-contained, does not require `luaclass.fdroid_android`, and does not call `getter.provider.*` while normal package evaluation remains plain.
479+
- Added a product-facing provider-backed package evaluation/update-check operation by routing only `update_check_package_issue_action` through the stable provider host; read-model `package_eval` remains plain.
480+
- Kept the Flutter/native bridge request shape narrow: no provider fixture body, cache mode, endpoint URL, or live transport fields are added to the product payload.
481+
- Added runtime tests proving static packages still work, F-Droid/GitHub provider modules work from Manifest-compatible provider cache entries, Manifest-incompatible cache fails closed, and no-update checks do not issue actions.
482+
483+
Still pending:
471484

472-
- Update ADR-0012, ADR-0005, `docs/lua-api/permissions.md`, `docs/lua-api/repository-layout.md`, and `CONTEXT.md` with stable provider module status.
473-
- Add pre-adoption regression coverage that generated F-Droid output remains self-contained, does not require `luaclass.fdroid_android`, and does not call `getter.provider.*` while normal package evaluation remains plain.
474-
- Before changing generated output, add a product-facing provider-backed package evaluation/update-check operation (not the fixture/dev-hidden harness) and route only intended update-check callers through it.
475485
- Update generated F-Droid output to use `luaclass.fdroid_android` only after the product provider-backed operation exists and tests prove generated packages remain usable through that operation.
476486
- Add generator tests proving generated output does not depend on `getter_dev.*` or repository-local copied modules.
477487

core-getter/src/main/rust/api_proxy/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,9 @@ fn runtime_operation_with_runtime(
497497
)
498498
})?;
499499
let db = open_main_db(data_dir)?;
500-
runtime_operations::issue_action_from_registered_package_json(runtime, &db, &payload)
500+
runtime_operations::issue_action_from_registered_package_json(
501+
runtime, data_dir, &db, &payload,
502+
)
501503
}
502504
"task_submit" => runtime_operations::submit_action_json(runtime, &payload),
503505
"task_get" => runtime_operations::task_get_json(runtime, &payload),

docs/architecture/adr/0007-flutter-getter-bridge-contract.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Internally, Rust/native bridge code scans Android inventory through the platform
6060

6161
`loadSnapshot()` composes smaller getter-owned read-model operations into the UI shell's first snapshot DTO. In the Android/native product path, `MethodChannelGetterAdapter` calls `readOperation` for `repository_list`, `tracked_package_list`, and `package_eval`; Rust getter reads SQLite repository/tracked-package state and evaluates registered Lua packages. Flutter may parse and combine those returned DTOs for rendering, but must not perform repository resolution, Lua validation/evaluation, version comparison, migration mapping, or update selection in Dart. `readMigrationReports()` must go through a getter operation such as `legacy report-list`; Flutter must not inspect getter's data-directory layout directly. Runtime task rendering must use ADR-0011 runtime task snapshot APIs and opaque action/task controls; Flutter must not synthesize task states, retry policy, installer behavior, or update decisions.
6262

63-
The first product click-through update flow is: App detail calls a typed getter update-check operation, receives a getter-issued `action_id`, submits only that `action_id` to the process-lifetime runtime, and opens Downloads to query authoritative task snapshots. Flutter may refresh the Downloads page after `RuntimeNotification.task_changed`, but the notification is only a trigger; `task_list`/equivalent runtime queries remain the source of truth.
63+
The first product click-through update flow is: App detail calls a typed getter update-check operation, receives a getter-issued `action_id`, submits only that `action_id` to the process-lifetime runtime, and opens Downloads to query authoritative task snapshots. The update-check operation may evaluate package Lua through the stable provider host for provider-backed packages, but provider/cache/Manifest logic stays in getter and the Flutter/native request remains package/update oriented: `package_id`, optional `repository_id`, `installed_version`, and `pin_version`. Flutter must not pass provider fixture bodies, cache-mode controls, endpoint URLs, raw provider payloads, or action/download details as product update-check input. Until live provider transport is accepted, provider-backed runtime checks use Manifest-compatible provider cache entries produced by getter provider operations. Flutter may refresh the Downloads page after `RuntimeNotification.task_changed`, but the notification is only a trigger; `task_list`/equivalent runtime queries remain the source of truth.
6464

6565
## Flutter DTOs
6666

docs/architecture/adr/0012-getter-owned-provider-modules-and-autogen-refresh.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Package version Lua resolves `require("luaclass.<name>")` in this order:
8787

8888
Repository-local modules deliberately win over getter-shipped modules. This gives trusted repositories and `local` overlays a normal source-level override path while keeping generated repositories boring: generated package directories do not need to copy shared standard modules, and `.autogen.jsonc` remains package-local ownership proof rather than a repository-root ownership system. Built-in modules are part of the getter binary/source distribution and are not repository source files; repository trust/signing still applies only to repository-provided files. Cross-repository module lookup is not accepted in this slice because it would make package behavior depend on unrelated repository priority and trust boundaries.
8989

90-
Implementation status: getter ships `luaclass.android`, `luaclass.fdroid_android`, and `luaclass.github_android_apk` as built-in fallback modules. The provider-named modules call the stable `getter.provider.*` host namespace and require a provider-backed operation to install those host functions; plain package evaluation does not install them and fails with a stable host-unavailable error if a package calls a provider module there. Generated F-Droid output does not depend on provider modules yet; switching generated output to `luaclass.fdroid_android` remains a later generator migration after this stable host/module behavior is validated.
90+
Implementation status: getter ships `luaclass.android`, `luaclass.fdroid_android`, and `luaclass.github_android_apk` as built-in fallback modules. The provider-named modules call the stable `getter.provider.*` host namespace and require a provider-backed operation to install those host functions; plain package evaluation does not install them and fails with a stable host-unavailable error if a package calls a provider module there. The product runtime update-check operation `update_check_package_issue_action` installs the stable provider host and runtime hooks, then evaluates package Lua before update selection, so provider-backed packages can issue normal getter-owned update actions from Manifest-compatible provider cache entries. The Flutter/native payload remains package/update oriented (`package_id`, optional `repository_id`, `installed_version`, and `pin_version`); provider fixture bodies, cache mode, endpoint URLs, and live transport controls are not bridge request fields in this slice. Generated F-Droid output does not depend on provider modules yet; switching generated output to `luaclass.fdroid_android` remains a later generator migration after this stable host/module behavior is validated.
9191

9292
### Stable provider host API v1 direction
9393

@@ -108,7 +108,7 @@ Candidate-returning provider functions return an envelope containing non-empty `
108108

109109
The GitHub `latest_commit` host shape is reserved because latest-commit checks are live/floating behavior. The default GitHub release/APK helper must not install or call it by default, and latest-commit results must not be silently treated as ordinary release candidates. A later explicit live operation/helper may install and use it after live-version UI/CLI semantics are implemented.
110110

111-
Provider functions must not bypass Manifest policy. For package scripts without `allow_free_network`, every external response body used to produce provider facts must match a package `Manifest` SHA-512 entry. Parsed provider cache hits are usable for non-free scripts only when cache provenance records the source response digest(s) and proves Manifest compatibility; missing provenance must fail closed or refetch/revalidate. The initial fixture-backed provenance slice stores source response SHA-512 digest(s), a provenance schema version, and freshness metadata placeholders with parsed provider cache entries so Manifest-compatible cache hits can be accepted while legacy/missing-provenance rows still fail closed.
111+
Provider functions must not bypass Manifest policy. For package scripts without `allow_free_network`, every external response body used to produce provider facts must match a package `Manifest` SHA-512 entry. Parsed provider cache hits are usable for non-free scripts only when cache provenance records the source response digest(s) and proves Manifest compatibility; missing provenance must fail closed or refetch/revalidate. The initial fixture-backed provenance slice stores source response SHA-512 digest(s), a provenance schema version, and freshness metadata placeholders with parsed provider cache entries so Manifest-compatible cache hits can be accepted while legacy/missing-provenance rows still fail closed. Until live provider transport is accepted and implemented, the product runtime update-check path is cache-backed: provider refresh/cache population remains the responsibility of provider operations rather than Flutter/Kotlin or the runtime update-check bridge payload.
112112

113113
### F-Droid reusable module
114114

0 commit comments

Comments
 (0)