@amityco/social-plus-vise 0.14.3 → 0.14.4

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,7 +4,7 @@ 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.3 — 2026-06-04
7
+ ## 0.14.4 — 2026-06-04
8
8
 
9
9
  **Theme:** Completeness-gap enforcement and add-feed guidance hardening (image upload + poll creation + pagination build step).
10
10
 
@@ -17,6 +17,7 @@ The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/
17
17
  ### Fixed
18
18
  - **`targetType` rule recommendation tightened:** the `validateFeedTargetTypeExplicit` validator recommendation now explicitly calls for binding `targetType` to the intake-resolved feed target (e.g. `communityId` from route params, `userId` from auth context) rather than simply avoiding a literal. Prevents agents from introducing an unbound variable that satisfies the literal check while leaving the same intent gap.
19
19
  - **Completeness assessment note language corrected:** `vise plan` completeness note and `assessCompleteness` output no longer say "advisory — never fails the check". They now accurately state that missing items cause `vise check` to exit `completeness-gap` (exit code 5).
20
+ - **Scope-omit markers now require a reason:** `// vise: scope-omit <id>` no longer clears a completeness gap by itself. The marker must include a reason (for example `// vise: scope-omit post-poll — polls disabled for this tenant`) or the capability remains `missing`.
20
21
 
21
22
  ### Changed
22
23
  - **`SKILL.md` scope-omit enforcement:** the Required Loop section now treats missing completeness items as a stop condition, not a suggestion. Agents must either implement or `// vise: scope-omit <id> — <reason>` each missing capability before reporting done.
package/README.md CHANGED
@@ -77,9 +77,9 @@ Vise validates on three layers, and the layer is set by the *kind of claim* —
77
77
  |---|---|---|---|
78
78
  | **SDK compliance** | "this is **wrong**" | 300 deterministic rules (session renewal, live-collection vs one-shot, no secret in logs, parent-child rendering, ban-state gating…) | **Hard gate** — `vise check` blocks until green or attested. A small advisory subset surfaces as informational only and never blocks. |
79
79
  | **Design conformance** | "this **looks off**" | extract the customer's design system into a contract, then check token usage | **Advisory** — `vise design check`/`preview`; never fails a build |
80
- | **Feature completeness** | "this is **missing**" | Vise proposes the full SDK feature surface per outcome; the agent opts out of anything out of scope with a recorded reason | **Advisory** — surfaced in `vise plan`/`check`; never fails a build |
80
+ | **Feature completeness** | "this is **missing**" | Vise proposes the full SDK feature surface per outcome; the agent opts out of anything out of scope with a recorded reason | **Decision gate** — `vise check` exits `completeness-gap` until each missing capability is built or validly opted out |
81
81
 
82
- Only correctness is gated (it can be made FP-free); conformance and completeness are surfaced, because "all post types" and "matches the brand" are legitimately scope-dependent. See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
82
+ Correctness is gated by deterministic rules or attestations. Completeness is gated by explicit scope decisions: if a capability is legitimately out of scope, record `// vise: scope-omit <id> — <reason>` and it no longer blocks. Conformance remains advisory because "matches the brand" is legitimately subjective. See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
83
83
 
84
84
  ### Relationship to social.plus Block Factory
85
85
 
@@ -414,7 +414,7 @@ jobs:
414
414
  | `2` | One or more rules have deterministic failures |
415
415
  | `3` | One or more blockers fired (missing prerequisite, e.g. `google-services.json`) |
416
416
  | `4` | Contract drift — rules in `sp-vise/compliance.json` no longer match the current ruleset |
417
- | `5` | One or more expected capabilities are neither implemented nor opted-out — add the capability or place `// vise: scope-omit <id> — <reason>` |
417
+ | `5` | One or more expected capabilities are neither implemented nor validly opted-out — add the capability or place `// vise: scope-omit <id> — <reason>` |
418
418
 
419
419
  `vise check --ci` is read-only. It never updates `sp-vise/`. The JSON output includes a `ci` block with structured details for pipeline logs.
420
420
 
@@ -1,10 +1,11 @@
1
1
  /**
2
- * Feature-completeness assessment — ADVISORY ONLY.
2
+ * Feature-completeness assessment.
3
3
  *
4
4
  * Boundary (see the validation-boundaries principle): completeness is a "this is
5
- * missing" claim — a universal-negative over open-ended correct implementations.
6
- * It is structurally false-positive-prone and therefore NEVER a hard gate. This
7
- * module only surfaces nudges; `vise check`'s status/exit code are untouched.
5
+ * missing" claim — a universal-negative over open-ended correct implementations
6
+ * unless the customer/agent explicitly removes it from scope. Missing capabilities
7
+ * now produce `completeness-gap` in `vise check`; a recorded scope-omit reason is
8
+ * the false-positive escape hatch.
8
9
  *
9
10
  * Memory-independence comes from inversion: VISE authors the canonical capability
10
11
  * set per outcome; the agent must OPT OUT of a capability with a recorded reason
@@ -367,7 +368,7 @@ export const CAPABILITIES = [
367
368
  hint: "respect Amity's server-side notification settings/preferences (getSettings)",
368
369
  },
369
370
  ];
370
- const ADVISORY_NOTE = "Build each missing capability, or opt out with a recorded reason: `// vise: scope-omit <id> <reason>`. Missing capabilities that are neither built nor opted-out cause `vise check` to exit with status `completeness-gap` (exit code 5).";
371
+ const ADVISORY_NOTE = "Build each missing capability, or opt out with a recorded reason: `// vise: scope-omit <id> <reason>`. A scope-omit marker without a reason is invalid and still counts as missing. Missing capabilities that are neither built nor validly opted-out cause `vise check` to exit with status `completeness-gap` (exit code 5).";
371
372
  /** The Vise-authored capability checklist for an outcome (for `vise plan` feed-forward). */
372
373
  export function capabilityChecklist(outcome) {
373
374
  return CAPABILITIES.filter((c) => c.outcomes.includes(outcome)).map((c) => ({ id: c.id, label: c.label, hint: c.hint }));
@@ -376,14 +377,24 @@ export function capabilityChecklist(outcome) {
376
377
  export function assessCompleteness(source, outcome) {
377
378
  const caps = CAPABILITIES.filter((c) => c.outcomes.includes(outcome));
378
379
  const optOuts = new Map();
380
+ const invalidOptOuts = new Map();
379
381
  const omitPattern = /vise:\s*scope-omit\s+([a-z][\w-]*)\s*(?:[—:|-]+\s*(.*))?/gi;
380
382
  let match;
381
383
  while ((match = omitPattern.exec(source)) !== null) {
382
- optOuts.set(match[1].toLowerCase(), (match[2] ?? "").trim() || "no reason given");
384
+ const id = match[1].toLowerCase();
385
+ const reason = (match[2] ?? "").trim();
386
+ if (reason) {
387
+ optOuts.set(id, reason);
388
+ invalidOptOuts.delete(id);
389
+ }
390
+ else if (!optOuts.has(id)) {
391
+ invalidOptOuts.set(id, "scope-omit marker must include a reason");
392
+ }
383
393
  }
384
394
  const present = [];
385
395
  const missing = [];
386
396
  const optedOut = [];
397
+ const invalid = [];
387
398
  for (const cap of caps) {
388
399
  if (optOuts.has(cap.id)) {
389
400
  optedOut.push({ id: cap.id, reason: optOuts.get(cap.id) });
@@ -392,10 +403,18 @@ export function assessCompleteness(source, outcome) {
392
403
  present.push({ id: cap.id, label: cap.label });
393
404
  }
394
405
  else {
395
- missing.push({ id: cap.id, label: cap.label, hint: cap.hint });
406
+ const invalidReason = invalidOptOuts.get(cap.id);
407
+ if (invalidReason) {
408
+ invalid.push({ id: cap.id, reason: invalidReason });
409
+ }
410
+ missing.push({
411
+ id: cap.id,
412
+ label: cap.label,
413
+ hint: invalidReason ? `${cap.hint}; found scope-omit marker without a reason, so add a reason or implement it` : cap.hint,
414
+ });
396
415
  }
397
416
  }
398
- return { outcome, present, missing, optedOut, note: ADVISORY_NOTE };
417
+ return { outcome, present, missing, optedOut, invalidOptOuts: invalid, note: ADVISORY_NOTE };
399
418
  }
400
419
  // ── Bounded source read (advisory; perf-bounded like the design check scan) ──
401
420
  const SCAN_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".dart", ".kt", ".java", ".swift", ".vue"]);
@@ -456,9 +456,9 @@ export async function checkCompliance(repoPath) {
456
456
  const needsAttestation = results.some((result) => result.status === "attestation-needed" || result.status === "stale");
457
457
  // Precedence: blocked (3) > deterministic-failures (2) > needs-attestation (1) > completeness-gap (5) > green (0).
458
458
  // Contract drift (exit 4) is handled earlier and short-circuits the loop.
459
- // Completeness-gap: capabilities that are neither present nor opted-out require an explicit decision
459
+ // Completeness-gap: capabilities that are neither present nor validly opted-out require an explicit decision
460
460
  // (build it, or place // vise: scope-omit <id> — <reason>). The scope-omit escape hatch keeps this
461
- // FP-free any capability can be excluded with a recorded reason. Failure to assess is silently ignored.
461
+ // FP-free because any capability can be excluded with a recorded reason. Failure to assess is silently ignored.
462
462
  const completeness = (await assessProjectCompleteness(inspection.effectiveRoot, compliance.outcome).catch(() => null)) ?? undefined;
463
463
  const hasCompletenessGap = (completeness?.missing.length ?? 0) > 0;
464
464
  // Blocked wins because the agent cannot proceed without customer input;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amityco/social-plus-vise",
3
- "version": "0.14.3",
3
+ "version": "0.14.4",
4
4
  "description": "Skill-guided deterministic CLI for social.plus SDK integration assistance.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
@@ -244,13 +244,13 @@ vise plan . --request "<feed or post request>"
244
244
 
245
245
  Require a concrete target from the app: current user feed, selected community, selected channel, or another user-provided domain object. Do not hardcode random target IDs.
246
246
 
247
- **Decide engagement scope explicitly — Vise authors the checklist, you subtract with a reason.** `vise plan` returns a `completenessChecklist` (the canonical capabilities for the outcome, e.g. comments, reactions, pagination, polls, media, moderation) and `vise check` reports each as present / missing / opted-out. The check gate never blocks on completeness (to avoid false positives from legitimately scope-limited integrations), but **missing items that are neither built nor opted-out are silent drops treat them as a stop condition, not a suggestion.** For each capability: build it, or explicitly opt out with a recorded marker in the code so the omission is reviewable, not accidental:
247
+ **Decide engagement scope explicitly — Vise authors the checklist, you subtract with a reason.** `vise plan` returns a `completenessChecklist` (the canonical capabilities for the outcome, e.g. comments, reactions, pagination, polls, media, moderation) and `vise check` reports each as present / missing / opted-out. Missing items that are neither built nor validly opted-out produce `completeness-gap` (exit code 5), because they are silent drops. For each capability: build it, or explicitly opt out with a recorded marker in the code so the omission is reviewable, not accidental:
248
248
 
249
249
  ```
250
250
  // vise: scope-omit poll — text + image feed only; polls disabled for this tenant
251
251
  ```
252
252
 
253
- Do not report the integration complete while any capability is `missing`. Re-run `vise check .` after placing a scope-omit marker to confirm it moves from `missing` to `opted-out`.
253
+ Do not report the integration complete while any capability is `missing`. A scope-omit marker must include a reason after the capability id; otherwise it remains invalid and the capability still counts as missing. Re-run `vise check .` after placing a scope-omit marker to confirm it moves from `missing` to `opted-out`.
254
254
 
255
255
  **Demo wiring (when the app needs to compile before the real target source exists):** even at the top-level `App` / `MaterialApp` / `_app.tsx` / `AppDelegate` wiring site, do not pass a literal string. Use the host platform's compile-time env channel so the rule sees no string literal at the call site:
256
256