From 1dac8325e095c041087d6cb28f55f39222804457 Mon Sep 17 00:00:00 2001 From: muzahidul-opti Date: Wed, 29 Apr 2026 21:32:13 +0600 Subject: [PATCH 1/3] docs: ratify project constitution v1.0.0 Add Optimizely Flutter SDK constitution with 8 core principles covering bridge pattern integrity, response object pattern, platform parity, type safety, thread safety, multi-instance isolation, version synchronisation, and native SDK version pinning. Includes platform compatibility standards and development workflow quality gates. Also excludes .specify/ from pub.dev release package via .pubignore and adds speckit framework files to .gitignore. Co-Authored-By: Claude Opus 4.6 --- .gitignore | 12 ++ .pubignore | 3 + .specify/memory/constitution.md | 258 ++++++++++++++++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 .specify/memory/constitution.md diff --git a/.gitignore b/.gitignore index f31992b..0a0224a 100644 --- a/.gitignore +++ b/.gitignore @@ -125,3 +125,15 @@ app.*.symbols .env .mcp.json .claude/settings.local.json +.claude/plans/ + +# Spec Kit framework files (managed by spec-kit, not committed) +.specify/extensions/ +.specify/scripts/ +.specify/templates/ +.specify/workflows/ +.specify/integrations/ +.specify/extensions.yml +.specify/init-options.json +.specify/integration.json +.claude/skills/speckit-*/ diff --git a/.pubignore b/.pubignore index 320af7b..22ce619 100644 --- a/.pubignore +++ b/.pubignore @@ -3,3 +3,6 @@ CLAUDE.md # Claude Code local configurations .claude/ + +# Spec Kit framework files +.specify/ diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md new file mode 100644 index 0000000..fbda87e --- /dev/null +++ b/.specify/memory/constitution.md @@ -0,0 +1,258 @@ + + +# Optimizely Flutter SDK Constitution + +## Core Principles + +### I. Bridge Pattern Integrity + +All features MUST follow the three-layer bridge architecture: + +1. **Dart API Layer** — Public-facing classes (`OptimizelyFlutterSdk`, + `OptimizelyUserContext`) that consumers import and call. +2. **MethodChannel Bridge** — `OptimizelyClientWrapper` serialises calls + to `Map` and dispatches via `MethodChannel`. +3. **Native Plugin Layer** — Platform-specific handlers + (`SwiftOptimizelyFlutterSdkPlugin.swift`, + `OptimizelyFlutterClient.java`) that delegate to the native + Optimizely SDKs. + +No Dart code may call native SDK APIs directly. No native plugin may +expose platform-specific behaviour that bypasses the Dart wrapper. +Every new feature MUST touch all three layers and use the dual +MethodChannel architecture (`optimizely_flutter_sdk` for API, +`optimizely_flutter_sdk_logger` for log forwarding). + +### II. Response Object Pattern (NON-NEGOTIABLE) + +Every public SDK method MUST return a `BaseResponse` derivative. +Methods MUST NOT throw exceptions to callers. Errors are communicated +exclusively through the `success` boolean and `reason` string fields. + +- `_invoke()` in `OptimizelyClientWrapper` catches + `PlatformException` and converts it to `{success: false, reason: message}`. +- Native plugins MUST return result maps with `success` and `reason` + keys, never throw unhandled exceptions across the MethodChannel. +- New response types MUST extend `BaseResponse` and live in + `lib/src/data_objects/`. + +### III. Platform Parity + +Every feature MUST be implemented on both Android and iOS before +merging to `master`. A feature that works on only one platform is +incomplete. + +- Method dispatch cases MUST exist in both + `SwiftOptimizelyFlutterSdkPlugin.handle()` and + `OptimizelyFlutterSdkPlugin.onMethodCall()`. +- Constants (API names, parameter keys, response keys) MUST be + synchronised across `Constants.dart`, `Constants.swift`, and + `Constants.java`. +- Behaviour MUST be functionally identical on both platforms, even + when native SDK APIs differ in shape. + +### IV. Type Safety Across the Bridge + +Platform-specific type encoding MUST be handled transparently by +`Utils.convertToTypedMap()` in the Dart layer. + +- **iOS** requires explicit type metadata: + `{"value": 123, "type": "int"}`. +- **Android** uses direct primitives: `{"attribute": 123}`. +- All supported types (string, int, double, bool, map, list) MUST be + covered by the conversion utility. +- The `forceIOSFormat` parameter MUST be used in tests to verify iOS + encoding without requiring a physical device. +- New attribute types MUST be added to the conversion utility before + they are used anywhere else. + +### V. Thread Safety + +All MethodChannel result callbacks MUST execute on the main thread. + +- **iOS**: Use the `mainThreadResult` wrapper for every `FlutterResult` + callback. This is required by iOS 16+ and prevents crashes. +- **Android**: Use the `MainThreadResult` wrapper to enforce main-thread + execution of `MethodChannel.Result` callbacks. +- Native → Dart notification dispatch (activate, track, decision, + logEvent, configUpdate) MUST use `invokeMethod` on the main thread. +- Logger bridge callbacks MUST be dispatched safely from background + task queues to the main channel. + +### VI. Multi-Instance State Isolation + +The SDK MUST support multiple concurrent instances keyed by `sdkKey`. + +- SDK instances, user contexts, and notification listeners MUST be + tracked in isolated maps: `sdkKey → resource`. +- User contexts MUST be uniquely identified by `sdkKey + userContextId`. +- `close()` MUST clean up all resources (instances, contexts, + listeners) for the given `sdkKey`. +- No global mutable state is permitted outside of the per-`sdkKey` + registry. + +### VII. Version Synchronisation (NON-NEGOTIABLE) + +The SDK version MUST be identical in exactly three locations: + +1. `pubspec.yaml` → `version: X.Y.Z` +2. `lib/package_info.dart` → `version = 'X.Y.Z'` +3. `README.md` → Installation example `^X.Y.Z` + +A release MUST NOT be tagged or published if these three values +diverge. Strict semantic versioning applies: breaking public API +changes MUST increment the major version. New features increment +minor. Bug fixes increment patch. + +### VIII. Native SDK Version Pinning + +Native Optimizely SDK versions are pinned in build configuration: + +- **iOS**: `OptimizelySwiftSDK` version in + `ios/optimizely_flutter_sdk.podspec`. +- **Android**: `com.optimizely.ab:android-sdk` version in + `android/build.gradle`. + +Native SDK upgrades MUST: + +1. Be performed in a dedicated branch (not bundled with feature work). +2. Update both platforms simultaneously when possible. +3. Verify that the bridge layer still functions correctly by running + the full test suite and integration tests. +4. Document the upgrade in `CHANGELOG.md` with the old and new + versions. + +## Platform Compatibility Standards + +### Minimum Platform Versions + +| Platform | Minimum | Compile/Target | +|----------|---------|----------------| +| Dart | >=2.16.2 | <4.0.0 | +| Flutter | >=2.5.0 | — | +| Android | API 21 (5.0) | API 35 (15) | +| iOS | 10.0 | — | + +Changes that raise minimum platform versions MUST be treated as +breaking changes (major version bump). + +### Language & Tooling + +| Layer | Language | Version | +|---------|------------|-----------| +| Dart | Dart | >=2.16.2 | +| Android | Java/Kotlin| Kotlin 2.1.0 | +| iOS | Swift | 5.0 | + +### Licensing + +All source code files (`.dart`, `.java`, `.swift`, `.kt`) MUST carry +the Apache 2.0 license header. Test files, configuration files, and +documentation are exempt. + +## Development Workflow & Quality Gates + +### Branching + +- **Never** commit directly to `master`. +- Feature branches: `feature/`, `fix/`. +- Release branches: `prepare-X.Y.Z`. +- All PRs target `master`. + +### Testing + +Tests MUST accompany all code changes. The testing approach is +flexible (TDD is encouraged but not mandated), provided that: + +- Unit tests exist in `test/` for all new Dart-layer behaviour. +- Mock MethodChannel responses via `TestDefaultBinaryMessenger`. +- Platform-specific type encoding is tested using `forceIOSFormat`. +- `flutter test` passes with zero failures before merge. +- `flutter analyze` reports zero issues before merge. + +### Commit Messages + +Follow Angular commit message guidelines: + +- `feat:` — New features +- `fix:` — Bug fixes +- `chore:` — Maintenance and releases +- `docs:` — Documentation only +- `refactor:` — Code restructuring +- `test:` — Test additions or modifications + +### CI Pipeline + +All four CI jobs MUST pass before merge: + +1. `unit_test_coverage` — Dart tests + Coveralls upload (macOS) +2. `build_test_android` — Android build validation (Ubuntu) +3. `build_test_ios` — iOS build validation (macOS) +4. Integration tests — Triggered in `optimizely-flutter-testapp` + +### Adding a Cross-Platform Feature (Checklist) + +1. Add data models in `lib/src/data_objects/` if needed. +2. Update `lib/src/optimizely_client_wrapper.dart` with MethodChannel + call. +3. Add handler case in `OptimizelyFlutterClient.java` (Android). +4. Add handler case in `SwiftOptimizelyFlutterSdkPlugin.swift` (iOS). +5. Handle type conversions (iOS metadata wrapping). +6. Write tests in `test/`. +7. Update public API in `lib/optimizely_flutter_sdk.dart`. + +### CLA Requirement + +All contributors MUST sign the Contributor License Agreement before +their first PR can be merged. + +## Governance + +This constitution is the authoritative reference for architectural +decisions and development standards in the Optimizely Flutter SDK. +All code changes MUST comply with the principles defined above. + +### Amendment Procedure + +1. Edit `.specify/memory/constitution.md` directly. +2. Increment the version according to semantic versioning: + - **MAJOR**: Principle removal or backward-incompatible redefinition. + - **MINOR**: New principle or materially expanded guidance. + - **PATCH**: Clarifications, wording, or non-semantic refinements. +3. Update `LAST_AMENDED_DATE` to the current date. +4. Commit with message format: + `docs: amend constitution to vX.Y.Z ()`. +5. Propagate changes to dependent templates if principles are + added, renamed, or removed. + +### Compliance + +- PRs SHOULD reference the relevant principle when introducing + architectural changes. +- Complexity beyond what the principles allow MUST be justified in + the PR description. +- Use `CLAUDE.md` for runtime development guidance that supplements + (but does not override) this constitution. + +**Version**: 1.0.0 | **Ratified**: 2022-06-07 | **Last Amended**: 2026-04-29 From 0930aa4d9c81d2ff0c71c86a9da7ed929156842d Mon Sep 17 00:00:00 2001 From: muzahidul-opti Date: Thu, 30 Apr 2026 00:07:32 +0600 Subject: [PATCH 2/3] docs: add Spec Kit plan context hook to CLAUDE.md Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 65b2312..c469c17 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -194,3 +194,8 @@ Follow [Angular guidelines](https://github.com/angular/angular/blob/master/CONTR - `ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift` - Plugin implementation (786 LOC) - `ios/Classes/OptimizelyFlutterLogger.swift` - Logger bridge with task queue - `ios/optimizely_flutter_sdk.podspec` - CocoaPods dependencies + + +For additional context about technologies to be used, project structure, +shell commands, and other important information, read the current plan + From 65dab58d1ebcb73e5c6fcc85b4b2e9d6033c480d Mon Sep 17 00:00:00 2001 From: muzahidul-opti Date: Thu, 30 Apr 2026 22:46:48 +0600 Subject: [PATCH 3/3] docs: add constitution guidance for AI assistants Address PR#104 review feedback: - Add Project Constitution section in CLAUDE.md emphasizing use for all changes (including day-to-day work not requiring full SDD) - Create .github/copilot-instructions.md to instruct GitHub Copilot to follow the project constitution during code generation Co-Authored-By: Claude Sonnet 4.5 --- .github/copilot-instructions.md | 69 +++++++++++++++++++++++++++++++++ CLAUDE.md | 12 ++++++ 2 files changed, 81 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..6529bec --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,69 @@ +# Copilot Instructions + +## Project Constitution + +All code changes MUST comply with the project constitution at `.specify/memory/constitution.md`. This document defines the team's non-negotiable standards for correctness, testing, security, observability, naming, PR discipline, and architectural simplicity. Read it before proposing changes. + +## Tech Stack + +This is a **Flutter SDK** wrapping native Optimizely SDKs for iOS and Android. + +**Technology Stack:** +- **Dart/Flutter**: Cross-platform API layer (>=2.16.2, Flutter >=2.5.0) +- **Swift**: iOS native bridge (Swift 5.0, iOS 10.0+) +- **Kotlin/Java**: Android native bridge (Kotlin 2.1.0, Android 5.0+) +- **Native SDKs**: OptimizelySwiftSDK 5.2.1 (iOS), android-sdk 5.1.1 (Android) + +## Folder Structure + +- `lib/` - Dart SDK code (public API, wrapper, data objects, user context) +- `android/` - Android native plugin code (Java/Kotlin) +- `ios/` - iOS native plugin code (Swift) +- `test/` - Dart unit tests +- `example/` - Example Flutter app demonstrating SDK usage + +## Code Conventions + +### Dart +- Follow official [Dart style guide](https://dart.dev/guides/language/effective-dart/style) +- Use `lowerCamelCase` for variables, methods, parameters +- Use `UpperCamelCase` for classes, types +- Prefix private members with underscore `_privateMethod` +- ALL methods return `BaseResponse` derivatives (never throw exceptions) +- Check `success` boolean and `reason` string for errors + +### Swift (iOS) +- Follow Swift naming conventions +- Use type-safe Optional unwrapping +- iOS attributes need type metadata: `{"value": 123, "type": "int"}` + +### Java/Kotlin (Android) +- Follow Android/Kotlin style guide +- Android uses direct primitives: `{"attribute": 123}` + +## Testing + +Run tests with: +```bash +flutter test # All tests +flutter test test/cmab_test.dart # Specific test +flutter test --coverage # With coverage +``` + +**Requirements:** +- Tests required for all code changes +- All CI checks must pass (4 parallel workflows) +- Test both success and error paths +- Mock platform channels appropriately + +## Commit Messages + +Follow [Angular guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines): +- `feat:` - New features +- `fix:` - Bug fixes +- `chore:` - Maintenance +- `docs:` - Documentation +- `refactor:` - Code restructuring +- `test:` - Test additions + +**Never commit directly to `master`** - use feature branches and PRs. diff --git a/CLAUDE.md b/CLAUDE.md index c469c17..c0247e5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -133,6 +133,18 @@ Month Day, Year ## Contributing Guidelines +### Project Constitution + +**All code changes MUST comply with the project constitution** at `.specify/memory/constitution.md`. This document defines the team's non-negotiable standards for correctness, testing, security, observability, naming, PR discipline, and architectural simplicity. + +**When to consult the constitution:** +- Before implementing any feature (large or small) +- During code reviews to validate adherence +- When making architectural decisions +- For day-to-day changes that don't require full SDD workflow + +Read the constitution before proposing changes. + ### Commit Messages Follow [Angular guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines): - `feat:` - New features