@amityco/social-plus-vise 0.14.17 → 0.14.18
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 +10 -0
- package/README.md +3 -3
- package/dist/capabilities.js +98 -0
- package/dist/outcomes.js +12 -3
- package/dist/productExpectations.js +81 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@ 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.18 — 2026-06-05
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- **Broader product-first rule surface:** feed target resolution, feed UI states, feed pagination, UGC moderation affordances, post status filtering, opaque pagination cursors, and server-synced unread counts now surface through shared product expectation IDs while preserving the exact platform `contractRuleId`/`validator.sensorId` evidence.
|
|
11
|
+
- **Capability feed-forward expansion:** the promoted feed/data expectations now participate in platform capability preflight where the bundled SDK surface proves support, so plans can show product-level expectations before implementation rather than only after `vise check`.
|
|
12
|
+
- **Validation checklist clarity:** add-feed, add-comments, and add-chat plans now use product-level expectation IDs for the promoted shared behaviors instead of exposing platform-specific validator names as the primary checklist items.
|
|
13
|
+
|
|
14
|
+
### Verified
|
|
15
|
+
- Focused CLI, fixture, MCP, product-flow, agent-flow, capability, native-idiom, and rule-coverage suites passed. A local iOS `whoops` plan smoke confirmed the broader product ids with iOS sensor evidence.
|
|
16
|
+
|
|
7
17
|
## 0.14.17 — 2026-06-05
|
|
8
18
|
|
|
9
19
|
### Changed
|
package/README.md
CHANGED
|
@@ -161,16 +161,16 @@ 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.
|
|
164
|
+
Version 0.14.18 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 `comments.thread-read-write` stay platform-agnostic while check results retain concrete `contractRuleId` and `validator.sensorId` evidence. |
|
|
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
172
|
| **Rule detection** | TP-track dashboard detects **311/311 seeded rule gaps (100.0%)** in the static corpus. |
|
|
173
|
-
| **Packed-package smoke** |
|
|
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
|
|
176
176
|
|
package/dist/capabilities.js
CHANGED
|
@@ -427,6 +427,104 @@ export const OPTIONAL_CAPABILITIES = [
|
|
|
427
427
|
},
|
|
428
428
|
];
|
|
429
429
|
export const SHARED_PRODUCT_EXPECTATIONS = [
|
|
430
|
+
{
|
|
431
|
+
id: "feed.target-resolved",
|
|
432
|
+
label: "Resolved feed target",
|
|
433
|
+
outcomes: ["add-feed"],
|
|
434
|
+
kind: "shared-expectation",
|
|
435
|
+
availability: [
|
|
436
|
+
{
|
|
437
|
+
label: "SDK feed target/query APIs",
|
|
438
|
+
symbols: [/\btargetId\b/i, /\btargetType\b/i, /\bgetUserFeed\b/i, /\bgetCommunityFeed\b/i, /\bgetGlobalFeed\b/i, /\bgetPosts\b/i, /\bqueryPosts\b/i],
|
|
439
|
+
},
|
|
440
|
+
],
|
|
441
|
+
deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
|
|
442
|
+
hint: "bind targetType and targetId to route params, auth context, or customer-owned selection state; do not invent literals",
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
id: "feed.ui-states-present",
|
|
446
|
+
label: "Feed loading/empty/error states",
|
|
447
|
+
outcomes: ["add-feed"],
|
|
448
|
+
kind: "shared-expectation",
|
|
449
|
+
availability: [
|
|
450
|
+
{
|
|
451
|
+
label: "SDK feed collection/query APIs",
|
|
452
|
+
symbols: [/\bgetUserFeed\b/i, /\bgetCommunityFeed\b/i, /\bgetGlobalFeed\b/i, /\bgetPosts\b/i, /\bqueryPosts\b/i],
|
|
453
|
+
},
|
|
454
|
+
],
|
|
455
|
+
deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
|
|
456
|
+
hint: "render loading, empty, error, and data states around the feed collection instead of only the success path",
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
id: "feed.pagination-wired",
|
|
460
|
+
label: "Feed pagination",
|
|
461
|
+
outcomes: ["add-feed"],
|
|
462
|
+
kind: "shared-expectation",
|
|
463
|
+
availability: [
|
|
464
|
+
{
|
|
465
|
+
label: "SDK pagination APIs",
|
|
466
|
+
symbols: [/\bnextPage\b/i, /\bnextPageToken\b/i, /\bloadMore\b/i, /\bonNextPage\b/i, /\bhasNext\b/i],
|
|
467
|
+
},
|
|
468
|
+
],
|
|
469
|
+
deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
|
|
470
|
+
hint: "wire load-more or automatic paging to the SDK collection; a fixed first page is incomplete",
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
id: "moderation.affordance-present",
|
|
474
|
+
label: "UGC moderation affordance",
|
|
475
|
+
outcomes: ["add-feed", "add-comments", "add-chat"],
|
|
476
|
+
kind: "shared-expectation",
|
|
477
|
+
availability: [
|
|
478
|
+
{
|
|
479
|
+
label: "SDK moderation/reporting APIs",
|
|
480
|
+
symbols: [/\bflagPost\b/i, /\bflagComment\b/i, /\bflagMessage\b/i, /\breport\b/i, /\bmoderation\b/i, /\bblockUser\b/i],
|
|
481
|
+
},
|
|
482
|
+
],
|
|
483
|
+
deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
|
|
484
|
+
hint: "show report/flag/block/hide affordances on user-generated content, scoped to the surface being built",
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
id: "posts.status-filtered",
|
|
488
|
+
label: "Post status filtering",
|
|
489
|
+
outcomes: ["add-feed"],
|
|
490
|
+
kind: "shared-expectation",
|
|
491
|
+
availability: [
|
|
492
|
+
{
|
|
493
|
+
label: "SDK post status/filter APIs",
|
|
494
|
+
symbols: [/\bstatus\b/i, /\bstatuses\b/i, /\bfeedType\b/i, /\bpublished\b/i, /\bincludeDeleted\b/i],
|
|
495
|
+
},
|
|
496
|
+
],
|
|
497
|
+
deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
|
|
498
|
+
hint: "filter post queries to published/non-deleted content so moderated or deleted posts do not leak into normal feeds",
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
id: "pagination.cursor-opaque",
|
|
502
|
+
label: "Opaque pagination cursors",
|
|
503
|
+
outcomes: ["add-feed", "add-comments", "add-chat"],
|
|
504
|
+
kind: "shared-expectation",
|
|
505
|
+
availability: [
|
|
506
|
+
{
|
|
507
|
+
label: "SDK cursor pagination APIs",
|
|
508
|
+
symbols: [/\bnextPage\b/i, /\bnextPageToken\b/i, /\bloadMore\b/i, /\bonNextPage\b/i, /\bhasNext\b/i],
|
|
509
|
+
},
|
|
510
|
+
],
|
|
511
|
+
deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
|
|
512
|
+
hint: "pass SDK-provided cursor tokens or call SDK next-page helpers; never compute numeric page offsets",
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
id: "unread.server-synced",
|
|
516
|
+
label: "Server-synced unread counts",
|
|
517
|
+
outcomes: ["add-feed", "add-chat"],
|
|
518
|
+
kind: "shared-expectation",
|
|
519
|
+
availability: [
|
|
520
|
+
{
|
|
521
|
+
label: "SDK unread state",
|
|
522
|
+
symbols: [/\bunreadCount\b/i, /\bChannelUnread\b/i, /\bobserveUserUnread\b/i, /\bgetUnread\w*\b/i, /\bgetTotalChannelUnread\b/i],
|
|
523
|
+
},
|
|
524
|
+
],
|
|
525
|
+
deterministicPlatforms: ["android", "flutter", "ios", "typescript"],
|
|
526
|
+
hint: "source unread badges from the SDK stream instead of counting stale local arrays",
|
|
527
|
+
},
|
|
430
528
|
{
|
|
431
529
|
id: "feed.rich-post-rendering",
|
|
432
530
|
label: "Rich post rendering",
|
package/dist/outcomes.js
CHANGED
|
@@ -653,7 +653,13 @@ const addFeed = {
|
|
|
653
653
|
validation: (platform) => [
|
|
654
654
|
"feed target identified",
|
|
655
655
|
"no invented communityId/targetId/feedId",
|
|
656
|
-
|
|
656
|
+
"feed.target-resolved",
|
|
657
|
+
"feed.ui-states-present",
|
|
658
|
+
"feed.pagination-wired",
|
|
659
|
+
"moderation.affordance-present",
|
|
660
|
+
"posts.status-filtered",
|
|
661
|
+
"pagination.cursor-opaque",
|
|
662
|
+
"unread.server-synced",
|
|
657
663
|
"feed.rich-post-rendering",
|
|
658
664
|
"feed.rich-post-composer-scope",
|
|
659
665
|
"comments.thread-read-write",
|
|
@@ -789,7 +795,8 @@ const addComments = {
|
|
|
789
795
|
"no invented postId/commentId",
|
|
790
796
|
`${platform}.comments.target-resolved`,
|
|
791
797
|
"comments.thread-read-write",
|
|
792
|
-
|
|
798
|
+
"moderation.affordance-present",
|
|
799
|
+
"pagination.cursor-opaque",
|
|
793
800
|
],
|
|
794
801
|
stopConditions: (ctx) => filterStops(ctx.answers, [
|
|
795
802
|
{ id: "comment_target", text: "The comment target entity is unknown; do not invent postId, commentId, or parent entity references." },
|
|
@@ -1021,7 +1028,9 @@ const addChat = {
|
|
|
1021
1028
|
`${platform}.chat.channel-target-resolved`,
|
|
1022
1029
|
`${platform}.chat.message-observer-cleanup`,
|
|
1023
1030
|
`${platform}.chat.send-error-handling`,
|
|
1024
|
-
|
|
1031
|
+
"moderation.affordance-present",
|
|
1032
|
+
"unread.server-synced",
|
|
1033
|
+
"pagination.cursor-opaque",
|
|
1025
1034
|
"chat.unread-visible",
|
|
1026
1035
|
...(platform === "android" || platform === "flutter" || platform === "ios" ? ["chat.message-order-explicit"] : []),
|
|
1027
1036
|
],
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
export const PRODUCT_EXPECTATION_TITLES = {
|
|
2
|
+
"feed.target-resolved": "Feed target comes from app state",
|
|
3
|
+
"feed.ui-states-present": "Feed renders loading, empty, and error states",
|
|
4
|
+
"feed.pagination-wired": "Feed pagination is wired",
|
|
5
|
+
"moderation.affordance-present": "UGC moderation affordance is present",
|
|
6
|
+
"posts.status-filtered": "Post queries filter unsafe statuses",
|
|
7
|
+
"pagination.cursor-opaque": "Pagination cursors stay opaque",
|
|
8
|
+
"unread.server-synced": "Unread counts use the server-synced stream",
|
|
2
9
|
"feed.rich-post-rendering": "Feed renders rich post types",
|
|
3
10
|
"feed.rich-post-composer-scope": "Feed composer surfaces rich post scope",
|
|
4
11
|
"comments.thread-read-write": "Comment threads support reading and creation",
|
|
@@ -6,7 +13,81 @@ export const PRODUCT_EXPECTATION_TITLES = {
|
|
|
6
13
|
"chat.message-order-explicit": "Chat message order is explicit",
|
|
7
14
|
"profile.social-counts": "Profile social counts come from the SDK",
|
|
8
15
|
};
|
|
16
|
+
const platformBindings = (expectationId, sensorsByPlatform) => Object.entries(sensorsByPlatform).flatMap(([platform, sensors]) => (Array.isArray(sensors) ? sensors : [sensors]).map((sensorId) => ({
|
|
17
|
+
expectationId,
|
|
18
|
+
sensorId,
|
|
19
|
+
platform,
|
|
20
|
+
})));
|
|
9
21
|
export const PRODUCT_EXPECTATION_BINDINGS = [
|
|
22
|
+
...platformBindings("feed.target-resolved", {
|
|
23
|
+
typescript: ["typescript.feed.target.literal", "typescript.feed.target-type-explicit"],
|
|
24
|
+
"react-native": ["react-native.feed.target.literal", "react-native.feed.target-type-explicit"],
|
|
25
|
+
android: ["android.feed.target.literal", "android.feed.target-type-explicit"],
|
|
26
|
+
flutter: ["flutter.feed.target.literal", "flutter.feed.target-type-explicit"],
|
|
27
|
+
ios: ["ios.feed.target.literal", "ios.feed.target-type-explicit"],
|
|
28
|
+
}),
|
|
29
|
+
...platformBindings("feed.ui-states-present", {
|
|
30
|
+
typescript: "typescript.feed.ui-states-present",
|
|
31
|
+
"react-native": "react-native.feed.ui-states-present",
|
|
32
|
+
android: "android.feed.ui-states-present",
|
|
33
|
+
flutter: "flutter.feed.ui-states-present",
|
|
34
|
+
ios: "ios.feed.ui-states-present",
|
|
35
|
+
}),
|
|
36
|
+
...platformBindings("feed.pagination-wired", {
|
|
37
|
+
typescript: "typescript.feed.pagination-wired",
|
|
38
|
+
"react-native": "react-native.feed.pagination-wired",
|
|
39
|
+
android: "android.feed.pagination-wired",
|
|
40
|
+
flutter: "flutter.feed.pagination-wired",
|
|
41
|
+
ios: "ios.feed.pagination-wired",
|
|
42
|
+
}),
|
|
43
|
+
...platformBindings("moderation.affordance-present", {
|
|
44
|
+
typescript: [
|
|
45
|
+
"typescript.feed.moderation-affordance-present",
|
|
46
|
+
"typescript.comments.moderation-affordance-present",
|
|
47
|
+
"typescript.chat.moderation-affordance-present",
|
|
48
|
+
],
|
|
49
|
+
"react-native": [
|
|
50
|
+
"react-native.feed.moderation-affordance-present",
|
|
51
|
+
"react-native.comments.moderation-affordance-present",
|
|
52
|
+
"react-native.chat.moderation-affordance-present",
|
|
53
|
+
],
|
|
54
|
+
android: [
|
|
55
|
+
"android.feed.moderation-affordance-present",
|
|
56
|
+
"android.comments.moderation-affordance-present",
|
|
57
|
+
"android.chat.moderation-affordance-present",
|
|
58
|
+
],
|
|
59
|
+
flutter: [
|
|
60
|
+
"flutter.feed.moderation-affordance-present",
|
|
61
|
+
"flutter.comments.moderation-affordance-present",
|
|
62
|
+
"flutter.chat.moderation-affordance-present",
|
|
63
|
+
],
|
|
64
|
+
ios: [
|
|
65
|
+
"ios.feed.moderation-affordance-present",
|
|
66
|
+
"ios.comments.moderation-affordance-present",
|
|
67
|
+
"ios.chat.moderation-affordance-present",
|
|
68
|
+
],
|
|
69
|
+
}),
|
|
70
|
+
...platformBindings("posts.status-filtered", {
|
|
71
|
+
typescript: "typescript.posts.status-filter-applied",
|
|
72
|
+
"react-native": "react-native.posts.status-filter-applied",
|
|
73
|
+
android: "android.posts.status-filter-applied",
|
|
74
|
+
flutter: "flutter.posts.status-filter-applied",
|
|
75
|
+
ios: "ios.posts.status-filter-applied",
|
|
76
|
+
}),
|
|
77
|
+
...platformBindings("pagination.cursor-opaque", {
|
|
78
|
+
typescript: "typescript.pagination.cursor-opaque",
|
|
79
|
+
"react-native": "react-native.pagination.cursor-opaque",
|
|
80
|
+
android: "android.pagination.cursor-opaque",
|
|
81
|
+
flutter: "flutter.pagination.cursor-opaque",
|
|
82
|
+
ios: "ios.pagination.cursor-opaque",
|
|
83
|
+
}),
|
|
84
|
+
...platformBindings("unread.server-synced", {
|
|
85
|
+
typescript: "typescript.unread.subscribed-not-counted",
|
|
86
|
+
"react-native": "react-native.unread.subscribed-not-counted",
|
|
87
|
+
android: "android.unread.subscribed-not-counted",
|
|
88
|
+
flutter: "flutter.unread.subscribed-not-counted",
|
|
89
|
+
ios: "ios.unread.subscribed-not-counted",
|
|
90
|
+
}),
|
|
10
91
|
{
|
|
11
92
|
expectationId: "feed.rich-post-rendering",
|
|
12
93
|
sensorId: "typescript.feed.post-datatype-handled",
|
package/package.json
CHANGED