@amityco/social-plus-vise 0.14.18 → 0.14.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,27 @@ All notable changes to `@amityco/social-plus-vise` are documented in this file.
4
4
 
5
5
  The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 0.14.20 — 2026-06-05
8
+
9
+ ### Changed
10
+ - **Product-first community/follow/notification flow:** community, follow/social-graph, and in-app notification plans now surface shared product expectation IDs before implementation, backed by platform capability preflight.
11
+ - **Community deterministic bindings:** community avatar, community display-name, and role-gated moderator action findings now report shared IDs (`community.avatar-from-sdk`, `community.display-name-from-sdk`, `moderation.role-gated-action`) while retaining exact platform `contractRuleId`/`validator.sensorId` evidence.
12
+ - **Attestation fallback for non-deterministic product expectations:** community target/live/privacy, follow target/live/model, and notification tray/seen/preferences expectations are offered when bundled SDK facts show the surface exists, with `attestation-needed` status until dedicated deterministic sensors exist.
13
+ - **Availability-aware notification guidance:** `vise plan` now withholds unavailable notification tray/mark-seen capabilities from Flutter while still surfacing notification preferences, and withholds notification preferences from TypeScript/React Native where bundled facts do not expose notification settings APIs.
14
+
15
+ ### Verified
16
+ - Full `npm run validate` passed, including package E2E and pack dry-run for `@amityco/social-plus-vise@0.14.20`. Product-flow now verifies community/follow/notification plan feed-forward, unavailable notification capability reporting, and exact Android sensor evidence for promoted community/moderation expectations.
17
+
18
+ ## 0.14.19 — 2026-06-05
19
+
20
+ ### Changed
21
+ - **Deeper product-first chat/comments surface:** comment target resolution, chat channel source, chat observer cleanup, chat send failure handling, chat channel shape, and TypeScript/React Native chat message ordering now surface through shared product expectation IDs while preserving exact platform `contractRuleId`/`validator.sensorId` evidence.
22
+ - **Capability feed-forward expansion:** chat plans now preflight the new product expectations against bundled SDK surface facts before implementation, so agents see product-level expectations such as `chat.channel-target-resolved`, `chat.message-observer-cleanup`, and `chat.send-error-handling`.
23
+ - **Validation checklist clarity:** add-comments and add-chat validation lists no longer expose platform-specific primary IDs for the promoted target/lifecycle/send/channel-shape checks.
24
+
25
+ ### Verified
26
+ - Focused capability, product-flow, native-idiom, CLI, MCP, compliance, and rule-coverage suites passed. Product-flow now verifies plan and check output for the new shared chat/comment IDs with Android/TypeScript contract evidence.
27
+
7
28
  ## 0.14.18 — 2026-06-05
8
29
 
9
30
  ### Changed
package/README.md CHANGED
@@ -161,15 +161,15 @@ Aggregate: **98/99 expected feed capabilities** and **27/27 selected optional ca
161
161
 
162
162
  ### Current Release Validation
163
163
 
164
- Version 0.14.18 carries current release proof around the full feed-forward, product-expectation, and validation flow:
164
+ Version 0.14.20 carries current release proof around the full feed-forward, product-expectation, and validation flow:
165
165
 
166
166
  | Surface | What was validated |
167
167
  |---|---|
168
168
  | **Product flow** | Local end-to-end smoke covers design extraction, plan feed-forward, blocking intake, answered init, capability check, design conformance, and sensor discovery. |
169
169
  | **Plan questions** | Plans surface blocking questions such as `feature_surface` and `design_contract_confirmation`, plus optional choices such as `feed_optional_capabilities`. |
170
170
  | **Capability-to-sensor flow** | Vise checks platform support, matches the prompt to available capabilities, offers supported features as questions, records answers, and turns selected answers into sensors in `vise check`. |
171
- | **Shared product expectations** | Public IDs such as `feed.target-resolved`, `moderation.affordance-present`, `comments.thread-read-write`, and `chat.unread-visible` stay platform-agnostic while check results retain concrete `contractRuleId` and `validator.sensorId` evidence. |
172
- | **Rule detection** | TP-track dashboard detects **311/311 seeded rule gaps (100.0%)** in the static corpus. |
171
+ | **Shared product expectations** | Public IDs such as `feed.target-resolved`, `comments.thread-read-write`, `chat.channel-target-resolved`, `community.avatar-from-sdk`, `community.display-name-from-sdk`, `moderation.role-gated-action`, `follow.relationship-live`, `profile.social-counts`, and `notifications.tray-live` stay platform-agnostic while check results retain concrete `contractRuleId` and `validator.sensorId` evidence when deterministic sensors exist. |
172
+ | **Rule detection** | TP-track dashboard detects **321/321 seeded rule gaps (100.0%)** in the static corpus. |
173
173
  | **Packed-package smoke** | Packed-package and host-agent smokes exercise the release tarball path, surfaced plan questions, selected optional capability sensors, rejected design confirmation handling, and exact contract-rule evidence for shared product expectations. |
174
174
 
175
175
  ### Supporting Proof
@@ -569,6 +569,20 @@ export const SHARED_PRODUCT_EXPECTATIONS = [
569
569
  deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
570
570
  hint: "implement the selected rich composer paths or record an explicit text-only/rich-post scope decision",
571
571
  },
572
+ {
573
+ id: "comments.target-resolved",
574
+ label: "Resolved comment target",
575
+ outcomes: ["add-comments"],
576
+ kind: "shared-expectation",
577
+ availability: [
578
+ {
579
+ label: "SDK comment target/query APIs",
580
+ symbols: [/\bgetComments\b/i, /\bqueryComments\b/i, /\bcreateComment\b/i, /\breferenceId\b/i, /\breferenceType\b/i],
581
+ },
582
+ ],
583
+ deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
584
+ hint: "pass the parent post/story/custom entity id from navigation, props, or app state; do not invent postId/commentId literals",
585
+ },
572
586
  {
573
587
  id: "comments.thread-read-write",
574
588
  label: "Comment thread read/write",
@@ -581,6 +595,62 @@ export const SHARED_PRODUCT_EXPECTATIONS = [
581
595
  deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
582
596
  hint: "if comments are shown, pair the list with a composer and loading/error/empty states unless the surface is explicitly read-only",
583
597
  },
598
+ {
599
+ id: "chat.channel-target-resolved",
600
+ label: "Resolved chat channel",
601
+ outcomes: ["add-chat"],
602
+ kind: "shared-expectation",
603
+ availability: [
604
+ {
605
+ label: "SDK channel query/create APIs",
606
+ symbols: [/\bChannelRepository\b/i, /\bgetChannels\b/i, /\bqueryChannels\b/i, /\bcreateChannel\b/i, /\bchannelId\b/i, /\bconversationId\b/i],
607
+ },
608
+ ],
609
+ deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
610
+ hint: "resolve channelId/conversationId from SDK queries, user selection, routing, or app-owned creation flow; do not hardcode it",
611
+ },
612
+ {
613
+ id: "chat.message-observer-cleanup",
614
+ label: "Chat message observer cleanup",
615
+ outcomes: ["add-chat"],
616
+ kind: "shared-expectation",
617
+ availability: [
618
+ {
619
+ label: "SDK message live query APIs",
620
+ symbols: [/\bMessageRepository\b/i, /\bgetMessages\b/i, /\bqueryMessages\b/i, /\bLiveCollection\b/i, /\bobserve\b/i, /\bsubscribe\b/i, /\bdispose\b/i, /\bunobserve\b/i],
621
+ },
622
+ ],
623
+ deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
624
+ hint: "clean up message live collections/subscriptions on component unmount, view dismissal, or lifecycle disposal",
625
+ },
626
+ {
627
+ id: "chat.send-error-handling",
628
+ label: "Chat send failure handling",
629
+ outcomes: ["add-chat"],
630
+ kind: "shared-expectation",
631
+ availability: [
632
+ {
633
+ label: "SDK message send/failure state APIs",
634
+ symbols: [/\bMessageRepository\b/i, /\bcreate\w*Message\b/i, /\bsendMessage\b/i, /\bsyncState\b/i, /\bdeleteFailedMessages\b/i],
635
+ },
636
+ ],
637
+ deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
638
+ hint: "surface failed sends with error state, retry/delete affordances, or SDK failure cleanup instead of assuming optimistic success",
639
+ },
640
+ {
641
+ id: "chat.channel-shape-matched",
642
+ label: "Chat channel shape",
643
+ outcomes: ["add-chat"],
644
+ kind: "shared-expectation",
645
+ availability: [
646
+ {
647
+ label: "SDK channel type APIs",
648
+ symbols: [/\bchannelType\b/i, /\bChannelType\b/i, /\bAmityChannelType\b/i, /\bconversation\b/i, /\bcommunity\b/i, /\bbroadcast\b/i],
649
+ },
650
+ ],
651
+ deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
652
+ hint: "match the SDK channel type to the selected chat shape: conversation for direct messages, community/group for shared channels, broadcast where applicable",
653
+ },
584
654
  {
585
655
  id: "chat.unread-visible",
586
656
  label: "Chat unread counts",
@@ -618,6 +688,132 @@ export const SHARED_PRODUCT_EXPECTATIONS = [
618
688
  deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
619
689
  hint: "declare first-created/newest-created order in the SDK query or a clearly named UI sort so the thread cannot be reversed by defaults",
620
690
  },
691
+ {
692
+ id: "community.target-resolved",
693
+ label: "Resolved community target",
694
+ outcomes: ["add-community"],
695
+ kind: "shared-expectation",
696
+ availability: [
697
+ {
698
+ label: "SDK community query/target APIs",
699
+ symbols: [/\bcommunityId\b/i, /\bCommunityRepository\b/i, /\bgetCommunity\b/i, /\bqueryCommunities\b/i, /\bgetCommunities\b/i, /\bAmityCommunity\b/i],
700
+ },
701
+ ],
702
+ deterministicPlatforms: [],
703
+ hint: "resolve communityId from route params, user selection, SDK query, or a create flow; do not invent or hardcode it",
704
+ },
705
+ {
706
+ id: "community.members-live",
707
+ label: "Live community/member lists",
708
+ outcomes: ["add-community"],
709
+ kind: "shared-expectation",
710
+ availability: [
711
+ {
712
+ label: "SDK community/member live APIs",
713
+ symbols: [/\bCommunityLiveCollection\b/i, /\bCommunityMemberLiveCollection\b/i, /\bgetMembers\b/i, /\bsearchMembers\b/i, /\bgetLiveCollection\b/i, /\blisten\b/i, /\bobserve\b/i],
714
+ },
715
+ ],
716
+ deterministicPlatforms: [],
717
+ hint: "query communities and members through the SDK live collection/listener idiom, with lifecycle cleanup",
718
+ },
719
+ {
720
+ id: "community.privacy-flow-explicit",
721
+ label: "Community privacy/join flow",
722
+ outcomes: ["add-community"],
723
+ kind: "shared-expectation",
724
+ availability: [
725
+ {
726
+ label: "SDK join/leave and join-request APIs",
727
+ symbols: [/\bjoinCommunity\b/i, /\bleaveCommunity\b/i, /\bjoinRequest\b/i, /\bJoinRequest\b/i, /\bCommunityType\b/i, /\bMembershipAcceptanceType\b/i],
728
+ },
729
+ ],
730
+ deterministicPlatforms: [],
731
+ hint: "handle public instant-join and private join-request states explicitly instead of assuming one community privacy model",
732
+ },
733
+ {
734
+ id: "community.avatar-from-sdk",
735
+ label: "Community avatar from SDK",
736
+ outcomes: ["add-feed", "add-comments", "add-community"],
737
+ kind: "shared-expectation",
738
+ availability: [
739
+ {
740
+ label: "SDK avatar fields/accessors",
741
+ symbols: [/\bAmityCommunity\b/i, /\bAmity\.Community\b/i, /\bavatar\b/i, /\bavatarImage\b/i, /\bgetAvatar\b/i, /\bfileUrl\b/i, /\bfileURL\b/i],
742
+ },
743
+ ],
744
+ deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
745
+ hint: "render the SDK avatar URL when present and fall back to initials only when no SDK avatar exists",
746
+ },
747
+ {
748
+ id: "community.display-name-from-sdk",
749
+ label: "Community display name from SDK",
750
+ outcomes: ["add-feed", "add-comments", "add-community"],
751
+ kind: "shared-expectation",
752
+ availability: [
753
+ {
754
+ label: "SDK community display name",
755
+ symbols: [/\bdisplayName\b/i, /\bgetDisplayName\b/i],
756
+ },
757
+ ],
758
+ deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
759
+ hint: "render community.displayName or the platform equivalent; do not show raw community IDs as names",
760
+ },
761
+ {
762
+ id: "moderation.role-gated-action",
763
+ label: "Role-gated moderator actions",
764
+ outcomes: ["add-community", "add-moderation"],
765
+ kind: "shared-expectation",
766
+ availability: [
767
+ {
768
+ label: "SDK role or member-moderation APIs",
769
+ symbols: [/\baddRole\b/i, /\bremoveRole\b/i, /\bbanMember\b/i, /\bremoveMember\b/i, /\broles?\b/i, /\bpermissions\b/i, /\bmoderation\b/i],
770
+ },
771
+ ],
772
+ deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
773
+ hint: "gate moderator-only role, ban, remove, mute, approve, or decline actions behind SDK role/permission state",
774
+ },
775
+ {
776
+ id: "follow.target-resolved",
777
+ label: "Resolved follow target",
778
+ outcomes: ["add-follow"],
779
+ kind: "shared-expectation",
780
+ availability: [
781
+ {
782
+ label: "SDK user relationship target APIs",
783
+ symbols: [/\buserId\b/i, /\btargetUserId\b/i, /\bUserRepository\b/i, /\bfollow\b/i, /\bunfollow\b/i, /\bgetFollowInfo\b/i],
784
+ },
785
+ ],
786
+ deterministicPlatforms: [],
787
+ hint: "resolve the target userId from route params, selected profile, or current user context; do not invent it",
788
+ },
789
+ {
790
+ id: "follow.relationship-live",
791
+ label: "Live follow relationship",
792
+ outcomes: ["add-follow"],
793
+ kind: "shared-expectation",
794
+ availability: [
795
+ {
796
+ label: "SDK follower/following live APIs",
797
+ symbols: [/\bFollowerLiveCollection\b/i, /\bFollowingLiveCollection\b/i, /\bgetFollowers\b/i, /\bgetFollowings\b/i, /\bgetLiveCollection\b/i, /\blisten\b/i, /\bonFollow/i],
798
+ },
799
+ ],
800
+ deterministicPlatforms: [],
801
+ hint: "keep follow state and follower/following lists live through SDK subscriptions or live collections, with cleanup",
802
+ },
803
+ {
804
+ id: "follow.model-explicit",
805
+ label: "Follow approval model",
806
+ outcomes: ["add-follow"],
807
+ kind: "shared-expectation",
808
+ availability: [
809
+ {
810
+ label: "SDK follow status/request APIs",
811
+ symbols: [/\bFollowStatus\b/i, /\bFollowStatusFilter\b/i, /\bpending\b/i, /\bacceptMyFollower\b/i, /\bdeclineMyFollower\b/i],
812
+ },
813
+ ],
814
+ deterministicPlatforms: [],
815
+ hint: "make automatic follow vs pending approval explicit, including accept/decline states where the SDK exposes them",
816
+ },
621
817
  {
622
818
  id: "profile.social-counts",
623
819
  label: "Profile follower/following counts",
@@ -639,6 +835,54 @@ export const SHARED_PRODUCT_EXPECTATIONS = [
639
835
  deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
640
836
  hint: "if follower/following labels are rendered, source the counts or lists from the SDK instead of placeholders",
641
837
  },
838
+ {
839
+ id: "notifications.tray-live",
840
+ label: "Live notification tray",
841
+ outcomes: ["add-notifications"],
842
+ kind: "shared-expectation",
843
+ availability: [
844
+ {
845
+ label: "SDK notification tray APIs",
846
+ symbols: [/\bnotificationTray\b/i, /\bNotificationTray\b/i, /\bgetNotificationTrayItems\b/i, /\bgetNotificationTraySeen\b/i],
847
+ },
848
+ ],
849
+ deterministicPlatforms: [],
850
+ hint: "observe the in-app notification tray/list or seen object through the SDK; do not treat it as push setup",
851
+ },
852
+ {
853
+ id: "notifications.mark-seen",
854
+ label: "Notification seen state",
855
+ outcomes: ["add-notifications"],
856
+ kind: "shared-expectation",
857
+ availability: [
858
+ {
859
+ label: "SDK tray seen/mark-seen APIs",
860
+ symbols: [/\bmarkTraySeen\b/i, /\bmarkItemsSeen\b/i, /\bmarkSeen\b/i, /\bNotificationTraySeen\b/i],
861
+ },
862
+ ],
863
+ deterministicPlatforms: [],
864
+ hint: "call the SDK mark-seen API so tray badges clear server-side after the user opens the notification surface",
865
+ },
866
+ {
867
+ id: "notifications.preferences-respected",
868
+ label: "Notification preferences",
869
+ outcomes: ["add-notifications"],
870
+ kind: "shared-expectation",
871
+ availability: [
872
+ {
873
+ label: "SDK notification settings/preferences APIs",
874
+ symbols: [
875
+ /\bAmity(?:Channel|Community|User)Notifications?Manager\.getSettings\b/i,
876
+ /\bAmity(?:Channel|Community|User)Notification\.getSettings\b/i,
877
+ /\bAmitySocialClient\.getSettings\b/i,
878
+ /\bnotificationRepository\.getSettings\b/i,
879
+ /\bnotifications\(\)\.getSettings\b/i,
880
+ ],
881
+ },
882
+ ],
883
+ deterministicPlatforms: [],
884
+ hint: "when settings are in scope, read or respect SDK notification preferences rather than showing hardcoded toggles",
885
+ },
642
886
  ];
643
887
  function availabilityDefinitionsFor(outcome) {
644
888
  return [
package/dist/outcomes.js CHANGED
@@ -793,7 +793,7 @@ const addComments = {
793
793
  validation: (platform) => [
794
794
  "comment target resolved",
795
795
  "no invented postId/commentId",
796
- `${platform}.comments.target-resolved`,
796
+ "comments.target-resolved",
797
797
  "comments.thread-read-write",
798
798
  "moderation.affordance-present",
799
799
  "pagination.cursor-opaque",
@@ -903,6 +903,7 @@ const addModeration = {
903
903
  `${platform}.moderation.block-or-mute-state-applied`,
904
904
  `${platform}.moderation.hidden-content-rendering-present`,
905
905
  `${platform}.moderation.confirmation-ux-present`,
906
+ "moderation.role-gated-action",
906
907
  ],
907
908
  stopConditions: (ctx) => filterStops(ctx.answers, [
908
909
  { id: "moderation_target", text: "The moderation target content types are unknown." },
@@ -1025,9 +1026,10 @@ const addChat = {
1025
1026
  ];
1026
1027
  },
1027
1028
  validation: (platform) => [
1028
- `${platform}.chat.channel-target-resolved`,
1029
- `${platform}.chat.message-observer-cleanup`,
1030
- `${platform}.chat.send-error-handling`,
1029
+ "chat.channel-target-resolved",
1030
+ "chat.message-observer-cleanup",
1031
+ "chat.send-error-handling",
1032
+ "chat.channel-shape-matched",
1031
1033
  "moderation.affordance-present",
1032
1034
  "unread.server-synced",
1033
1035
  "pagination.cursor-opaque",
@@ -1155,10 +1157,12 @@ const addCommunity = {
1155
1157
  ];
1156
1158
  },
1157
1159
  validation: () => [
1158
- "community membership uses a Live Collection (not a one-shot query)",
1159
- "join/leave handles public vs private (join-request) flows",
1160
- "no invented communityId",
1161
- "community/member observer cleaned up on lifecycle end",
1160
+ "community.target-resolved",
1161
+ "community.members-live",
1162
+ "community.privacy-flow-explicit",
1163
+ "community.avatar-from-sdk",
1164
+ "community.display-name-from-sdk",
1165
+ "moderation.role-gated-action",
1162
1166
  "validate_setup",
1163
1167
  "run_sensors",
1164
1168
  ],
@@ -1274,11 +1278,10 @@ const addFollow = {
1274
1278
  ];
1275
1279
  },
1276
1280
  validation: () => [
1277
- "follower/following lists use a Live Collection (not a one-shot query)",
1278
- "follow model handled (automatic vs follow-request approval)",
1281
+ "follow.target-resolved",
1282
+ "follow.relationship-live",
1283
+ "follow.model-explicit",
1279
1284
  "profile.social-counts",
1280
- "no invented userId",
1281
- "relationship observer cleaned up on lifecycle end",
1282
1285
  "validate_setup",
1283
1286
  "run_sensors",
1284
1287
  ],
@@ -1372,9 +1375,9 @@ const addNotifications = {
1372
1375
  ];
1373
1376
  },
1374
1377
  validation: () => [
1375
- "notification tray observed as a Live Object/Collection (not a one-shot query)",
1376
- "tray/items marked seen so the unseen count clears server-side",
1377
- "tray observer cleaned up on lifecycle end",
1378
+ "notifications.tray-live",
1379
+ "notifications.mark-seen",
1380
+ "notifications.preferences-respected",
1378
1381
  "this is in-app tray, not push setup",
1379
1382
  "validate_setup",
1380
1383
  "run_sensors",
@@ -8,10 +8,27 @@ export const PRODUCT_EXPECTATION_TITLES = {
8
8
  "unread.server-synced": "Unread counts use the server-synced stream",
9
9
  "feed.rich-post-rendering": "Feed renders rich post types",
10
10
  "feed.rich-post-composer-scope": "Feed composer surfaces rich post scope",
11
+ "comments.target-resolved": "Comment target comes from the parent entity",
11
12
  "comments.thread-read-write": "Comment threads support reading and creation",
13
+ "chat.channel-target-resolved": "Chat channel comes from app state",
14
+ "chat.message-observer-cleanup": "Chat message observers clean up on lifecycle end",
15
+ "chat.send-error-handling": "Chat send failures are handled",
16
+ "chat.channel-shape-matched": "Chat channel type matches the requested shape",
12
17
  "chat.unread-visible": "Chat unread counts are visible",
13
18
  "chat.message-order-explicit": "Chat message order is explicit",
19
+ "community.target-resolved": "Community target comes from app state",
20
+ "community.members-live": "Community and member lists stay live",
21
+ "community.privacy-flow-explicit": "Community privacy flow is explicit",
22
+ "community.avatar-from-sdk": "Community avatars come from the SDK",
23
+ "community.display-name-from-sdk": "Community display names come from the SDK",
24
+ "moderation.role-gated-action": "Moderator-only actions are role gated",
25
+ "follow.target-resolved": "Follow target comes from app state",
26
+ "follow.relationship-live": "Follow relationships stay live",
27
+ "follow.model-explicit": "Follow approval model is explicit",
14
28
  "profile.social-counts": "Profile social counts come from the SDK",
29
+ "notifications.tray-live": "Notification tray is observed live",
30
+ "notifications.mark-seen": "Notification seen state clears server-side",
31
+ "notifications.preferences-respected": "Notification preferences are respected",
15
32
  };
16
33
  const platformBindings = (expectationId, sensorsByPlatform) => Object.entries(sensorsByPlatform).flatMap(([platform, sensors]) => (Array.isArray(sensors) ? sensors : [sensors]).map((sensorId) => ({
17
34
  expectationId,
@@ -163,6 +180,13 @@ export const PRODUCT_EXPECTATION_BINDINGS = [
163
180
  sensorId: "ios.feed.rich-post-composer-surfaced",
164
181
  platform: "ios",
165
182
  },
183
+ ...platformBindings("comments.target-resolved", {
184
+ typescript: "typescript.comments.target-resolved",
185
+ "react-native": "react-native.comments.target-resolved",
186
+ android: "android.comments.target-resolved",
187
+ flutter: "flutter.comments.target-resolved",
188
+ ios: "ios.comments.target-resolved",
189
+ }),
166
190
  {
167
191
  expectationId: "comments.thread-read-write",
168
192
  sensorId: "typescript.comments.query-has-limit",
@@ -268,6 +292,34 @@ export const PRODUCT_EXPECTATION_BINDINGS = [
268
292
  sensorId: "ios.comments.ui-states-present",
269
293
  platform: "ios",
270
294
  },
295
+ ...platformBindings("chat.channel-target-resolved", {
296
+ typescript: "typescript.chat.channel-target-resolved",
297
+ "react-native": "react-native.chat.channel-target-resolved",
298
+ android: "android.chat.channel-target-resolved",
299
+ flutter: "flutter.chat.channel-target-resolved",
300
+ ios: "ios.chat.channel-target-resolved",
301
+ }),
302
+ ...platformBindings("chat.message-observer-cleanup", {
303
+ typescript: "typescript.chat.message-observer-cleanup",
304
+ "react-native": "react-native.chat.message-observer-cleanup",
305
+ android: "android.chat.message-observer-cleanup",
306
+ flutter: "flutter.chat.message-observer-cleanup",
307
+ ios: "ios.chat.message-observer-cleanup",
308
+ }),
309
+ ...platformBindings("chat.send-error-handling", {
310
+ typescript: "typescript.chat.send-error-handling",
311
+ "react-native": "react-native.chat.send-error-handling",
312
+ android: "android.chat.send-error-handling",
313
+ flutter: "flutter.chat.send-error-handling",
314
+ ios: "ios.chat.send-error-handling",
315
+ }),
316
+ ...platformBindings("chat.channel-shape-matched", {
317
+ typescript: ["typescript.channel.type-matches-shape", "typescript.chat.channel-type-dm"],
318
+ "react-native": ["react-native.channel.type-matches-shape", "react-native.chat.channel-type-dm"],
319
+ android: "android.channel.type-matches-shape",
320
+ flutter: "flutter.channel.type-matches-shape",
321
+ ios: "ios.channel.type-matches-shape",
322
+ }),
271
323
  {
272
324
  expectationId: "chat.unread-visible",
273
325
  sensorId: "typescript.chat.unread-visible",
@@ -293,6 +345,16 @@ export const PRODUCT_EXPECTATION_BINDINGS = [
293
345
  sensorId: "ios.chat.unread-visible",
294
346
  platform: "ios",
295
347
  },
348
+ {
349
+ expectationId: "chat.message-order-explicit",
350
+ sensorId: "typescript.chat.sort-explicit",
351
+ platform: "typescript",
352
+ },
353
+ {
354
+ expectationId: "chat.message-order-explicit",
355
+ sensorId: "react-native.chat.sort-explicit",
356
+ platform: "react-native",
357
+ },
296
358
  {
297
359
  expectationId: "chat.message-order-explicit",
298
360
  sensorId: "android.chat.sort-explicit",
@@ -308,6 +370,27 @@ export const PRODUCT_EXPECTATION_BINDINGS = [
308
370
  sensorId: "ios.chat.sort-explicit",
309
371
  platform: "ios",
310
372
  },
373
+ ...platformBindings("community.avatar-from-sdk", {
374
+ typescript: "typescript.community.avatar-from-sdk",
375
+ "react-native": "react-native.community.avatar-from-sdk",
376
+ android: "android.community.avatar-from-sdk",
377
+ flutter: "flutter.community.avatar-from-sdk",
378
+ ios: "ios.community.avatar-from-sdk",
379
+ }),
380
+ ...platformBindings("community.display-name-from-sdk", {
381
+ typescript: "typescript.community.display-name-from-sdk",
382
+ "react-native": "react-native.community.display-name-from-sdk",
383
+ android: "android.community.display-name-from-sdk",
384
+ flutter: "flutter.community.display-name-from-sdk",
385
+ ios: "ios.community.display-name-from-sdk",
386
+ }),
387
+ ...platformBindings("moderation.role-gated-action", {
388
+ typescript: "typescript.moderation.role-gated-action",
389
+ "react-native": "react-native.moderation.role-gated-action",
390
+ android: "android.moderation.role-gated-action",
391
+ flutter: "flutter.moderation.role-gated-action",
392
+ ios: "ios.moderation.role-gated-action",
393
+ }),
311
394
  {
312
395
  expectationId: "profile.social-counts",
313
396
  sensorId: "typescript.profile.social-counts-from-sdk",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amityco/social-plus-vise",
3
- "version": "0.14.18",
3
+ "version": "0.14.20",
4
4
  "description": "Skill-guided deterministic CLI for social.plus SDK integration assistance.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
package/rules/feed.yaml CHANGED
@@ -2595,6 +2595,7 @@
2595
2595
  "outcomes": [
2596
2596
  "add-feed",
2597
2597
  "add-comments",
2598
+ "add-community",
2598
2599
  "validate-setup"
2599
2600
  ]
2600
2601
  },
@@ -2632,6 +2633,7 @@
2632
2633
  "outcomes": [
2633
2634
  "add-feed",
2634
2635
  "add-comments",
2636
+ "add-community",
2635
2637
  "validate-setup"
2636
2638
  ]
2637
2639
  },
@@ -2669,6 +2671,7 @@
2669
2671
  "outcomes": [
2670
2672
  "add-feed",
2671
2673
  "add-comments",
2674
+ "add-community",
2672
2675
  "validate-setup"
2673
2676
  ]
2674
2677
  },
@@ -2706,6 +2709,7 @@
2706
2709
  "outcomes": [
2707
2710
  "add-feed",
2708
2711
  "add-comments",
2712
+ "add-community",
2709
2713
  "validate-setup"
2710
2714
  ]
2711
2715
  },
@@ -2743,6 +2747,7 @@
2743
2747
  "outcomes": [
2744
2748
  "add-feed",
2745
2749
  "add-comments",
2750
+ "add-community",
2746
2751
  "validate-setup"
2747
2752
  ]
2748
2753
  },
@@ -2837,7 +2842,7 @@
2837
2842
  "rationale": "Using a raw communityId as a displayName fallback (e.g. when passing only the ID in navigation state) shows a UUID to users instead of the community's actual name.",
2838
2843
  "applies_when": {
2839
2844
  "platforms": ["typescript"],
2840
- "outcomes": ["add-feed", "add-comments", "validate-setup"]
2845
+ "outcomes": ["add-feed", "add-comments", "add-community", "validate-setup"]
2841
2846
  },
2842
2847
  "enforcement": {
2843
2848
  "deterministic": [
@@ -2961,7 +2966,7 @@
2961
2966
  "rationale": "Using a raw communityId as a displayName fallback (e.g. when passing only the ID in navigation state) shows a UUID to users instead of the community's actual name.",
2962
2967
  "applies_when": {
2963
2968
  "platforms": ["react-native"],
2964
- "outcomes": ["add-feed", "add-comments", "validate-setup"]
2969
+ "outcomes": ["add-feed", "add-comments", "add-community", "validate-setup"]
2965
2970
  },
2966
2971
  "enforcement": {
2967
2972
  "deterministic": [
@@ -3085,7 +3090,7 @@
3085
3090
  "rationale": "Using a raw communityId as a displayName fallback (e.g. when passing only the ID in navigation state) shows a UUID to users instead of the community's actual name.",
3086
3091
  "applies_when": {
3087
3092
  "platforms": ["flutter"],
3088
- "outcomes": ["add-feed", "add-comments", "validate-setup"]
3093
+ "outcomes": ["add-feed", "add-comments", "add-community", "validate-setup"]
3089
3094
  },
3090
3095
  "enforcement": {
3091
3096
  "deterministic": [
@@ -3178,7 +3183,7 @@
3178
3183
  "rationale": "Using a raw communityId as a displayName fallback (e.g. when passing only the ID in navigation state) shows a UUID to users instead of the community's actual name.",
3179
3184
  "applies_when": {
3180
3185
  "platforms": ["ios"],
3181
- "outcomes": ["add-feed", "add-comments", "validate-setup"]
3186
+ "outcomes": ["add-feed", "add-comments", "add-community", "validate-setup"]
3182
3187
  },
3183
3188
  "enforcement": {
3184
3189
  "deterministic": [
@@ -3302,7 +3307,7 @@
3302
3307
  "rationale": "Using a raw communityId as a displayName fallback (e.g. when passing only the ID in navigation state) shows a UUID to users instead of the community's actual name.",
3303
3308
  "applies_when": {
3304
3309
  "platforms": ["android"],
3305
- "outcomes": ["add-feed", "add-comments", "validate-setup"]
3310
+ "outcomes": ["add-feed", "add-comments", "add-community", "validate-setup"]
3306
3311
  },
3307
3312
  "enforcement": {
3308
3313
  "deterministic": [
@@ -733,6 +733,7 @@
733
733
  "typescript"
734
734
  ],
735
735
  "outcomes": [
736
+ "add-community",
736
737
  "add-moderation",
737
738
  "validate-setup"
738
739
  ]
@@ -769,6 +770,7 @@
769
770
  "react-native"
770
771
  ],
771
772
  "outcomes": [
773
+ "add-community",
772
774
  "add-moderation",
773
775
  "validate-setup"
774
776
  ]
@@ -805,6 +807,7 @@
805
807
  "android"
806
808
  ],
807
809
  "outcomes": [
810
+ "add-community",
808
811
  "add-moderation",
809
812
  "validate-setup"
810
813
  ]
@@ -841,6 +844,7 @@
841
844
  "flutter"
842
845
  ],
843
846
  "outcomes": [
847
+ "add-community",
844
848
  "add-moderation",
845
849
  "validate-setup"
846
850
  ]
@@ -877,6 +881,7 @@
877
881
  "ios"
878
882
  ],
879
883
  "outcomes": [
884
+ "add-community",
880
885
  "add-moderation",
881
886
  "validate-setup"
882
887
  ]