@amityco/social-plus-vise 1.4.6 → 1.5.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amityco/social-plus-vise",
3
- "version": "1.4.6",
3
+ "version": "1.5.0",
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
@@ -68,6 +68,28 @@
68
68
  }
69
69
  }
70
70
  },
71
+ {
72
+ "id": "ios.feed.source-used",
73
+ "version": 1,
74
+ "title": "iOS feed integration must use SDK post APIs",
75
+ "severity": "warning",
76
+ "rationale": "A community/profile-only SDK integration is not an add-feed implementation. Feed surfaces must query or create SDK posts and render SDK post data.",
77
+ "applies_when": {
78
+ "platforms": ["ios"],
79
+ "outcomes": ["add-feed", "validate-setup"]
80
+ },
81
+ "enforcement": {
82
+ "deterministic": [
83
+ { "check": "validator-finding-absent", "finding_rule_id": "ios.feed.source-used" }
84
+ ],
85
+ "attestation": {
86
+ "allowed": false,
87
+ "host_agent_min_confidence": "high",
88
+ "human_allowed": false,
89
+ "evidence_required": []
90
+ }
91
+ }
92
+ },
71
93
  {
72
94
  "id": "typescript.feed.target.literal",
73
95
  "version": 1,
@@ -1547,9 +1569,9 @@
1547
1569
  "id": "typescript.feed.target-type-explicit",
1548
1570
  "version": 1,
1549
1571
  "symbol_anchored": {"platform":"typescript","basis":"pattern"},
1550
- "title": "Explicit targetType for TypeScript createPost calls must not be hardcoded to COMMUNITY",
1572
+ "title": "TypeScript createPost targetType must be a valid, bound write target",
1551
1573
  "severity": "warning",
1552
- "rationale": "TypeScript feed targets must be passed dynamically (e.g. from props or state), not hardcoded as AmityPostTargetType.COMMUNITY.",
1574
+ "rationale": "TypeScript createPost targets must resolve to a valid SDK write target (user or community) with a targetId from props/state/auth/route, never a global aggregate feed target.",
1553
1575
  "applies_when": {
1554
1576
  "platforms": [
1555
1577
  "typescript"
@@ -1573,7 +1595,7 @@
1573
1595
  "evidence_required": [
1574
1596
  {
1575
1597
  "field": "target_type_rationale",
1576
- "description": "Reason why this composer is hardcoded to a specific target type.",
1598
+ "description": "Reason why this composer uses this targetType/targetId binding.",
1577
1599
  "upload_policy": "upload-with-consent"
1578
1600
  }
1579
1601
  ]
@@ -1584,9 +1606,9 @@
1584
1606
  "id": "react-native.feed.target-type-explicit",
1585
1607
  "version": 1,
1586
1608
  "symbol_anchored": {"platform":"react-native","basis":"pattern"},
1587
- "title": "Explicit targetType for React Native createPost calls must not be hardcoded to COMMUNITY",
1609
+ "title": "React Native createPost targetType must be a valid, bound write target",
1588
1610
  "severity": "warning",
1589
- "rationale": "React Native feed targets must be passed dynamically (e.g. from props or state), not hardcoded as AmityPostTargetType.COMMUNITY.",
1611
+ "rationale": "React Native createPost targets must resolve to a valid SDK write target (user or community) with a targetId from props/state/auth/route, never a global aggregate feed target.",
1590
1612
  "applies_when": {
1591
1613
  "platforms": [
1592
1614
  "react-native"
@@ -1610,7 +1632,7 @@
1610
1632
  "evidence_required": [
1611
1633
  {
1612
1634
  "field": "target_type_rationale",
1613
- "description": "Reason why this composer is hardcoded to a specific target type.",
1635
+ "description": "Reason why this composer uses this targetType/targetId binding.",
1614
1636
  "upload_policy": "upload-with-consent"
1615
1637
  }
1616
1638
  ]
@@ -1621,9 +1643,9 @@
1621
1643
  "id": "android.feed.target-type-explicit",
1622
1644
  "version": 1,
1623
1645
  "symbol_anchored": {"platform":"android","basis":"pattern"},
1624
- "title": "Explicit targetType for Android createPost calls must not be hardcoded to COMMUNITY",
1646
+ "title": "Android createPost targetType must be a valid, bound write target",
1625
1647
  "severity": "warning",
1626
- "rationale": "Android feed targets must be passed dynamically (e.g. from Intent extras or ViewModel state), not hardcoded as AmityPostTargetType.COMMUNITY.",
1648
+ "rationale": "Android createPost targets must resolve to a valid SDK write target (user or community) with a targetId from Intent extras/ViewModel/auth/route state, never a global aggregate feed target.",
1627
1649
  "applies_when": {
1628
1650
  "platforms": [
1629
1651
  "android"
@@ -1647,7 +1669,7 @@
1647
1669
  "evidence_required": [
1648
1670
  {
1649
1671
  "field": "target_type_rationale",
1650
- "description": "Reason why this composer is hardcoded to a specific target type.",
1672
+ "description": "Reason why this composer uses this targetType/targetId binding.",
1651
1673
  "upload_policy": "upload-with-consent"
1652
1674
  }
1653
1675
  ]
@@ -1658,9 +1680,9 @@
1658
1680
  "id": "flutter.feed.target-type-explicit",
1659
1681
  "version": 1,
1660
1682
  "symbol_anchored": {"platform":"flutter","types":["AmityPostTargetType"],"basis":"names-only"},
1661
- "title": "Explicit targetType for Flutter createPost calls must not be hardcoded to COMMUNITY",
1683
+ "title": "Flutter createPost targetType must be a valid, bound write target",
1662
1684
  "severity": "warning",
1663
- "rationale": "Flutter feed targets must be passed dynamically (e.g. from Widget properties), not hardcoded as AmityPostTargetType.COMMUNITY.",
1685
+ "rationale": "Flutter createPost targets must resolve to a valid SDK write target (user or community) with a targetId from Widget/auth/route state, never a global aggregate feed target.",
1664
1686
  "applies_when": {
1665
1687
  "platforms": [
1666
1688
  "flutter"
@@ -1684,7 +1706,7 @@
1684
1706
  "evidence_required": [
1685
1707
  {
1686
1708
  "field": "target_type_rationale",
1687
- "description": "Reason why this composer is hardcoded to a specific target type.",
1709
+ "description": "Reason why this composer uses this targetType/targetId binding.",
1688
1710
  "upload_policy": "upload-with-consent"
1689
1711
  }
1690
1712
  ]
@@ -1695,9 +1717,9 @@
1695
1717
  "id": "ios.feed.target-type-explicit",
1696
1718
  "version": 1,
1697
1719
  "symbol_anchored": {"platform":"ios","types":["AmityPostTargetType"],"basis":"names-only"},
1698
- "title": "Explicit targetType for iOS createPost calls must not be hardcoded to COMMUNITY",
1720
+ "title": "iOS createPost targetType must be a valid, bound write target",
1699
1721
  "severity": "warning",
1700
- "rationale": "iOS feed targets must be passed dynamically (e.g. from View state or initializer), not hardcoded as AmityPostTargetType.community.",
1722
+ "rationale": "iOS createPost targets must resolve to a valid SDK write target (user or community) with a targetId from view/auth/route state, never a global aggregate feed target.",
1701
1723
  "applies_when": {
1702
1724
  "platforms": [
1703
1725
  "ios"
@@ -1721,7 +1743,7 @@
1721
1743
  "evidence_required": [
1722
1744
  {
1723
1745
  "field": "target_type_rationale",
1724
- "description": "Reason why this composer is hardcoded to a specific target type.",
1746
+ "description": "Reason why this composer uses this targetType/targetId binding.",
1725
1747
  "upload_policy": "upload-with-consent"
1726
1748
  }
1727
1749
  ]
@@ -524,7 +524,8 @@
524
524
  "human_allowed": false,
525
525
  "evidence_required": []
526
526
  }
527
- }
527
+ },
528
+ "symptoms": ["notLoggedIn", "NOT_LOGGED_IN", "session is not established", "session not ready", "user is not logged in", "SessionState"]
528
529
  },
529
530
  {
530
531
  "id": "flutter.live-collection.session-ready-requery",
@@ -546,7 +547,8 @@
546
547
  "human_allowed": false,
547
548
  "evidence_required": []
548
549
  }
549
- }
550
+ },
551
+ "symptoms": ["notLoggedIn", "NOT_LOGGED_IN", "session is not established", "session not ready", "user is not logged in", "SessionState"]
550
552
  },
551
553
  {
552
554
  "id": "ios.live-collection.session-ready-requery",
@@ -568,7 +570,8 @@
568
570
  "human_allowed": false,
569
571
  "evidence_required": []
570
572
  }
571
- }
573
+ },
574
+ "symptoms": ["notLoggedIn", "NOT_LOGGED_IN", "session is not established", "session not ready", "user is not logged in", "SessionState"]
572
575
  },
573
576
  {
574
577
  "id": "typescript.live-collection.session-ready-requery",
@@ -590,7 +593,8 @@
590
593
  "human_allowed": false,
591
594
  "evidence_required": []
592
595
  }
593
- }
596
+ },
597
+ "symptoms": ["notLoggedIn", "NOT_LOGGED_IN", "session is not established", "session not ready", "user is not logged in", "SessionState"]
594
598
  },
595
599
  {
596
600
  "id": "react-native.live-collection.session-ready-requery",
@@ -612,7 +616,8 @@
612
616
  "human_allowed": false,
613
617
  "evidence_required": []
614
618
  }
615
- }
619
+ },
620
+ "symptoms": ["notLoggedIn", "NOT_LOGGED_IN", "session is not established", "session not ready", "user is not logged in", "SessionState"]
616
621
  }
617
622
  ]
618
623
  }
@@ -2323,6 +2323,29 @@
2323
2323
  },
2324
2324
  "symptoms": ["Dependency-only integration", "Static social shell", "No SDK-backed runtime data"]
2325
2325
  },
2326
+ {
2327
+ "id": "ios.sdk.source-used",
2328
+ "version": 1,
2329
+ "title": "iOS SDK dependency must be used by product source",
2330
+ "severity": "warning",
2331
+ "rationale": "Installing the iOS social.plus SDK is not an integration. Product Swift source must use the SDK or UIKit manager beyond static initialization: login/register a runtime user and query or create social.plus data.",
2332
+ "applies_when": {
2333
+ "platforms": ["ios"],
2334
+ "outcomes": ["setup-sdk", "setup-live-data", "add-feed", "add-comments", "add-chat", "add-community", "add-follow", "validate-setup"]
2335
+ },
2336
+ "enforcement": {
2337
+ "deterministic": [
2338
+ { "check": "validator-finding-absent", "finding_rule_id": "ios.sdk.source-used" }
2339
+ ],
2340
+ "attestation": {
2341
+ "allowed": false,
2342
+ "host_agent_min_confidence": "high",
2343
+ "human_allowed": false,
2344
+ "evidence_required": []
2345
+ }
2346
+ },
2347
+ "symptoms": ["Dependency-only integration", "Static social shell", "No SDK-backed runtime data"]
2348
+ },
2326
2349
  {
2327
2350
  "id": "react-native.ui.runtime-probe-copy",
2328
2351
  "version": 1,
@@ -19,9 +19,11 @@ vise plan . --request "<user intent>"
19
19
  vise init . --request "<user intent>"
20
20
  ```
21
21
 
22
+ **This 3-step order is the single-surface path.** For a **broad / multi-surface / experience** request, `vise init` will *refuse* until the blueprint is signed off (exit 7) — so the real order there is `inspect → plan → creative → creative accept → workplan next` (sign the blueprint) `→ init` per surface. Do not treat the exit-7 refusal from `vise init` as an error: it means "run the workplan/blueprint gate first." The full multi-surface sequence is under "Blueprint sign-off" below; if you are unsure which path you are on, run `vise plan` and check for a `socialWorkplan` (multi-surface) or an `experienceHint` (a single-outcome request that likely wants expansion — run `vise creative`).
23
+
22
24
  For a **feed / community / experience** request, also run `vise creative . --request "<user intent>"` (the advisory Engagement Intelligence layer) before building — it surfaces engagement options (post types, polls, reactions, discovery/achievement loops) that `vise plan` only lists tersely under `optionalCapabilities` / `engagement`. Advisory, never a gate — full guidance under "Creative pre-planning" below.
23
25
 
24
- **You own the goal→experience inference; EI is advisory data, not a decider.** `vise plan`'s automatic `socialWorkplan` expansion is a deterministic *convenience* that fires only on explicit experience **vocabulary** ("community feed", "direct messaging", "discussion forum", "creator platform") — it will **not** expand a goal phrased in natural product language ("let runners form local clubs and share their weekend routes", "buyers and sellers negotiate a sale privately", "users ask questions and get threaded answers"). So when the goal is experience-shaped but `vise plan` returns **no** `socialWorkplan`, do not conclude there is no fuller experience: run `vise creative . --request "<goal>"`, read its `candidateSolutions` as the advisory **menu** of experiences, and **infer which one fits the user's intent yourself** — mapping a fuzzy goal to an experience is your job (you are the inferential layer), not a keyword match (`creative`'s ranking is advisory; the *right* candidate is often in the set but not ranked first).
26
+ **You own the goal→experience inference; EI is advisory data, not a decider.** Multi-surface `socialWorkplan` expansion is driven by an accepted EI selection, not raw request keyword matching. If the goal is experience-shaped, run `vise creative . --request "<goal>"`, read its `candidateSolutions` as the advisory **menu** of experiences, and **infer which one fits the user's intent yourself** — mapping a fuzzy goal to an experience is your job (you are the inferential layer), not a keyword match (`creative`'s ranking is advisory; the *right* candidate is often in the set but not ranked first). Then accept the chosen variant so `vise workplan` and the blueprint gate have a concrete companion-surface sequence to govern. Never treat `vise plan` returning no `socialWorkplan` before `creative accept` as proof that no fuller experience applies.
25
27
 
26
28
  Before accepting a variant, **show the EI choice explicitly**. Do not compress this step into one sentence like "community-first is best." Present a compact decision block with:
27
29
  - recommended experience and 2-3 concrete request/project signals that make it fit;
@@ -77,7 +79,7 @@ renders feed, composer, comments, reactions, profile/follow, moderation, or chat
77
79
  - If data is absent, ask whether to prepare it in Console or create safe seed data through SDK functions before judging the integration. If they decline, say that only static checks / resolved empty states can be claimed, not populated product proof.
78
80
  - When safe SDK seed data is created, keep the returned community/feed/post/comment objects in runtime state or wait for a confirmed re-query/live-collection update before final handoff. A default path that still shows `0 posts`, `syncing`, `waiting on content`, create/prepare failure copy, or only disabled affordances is not populated runtime proof. If the exact product-context target cannot be created or populated because of tenant permissions or review mode, fall back to the nearest discovered readable target with visible posts/messages/users and map it back into the product context with honest copy. Do not silently swallow seed/query errors; record failures in handoff notes and show a product-native retry/error state.
79
81
  - Do not dump arbitrary readable tenant data into product UI just because discovery returned it. Filter discovered communities/users/channels by product context, or create a product-native seed target. Names/descriptions that are raw IDs, numeric-only labels, short random strings such as `rand2`, lorem/test data, `sampleapp` fixtures, or unrelated generated business copy are not natural targets; hide or skip them and keep searching/seeding before claiming runtime proof. Prefer a product-owned namespace/allowlist such as app-created names, metadata tags, session/program identifiers, or cached IDs returned by the app's own create flow; if the SDK query returns mixed tenant data, render only product-safe matches and never let an unsafe target become the active selected context. Deduplicate discovered/seeded targets by stable SDK ID or normalized product label, and prioritize populated product-owned targets before empty clones; a long rail of repeated zero-post targets is not polished populated proof. Do not rewrite unsafe tenant labels into product copy to make them look acceptable — exclude the object. Apply this filtering to every visible rail/list/card and author fallback, not only the selected target.
80
- - Runtime proof can consume browser/simulator/emulator/device resources and additional agent tokens. Ask the user before running it; if they decline, explain the remaining runtime risks instead of claiming the app was proven at runtime.
82
+ - Runtime proof can consume browser/simulator/emulator/device resources and additional agent tokens. Ask the user before running it; if they decline, explain the remaining runtime risks instead of claiming the app was proven at runtime. **Precedence (resolves the apparent conflict with "Pre-authorized dogfood/benchmark sign-off" above):** the "ask first" rule is the default for an interactive session. A dogfood/benchmark prompt that *explicitly* grants runtime-proof consent (per that clause) IS the user's answer — do not re-ask in that run. If consent was neither given interactively nor explicitly in the prompt, do not run device/browser proof: proceed with static checks and say so. Never infer consent from silence.
81
83
  - Record the expected smoke level: use `populated` for data-backed surfaces where empty screens are not product proof, and `resolved` only where an empty state is legitimate.
82
84
  - Never delete a runnable entry file such as `App.tsx`, `lib/main.dart`, or the app's root view as a standalone step while preparing a replacement. Edit it in place, or add/import a new child component/widget first, so interruptions and failed patches do not leave the project without an entry point.
83
85
  - Record runtime readiness/proof status in evidence files, screenshots, or handoff notes — not as end-user product UI. Do not ship visible `CLIENT`, `SESSION`, `RUNTIME`, SDK, env-var, region, setup, readiness-debug labels, runtime/probe/status panels, or hidden no-op controls just to prove the app connected; the normal screen should express the product state naturally.
@@ -85,7 +87,7 @@ renders feed, composer, comments, reactions, profile/follow, moderation, or chat
85
87
  - A repository query that stores SDK objects in state but never renders or passes that state into a visible widget/component is a hidden no-op, not runtime proof. The first social surface must consume SDK-returned communities/posts/comments/users in the actual product tree; returning the original screen after setup/login is still a failed integration.
86
88
  - Native runtime proof must make the core social loop visibly reachable. Do not spend the whole first viewport on intro, hero, or community chrome while feed/composer/comment/reaction/report/profile surfaces are buried below an unverified scroll. For Flutter and React Native dogfood, keep at least one SDK-backed feed item and key actions visible in the initial route, or expose them through obvious product tabs/buttons that screenshots can capture; automated text/tap probes may not see Flutter/RN accessibility text.
87
89
  - Runtime screenshots must be product-clean. Flutter/React Native debug artifacts such as yellow/black `RenderFlex` overflow banners, `BOTTOM OVERFLOWED BY ... PIXELS`, red error boxes, or clipped action rows are runtime failures to repair, not acceptable evidence. Use bounded card dimensions, `Flexible`/`Expanded`/`Wrap`, `maxLines`, ellipsis, and responsive spacing before handoff.
88
- - If `vise check` fails `<platform>.live-collection.session-ready-requery` because `sp-vise/evidence/runtime-smoke.json` is missing or failed, do **not** attest it and do not call the surface complete. Declare `sp-vise/smoke.json` for the mounted collection surfaces, emit log-only markers from the real SDK query lifecycle (`VISE_SMOKE surface=<id> state=loading|empty|loaded count=N|error:<message>`), cold-launch the app into the social route, capture the device/browser log, run `vise smoke . --log <capture>`, and rerun `vise check . --ci`. The markers must never include secrets, PII, raw social IDs, or end-user setup/debug labels; they are evidence artifacts, not product UI. For Flutter/React Native dogfood, capture bounded Android logcat/simulator logs before `workplan complete` when the surface uses live collections.
90
+ **Recovering a red `<platform>.live-collection.session-ready-requery` (this is a GATE remedy — NOT advisory like the bullets above; the surface cannot go green or be completed without it).** If `vise check` fails `<platform>.live-collection.session-ready-requery` because `sp-vise/evidence/runtime-smoke.json` is missing or failed, do **not** attest it and do not call the surface complete. Declare `sp-vise/smoke.json` for the mounted collection surfaces, emit log-only markers from the real SDK query lifecycle (`VISE_SMOKE surface=<id> state=loading|empty|loaded count=N|error:<message>`), cold-launch the app into the social route, capture the device/browser log, run `vise smoke . --log <capture>`, and rerun `vise check . --ci`. The markers must never include secrets, PII, raw social IDs, or end-user setup/debug labels; they are evidence artifacts, not product UI. For Flutter/React Native dogfood, capture bounded Android logcat/simulator logs before `workplan complete` when the surface uses live collections. (See also `vise debug` — the requery rules now carry session-state symptoms, so a pasted `notLoggedIn`/`session not established` crash correlates here.)
89
91
 
90
92
  Implement one surface at a time. Surface that focused plan's intake questions to
91
93
  the user, including opt-in capability questions, then run the normal check loop.
@@ -104,9 +106,10 @@ vise workplan status . --request "<user intent>"
104
106
 
105
107
  `workplan complete` is evidence-backed: it refuses non-green `vise check`
106
108
  results and snapshots the surface's compliance/check sidecar under
107
- `sp-vise/workplan-snapshots/<surface>/`. Repeat until `workplan status` reports
108
- the broad request complete, then run one final `vise check`, `vise validate`,
109
- and `vise run-sensors` before handoff.
109
+ `sp-vise/workplan-snapshots/<surface>/` with a snapshot integrity manifest.
110
+ `workplan status` ignores missing or drifted snapshot evidence. Repeat until it
111
+ reports the broad request complete, then run one final `vise check`,
112
+ `vise validate`, and `vise run-sensors` before handoff.
110
113
 
111
114
  Then fetch docs cited by the plan or relevant to the requested feature:
112
115
 
@@ -115,7 +118,7 @@ vise search-docs "<SDK feature or API pattern>"
115
118
  vise get-doc-page "<canonical-doc-path>"
116
119
  ```
117
120
 
118
- **Implementation pacing matters.** Once the blueprint/intake gates are clear, make a visible product-source edit before broad research: route the host entry point to the new social surface, or create and import a product-native component for that surface. In bounded dogfood/benchmark runs, this is a hard ordering requirement: after the first `vise init` or focused surface command clears, edit product source before fetching a second docs page, grepping generated SDK/framework interfaces, resolving broad native package internals, or polishing UI. Do not create a shell-first component; the first social component should already import the relevant social.plus SDK package and contain setup/login plus at least one SDK data API call. If you need exact symbols, use package-root imports first, inspect the narrow package-root exports or one targeted type file, then let TypeScript/build errors guide the next lookup. Do not stop at static feature-preview cards that merely describe feed/comments/reactions/profile/chat; those are product copy, not integration. A run that only creates `sp-vise/` artifacts, installs dependencies, reads docs, edits dependency manifests/project files, or stops at a product-looking shell without SDK-backed source is not a completed Vise implementation.
121
+ **Implementation pacing matters.** Once the blueprint/intake gates are clear, make a visible product-source edit before broad research: route the host entry point to the new social surface, or create and import a product-native component for that surface. In bounded dogfood/benchmark runs, this is a hard ordering requirement: after the first `vise init` or focused surface command clears, edit product source before fetching a second docs page, grepping generated SDK/framework interfaces, resolving broad native package internals, or polishing UI. (No contradiction with the Required Loop / per-feature `vise search-docs` recipes: the *first* docs fetch that the plan or feature recipe calls for is expected — this rule only bars *stacking more* research before your first SDK-backed edit. Fetch once, edit, then let build/type errors drive further lookups.) Do not create a shell-first component; the first social component should already import the relevant social.plus SDK package and contain setup/login plus at least one SDK data API call. If you need exact symbols, use package-root imports first, inspect the narrow package-root exports or one targeted type file, then let TypeScript/build errors guide the next lookup. Do not stop at static feature-preview cards that merely describe feed/comments/reactions/profile/chat; those are product copy, not integration. A run that only creates `sp-vise/` artifacts, installs dependencies, reads docs, edits dependency manifests/project files, or stops at a product-looking shell without SDK-backed source is not a completed Vise implementation.
119
122
 
120
123
  The visible edit must also **use** the SDK data it fetches. If you add `_communities`, `posts`, `comments`, or similar SDK-backed state, render it or pass it into a rendered child before moving on. Unused SDK state, hidden controls, `void Repository` markers, iOS `let _ = AmityCommunityRepository.self` / type-only repository references, or a wrapper that still returns the original product screen are scanner-only integration and should be fixed before `vise check`.
121
124
 
@@ -166,6 +169,17 @@ Treat Vise runtime smoke sensors as real validation. For TypeScript/React Native
166
169
 
167
170
  In CI or pull-request pipelines, use `vise check . --ci`. It is read-only, exits non-zero unless compliance is green, and never writes deterministic-pass records; use `vise sync` only during the implementation loop after a local green check.
168
171
 
172
+ ## Resuming an in-progress flow
173
+
174
+ The `sp-vise/` sidecar IS the flow's state — Vise re-derives from it on every command, so a flow is resumable across turns and never restarts from scratch. When the user says "continue" (or you pick up a partially-built integration):
175
+
176
+ - **Run `vise workplan status . --request "<intent>"` FIRST.** It reads the sidecar directly and tells you exactly where the journey stands — completed surfaces, the next pending surface, the accepted experience, and the signed blueprint — so you don't re-plan or re-ask decisions Vise already recorded (an accepted `vise creative` variant, the signed `blueprint_confirmation`, the chosen `solution_path`, and completed surfaces all persist and are replayed).
177
+ - **Prefer the ORIGINAL request wording.** Resume matching is deterministic (not semantic): the same/substring request, or one whose resolved outcome is a stage of the signed journey (or a companion — comments↔feed), re-attaches. A loosely reworded request may not; when in doubt, reuse the exact original request string.
178
+ - **`status: "not-applicable"` does not mean "nothing to do."** If a signed multi-surface flow exists but your request didn't re-attach, the response carries a `signedFlowAvailable` block naming the canonical request and how to resume. Re-run with that request rather than starting a fresh single-surface build that would orphan the journey.
179
+ - **Do not hand-edit the sidecar to "fix" state.** `flow.json`, `workplan.json`, and the snapshot manifests are integrity-checked; a hand-authored progress/snapshot entry is ignored. Drive state only through the `vise` commands.
180
+
181
+ **When runtime proof can't be produced (declined / deviceless CI).** If the user declines device/emulator runtime proof, or you're in a deviceless environment, do not leave a live-collection surface stuck red-forever and do not fake evidence. Record an honest, auditable waiver: `vise smoke waive . --reason "<why proof isn't being run>" --mode declined|deviceless`. `vise check` then reports `runtime-proof-waived` (exit 9 — CI still blocks by default; pass `--allow-proof-waiver` to accept it and exit 0), and `vise workplan complete` will record the surface with the waiver noted. A waiver is an explicit UNDER-claim — never report a waived surface as "runtime-proven"; state in the handoff that only static checks are claimed. Remove `sp-vise/evidence/runtime-proof-waiver.json` once real proof is captured; genuine passing runtime-smoke evidence always overrides a waiver.
182
+
169
183
  ## Prefer Installable Blocks When a Registry Is Available (preview)
170
184
 
171
185
  **Installable social.plus blocks are a preview capability that requires a block registry.** A registry is not generally available yet, so unless the user explicitly provides a `--registry <path>` or `sp-vise/blocks.json` already exists in the project, hand-build the surface as normal — the rest of this skill fully governs the hand-built path. When a registry IS provided, run `vise blocks list --registry <path>` before implementing the surface by hand. When a block exists for the outcome, prefer the governed install path:
@@ -182,7 +196,7 @@ No registry available means hand-build as normal — never assume a block or a r
182
196
 
183
197
  ## Debugging (Day 2 Operations)
184
198
 
185
- If the customer reports an **SDK-specific** runtime crash, build failure, or data-not-loading bug, start with `vise debug .` (with `--error` / `--error-file`) **before** broad repo inspection — do not guess the fix first. Scope limit: only for errors mentioning `social.plus`/`Amity`/`live-collection` or in files importing the SDK; never for generic UI/CSS issues. Full `vise debug` workflow and `repairBrief` format: **see `reference/debugging.md`**.
199
+ If the customer reports an **SDK-specific** runtime crash, build failure, or data-not-loading bug, start with `vise debug .` (with `--error` / `--error-file`) **before** broad repo inspection — do not guess the fix first. Scope limit: only for errors mentioning `social.plus`/`Amity`/`live-collection`, **or whose stack/blame points at a file that imports the SDK, or that surfaced on an SDK-backed social surface** (feed/comments/chat/community/profile). The error *text* need not contain those keywords — a generic-looking `NullPointerException`, `401`, `OutOfMemoryError`, or a `notLoggedIn`/`session not established` message thrown from the social path IS in scope (that is exactly the flagship "feed stays empty / signing-in" class). Skip only genuinely non-SDK UI/CSS/build issues unrelated to any social surface. Full `vise debug` workflow and `repairBrief` format: **see `reference/debugging.md`**.
186
200
 
187
201
  (If `vise` isn't installed: `npm install -g @amityco/social-plus-vise`. Engagement-scope handling — `sp-vise/engagement.json` — is in `reference/operations.md`.)
188
202
 
@@ -290,7 +304,7 @@ A read *count* with no way to clear it is half a feature: when a channel/thread
290
304
 
291
305
  A sent message starts in a `syncing` state and can land in `error` (e.g. network failure, or after an SDK session restart). A composer that renders only the optimistic success leaves failed messages silently stuck.
292
306
 
293
- - **Correct pattern**: Observe each message's `syncState` and surface failed sends with a retry/delete affordance; clean up unrecoverable failures (e.g. `deleteFailedMessages()`) on init.
307
+ - **Correct pattern**: Observe each message's `syncState` and surface failed sends with a retry/delete affordance; where the platform SDK exposes a failed-message cleanup helper, use it on init, otherwise keep retry/delete behavior in product state with supported message APIs.
294
308
  - **Wrong pattern**: Calling `createMessage` and rendering success unconditionally, with no handling for the `error` syncState.
295
309
 
296
310
  ### File Upload & Media
@@ -316,6 +330,12 @@ When querying lists of entities (e.g., `getPosts`, `getCommunityFeed`), always u
316
330
 
317
331
  When using a LiveCollection or live object, also handle connection-state changes. The SDK exposes a connection state stream; render a "reconnecting" indicator or disable interaction controls when the connection is lost. An app that silently shows stale data on network drops generates support tickets attributed to the SDK rather than the integration.
318
332
 
333
+ ### Seeding Data When Empty (read-after-write lag)
334
+ When a surface has no product data and you create safe seed data through the SDK (`createCommunity` / `createChannel` / `createPost`), a **freshly created object does not reliably reappear in an immediate list re-query** — the backing list index lags the write, often returning empty across several cold-launch attempts. Treating the empty re-query as "no data" is the single biggest time-sink when populating a first surface (observed repeatedly on native dogfoods where a community was created but the crew list re-query stayed empty).
335
+ - **Correct pattern:** Merge the create-response object **directly into the rendered/published list** (keyed by its returned ID) instead of waiting for the list re-query to catch up. **Persist created IDs** to local storage/cache (`UserDefaults`/`localStorage`/prefs — never a source constant) so a relaunch rehydrates via a **direct `getCommunity(id)` / `getChannel(id)` fetch** (immune to list-index lag) rather than re-seeding duplicates.
336
+ - **Wrong pattern:** `create(...)` → immediately re-query the list → render the (still-empty) list → conclude "seeding failed / no data". Also wrong: re-seeding on every launch because the previous run's IDs weren't persisted, producing a rail of duplicate crews.
337
+ - **Bounded retry, not give-up or infinite-spin:** a cold launch can transiently return `401`/`notLoggedIn` or a stalled first query before the session settles (see Session Renewal). Wrap seeding + the first query in a **bounded** retry (a few attempts with backoff) that ends in a product-native retry affordance — never an unbounded loop and never a silent swallow. Do not fire the seed/query in the same synchronous tick as `login()`.
338
+
319
339
  ### Post Status Filters
320
340
  Always filter post queries to exclude deleted or flagged content. Amity's older SDKs include flagged/deleted posts by default, which can leak moderated content into the feed UI if unfiltered.
321
341
  - **Correct pattern:** Apply `.includeDeleted(false)`, `.statuses([.published])`, or `.feedType(AmityFeedType.PUBLISHED)` to your query builders.
@@ -354,8 +374,8 @@ A comment thread is incomplete if it only lists comments. Users expect to post.
354
374
 
355
375
  ### Explicit Feed Target Types
356
376
  When calling `createPost`, do not hardcode the `targetType` to a literal value like `AmityPostTargetType.COMMUNITY` if the composer component is meant to be reusable.
357
- - **Correct pattern:** Pass the `targetType` dynamically (e.g. from props, parameters, or intent extras) so the composer can post to a user feed, community feed, or global feed interchangeably.
358
- - **Wrong pattern:** Hardcoding `targetType: AmityPostTargetType.COMMUNITY` inside a generic post composer.
377
+ - **Correct pattern:** Pass the `targetType` dynamically (e.g. from props, parameters, or intent extras) so the composer can post to a valid SDK target: user or community. A global feed is an aggregate read surface from followed users and joined communities; it is not a post creation target.
378
+ - **Wrong pattern:** Hardcoding `targetType: AmityPostTargetType.COMMUNITY` inside a generic post composer, or offering `global` as a createPost target.
359
379
 
360
380
  ### Comment Reference Type Enum
361
381
  When creating comments, always use the SDK's provided enum types for the reference type rather than raw string literals.
@@ -406,7 +426,7 @@ On **iOS**, the SwiftPM package is `github.com/AmityCo/Amity-Social-Cloud-SDK-iO
406
426
 
407
427
  ## Resolving `vise check` Findings
408
428
 
409
- `vise check` reports each rule as `deterministic-pass`, `attestation-needed`, `failed`, or `blocked`. **`attestation-needed` and `failed` block "I'm done" — they are not skippable warnings.** Resolve each one of two ways: (1) **preferred** — adjust the code so the deterministic check fires (`vise explain <rule-id>` shows what it wants), then `vise check` green → `vise sync`; or (2) record `vise attest` with evidence when the architecture is genuinely unconventional. Confidence honesty, the `vise attest` evidence-file format, escalation/human-signer rules, and "`vise sync` is not attestation": **see `reference/operations.md`**.
429
+ `vise check` reports overall statuses such as `green`, `needs-attestation`, `deterministic-failures`, `blocked`, `contract-drift`, `completeness-gap`, `selected-capability-failures`, `no-platform` (no social.plus SDK platform detected — reported as a failure, never a vacuous green), and `runtime-proof-waived` (see the runtime-proof waiver note above); individual rules use `deterministic-pass`, `deterministic-fail`, `attestation-needed`, `blocked`, `stale`, or `advisory`. **Non-green statuses block "I'm done" — they are not skippable warnings.** Resolve each one of two ways: (1) **preferred** — adjust the code so the deterministic check fires (`vise explain <rule-id>` shows what it wants), then `vise check` green → `vise sync`; or (2) record `vise attest` with evidence when the architecture is genuinely unconventional and the rule allows attestation. Confidence honesty, the `vise attest` evidence-file format, escalation/human-signer rules, and "`vise sync` is not attestation": **see `reference/operations.md`**.
410
430
 
411
431
  ## Feature Guidance
412
432
 
@@ -520,7 +540,7 @@ vise search-docs "community create join leave members invitation"
520
540
  vise plan . --request "<community request>"
521
541
  ```
522
542
 
523
- Require the community surface (create, browse/join, detail + members, or membership management), the privacy model (public instant-join vs private join-request approval — they differ), and a natural community source (discovery query, create-flow return value, route/app state, or user selection; never hardcode a communityId). Query communities and members through a Live Collection, handle the join-request flow for private communities, gate moderator actions (roles/ban) by role, and clean up observers. `vise plan` returns the community `completenessChecklist`; opt out of anything out of scope with `// vise: scope-omit <id> <reason>`.
543
+ Require the community surface (create, browse/join, detail + members, or membership management), the privacy model (public instant-join vs private join-request approval — they differ), and a natural community source (discovery query, create-flow return value, route/app state, or user selection; never hardcode a communityId). Query communities and members through a Live Collection, handle the join-request flow for private communities, gate moderator actions (roles/ban) by role, and clean up observers. `vise plan` returns the community `completenessChecklist`; opt out of anything out of scope with `// vise: scope-omit <id> <reason>`.
524
544
 
525
545
  For the social graph (follow/followers):
526
546