Skip to content

V2 - #1

Merged
Arenukvern merged 72 commits into
mainfrom
v2
Sep 8, 2026
Merged

V2#1
Arenukvern merged 72 commits into
mainfrom
v2

Conversation

@Arenukvern

Copy link
Copy Markdown
Owner

No description provided.

- Added full plugin packaging capabilities, including Java/Kotlin source compilation and dependency resolution.
- Introduced multi-dex handling with support for multiple DEX files in APKs.
- Updated version to 0.1.6 and modified build command to package all plugins by default.
- Enhanced dependency cache to handle AndroidX multiplatform artifacts and improved error handling.
- Added tests for multi-dex packaging and dependency resolution.
Opt-in resolution pass for the dry-run: composes the plugin dependency plan
from declared inputs (gradle-parsed + conditionally deduplicated roots,
pipeline.extra_deps, flutter-embedding set) and resolves it through the same
DependencyCache the build uses.

- extract PluginPackager.collectDeclaredDeps so packaging and the plan share
  one collector (no parser drift)
- MavenResolver.resolveWithTransitives gains onFailure: per-artifact failure
  isolation stays, but failures become observable (were verbose-only)
- cache-only by default (offline-safe; misses are non-fatal warnings);
  --network opts into full resolution where hard failures exit 1
- typed DependencyPlanReport (entries/resolved/findings), no new YAML keys
- ADR-0008 + docs (index, build guide Q&A, hardening roadmap, checklist)
- tests: test/dependency_plan_test.dart (8) over mobile_scanner fixture
- docs/PHASE_CHECKLIST.md now lists only items to address: cargo-apk hybrid
  removal (ADR-0009, proposed) + multi-dex determinism, with follow-ups
- completed ADR-0006/0007/0008 phases with evidence archived under
  docs/archive/PHASE_CHECKLIST_adr0006-0008.md (sidebar path unchanged)
- ADR-0009 (proposed): full rust/cargo inventory — zero production usage,
  quarantine test fails every CI run — and complete removal plan, awaiting
  sign-off
Completes ADR-0001's demotion: the no-Gradle pipeline is the only build path.

Removed:
- rust_wrapper/ (NativeActivity experiment, unused by every build path)
- test/cargo_apk_manifest_test.dart (the known-failing quarantine test —
  dart test is now fully green, no baseline caveat, CI stops failing)
- CargoApkManifest + barrel export (zero production callers)
- CargoApkConfig + OkaConfig.cargoApk getter + barrel export (zero callers)
- FlutterAndroidBuilder compatibility wrapper (only refused the cargo path)
- example/oka.yaml dead cargo_apk section; stale cargo comments/docs

Docs: ADR-0009 accepted+executed, ADR-0001 annotated, design FAQ /
why_this_repo_matters / contribution guide / AGENTS.md updated (the
rust_wrapper non-negotiable is moot).

Evidence: dart test 178/178 green; grep cargo over bin/lib/packages/lib/test
clean (RuStore vendor routing unrelated); example oka explain unchanged.

BREAKING CHANGE: CargoApkConfig/CargoApkManifest removed from oka_core and
oka_android public barrels; oka.yaml cargo_apk key is no longer read.
Research: oka.yaml base config (android:/flutter:) can move into the project
Dart pipeline because every config consumer reads ctx.config — an OkaConfig
extension type over a map — so typed values materializing that map plug in
with zero step-layer changes. Missing pieces: writable AndroidBuild/
FlutterBuild values, precedence merge in okaRun, hook discovery without
oka.yaml (convention, no new YAML key), oka init --from-yaml migration tool.
Staged: oka_core values -> example app -> last_answer -> doctor/init.
All stages executed:

Stage 1 (oka_core): AndroidBuild + FlutterBuild — const-constructible,
copyWith, toConfigMap() materializing the exact oka.yaml-shaped map. New
PlatformPipeline.configOverrides seam: okaRun deep-merges typed config over
oka.yaml over defaults; steps keep reading ctx.config (zero step-layer
changes). --print-config on okaRun emits the merged config as JSON.

Stage 2 (example app): full-Dart migration — config/flutterConfig/overrides
in example/tool/oka_pipeline.dart (renamed from bin/custom_pipeline.dart,
now also the discovery target), oka.yaml deleted. Byte-equivalence gate:
same-hook A/B (yaml-config vs AndroidBuild) → badging, AndroidManifest.xml,
resources.arsc, classes.dex all identical; residual diffs are only the
example's timestamped build_info.txt stamp (custom step) + signature cascade.

Stage 3: oka init --from-yaml converts oka.yaml 1:1 into the typed
entrypoint (last_answer migration path); oka init --dart scaffolds full-Dart.

Stage 4: entrypoint discovery (explicit dart_entrypoint → tool/oka_pipeline.dart
→ bin/oka_pipeline.dart) wired into build/explain/doctor; oka debug step
materializes full-Dart config via the hook's --print-config.

ADR fix: the parallel hot-reload ADR collided on number 0010 → renumbered to
0011 (file, plan, checklist, index, AGENTS, charter references).

Docs: ADR-0010 accepted + executed; build guide gains a Full-Dart config
Q&A (field mapping, precedence, migration); checklist/README/AGENTS updated.

Evidence: dart test 189/189 green; dart analyze 0 errors; check-contracts
green; example explain/doctor/debug-step verified live.

BREAKING CHANGE: none for API consumers — additive (AndroidBuild/FlutterBuild,
configOverrides). example/oka.yaml removed (hook is the config); yaml
projects unaffected.
…0010)

last_answer (first production app, 18 plugins) is now full-Dart config:
tool/oka_pipeline.dart generated via oka init --from-yaml, oka.yaml deleted.
Gate: yaml-config vs Dart-config debug builds are byte-equivalent (badging +
zip entries identical); explain/doctor/debug-step verified without oka.yaml.

Adoption surfaced three real gaps, all fixed behavior-preserving:

1. archive ^3.4.10 -> ^4.0.9: host apps depending on image ^4.5 (e.g.
   flutter_native_splash) couldn't resolve oka_android. API migration:
   ZipEncoder().encode -> encodeBytes, compress -> CompressionType
   (resources.arsc stays STORED — install -124 invariant kept), encode no
   longer nullable.

2. Explicit steps: lists dropped fast-settings (pre-existing ADR-0006 gap):
   AndroidPipeline.run now seeds the merged PipelineOverrides into
   PipelineState (runtime scope) and steps fall back to it when their
   constructor values are unset — exclude_plugins, extra_deps, manifest,
   icon, res_dirs, signing, resource_configs, extra_assets, local_aars,
   max_size_mb. _ExtraDepsStep/_LocalAarsStep are public ExtraDepsStep/
   LocalAarsStep; defaultSteps gains extra-deps/local-aars/extra-assets/
   post-build-lint so hooks using [...defaultSteps] get the full surface.

3. flutter assemble subprocesses now receive the located ANDROID_SDK_ROOT/
   ANDROID_HOME — projects with a stale android/local.properties (like
   last_answer's dead sdk.dir) no longer fail the build_hooks target.

Docs: checklist evidence updated; AndroidPipeline.run merge also threads
res_dirs/exclude_plugins/max_size_mb.

Tests: 191/191 green (13 ADR-0010 incl. overrides-seeding + ExtraAssetsStep
fallback); analyze clean; check-contracts green.
… publish readiness

oka init (ADR-0010):
- default flow scaffolds tool/oka_pipeline.dart (typed config derived from
  pubspec name/version) — no oka.yaml; discovery needs no YAML key
- --yaml opts into the legacy YAML-first flow (AI gradle conversion kept)
- --from-yaml unchanged; overwrite prompts are TTY-gated (non-interactive
  sessions cancel gracefully; --force forces)

Multi-dex determinism (ADR-0007 open item, closed):
- d8 program/lib jar lists sorted: parallel dependency resolution made
  argument order vary, and d8 partitions classesN.dex in argument order, so
  part count + content distribution were non-reproducible
- zipStagingToApk / zipBundle write entries in sorted path order instead of
  filesystem order — APK/AAB bytes are now reproducible
- test/determinism_test.dart: byte-identical APK/AAB across runs and
  directory orders; real-d8 reproducibility when an SDK is present

OSS publish readiness (ADR-0006 package split):
- oka_core/oka_android: LICENSE, README, CHANGELOG; oka_android declares
  hosted oka_core ^0.1.6 (path deps block publishing); root resolves
  siblings via dependency_overrides for local development
- pub_publish workflow: per-package dry-run preflight + publish train
  oka_core -> oka_android -> oka; check_version_sync extended to the split
  packages
- host bootstrap (pre-first-release dependency_overrides) documented in the
  build guide; design FAQ gains the determinism rationale

Evidence: dart test 195/195 green; analyze 0 errors; check-contracts green;
publish dry-run — oka_core/oka publishable, oka_android resolves once
oka_core's first release is up.
…roid first

- README: leads with the north star (typed, composable, agent-operable
  platform builds), Android-first status with production evidence, the agent
  surface table (explain/compare/debug step/doctor/dev), packages table,
  and 'The long game' — criteria-gated platform expansion (depth before
  breadth, abstraction hygiene, iOS as second-platform candidate, stay in
  the Flutter+agent-native+no-Gradle wedge)
- charter (why_this_repo_matters): the three design words (declarative/
  compositional/AI-native) as design law, 'What oka does not own' updated
  (iOS/desktop criteria-gated, not forever-never), expansion criteria
  section
- design FAQ: what carries over to future platforms
- AGENTS.md: north-star one-liner

No code changes; all gates green (195 tests, analyze clean, contracts).
Oka was created not because Gradle is slow but because platform build
configs are locked, scattered across a dozen untyped formats, endlessly
repeated per project, and impossible to unify or copy. The reframe:

- README 'Why oka was created': the config chaos is the disease; one typed,
  composable, copyable Dart surface is the cure; speed (~23s incremental,
  no daemon) is a consequence, not the pitch
- charter: 'The problem oka was created for' rewritten (lock-in +
  unmanageability + repetition across projects); success metrics now lead
  with 'one copyable Dart file' instead of raw speed; future generations
  named as pushing more per-platform noise into the single Dart surface
- AGENTS.md one-liner updated to match

No code changes; all gates green.
…enchmarks

- steward.yaml (adopted via steward adopt --archetype cli_tool, aligned with
  the mcp_flutter pattern): governance charter AGENTS.md, adr_dir
  docs/decisions, validate make check-contracts, registry skills.sh.json,
  evidence .steward/benchmark-summaries
- four typed contract actions wrapping the release gates (version-sync,
  docs-drift, changelog-markdown, no-personal-paths) + contract smoke
  scenario oka.contract-status-smoke with safe-first probe
- tool/benchmarks/build_benchmarks.sh + make bench: wall-clock benchmarks
  for the agent-loop primitives (explain / incremental build / compare /
  debug step) with environment metadata, summaries in
  .steward/benchmark-summaries (gitignored, machine-local)
- skills.json lists the installable oka-maintenance skill

steward doctor: config valid; benchmark durability requires committed
contract artifacts, hence this commit precedes the first recorded run.
… phase items

Secrets: dart-define/fromEnvironment/define-from-file stay first-class for
app-visible non-secrets; credential contents are build-host files referenced
by PATH (asset pattern), resolved via an ordered doctor-printable policy
(config path -> OKA_<TARGET>_* env -> ~/.oka/credentials); doctor secret
audit + gitignore gate; PublishTarget conformance laws (dry-run without
credentials, no stdin, no secret values in state).

refactor: CLI platform-leakage ratchet emptied (ADR-0015 follow-up)

get/compare/doctor/build are parse-and-delegate shims; SDK install mechanics
-> oka_android provisioning.dart, doctor checks -> doctor_checks.dart, aapt2
resolution absorbed into compareArtifacts. Allowlist deleted except one
documented flag-name exception (--skip-badging). Outputs byte-identical.

338 tests passing, analyze clean, contract gates green.
… audit (P0)

ADR-0014 P0: PublishTarget with dry-run conformance law, CredentialRef
(redacting) + ordered credential-path policy (config path -> OKA_<TARGET>_*
env -> ~/.oka/credentials), dart-define secret audit, credential-file
gitignore check, expectPublishConformance helper. Doctor outputs via
parse-and-delegate; leakage gate respected.

Evidence: test counts + doctor audit + dry-run plan in PHASE_CHECKLIST.
…idation (P2)

ADR-0014 P1: packages/oka_conformance (shared publish-target conformance
suite: dry-run-without-credentials, no-stdin, no-secret-values-in-state);
packages/oka_play (PlayPublishTarget, androidpublisher/v3 Edits flow over
injectable transport, JWT->OAuth via googleapis_auth, offline-tested).

ADR-0014 P2: packages/oka_huawei (HuaweiPublishTarget, AGC REST flow offline-
tested, redaction on dumps/errors); GMS-exclusion variant via new oka_android
seam (gms-dep artifacts) — validator catches GMS-dependent steps in excluded
compositions before any tool runs.

CLI untouched (targets project-declared per ADR-0015). Tests: root 390 +
oka_play 27 + oka_conformance 11 + oka_huawei 31 — all green, analyze clean,
contract gates green.
…yer e2e (ADR-0011)

H0: debug APK hot-reload audit — kernel_blob.bin/static assertions + live
emulator probe (VM service reachable, attach --machine reaches app.started;
parser handles both 'is listening'/'is available' spellings). Decision
recorded: H3 uses attach --machine (Gradle-free).

H1: run_session.json (schema 1) recorded at build time; oka dev validates
and refuses mismatch (dart_defines, engine drift); flutter binary resolved
from recorded SDK path, never ambient PATH.

H2: 25 command-construction/parser/failure tests over scripted-fake adb;
live e2e on a provisioned API 34 emulator (oka run device -> install/
launch/logscan -> VM probe OK). System image fetched via parallel curl
(sdkmanager pathologically slow); one-time human commands recorded.

Evidence in PHASE_CHECKLIST + hot_reload_plan.md.
…art, doctor (ADR-0011)

H3: flutter attach --machine daemon adapter (protocol corrected by live
probe: both reload and restart are app.restart with fullRestart; app.reload
does not exist in flutter_tools 3.47) — human TTY loop + --json agent
stream; one session per device; attach child gets recorded-SDK tools on PATH.
Live e2e on h0test AVD: session.ready -> reload ~130ms -> restart ~625ms ->
detach clean.

H4: --watch change classification (Dart -> reload; native/res/manifest ->
honest rebuild routing, reload never suggested) + --rebuild-on-native loop;
17 table/debounce/routing tests.

H5: doctor [Dev Loop] readiness section; docs updated with the three-flow
story: oka run device (one-shot) / oka launch (alias) / oka dev (session).

Also (publish-gaps agent): okaRun prints publish plans on dry-run dispatch
(ADR-0014 law); AAB fallback path fixed in oka_play/oka_huawei to the real
oka output layout with typed override.

456 tests green, analyze clean, contract gates passed.
…sts)

Physical-device testing surfaced that -d/--device was silently dropped and
every device step ran bare adb (works on single-device hosts only; 'more
than one device' errors with two attached):

- adb arg builders + AdbTool gain serial (-s), threaded through
  install/launch/logcat/forward/VM-service operations
- DeviceTarget gains typed deviceId; steps carry it
- Target contract gains supportedInvocationArgs/applyInvocationArgs —
  typed invocation-time overrides via --oka-target-arg key=value;
  okaRun parses -d/--device + --oka-target-arg in target dispatch
- oka launch -d now FORWARDS instead of dropping; bare --device is a
  usage error; unknown invocation args rejected naming accepted keys
- launch alias fixture/models updated; serial + contract tests

522 tests passing, analyze clean.
…R-0011 follow-ups)

1. oka dev now writes the forwarded VM-service endpoint to
   .oka_cache/dev/vm.uri (one line, written on session.ready, cleared on
   exit) so verification/inspection tools (flutter_mcp_cli, agents) attach
   without scraping the --json stream.

2. Hot-restart relaunch fallback: on physical devices attach-mode
   app.restart(fullRestart) can stop the app instead of restarting it
   (flutter_tools lacks relaunch data when attached). The session races the
   restart against app.stop; on a mid-restart stop it hands back to DevFlow
   with DevSessionOutcome.relaunchRequested — relaunch + re-attach, no
   rebuild. Scripted-fake test with a silent app.restart reproduces the
   device failure mode end-to-end.

524 tests passing, analyze clean.
…-0013/0015)

oka run emulator: typed target (avdName/apiLevel/abi/headless/createIfMissing,
invocation-arg device=<serial>) compiling to ensure-avd + boot-emulator steps;
idempotent reuse of a running instance; boot-wait via sys.boot_completed;
provides the emulator-serial artifact for multi-device downstream steps;
StopEmulatorStep for teardown targets. Fail-closed non-interactive
provisioning remediation (yes | sdkmanager --licenses; sdkmanager <image>).

Found by the live smoke test: ensure-avd initially passed the emulator's
-list-avds flag to avdmanager — existence check always missed (spurious
--force re-create). Fixed with avdmanager list avd + Name: parsing.

16 tests (argv builders, scripted-fake boot/idempotence/remediation,
invocation args); example composition updated. 556 tests passing, gates green.
…cements; control-port default

Newer Flutter announces only 'The Dart VM service is listening on
http://host:port/TOKEN/' — no ws:// line. The H2 scrape stored that URI
without the /ws path, so downstream ws clients (flutter_mcp_cli) got
connection failures. VmServiceInfo.wsUri and forwardedVmServiceUri now
normalize to the ws endpoint (token path + /ws).

Also: oka dev --control-port defaults to ephemeral (0); control-server
lint cleanups. Integration smoke verified delegated reload through
flutter_mcp_cli (delegated:true, runner:oka-dev-session).
…er-session.json)

Dependency inversion: the toolkit defines the generic 'dev session'
contract; oka is a conforming runner (writes the file, never embedded in
the toolkit). Runner file moves from .oka_cache/dev/session.json to
<project>/.flutter_mcp/runner-session.json with the optional 'runner'
display field; .oka_cache/dev/vm.uri stays internal. Wire protocol
unchanged. 557 tests, gates green. Integration smoke: delegated reload
with runner:oka-dev from the file, oracle PASS.
@docs-page

docs-page Bot commented Sep 8, 2026

Copy link
Copy Markdown

To preview the documentation for this pull request, visit the following URL:

docs.page/arenukvern/oka~1

Documentation is deployed and generated using docs.page

…tic test key, zero analyzer infos

- dart pub get --no-example in CI: dart >= 3.13 resolves example/ by
  default; example is a Flutter app and cannot resolve without the
  Flutter SDK (flutter_test is sdk-sourced). The root suite skips
  gracefully without Flutter/Android SDKs.
- dart publish → dart pub publish in the validate job (dart publish is
  not a command).
- false_secrets: pub's leak detector flags the SYNTHETIC Play test key
  fixture in packages/oka_play/test/synthetic_credentials.dart when the
  root archive (which includes workspace members) is validated.
- dart fix + manual cleanup: zero analyzer issues so --fatal-infos holds
  (unnecessary_async kept future-error semantics via Future<Never>.error).
… not a package

Why: pub now fails validation for any archive containing a top-level
docs/ directory (plural-name convention error), and the root package
archive necessarily included docs/ (plus workspace members). The docs/
directory stays — it is the docs.page source — so the published CLI
moves instead, mirroring the mcp_flutter layout (workspace root with
publish_to: none + published packages).

- packages/oka: bin/, lib/, CHANGELOG.md, LICENSE, pubspec (name: oka,
  executables: oka). The pub.dev 'oka' package continues unchanged.
- Root pubspec: name oka_workspace, publish_to: none; cross-package ADR
  conformance tests stay at the root and depend on workspace members.
- false_secrets moved into packages/oka_play (the synthetic key fixture
  is only in its own archive now).
- CI: root suite + every member package suite; publish dry-runs loop
  over publishable members; pub_publish.yml publishes packages/oka and
  uses 'dart pub publish' (dart publish is not a command).
- Version sync/changelog contracts + release-please config track
  packages/oka.
- install.sh: curl | bash installer (dart pub global activate; --from-git
  for main @ HEAD); README quickstart shows both paths.
- Test harness paths updated (packages/oka/bin/oka.dart, lib/src/cli).
… are absent (CI without Android SDK)

The step resolves adb + emulator from PATH/toolchain before the injected
scripted runner matters, so the 4 emulator-lifecycle tests failed on CI
('adb/emulator not found' instead of the scripted behavior). Applies the
determinism_test skip-guard pattern.
@Arenukvern
Arenukvern merged commit c6155fc into main Sep 8, 2026
6 checks passed
@Arenukvern
Arenukvern deleted the v2 branch September 8, 2026 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant