Skip to content

feat(harness): evidence-bound completion, coverage CI, drift-safe verification - #41

Merged
fikrilal merged 50 commits into
mainfrom
demo/merchant-onboarding-validation
Sep 28, 2026
Merged

fikrilal merged 50 commits into
mainfrom
demo/merchant-onboarding-validation

Conversation

@fikrilal

@fikrilal fikrilal commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Summary

Evidence-bound harness completion: handoff check gates local acceptance on
current passing oracle evidence; coverage moves into CI Required; CI Runtime
executes both registered integration targets on an Android 35 emulator;
verification re-checks candidate identity after the lane; maintenance detects
dirty-file content mutation with independent dep/codegen outcomes; three
focused regressions registered as oracles; evidence-collection workflow
documented. See docs/exec-plans/completed/2026-09-07_harness-evidence-integrity-v4.md.

Commits in this PR:

  • 84d10d3 feat(harness): evidence-bound completion, coverage CI, drift-safe verification
  • efe1c8e docs(exec-plans): retire committed v2 plan, begin push baseline

Risk Class

  • low
  • medium
  • high

Risk notes:

  • Production impact areas touched (if any): none (harness/CI/docs/tests only).
  • Why this risk class was selected: harness + CI + release paths per
    risk_classifier.dart; new oracle kind consumers, CI aggregate change,
    verification-controller behavior change.

Acceptance Criteria

  1. Missing/failed/stale oracle evidence blocks handoff check; drafts disclose it.
  2. Coverage failure fails CI Required; CI Runtime runs both integration targets.
  3. Candidate drift during verify prevents verified.
  4. Maintenance catches already-dirty edits; dep/codegen outcomes independent.
  5. Focused regressions discoverable in harness/oracles.yaml.
  6. Collection workflow requires genuine human review + exact-revision hosted CI.

Checks Run

dart run mobile_core_kit_cli:mobilekit task verify --task harness-evidence-commit-v2 --env dev
# OK [verify.full], verified (attempt 1), 664 app tests + CLI/lint/codegen/oracles/contracts/duplication
dart run mobile_core_kit_cli:mobilekit handoff check --task harness-evidence-commit-v2
# Local acceptance evidence passed (read-only; hosted CI + review independent)
dart test packages/mobile_core_kit_cli/test/handoff_service_test.dart packages/mobile_core_kit_cli/test/maintenance_service_test.dart packages/mobile_core_kit_cli/test/task_controller_test.dart packages/mobile_core_kit_cli/test/ci_workflow_policy_test.dart packages/mobile_core_kit_cli/test/operating_evidence_test.dart
# 55 passed
fvm flutter test integration_test/auth_happy_path_test.dart -d emulator-5554 --flavor dev --dart-define=ENV=dev
# passed (Android 15 emulator, local observation)
fvm flutter test integration_test/startup_deep_link_resume_test.dart -d emulator-5554 --flavor dev --dart-define=ENV=dev
# passed (Android 15 emulator, local observation)

Hosted checks:

  • CI Risk passed
  • CI Full passed
  • CI Coverage passed
  • CI Runtime passed or was intentionally skipped by classification
  • CI Governance passed
  • Stable CI Required aggregate passed

Evidence

  • Tests added/updated where behavior changed
  • Screenshots/video attached (UI changes) — N/A, no UI changes
  • Logs/error traces attached — N/A, no failure paths changed
  • Mobile runtime evidence attached for medium/high UI/runtime PRs — local
    emulator runs above; hosted runtime pending on this PR
  • Runtime evidence fingerprint matches the final reviewed candidate —
    pending hosted run
  • No speculative refactor mixed into this PR
  • Handoff used fresh action-specific evidence and explicit publication authority
  • No force push, merge, deployment, signing, migration, or release was performed by the harness

Links/artifacts:

  • Task fingerprints: ee8a208b… (v4/commit baseline, full green x3),
    2084afb1… (clean push baseline, full green)
  • Local handoff check: passed read-only for both baselines

Runtime evidence details (if applicable):

  • Task fingerprint: ee8a208b…
  • Device identifier hash: (local emulator runs; hosted device hash pending)
  • Flavor: dev
  • Registered oracle results: auth.integration, startup.integration passed locally
  • Evidence artifact paths: local only (.tmp/harness-*-integration.log, ignored)

Safety And Rollback

  • Potential failure mode: CI aggregate or evidence checks falsely accept/block work.
  • Rollback strategy: revert 84d10d3 via follow-up PR through normal review; never force-push.
  • Follow-up required after merge (if any): collect first genuine operating-evidence
    records through the documented workflow (human review + exact-revision hosted CI).

Reviewer Focus

  • packages/mobile_core_kit_cli/lib/src/handoff/completion_evidence.dart (new
    reader: latest-wins, tamper checks, manual attestation limits)
  • packages/mobile_core_kit_cli/lib/src/handoff/handoff_service.dart (check vs
    publication split; draft disclosure)
  • packages/mobile_core_kit_cli/lib/src/task/task_controller.dart (post-lane
    fingerprint re-check)
  • .github/workflows/required.yml (coverage job + runtime integration execution
    • aggregate wiring)
  • harness/oracles.yaml (3 new regression oracles)

fikrilal and others added 30 commits August 30, 2026 19:40
Implement the merchant-onboarding reference feature end to end: pure
domain validation (value objects, child/root aggregates, stable failure
codes and paths), raw form input, use-case and typed repository
boundaries, a deterministic fake adapter, one feature Cubit with
one-shot effects, four design-system step pages with dynamic owner
rows, review masking, an isolated GoRouter route, a localized Home
entry, and mirrored domain/cubit/widget/DI tests. Adds the merchant
feature boundary to the architecture lint configuration and makes the
validated aggregate, raw input, reference snapshot, and bank schedules
immutable.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Add the 94 merchant-onboarding keys (labels, actions, errors, and
declarations) to the en, id, ar, en-XA, and ar-XB ARB catalogs with
generated output, keeping the demo fully localized.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Move the plan to completed with the full acceptance record: three work
packages, controlled verification evidence (profile full, attempt 1),
the three reviewer-fix rounds (typed-id conditionals, immutable
snapshots and aggregates, complete focus routing, bank schedule
defensive copy), runtime evidence limitations, and the backend
integration follow-up.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Sync the accepted backend artifact (b10a5bf9) into the mobile-owned
snapshot with its full SHA-256 digest and revision, adding the
authenticated reference-data and idempotent application submission
paths.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Add the authenticated remote datasource (core host, standard envelope,
one Idempotency-Key per invocation), Freezed reference/submit DTOs, pure
mappers with lossless integer basis-point conversion and leading-zero
account numbers, and a repository adapter mapping every documented
backend error code into the feature failure taxonomy. Production DI now
registers the real datasource and repository; the deterministic fake
moves to test support and the merchant step-widget pairs are recorded as
reviewed-acceptable duplication.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Extend the failure taxonomy with server validation, registration
conflict, stale terms, and idempotency outcomes; route recognized server
field failures through the existing Cubit step/focus behavior; and add
localized repository-level copy (unauthorized, already submitted,
conflict, stale reference/terms, idempotency, retryable) across all ARB
catalogs.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Move the plan to completed with the acceptance record: contract sync
from the accepted backend commit b10a5bf9, remote adapter and DTOs,
failure taxonomy and localization, production DI wiring, reviewed
duplication allowlist, and controlled full verification evidence
(profile full, attempt 1). The live E2E plan remains queued.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
…h repository guides

- Eliminate standalone data mappers in favor of model-owned methods
- Extract backend error codes and failure mapping into data/error/
- Refactor MerchantOnboardingRepositoryImpl to use toEitherWithFallback
- Remove pure pass-through LoadMerchantReferenceDataUseCase
- Standardize remote DTO naming to Model
- Strip explanatory comments across the feature
…presentation cubit

- Decompose monolithic reference data into discrete entities under domain/entity/
- Decompose monolithic value objects into discrete single-purpose files under domain/value/
- Streamline MerchantOnboardingCubit adhering to forms-use-cubit pattern
- Encapsulate wizard step routing and field path mappings in MerchantOnboardingStep extensions
- Extract OwnerMoveDirection to presentation/models/
- Update widgets, DI, routing, and unit/widget/integration tests
- Record reference entity refactoring plan
- Record domain types decomposition plan
- Record BLoC conversion plan
- Record clean Cubit refactoring plan
Remove effect streams from account cubits and manage snackbars and
dialogs through BlocListener. Convert AccountPage, CompleteProfilePage,
and RequestAccountDeletionPage to StatelessWidget.
…e and fix wizard navigation

Remove effect streams from MerchantOnboardingCubit in favor of BlocListener
on submission status and local failures. Fix Android system back to navigate
wizard steps backwards rather than immediately exiting, handle empty validation
failures safely without throwing StateError, and update unit and widget tests.
Add headerName and headers([String? key]) helper to IdempotencyKeyUtils
to avoid repeating boilerplate header maps across remote datasources.
Refactor account, profile, auth, and merchant onboarding remote
datasources to use the helper, and add dedicated unit tests.
Local emulator proof, not CI. Split plumbing vs login
pilot because oracle IDs must exist at task begin.

Park evidence-push so plumbing is the single active V2.
mobilekit runtime evidence runs maestro-flow oracles.
Raw Maestro CLI and MCP stay iteration only.

Local emulator proof. Not CI or Cloud.
dart:io File == is identity, so summary.md was tagged
transient-local-log and handoff ignored passing Maestro runs.
Cold start hits onboarding then complete-profile before Home.
Labels are not EditTexts; text selectors are regex. Never
hideKeyboard on this emulator.
YAML runs no longer need --task. They attach flutter logs for the
Maestro process. Drop the runtime logs command. Add register.yaml
and close the login and register pilots.
Merchant onboarding, password-reset request, logout, and change
password each get a maestro-flow oracle. Document the allowed
command subset so agents stop using point taps, swipe, and greedy
regex. Close the iterate CLI plan.
…edundant Value Objects

Remove 9 redundant ID Value Object classes that performed external catalog
lookups or wrapped client-side UUIDs. Store plain String identifiers directly
in aggregates (BusinessProfile, OwnershipStructure, SettlementAccount, OwnerRow)
and validate catalog constraints against MerchantReferenceDataEntity. Use
UuidV4Utils.generate() for owner row IDs.
Keep field vs operation failure types. Stop parking them on the
domain root next to aggregates and value objects.
One state stream. Builder paints. Listener handles snackbar and
navigation. Drop the second cubit effect stream from the guide.
Kick reference load from BlocProvider. Submit failure is an effect
instead of a build-time snackbar. Add SignInPageOfc as the
BlocListener-shaped login reference.
Remove effect streams from auth cubits and use BlocListener with listenWhen
for one-shot UI actions (snackbars, navigation). Convert pages to
StatelessWidget and clean up prototype sign_in_page_ofc.
- Align scaffold page imports with design system barrels (adaptive, button, loading)
- Adopt AppStateMessagePanel for scaffolded success and error states
- Support incremental slice scaffolding for existing features
- Prune empty directory generation to only create populated directories
- Fix AppDotWave required color parameter and lowerCamelCase route list identifier
- Update next-steps guidance to reference feature_modules_registrar.dart
- Upgrade generated unit tests to use bloc_test
- Add test coverage verifying incremental slicing, barrel imports, and directory pruning
Implement mobilekit scaffold data subcommand to generate Freezed DTOs, core endpoint constants, and remote datasource methods from local OpenAPI spec with targeted build_runner execution.
… data

Recursively collect transitive sub-schemas and enums for Freezed DTO generation, support allOf schema references, and remove deprecated build_runner flag.
CLI reference lagged the scaffold data and scaffold all
commands already on this branch.
Coordinate swipes missed fields after layout shifts.
Scroll to the field label, then tap below it.
flutter logs is logcat only, so Maestro evidence missed
dart:developer lines. Forward the VM service port and
subscribe to the Logging stream.
event intake would have pushed 84d10d3, which is no longer
the branch head. No push and no draft PR were made.
A green Maestro exit could hide a missing VM log or a 4xx.
evidence.json stores the signal ids only.
Core actionable duplication now fails verification. Small-helper
and presentation reports stay advisory. Golden tests are a real
oracle, and CI runtime reads those targets from the registry.
Invented or local-only operating-evidence revisions are rejected.
Engineering guides now live in subject folders.
Flutter 3.47.5 cannot format freezed 3 output, and freezed 4 needs
analyzer 14 while custom_lint still pins analyzer 8. Flutter 3.44.9
makes IconData final, which phosphor_flutter 2.1.0 extends. The
3.41.9 clone failed, so the pin stays 3.41.4. Took the newest
packages that resolve there, including secure storage 11 and
go_router 17.5.0. Dio transform timeouts and permanently denied
notification permission are now handled.
Current stable is 3.47.5 (Dart 3.13.4). phosphor_flutter 2.1.0
extends IconData, which is final on this SDK, so icons move to
phosphor_icons 3.0.1. go_router stays on 17.5.0: 18.0.1 looks up
material_ui's MaterialApp, and this SDK still ships
flutter/material.dart, so 18 would drop platform transitions.
freezed stays on 3.2.3 and the language floor stays 3.10.3 because
freezed 4 needs analyzer 14 and custom_lint 0.8.1 still pins
analyzer 8. The compact settings golden matches the 3.47 border
raster. The merchant phone tap is bounded above Next so the input
lands in the phone field.
Core actionable groups exit 1 inside verify --profile full and ci.
small-helpers and presentation stay reports. The registry has no
metric-assertion kind, so the oracle and runtime docs stop requiring one.
CI formats the CLI and lint packages at language 3.10. Those files
had been formatted at 3.13 through a stale nested package config.
Gradle 8.13 is below Flutter's 8.14 minimum, and Kotlin 2.1.0 is
below the 2.2.20 minimum.
The emulator runner executes its script with /bin/sh. mapfile and
process substitution are bash-only, so the Android lane exited before
any integration test started.
android-emulator-runner runs each script line as its own sh -c,
so a multi-line while loop never reached done.
@fikrilal
fikrilal marked this pull request as ready for review September 28, 2026 12:58
@fikrilal
fikrilal merged commit afbc261 into main Sep 28, 2026
10 checks passed
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