diff --git a/.codeyam/dependency-graph.json b/.codeyam/dependency-graph.json index 8b466e8..a53c70b 100644 --- a/.codeyam/dependency-graph.json +++ b/.codeyam/dependency-graph.json @@ -1,526 +1,526 @@ { "files": { - "ios/Sources/AppCore/CodeyamIsolated/CounterListPanelIsolated.swift": { + ".claude/hooks/_step_metadata.py": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/PanelChrome.kt": { + "ios/Sources/AppCore/CodeyamIsolated/CounterGraphChartIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/SettingsOverlays.swift": { + "ios/Sources/AppCore/Theme.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/FeedbackDisclosureToggleIsolated.swift": { + "ios/Sources/AppCore/CodeyamIsolated/GraphPageIsolated.swift": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/model/CounterFeedback.kt": { + "ios/Sources/AppCore/CodeyamIsolated/AppSettingsPanelIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/GraphPageIsolated.swift": { + "android/app/src/main/java/com/codeyam/android/ui/GraphPage.kt": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/model/AppSettings.kt": { + "ios/Sources/AppCore/CodeyamIsolated/SettingsToggleRowIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/CounterGraphView.swift": { + "ios/Sources/AppCore/ContentView.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/SettingsToggleRow.swift": { + "ios/Sources/AppCore/CodeyamIsolated/ControlButtonIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/SeedPolicy.swift": { + "android/app/src/main/java/com/codeyam/android/ui/Theme.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/CounterColorPickerIsolated.swift": { + "android/app/build.gradle.kts": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/model/KeyValueStore.kt": { + "ios/Tests/AppCoreTests/ThemeTests.swift": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/ControlButton.kt": { + "android/app/src/main/java/com/codeyam/android/ui/CounterDot.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/HeaderAnchoredOverlay.swift": { + "ios/Sources/AppCore/CodeyamIsolated/OverridePickerIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/BoundedScrollIsolated.swift": { + "ios/App/App.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/HeaderBarIsolated.swift": { + "ios/Sources/AppCore/Views/CounterDot.swift": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/CounterListPanel.kt": { + "ios/Tests/AppCoreTests/CounterFeedbackOverrideTests.swift": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/CounterBottomBar.kt": { + "ios/Sources/AppCore/Views/CounterGraphChart.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/OverridePicker.swift": { + "android/app/src/main/java/com/codeyam/android/model/CounterFeedback.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/GraphCloseButton.swift": { + "ios/Sources/AppCore/CodeyamIsolated/CountHeroIsolated.swift": { "imports": [], "importedBy": [] }, - "android/app/src/test/java/com/codeyam/android/ui/CountHeroSnapshotTest.kt": { + "android/app/src/main/java/com/codeyam/android/ui/CounterScreen.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/ControlButtonIsolated.swift": { + "android/app/src/main/java/com/codeyam/android/ui/GraphGeometry.kt": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/model/Counter.kt": { + "ios/Sources/AppCore/CodeyamIsolated/FeedbackDisclosureToggleIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/CounterBottomBarIsolated.swift": { + "ios/Sources/AppCore/Views/AddCounterDot.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/History.swift": { + "android/app/src/main/java/com/codeyam/android/ui/CounterScreenState.kt": { "imports": [], "importedBy": [] }, - "ios/App/App.swift": { - "imports": [], + ".claude/skills/review-session/scripts/find-last-session.mjs": { + "imports": [ + ".claude/skills/review-session/scripts/find-last-session-helpers.mjs" + ], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/model/SeedPolicy.kt": { + "android/app/src/main/java/com/codeyam/android/ui/HeaderBar.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/SettingsField.swift": { + "ios/Sources/AppCore/CodeyamIsolated/CounterListPanelIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/CounterGraphChartIsolated.swift": { + "android/app/src/testDebug/java/com/codeyam/android/ui/AppSettingsPanelInteractionTest.kt": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/CounterIcons.kt": { + "ios/Sources/AppCore/Views/GraphHistorySelector.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/CounterGraphViewIsolated.swift": { + "ios/Sources/AppCore/Views/CountHero.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/CounterDot.swift": { + "ios/Sources/AppCore/Views/HeaderAnchoredOverlay.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/CounterStepStepper.swift": { - "imports": [], + ".claude/skills/review-session/scripts/extract-session.mjs": { + "imports": [ + ".claude/skills/review-session/scripts/extract-session-helpers.mjs" + ], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/SettingsToggleRowIsolated.swift": { + "android/app/src/main/java/com/codeyam/android/model/SettingsOverlays.kt": { "imports": [], "importedBy": [] }, - "ui/src/helpers/stepLabels.generated.ts": { + "ios/Sources/AppCore/CodeyamIsolated/GraphHeaderIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/GraphHeader.swift": { + "android/app/src/test/java/com/codeyam/android/ui/CountHeroSnapshotTest.kt": { "imports": [], "importedBy": [] }, - "android/app/build.gradle.kts": { + "ios/Sources/AppCore/CodeyamIsolated/BoundedScrollIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/ControlButton.swift": { + "ios/Sources/AppCore/Feedback.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/CounterBottomBar.swift": { + "android/app/src/test/java/com/codeyam/android/ui/GraphGeometryTest.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/GraphCloseButtonIsolated.swift": { + "ios/Sources/AppCore/CodeyamIsolated/CodeyamIsolationHost.swift": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/model/CounterModel.kt": { + "ui/src/helpers/stepLabels.generated.ts": { "imports": [], "importedBy": [] }, - "ios/Tests/AppCoreTests/CounterFeedbackOverrideTests.swift": { + "ios/Sources/AppCore/Views/CounterGraphView.swift": { "imports": [], "importedBy": [] }, - "ios/Tests/AppCoreTests/FeedbackTests.swift": { + "ios/Tests/AppCoreTests/ModelTests.swift": { "imports": [], "importedBy": [] }, - "ios/Tests/AppCoreTests/ModelTests.swift": { + "android/app/src/main/java/com/codeyam/android/MainActivity.kt": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/CounterScreen.kt": { + "android/app/src/main/java/com/codeyam/android/ui/CounterBottomBar.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/AppSettings.swift": { + "android/app/src/test/java/com/codeyam/android/ui/CountFormatTest.kt": { "imports": [], "importedBy": [] }, - "ios/Package.swift": { + "android/build.gradle.kts": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/CounterGraphChart.swift": { + "ios/Sources/AppCore/CodeyamIsolated/CounterSettingsPanelIsolated.swift": { "imports": [], "importedBy": [] }, - "android/build.gradle.kts": { + ".claude/skills/review-session/scripts/find-last-session-helpers.mjs": { "imports": [], - "importedBy": [] + "importedBy": [ + ".claude/skills/review-session/scripts/find-last-session.mjs" + ] }, - "ios/Tests/AppCoreTests/ThemeTests.swift": { + "ios/Tests/AppCoreTests/SettingsOverlaysTests.swift": { "imports": [], "importedBy": [] }, - "android/app/src/test/java/com/codeyam/android/model/CounterThemeTest.kt": { + "android/app/src/test/java/com/codeyam/android/ui/CountHeroSizingTest.kt": { "imports": [], "importedBy": [] }, - ".claude/skills/review-session/scripts/extract-session.mjs": { - "imports": [ - ".claude/skills/review-session/scripts/extract-session-helpers.mjs" - ], + "ios/Tests/AppCoreTests/AppSettingsTests.swift": { + "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/GearButtonIsolated.swift": { + "ios/Sources/AppCore/CodeyamIsolated/AddCounterDotIsolated.swift": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/model/CounterTheme.kt": { + "ios/Sources/AppCore/CodeyamIsolated/DeleteCounterButtonIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/IncrementFaceButtonStyle.swift": { + "ios/Sources/AppCore/AppSettings.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/IncrementBarIsolated.swift": { + "ios/Sources/AppCore/Views/GraphPage.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/DeleteCounterButtonIsolated.swift": { + "ios/Sources/AppCore/Views/GraphHeader.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/GraphPage.swift": { + "ios/Sources/AppCore/Views/AppSettingsPanel.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/GraphHistorySelectorIsolated.swift": { + "android/app/src/main/java/com/codeyam/android/ui/CounterSwitcherCard.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/GraphEventListIsolated.swift": { + "ios/Sources/AppCore/CodeyamIsolated/GraphCloseButtonIsolated.swift": { "imports": [], "importedBy": [] }, - "android/settings.gradle.kts": { + "android/app/src/main/java/com/codeyam/android/ui/PanelChrome.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/AddCounterDotIsolated.swift": { + "ios/Sources/AppCore/CodeyamIsolated/CounterBottomBarIsolated.swift": { "imports": [], "importedBy": [] }, - "android/app/src/test/java/com/codeyam/android/model/AppSettingsTest.kt": { + "android/app/src/test/java/com/codeyam/android/ui/AndroidFeedbackTest.kt": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/SettingsControls.kt": { + "android/app/src/main/java/com/codeyam/android/ui/CountFormat.kt": { "imports": [], "importedBy": [] }, - "android/app/src/test/java/com/codeyam/android/MainViewModelTest.kt": { + "android/app/src/main/java/com/codeyam/android/ui/CounterSettingsPanel.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/AppSettingsPanelIsolated.swift": { + "android/scripts/merge-test-results.py": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/DeleteCounterButton.swift": { + "android/app/src/test/java/com/codeyam/android/ui/CounterScreenStateTest.kt": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/GraphPage.kt": { + "ios/Sources/AppCore/Views/SettingsField.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Theme.swift": { + ".claude/skills/review-session/scripts/extract-session-helpers.mjs": { "imports": [], - "importedBy": [] + "importedBy": [ + ".claude/skills/review-session/scripts/extract-session.mjs" + ] }, - "ios/Sources/AppCore/Views/IncrementBar.swift": { + "android/app/src/main/java/com/codeyam/android/model/CounterModel.kt": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/CountFormat.kt": { + "ios/Sources/AppCore/SettingsOverlays.swift": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/CounterSwitcherCard.kt": { + "android/app/src/test/java/com/codeyam/android/model/FeedbackTest.kt": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/CounterDot.kt": { + "ios/Sources/AppCore/Views/GraphEventList.swift": { "imports": [], "importedBy": [] }, - "ios/Tests/AppCoreTests/AppSettingsTests.swift": { + ".claude/hooks/editor-step-hook.py": { "imports": [], "importedBy": [] }, - ".claude/hooks/_step_metadata.py": { + "store/appstore/gen_assets.py": { "imports": [], "importedBy": [] }, - "android/scripts/merge-test-results.py": { + "ios/Sources/AppCore/SeedPolicy.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/GraphHeaderIsolated.swift": { + "ios/Package.swift": { "imports": [], "importedBy": [] }, - ".claude/skills/review-session/scripts/find-last-session.mjs": { - "imports": [ - ".claude/skills/review-session/scripts/find-last-session-helpers.mjs" - ], + "ios/Sources/AppCore/Model.swift": { + "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/model/CounterHistory.kt": { + "ios/Sources/AppCore/Views/GearButton.swift": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/AppSettingsPanel.kt": { + "ios/Sources/AppCore/CodeyamIsolated/BottomControlRowIsolated.swift": { "imports": [], "importedBy": [] }, - "android/app/src/test/java/com/codeyam/android/ui/GraphGeometryTest.kt": { + "ios/Sources/AppCore/Views/CounterSettingsPanel.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/CounterColorPicker.swift": { + "android/app/src/test/java/com/codeyam/android/model/CounterThemeTest.kt": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/model/SettingsOverlays.kt": { + "ios/Sources/AppCore/Views/GraphCloseButton.swift": { "imports": [], "importedBy": [] }, - "android/app/src/test/java/com/codeyam/android/ui/CountHeroSizingTest.kt": { + "android/app/src/main/java/com/codeyam/android/ui/CounterIcons.kt": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/Theme.kt": { + "ios/Sources/AppCore/CodeyamIsolated/IncrementBarIsolated.swift": { "imports": [], "importedBy": [] }, - "android/app/src/test/java/com/codeyam/android/ui/CountFormatTest.kt": { + "ios/Sources/AppCore/Views/IncrementFaceButtonStyle.swift": { "imports": [], "importedBy": [] }, - ".claude/skills/review-session/scripts/extract-session-helpers.mjs": { + "ios/Sources/AppCore/CodeyamIsolated/GraphHistorySelectorIsolated.swift": { "imports": [], - "importedBy": [ - ".claude/skills/review-session/scripts/extract-session.mjs" - ] + "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/BottomControlRowIsolated.swift": { + "android/app/src/main/java/com/codeyam/android/model/AppSettings.kt": { "imports": [], "importedBy": [] }, - "store/appstore/gen_assets.py": { + "android/app/src/main/java/com/codeyam/android/model/KeyValueStore.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/CounterSwitcherCardIsolated.swift": { + "ios/Sources/AppCore/CodeyamIsolated/GearButtonIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/CounterDotIsolated.swift": { + "ios/Sources/AppCore/CodeyamIsolated/CounterGraphViewIsolated.swift": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/MainActivity.kt": { + "ios/Sources/AppCore/Views/ControlButton.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Feedback.swift": { + "ios/Sources/AppCore/CodeyamIsolated/GraphEventListIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Model.swift": { + "ios/Sources/AppCore/CodeyamIsolated/HeaderBarIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/GraphEventList.swift": { + "ios/Sources/AppCore/Views/PanelScrollSupport.swift": { "imports": [], "importedBy": [] }, - ".claude/hooks/editor-step-hook.py": { + "android/app/src/main/java/com/codeyam/android/ui/ControlButton.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/BottomControlRow.swift": { + "android/app/src/main/java/com/codeyam/android/model/CounterHistory.kt": { "imports": [], "importedBy": [] }, - ".claude/hooks/editor-pretool-hook.py": { + "ios/Tests/AppCoreTests/FeedbackTests.swift": { "imports": [], "importedBy": [] }, - "android/app/src/testDebug/java/com/codeyam/android/ui/AppSettingsPanelInteractionTest.kt": { + "android/app/src/test/java/com/codeyam/android/MainViewModelTest.kt": { "imports": [], "importedBy": [] }, - "ios/Tests/AppCoreTests/SettingsOverlaysTests.swift": { + "ios/Sources/AppCore/Views/SettingsToggleRow.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/AddCounterDot.swift": { + "ios/Sources/AppCore/Views/CounterBottomBar.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/HeaderBar.swift": { + "android/app/src/main/java/com/codeyam/android/ui/SettingsControls.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/CounterSettingsPanel.swift": { + "android/app/src/test/java/com/codeyam/android/model/SettingsOverlaysTest.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/CountHeroIsolated.swift": { + "android/app/src/main/java/com/codeyam/android/ui/AndroidFeedback.kt": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/AndroidFeedback.kt": { + "ios/Sources/AppCore/CodeyamIsolated/CounterSwitcherCardIsolated.swift": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/GraphGeometry.kt": { + "android/app/src/main/java/com/codeyam/android/model/Counter.kt": { "imports": [], "importedBy": [] }, - "android/app/src/test/java/com/codeyam/android/model/SettingsOverlaysTest.kt": { + "android/app/src/main/java/com/codeyam/android/model/CounterTheme.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/CountHero.swift": { + "ios/Sources/AppCore/Views/IncrementBar.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/AppSettingsPanel.swift": { + "ios/Sources/AppCore/CodeyamIsolated/CounterStepStepperIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/OverridePickerIsolated.swift": { + "ios/Sources/AppCore/Views/OverridePicker.swift": { "imports": [], "importedBy": [] }, - "android/app/src/test/java/com/codeyam/android/model/FeedbackTest.kt": { + "ios/Sources/AppCore/Views/BottomControlRow.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/CounterListPanel.swift": { + "android/app/src/test/java/com/codeyam/android/model/AppSettingsTest.kt": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/CountHero.kt": { + "ios/Sources/AppCore/Views/CounterColorPicker.swift": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/CounterGraphChart.kt": { + "android/app/src/test/java/com/codeyam/android/model/CounterModelTest.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/CounterStepStepperIsolated.swift": { + "android/app/src/main/java/com/codeyam/android/ui/CounterGraphChart.kt": { "imports": [], "importedBy": [] }, - ".claude/skills/review-session/scripts/find-last-session-helpers.mjs": { + "android/settings.gradle.kts": { "imports": [], - "importedBy": [ - ".claude/skills/review-session/scripts/find-last-session.mjs" - ] + "importedBy": [] }, - "ios/Sources/AppCore/Views/PanelScrollSupport.swift": { + "ios/Sources/AppCore/Views/HeaderBar.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/GearButton.swift": { + "ios/Sources/AppCore/Views/CounterListPanel.swift": { "imports": [], "importedBy": [] }, - "android/app/src/test/java/com/codeyam/android/ui/AndroidFeedbackTest.kt": { + "ios/Sources/AppCore/History.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/CodeyamIsolationHost.swift": { + "android/app/src/main/java/com/codeyam/android/ui/AppSettingsPanel.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/CodeyamIsolated/CounterSettingsPanelIsolated.swift": { + "ios/Sources/AppCore/Views/CounterSwitcherCard.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/GraphHistorySelector.swift": { + "android/app/src/main/java/com/codeyam/android/ui/CounterListPanel.kt": { "imports": [], "importedBy": [] }, - "android/app/src/test/java/com/codeyam/android/ui/CounterScreenStateTest.kt": { + "ios/Sources/AppCore/Views/CounterStepStepper.swift": { "imports": [], "importedBy": [] }, - "android/app/src/test/java/com/codeyam/android/model/CounterModelTest.kt": { + "ios/Sources/AppCore/CodeyamIsolated/CounterColorPickerIsolated.swift": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/Views/CounterSwitcherCard.swift": { + ".claude/hooks/editor-pretool-hook.py": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/CounterScreenState.kt": { + "ios/Sources/AppCore/CodeyamIsolated/CounterDotIsolated.swift": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/CounterSettingsPanel.kt": { + "android/app/src/main/java/com/codeyam/android/ui/CountHero.kt": { "imports": [], "importedBy": [] }, - "ios/Sources/AppCore/ContentView.swift": { + "android/app/src/main/java/com/codeyam/android/model/SeedPolicy.kt": { "imports": [], "importedBy": [] }, - "android/app/src/main/java/com/codeyam/android/ui/HeaderBar.kt": { + "ios/Sources/AppCore/Views/DeleteCounterButton.swift": { "imports": [], "importedBy": [] } @@ -544,5 +544,5 @@ "importedBy": [] } }, - "lastUpdated": "2026-07-29T12:50:21Z" + "lastUpdated": "2026-07-29T16:00:44Z" } \ No newline at end of file diff --git a/.codeyam/state/finalize-debt.json b/.codeyam/state/finalize-debt.json index fd2e5fe..4bf49e1 100644 --- a/.codeyam/state/finalize-debt.json +++ b/.codeyam/state/finalize-debt.json @@ -1,7 +1,7 @@ { - "lastFinalizedAt": "2026-07-29T12:50:26Z", - "lastFinalizedSha": "c10509e9f2cec7b9177d65af78384cb5c25b5071", - "lastFullFinalizeSha": "c10509e9f2cec7b9177d65af78384cb5c25b5071", - "lastFullFinalizeTree": "a29f2b2e3ea8a8170d5391b7875c162cb0516baa11e99e8b710f74355a60e032", + "lastFinalizedAt": "2026-07-29T16:00:47Z", + "lastFinalizedSha": "867412a06316387dad9a41c812d9bfc12486f5c1", + "lastFullFinalizeSha": "867412a06316387dad9a41c812d9bfc12486f5c1", + "lastFullFinalizeTree": "475c75c73964da583882770e7cf16858a95257554a4ef8250666794e8c337045", "deferred": [] } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 16d5425..6ef060b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: # `--disable-swift-testing` flag used below (absent on older toolchains). runs-on: macos-15 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Swift version run: swift --version @@ -30,11 +30,11 @@ jobs: # no emulator is booted — this is compile + JVM unit tests only. runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Set up JDK 17 # Gradle 8.7 + Android Gradle Plugin require JDK 17. - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: temurin java-version: "17" @@ -42,7 +42,7 @@ jobs: - name: Set up Android SDK # Installs the SDK and accepts licenses, exposing ANDROID_SDK_ROOT so # Gradle resolves it without the gitignored android/local.properties. - uses: android-actions/setup-android@v3 + uses: android-actions/setup-android@v4 - name: Build run: android/gradlew -p android compileDebugKotlin diff --git a/.github/workflows/codeyam-protection.yml b/.github/workflows/codeyam-protection.yml new file mode 100644 index 0000000..07f7045 --- /dev/null +++ b/.github/workflows/codeyam-protection.yml @@ -0,0 +1,71 @@ +name: codeyam-protection + +# codeyam-managed: merge-readiness gates. +# +# `ci.yml` proves the code builds and its tests pass. This workflow proves the +# codeyam state that travels with the code — scenarios, glossary, test registry +# — is actually finalized, which a build/test run cannot see. The two are split +# so a metadata-debt failure is legible on its own rather than reading as a +# broken app. +# +# These are the authoritative backstop for the pre-push hook: a contributor +# pushing from a fork (or with hooks bypassed) is caught here instead. +# +# Recommended: make `Merge-readiness gates` a required status check on `main` +# in repository settings → Branches. + +on: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + gates: + name: Merge-readiness gates + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + # Every gate walks history: the deferred-finalize check diffs a commit + # range and the full-finalize check resolves a recorded SHA. A shallow + # clone makes both unresolvable. + fetch-depth: 0 + + - name: Fetch the base branch + # `fetch-depth: 0` gives full history for the checked-out ref, but on a + # pull_request event the `origin/main` remote-tracking ref the + # deferred-finalize gate defaults to may not exist locally. Fetch it + # explicitly so `--base origin/main` always resolves. + run: git fetch --no-tags origin main:refs/remotes/origin/main || true + + - name: Set up Node + uses: actions/setup-node@v5 + with: + node-version: "20" + + - name: Install codeyam-editor + run: npm install -g @codeyam-editor/codeyam-editor@latest + + - name: Verify no deferred-finalize commits + # Fails when a commit carries `Codeyam-Finalize: deferred` without a + # later `session-finalize` covering it — i.e. Fast Commit debt that was + # never paid down. + run: | + codeyam-editor editor verify-no-deferred-finalize \ + --base origin/main \ + --head HEAD \ + --format text + + - name: Verify a full branch-wide finalize covers HEAD + # The deferred check above only catches *trailered* commits. This one + # catches a branch that simply never ran a full finalize, keeping + # whole-repo debt — invisible to the diff-only Fast Commit gate — off + # `main`. + run: codeyam-editor editor verify-full-finalize --format text + + - name: Verify completed plans still have their implementations + # Guards the merge boundary against a post-finalize rebase silently + # dropping the code a plan was archived as "completed" for. Plans with + # no deliverables manifest are reported as needs-review, not failed. + run: codeyam-editor editor verify-completed-plans --format text diff --git a/.github/workflows/play-release.yml b/.github/workflows/play-release.yml index 4eb449d..3c867fa 100644 --- a/.github/workflows/play-release.yml +++ b/.github/workflows/play-release.yml @@ -1,11 +1,12 @@ name: Play Release # Manual trigger — build a signed AAB and promote it to a chosen Play track, -# including **production**. The sibling `play-internal.yml` is the zero-argument -# "just get a build to internal testing" button; this one is the parameterized +# including **production**. This is the only Play upload path: the parameterized # release lever with staged rollout, release notes, and R8 deobfuscation upload. +# It replaced the retired zero-argument `play-internal.yml`; pick the `internal` +# track here for what that button used to do. # -# Secrets are the SAME five `play-internal.yml` already uses (all configured): +# Secrets are the five the retired workflow used (all configured): # ANDROID_KEYSTORE_BASE64 / ANDROID_KEYSTORE_PASSWORD / # ANDROID_KEY_ALIAS / ANDROID_KEY_PASSWORD / PLAY_SERVICE_ACCOUNT_JSON # @@ -58,7 +59,7 @@ jobs: - uses: actions/checkout@v5 - name: Set up JDK 17 - # Gradle 8.4 + AGP require JDK 17 (matches ci.yml and play-internal.yml). + # Gradle 8.4 + AGP require JDK 17 (matches ci.yml). uses: actions/setup-java@v5 with: distribution: temurin diff --git a/.github/workflows/testflight.yml b/.github/workflows/testflight.yml index 3bdcc7b..ed7e91c 100644 --- a/.github/workflows/testflight.yml +++ b/.github/workflows/testflight.yml @@ -10,7 +10,7 @@ jobs: name: Archive & upload to TestFlight runs-on: macos-26 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Show toolchain run: | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2bf99e7..a0e2428 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,7 +20,7 @@ git clone https://github.com/codeyam-ai/codeyam-counter && cd codeyam-counter npm install -g @codeyam-editor/codeyam-editor@latest # Launch the editor (split-screen terminal + live preview) -codeyam-editor editor +codeyam-editor start ``` codeyam-editor requires a subscription to Claude, Gemini, or Codex. Inside the @@ -35,7 +35,7 @@ you're changing. - **iOS** — macOS with a recent Xcode (Swift 6 toolchain) and an iOS 15+ simulator or device. -- **Android** — JDK 17 plus the Android SDK (compile SDK 34), and an emulator +- **Android** — JDK 17 plus the Android SDK (compile SDK 35), and an emulator image for the preview. See [ANDROID_SETUP.md](ANDROID_SETUP.md). ## Building and testing by hand — iOS @@ -73,9 +73,26 @@ build and test commands are: ```bash android/gradlew -p android compileDebugKotlin android/gradlew -p android testDebugUnitTest + +# Verify the committed Compose snapshots still match +android/gradlew -p android verifyPaparazziDebug +``` + +[Paparazzi](https://github.com/cashapp/paparazzi) renders the Compose components +off-device on the JVM, so the goldens under +`android/app/src/test/snapshots/` are checked without an emulator. **CI runs +`verifyPaparazziDebug` too**, so a change to a component's rendering fails there +unless you re-record and commit the new goldens: + +```bash +android/gradlew -p android recordPaparazziDebug ``` -CI runs these same two commands on Ubuntu with JDK 17. Put JVM unit tests under +Review the resulting image diff before committing it — a re-record makes the +check pass by definition, so it is only correct when the visual change is +intended. + +CI runs these same commands on Ubuntu with JDK 17. Put JVM unit tests under `android/app/src/test/` and register them with the editor (`codeyam-editor editor reconcile-registry --auto-apply`) so they stay tracked alongside the scenarios, exactly as on the iOS side. @@ -87,7 +104,8 @@ alongside the scenarios, exactly as on the iOS side. captured and registered as you go. 3. Ensure the build and tests pass for the platform(s) you touched — the iOS `swift build`/`swift test` commands and/or the Android - `compileDebugKotlin`/`testDebugUnitTest` commands above. CI runs both. + `compileDebugKotlin`/`testDebugUnitTest`/`verifyPaparazziDebug` commands + above. CI runs both platforms. 4. Open a PR describing what changed and why, and fill in the PR template. ## Code of conduct diff --git a/README.md b/README.md index b4fad8c..a0a8496 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ git clone https://github.com/codeyam-ai/codeyam-counter && cd codeyam-counter npm install -g @codeyam-editor/codeyam-editor@latest # Launch the editor (split-screen terminal + live preview) -codeyam-editor editor +codeyam-editor start ``` @@ -61,7 +61,7 @@ device. See [IOS_SETUP.md](IOS_SETUP.md) for simulator prerequisites. ### Android A native Kotlin + Jetpack Compose port lives in [`android/`](android/). Requires -JDK 17 and the Android SDK (compile SDK 34). +JDK 17 and the Android SDK (compile SDK 35). ```bash # Compile the sources and run the JVM unit tests @@ -85,33 +85,33 @@ States captured as runnable scenarios with codeyam-editor: Android Counter - Active count -### Android Counter - Added blank slot selected +### Counter - Active count -Android Counter - Added blank slot selected +Counter - Active count -### Android Counter - All but one deleted +### Android Counter - Added blank slot selected -Android Counter - All but one deleted +Android Counter - Added blank slot selected -### Android Counter - All counters list +### Counter - Added blank slot selected -Android Counter - All counters list +Counter - Added blank slot selected -### Android Counter - All counters list with blank slot +### Android Counter - All but one deleted -Android Counter - All counters list with blank slot +Android Counter - All but one deleted -### Android Counter - App Settings open +### Counter - All but one deleted -Android Counter - App Settings open +Counter - All but one deleted -### Android Counter - App Settings sound and haptic on +### Android Counter - All counters list -Android Counter - App Settings sound and haptic on +Android Counter - All counters list -### Android Counter - Blank slot incremented +### Counter - All counters list -Android Counter - Blank slot incremented +Counter - All counters list ## Contributing diff --git a/store/playstore/README.md b/store/playstore/README.md index b0c50c0..ac5acea 100644 --- a/store/playstore/README.md +++ b/store/playstore/README.md @@ -107,7 +107,7 @@ These are decisions, not bugs. Do not "fix" them. - **`versionCode` must increase on every single upload**, including a re-upload to the same track, and can never be reused. This is the most common cause of a rejected Play upload. Local builds default to `1`; CI passes - `-PversionCodeOverride=` (see `.github/workflows/play-internal.yml`). + `-PversionCodeOverride=` (see `.github/workflows/play-release.yml`). - **Upload key** lives at `android/app/upload-keystore.jks` (git-ignored), with credentials in `android/keystore.properties` (git-ignored) or the `ANDROID_KEYSTORE_*` env vars. **Play App Signing** is enrolled, so this is @@ -128,7 +128,8 @@ These are decisions, not bugs. Do not "fix" them. - Fill the Play Console store listing from `listing.md` and upload the graphics above. -- Clear the App content declarations using `PLAY_CONSOLE_CHEATSHEET.md`. +- Clear the App content declarations using + [PLAY_CONSOLE_CHEATSHEET.md](PLAY_CONSOLE_CHEATSHEET.md). - **Closed testing gate:** a recently-created *personal* developer account must run a closed test with **≥12 testers for 14 continuous days** before production access is unlocked. This does not affect Internal testing. Confirm @@ -136,5 +137,8 @@ These are decisions, not bugs. Do not "fix" them. - Optionally upload the R8 deobfuscation mapping file (`android/app/build/outputs/mapping/release/mapping.txt`) so Play can symbolicate release crash reports. -- The privacy policy page mentions iCloud backups; consider making that line - OS-neutral (Android uses Google Auto Backup) for a public launch. + +The privacy policy at `https://codeyam.com/counter/privacy` is already +OS-neutral — the backup clause names both Apple and Google, so it reads +correctly for an Android reviewer. The page lives in `codeyam-ai/codeyam` +(`dashboard/app/routes/counter.privacy.tsx`), not this repo.