@amityco/social-plus-vise 0.14.25 → 0.14.27

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,30 @@ 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.27 — 2026-06-10
8
+
9
+ **Theme:** social-plus-forge monorepo move. No runtime behavior changes.
10
+
11
+ ### Changed
12
+ - **Repository metadata:** the package now lives in the `vise/` module of the [social-plus-forge monorepo](https://github.com/AmityCo/social-plus-forge); `repository` (with `directory: vise`), `homepage`, and `bugs` URLs updated from the retired `social-plus-foundry`/`social-plus-vise` repos.
13
+ - **Tarball slimmed 1.9 MB → ~0.5 MB:** `social.plus-vise.png` is no longer shipped in the npm package (it was 79% of the install and never referenced by the README).
14
+
15
+ ### Fixed
16
+ - **`ajv` declared as a devDependency:** it was imported by the catalog-schema gate and `scripts/catalog-sheets.mjs` but rode in transitively under npm's flat hoisting; pnpm's strict layout surfaced the gap.
17
+
18
+ ### Docs
19
+ - Backfilled the `vise blocks` installer namespace into the `0.14.5` changelog entry (shipped there, never recorded).
20
+ - `RELEASE.md` no longer hardcodes the current npm version; `RULES.md`/`ARCHITECTURE.md` defer exact rule counts to the rule-coverage gate.
21
+
22
+ ## 0.14.26 — 2026-06-06
23
+
24
+ ### Added
25
+ - **Creative selection bridge:** `vise creative accept --variant <id>` / MCP `creative_accept` now persists `sp-vise/creative-selection.json` from a chosen creative brief candidate.
26
+ - **Plan/init/workplan feed-forward:** matching `vise plan`, `vise init`, and `vise workplan next/status` runs now read accepted creative selections, add a `creativeContext` block, prepend a selected-variant implementation step, mirror the selection into `sp-vise/intake.json`, and derive multi-surface workplan order from selected experience objects.
27
+
28
+ ### Verified
29
+ - Expanded `test:creative` to cover creative accept, selection sidecar writes, plan feed-forward, creative-derived workplan ordering, init sidecar mirroring, and MCP `creative_accept` smoke coverage.
30
+
7
31
  ## 0.14.25 — 2026-06-06
8
32
 
9
33
  ### Added
@@ -208,6 +232,9 @@ The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/
208
232
 
209
233
  **Theme:** Optional feed capabilities become explicit opt-in sensors.
210
234
 
235
+ ### Added
236
+ - *(backfilled 2026-06-10 — shipped in this release but was never recorded)* **Block installer namespace:** `vise blocks list / plan / add / validate` (PR #143). Reads a social.plus Block Factory registry, plans safe package/source-anchor/sidecar changes, applies them behind `--dry-run`/`--apply`, writes `sp-vise/blocks.json`, and validates installed block state and drift.
237
+
211
238
  ### Changed
212
239
  - **Add-feed completeness baseline narrowed to pagination:** image upload, poll creation, and edit post are no longer baseline completeness requirements. The add-feed `completenessChecklist` now gates pagination / load-more only.
213
240
  - **Optional feed capabilities require explicit opt-in:** `vise plan` now offers image upload, poll creation, and edit post as `optionalCapabilities`. When the user selects one and the agent carries it into `vise init --answer feed_optional_capabilities=...`, `vise check` runs selected source sensors and exits `selected-capability-failures` (exit code 6) until the selected capability is implemented.
package/README.md CHANGED
@@ -83,7 +83,9 @@ Correctness is gated by deterministic rules or attestations. Baseline completene
83
83
 
84
84
  ### Engagement Intelligence roadmap
85
85
 
86
- Vise's next architecture track is the social.plus **Engagement Intelligence System**: an outcome-to-experience layer that maps customer goals, archetypes, solution patterns, experience objects, UX patterns, and variants before normal implementation planning. The first advisory runtime slice is `vise creative`: it consumes a request plus optional requirements/prototype inputs, or runs in exploratory mode when requirements are absent, then writes a local creative brief for user variant selection. See [docs/ENGAGEMENT_INTELLIGENCE_SYSTEM.md](docs/ENGAGEMENT_INTELLIGENCE_SYSTEM.md), [docs/MONOREPO_ARCHITECTURE.md](docs/MONOREPO_ARCHITECTURE.md), and [packages/intelligence](packages/intelligence).
86
+ Vise's next architecture track is the social.plus **Engagement Intelligence System**: an outcome-to-experience layer that maps customer goals, archetypes, solution patterns, experience objects, UX patterns, and variants before normal implementation planning. The first advisory runtime slice is `vise creative`: it consumes a request plus optional requirements/prototype inputs, or runs in exploratory mode when requirements are absent, writes a local creative brief for user variant selection, and records the accepted variant so `vise plan`, `vise init`, and `vise workplan` can carry that product/UX direction forward. See [docs/ENGAGEMENT_INTELLIGENCE_SYSTEM.md](docs/ENGAGEMENT_INTELLIGENCE_SYSTEM.md), [docs/MONOREPO_ARCHITECTURE.md](docs/MONOREPO_ARCHITECTURE.md), and [packages/intelligence](packages/intelligence).
87
+
88
+ The current milestone is the **Learning Engine sensor bridge with score calibration guardrails**. After creative selection, experience compilation, and sensor review, Vise can keep local learning events that snapshot the selected variant, outcome, Experience Report, and Experience Sensor Framework, then summarize recurring review gaps by variant, outcome, and dimension. The shadow calibration track now has 70 measured cells, including a v2 independent candidate-ranking matrix that ranked the expected variant first in 21/21 registered cells while preserving visible review gaps. The v2 human gate has named product FP/FN and privacy sign-off recorded, including approval that `event-first` beats `creator-first` in the five thin-margin cross-platform cells. Gate 2 exposes this evidence only as an explicit `vise creative --ranking-preview` local advisory preview; the current local dogfood pass covers 18 synthetic prompts spanning ten archetypes and all ten catalog variants (seven available, three gamification variants gated as in-development). Of the 14 available-variant cases, 13 align and 1 is a declared near-miss — in the opt-in preview only, the shadow-policy-v2-draft ranking ranks `live-commerce` just above `discovery-first` for an ecommerce social-discovery prompt, while the brief's keyword default and the agent both pick the human-correct `discovery-first` — with 0 undeclared ranking concerns and 0 candidate-surfacing gaps; the other 4 gamification cases are correctly gated. The paired `live-shopping-stream` control (a clear live-selling prompt) shows the preview correctly elevating `live-commerce` over the keyword default. There are still no uploads, no changed `vise check` exit codes, no calibrated single score, no auto-acceptance, and no default recommendation ranking. See [docs/UX_HARNESS_MVP.md](docs/UX_HARNESS_MVP.md), [docs/LEARNING_ENGINE_MVP.md](docs/LEARNING_ENGINE_MVP.md), [docs/EXPERIENCE_SCORE_CALIBRATION.md](docs/EXPERIENCE_SCORE_CALIBRATION.md), and [docs/ENGAGEMENT_INTELLIGENCE_SYSTEM.md](docs/ENGAGEMENT_INTELLIGENCE_SYSTEM.md).
87
89
 
88
90
  ### Relationship to social.plus Block Factory
89
91
 
@@ -165,15 +167,17 @@ Aggregate: **98/99 expected feed capabilities** and **27/27 selected optional ca
165
167
 
166
168
  ### Current Release Validation
167
169
 
168
- Version 0.14.25 carries current release proof around the full feed-forward, product-expectation, creative pre-planning, and validation flow:
170
+ Version 0.14.26 carries current release proof around the full feed-forward, product-expectation, creative pre-planning, and validation flow:
169
171
 
170
172
  | Surface | What was validated |
171
173
  |---|---|
172
174
  | **Creative pre-planning** | `vise creative` produces requirements-driven or exploratory Engagement Intelligence briefs, writes `sp-vise/creative-brief.json` / `.md`, asks for `preferred_solution`, and survives packed-package installation with the intelligence catalog bundled. |
175
+ | **Creative selection bridge** | `vise creative accept --variant <id>` writes `sp-vise/creative-selection.json` and `sp-vise/ux-harness.json`; matching `vise plan`, `vise init`, and `vise workplan next` runs surface the accepted variant, UX expectations, derive workplan surfaces from its experience objects, and mirror the selection into `sp-vise/intake.json`. |
173
176
  | **Product flow** | Local end-to-end smoke covers design extraction, plan feed-forward, blocking intake, answered init, capability check, design conformance, and sensor discovery. |
174
177
  | **Multi-surface planning** | Broad social requests are decomposed into a `socialWorkplan` sequence for feed, comments, chat, and profile work instead of forcing a single top-level surface choice. `vise workplan next` tells the host agent which surface to implement next, and `vise workplan complete` records green-check progress in `sp-vise/workplan.json` with per-surface snapshots under `sp-vise/workplan-snapshots/<surface>/`. |
175
178
  | **Plan questions** | Plans surface blocking questions such as `design_contract_confirmation`, product-scope questions such as `feed_post_type_scope`, `feed_composer_type_scope`, `comment_tray_scope`, `chat_inbox_scope`, and `profile_identity_scope`, plus optional choices such as `feed_optional_capabilities`. Focused plans still accept `feature_surface` answers when the agent is ready to implement one surface. |
176
179
  | **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`. |
180
+ | **Experience Score calibration guard** | Experience Report, Experience Sensors, and Learning Engine snapshots keep `score: null`, while `learning-summary.json` keeps `recommendationOptimization.status: "not-active"`. The shadow benchmark has 70 measured cells; `shadow-policy-v2-draft` independently ranked expected variants first in 21/21 registered ranking/cross-platform cells, its human gate package has named product FP/FN and privacy sign-off recorded, and runtime exposure is limited to the opt-in local `vise creative --ranking-preview` artifact. |
177
181
  | **Android workplan dogfood** | A brownfield Android music-player app refreshed under `0.14.24` reached `vise check` green with **43/43 deterministic passes** on the focused feed surface and recorded a green-check workplan snapshot. This is dogfood evidence, not a controlled multi-agent benchmark. |
178
182
  | **Shared product expectations** | Public IDs such as `feed.target-resolved`, `feed.post-type-scope-explicit`, `comments.creation-affordance`, `chat.channel-list-order-explicit`, `community.avatar-from-sdk`, `moderation.role-gated-action`, `follow.relationship-live`, `profile.identity-from-sdk`, `profile.social-counts`, and `notifications.tray-live` stay platform-agnostic while check results retain concrete `contractRuleId` and `validator.sensorId` evidence when deterministic sensors exist. |
179
183
  | **Rule detection** | TP-track dashboard detects **321/321 seeded rule gaps (100.0%)** in the static corpus. |
@@ -186,6 +190,7 @@ Version 0.14.25 carries current release proof around the full feed-forward, prod
186
190
  | **Feature completeness** | Vise helps agents build more of the expected SDK capability surface. | Latest comparison: **21-30% without Vise vs 97-100% with Vise**, with **98/99** expected feed capabilities implemented in aggregate. Earlier Capability Matrix work also showed silently dropped items falling from 7.67/11 to 4.0/11. |
187
191
  | **SDK compliance** | Vise checks catch greenfield SDK compliance gaps that docs or static guidance can miss. | Commune benchmark: Vise averaged **100% greenfield SDK compliance** where docs/RAG-style controls averaged **67%** across the reported slices. |
188
192
  | **Design conformance** | Vise design checks reduce design drift under ambiguous briefs. | Ambiguous Spotify-style design test: Vise design runs produced **0 / 0 / 0 hex literals** across three seeds; without Vise, runs varied **0 / 2 / 15**. This supports variance reduction, not pixel-perfect visual quality. |
193
+ | **Candidate ranking calibration** | Vise can optionally preview `shadow-policy-v2-draft` ranking for surfaced creative variants, without changing default runtime recommendations. | Experience calibration track: **70 measured cells**. `shadow-policy-v2-draft` ranked the expected variant first in **21/21** cells, produced **14** improvement opportunities, has named product approval for **5** thin-margin event-first-over-creator-first cells plus named privacy approval for the benchmark evidence boundary, and is exposed only through explicit `--ranking-preview`. Current local dogfood has **18** prompts (ten archetypes, all **ten** variants — seven available, three gamification gated): of the **14** available-variant cases, **13** aligned and **1** declared near-miss (in the opt-in preview only; the keyword default and the agent both pick the human-correct variant), **0** undeclared ranking concerns, **0** candidate-surfacing gaps; the other **4** gamification cases are gated, and the paired positive control shows the preview correctly elevating the human-correct variant over the keyword default; default activation remains disabled. |
189
194
 
190
195
  ### Why the workflow works
191
196
 
@@ -303,7 +308,14 @@ The flow above is what the skill teaches your AI agent. You — the human — dr
303
308
  |---|---|
304
309
  | `vise doctor` | Verify install; print version, install path, docs source |
305
310
  | `vise inspect [path]` | Detect platform, monorepo surfaces, design signals, available sensors |
306
- | `vise creative [path] --request "..." [--requirements <path\|none>] [--prototype <html>]` | Produce an advisory Engagement Intelligence brief with 2-3 solution variants before normal implementation planning; writes `sp-vise/creative-brief.json` and `.md` unless `--no-write` is set |
311
+ | `vise creative [path] --request "..." [--requirements <path\|none>] [--prototype <html>] [--ranking-preview]` | Produce an advisory Engagement Intelligence brief with 2-3 solution variants before normal implementation planning; `--ranking-preview` also writes an opt-in local candidate-ranking preview without changing the candidate order |
312
+ | `vise creative accept [path] --variant <id>` | Accept a creative variant and write `sp-vise/creative-selection.json` so subsequent `plan`, `init`, and `workplan` runs include the selected product/UX direction. Use `--variant none --rationale "<what is missing>"` to instead record a local `sp-vise/catalog-gap.json` no-fit signal for human catalog review |
313
+ | `vise ux-harness [path]` | Generate or refresh `sp-vise/ux-harness.json` from the accepted creative selection; advisory UX expectations only |
314
+ | `vise experience compile [path]` | Compile the accepted creative variant into `sp-vise/experience-compiler.json`: install guidance, navigation placement, surface plans, UX expectations, Block Factory bridge candidates, design adaptation, and validation commands |
315
+ | `vise experience sensors [path]` | Write `sp-vise/experience-sensors.json`, an advisory sensor framework across technical, design, UX, accessibility, and business-alignment dimensions; no calibrated score yet |
316
+ | `vise experience-report [path]` | Write `sp-vise/experience-report.json`, an advisory dimensioned report for technical compliance, design, UX Harness evidence, and business alignment; no calibrated single score yet |
317
+ | `vise learning record [path]` | Append a local-only learning event for explicit feedback, outcome metrics, or report review; refreshes `sp-vise/learning-summary.json` |
318
+ | `vise learning show [path]` | Read the local learning summary; recommendation ranking is not changed by these events yet |
307
319
  | `vise plan [path] --request "..."` | Produce a grounded implementation plan with intake questions and docs citations |
308
320
  | `vise plan-harness [path] --request "..."` | (Pre-planning step) Build the harness around the request |
309
321
  | `vise workplan next [path] --request "..."` | For broad social requests, print the next uncompleted surface plus focused `plan` / `init` / verification commands |
@@ -408,7 +420,7 @@ MCP-capable hosts can call Vise as structured tool calls instead of shell comman
408
420
 
409
421
  ### Tool names (snake_case per MCP convention)
410
422
 
411
- `inspect_project`, `creative_brief`, `plan_harness`, `plan_integration`, `init_compliance`, `check_compliance`, `sync_compliance`, `attest_rule`, `explain_rule`, `init_engagement`, `show_engagement`, `resolve_request`, `search_docs`, `get_doc_page`, `debug_issue`, `validate_setup`, `run_sensors`, `suggest_patch`, `design_extract`, `design_check`, `design_preview`, `design_reference`, `design_init_tokens`.
423
+ `inspect_project`, `creative_brief`, `creative_accept`, `ux_harness`, `compile_experience`, `experience_sensors`, `plan_harness`, `plan_integration`, `init_compliance`, `check_compliance`, `experience_report`, `record_learning`, `show_learning`, `sync_compliance`, `attest_rule`, `explain_rule`, `init_engagement`, `show_engagement`, `resolve_request`, `search_docs`, `get_doc_page`, `debug_issue`, `validate_setup`, `run_sensors`, `suggest_patch`, `design_extract`, `design_check`, `design_preview`, `design_reference`, `design_init_tokens`.
412
424
 
413
425
  These are the same operations as the CLI commands above, exposed as MCP tools.
414
426
 
@@ -461,9 +473,18 @@ Vise writes local planning, compliance, design, and evidence artifacts under `sp
461
473
  | File | Created by | What it contains |
462
474
  |---|---|---|
463
475
  | `sp-vise/compliance.json` | `vise init` | The rules selected for this integration, the Vise version, the ruleset digest, the target app surface, selected optional capabilities, optional engagement link, and an accepted design-contract digest when confirmed. |
464
- | `sp-vise/intake.json` | `vise init` | The request, outcome, intake answers, remaining blocking count, design-review status (`absent`, `needs-confirmation`, `accepted`, or `rejected`), and any retrospective `--allow-unresolved-intake` acknowledgement. |
476
+ | `sp-vise/intake.json` | `vise init` | The request, outcome, intake answers, remaining blocking count, optional creative-selection mirror, design-review status (`absent`, `needs-confirmation`, `accepted`, or `rejected`), and any retrospective `--allow-unresolved-intake` acknowledgement. |
465
477
  | `sp-vise/creative-brief.json` | `vise creative` | Advisory Engagement Intelligence brief: mode, objective, inferred goals/archetypes, candidate solution variants, feasibility summary, preferred-solution question, and next plan/workplan commands. |
466
478
  | `sp-vise/creative-brief.md` | `vise creative` | Human-readable version of the creative brief for review with the user before selecting a variant. |
479
+ | `sp-vise/candidate-ranking-preview.json` | `vise creative --ranking-preview` | Opt-in local advisory ranking preview for the surfaced creative candidates using `shadow-policy-v2-draft`; preserves the original candidate order and writes `experience_score: null` with runtime boundary fields confirming no uploads, no auto-acceptance, and no default ranking change. |
480
+ | `sp-vise/creative-selection.json` | `vise creative accept` | Accepted creative variant: source brief, selected goals/archetypes/patterns/objects/UX patterns, surface hints, feasibility notes, and plan/workplan feed-forward context. |
481
+ | `sp-vise/catalog-gap.json` | `vise creative accept --variant none` | Recorded no-fit: the request the agent found no fitting variant for, what the catalog is missing, the nearest existing variant, and the grounding signal. A local-only signal for human catalog review — it does not accept a variant, change the catalog, or upload anything. |
482
+ | `sp-vise/ux-harness.json` | `vise creative accept` or `vise ux-harness` | Advisory UX Harness: selected UX pattern expectations, tradeoffs, anti-patterns, surface expectations, and capability-feed-forward boundary notes. |
483
+ | `sp-vise/experience-compiler.json` | `vise experience compile` | Advisory implementation artifact plan: install guidance, navigation placement, focused surface plans, UX expectations, optional Block Factory bridge candidates, design adaptation, and validation commands. |
484
+ | `sp-vise/experience-sensors.json` | `vise experience sensors` | Advisory sensor framework: technical, design, UX, accessibility, and business-alignment evidence summary, review gaps, commands, and `score: null` until calibrated. |
485
+ | `sp-vise/experience-report.json` | `vise experience-report` | Advisory dimensioned review artifact: technical compliance status, design contract presence, UX Harness evidence, business alignment, optional Experience Sensor snapshot, and `score: null` until calibrated by benchmark/dogfood evidence. |
486
+ | `sp-vise/learning-events.jsonl` | `vise learning record` | Append-only local learning event log for explicit customer/reviewer feedback, outcome metrics, selected variant snapshots, outcome snapshots, Experience Report snapshots, and Experience Sensor snapshots. |
487
+ | `sp-vise/learning-summary.json` | `vise learning record` | Derived local learning summary: feedback counts, variant feedback, metric keys, report/sensor snapshots, recurring review gaps by variant/outcome/dimension, and `recommendationOptimization.status: "not-active"`. |
467
488
  | `sp-vise/attestations/*.json` | `vise sync` (deterministic) or `vise attest` (host-agent / human) | Per-rule evidence: signer, confidence, rationale, cited files (with source fingerprints for drift detection). |
468
489
  | `sp-vise/inspection.json` | `vise init` | The platform, monorepo surface, and design-token signals detected at init time. |
469
490
  | `sp-vise/workplan.json` | `vise workplan complete` | Local progress for broad social workplans: request, completed surface IDs, outcomes, timestamps, green-check evidence, snapshot paths, and optional host-agent notes. |
@@ -1168,7 +1168,7 @@ function symbolHaystack(symbols) {
1168
1168
  return [...new Set(values)];
1169
1169
  }
1170
1170
  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).";
1171
- const BASELINE_CAPABILITY_IDS_BY_OUTCOME = {
1171
+ export const BASELINE_CAPABILITY_IDS_BY_OUTCOME = {
1172
1172
  "add-feed": ["pagination"],
1173
1173
  "add-comments": ["comment-composer"],
1174
1174
  "add-chat": ["send-message", "read-state"],
@@ -0,0 +1,107 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ // Deterministic grounding contract for agent-driven variant selection (experience-factory rebuild,
5
+ // Option A). The factory does NOT call a model: the driving coding agent performs the semantic
6
+ // understanding (customer request -> variant) and hands the factory a selection. This module is the
7
+ // factory's deterministic half — it enforces that the agent's selection is GROUNDED in the catalog
8
+ // and surfaces honest review signals. It performs no inference and no IO in its core function, so it
9
+ // is fully reproducible (the determinism lives here; the non-determinism lives in the visible driver).
10
+ //
11
+ // Contract, by evidence from the spike + stress test (benchmarks/experience-calibration/
12
+ // semantic-understanding-spike.mjs and -stresstest.mjs):
13
+ // - variantId MUST be a catalog id, or the literal "none" (the agent's honest no-fit answer).
14
+ // Anything else is a hallucination and is REJECTED.
15
+ // - rationale is REQUIRED (explainability is a core principle of the factory).
16
+ // - confidence is expected (high|medium|low); low confidence and "none" are not failures — they are
17
+ // honest signals that the human/agent should reconsider or that the catalog may need a new variant.
18
+ export const GROUNDING_SCHEMA_VERSION = "2026-06-07.vise-grounding.v1";
19
+ export const NO_FIT = "none";
20
+ const CONFIDENCE_VALUES = ["high", "medium", "low"];
21
+ /**
22
+ * Validate an agent-provided variant selection against the catalog. Pure and deterministic: given the
23
+ * same selection and the same catalog id set it always returns the same result.
24
+ */
25
+ export function groundSelection(selection, catalogVariantIds) {
26
+ const ids = [...catalogVariantIds];
27
+ const idSet = new Set(ids);
28
+ const signals = [];
29
+ const rawVariant = typeof selection?.variantId === "string" ? selection.variantId.trim() : "";
30
+ const rationale = typeof selection?.rationale === "string" ? selection.rationale.trim() : "";
31
+ const rawConfidence = typeof selection?.confidence === "string" ? selection.confidence.trim().toLowerCase() : "";
32
+ const isNoFit = rawVariant.toLowerCase() === NO_FIT;
33
+ const isKnownVariant = idSet.has(rawVariant);
34
+ // 1. Grounding: variant must be a catalog id or the explicit no-fit answer.
35
+ if (!isNoFit && !isKnownVariant) {
36
+ signals.push({
37
+ code: "hallucinated-variant",
38
+ severity: "error",
39
+ message: rawVariant
40
+ ? `Selected variant "${rawVariant}" is not in the catalog. The agent must choose a catalog id or "${NO_FIT}".`
41
+ : `No variant was provided. The agent must choose a catalog id or "${NO_FIT}".`,
42
+ });
43
+ }
44
+ else if (isNoFit) {
45
+ signals.push({
46
+ code: "no-fit",
47
+ severity: "warn",
48
+ message: `The agent reported no catalog variant fits this request. Reconsider the request, or treat this as a candidate for a new catalog variant.`,
49
+ });
50
+ }
51
+ // 2. Rationale is required for explainability (applies to a real variant and to "none").
52
+ if (!rationale) {
53
+ signals.push({
54
+ code: "missing-rationale",
55
+ severity: "error",
56
+ message: `A rationale is required: the selection must explain, grounded in the request and catalog, why this variant (or "${NO_FIT}") was chosen.`,
57
+ });
58
+ }
59
+ // 3. Confidence (advisory but expected). Invalid value is a contract violation; absence/low are signals.
60
+ let confidence = null;
61
+ if (!rawConfidence) {
62
+ signals.push({ code: "missing-confidence", severity: "warn", message: `No confidence was provided; expected one of ${CONFIDENCE_VALUES.join(", ")}.` });
63
+ }
64
+ else if (CONFIDENCE_VALUES.includes(rawConfidence)) {
65
+ confidence = rawConfidence;
66
+ if (confidence === "low" && isKnownVariant) {
67
+ signals.push({ code: "low-confidence", severity: "warn", message: `The agent was not confident in this selection; review before accepting.` });
68
+ }
69
+ }
70
+ else {
71
+ signals.push({ code: "invalid-confidence", severity: "error", message: `Confidence "${rawConfidence}" is invalid; expected one of ${CONFIDENCE_VALUES.join(", ")}.` });
72
+ }
73
+ const hasError = signals.some((s) => s.severity === "error");
74
+ const status = hasError ? "rejected" : signals.length > 0 ? "needs-review" : "grounded";
75
+ const variantId = hasError || isNoFit ? null : rawVariant;
76
+ return {
77
+ schemaVersion: GROUNDING_SCHEMA_VERSION,
78
+ status,
79
+ variantId,
80
+ confidence,
81
+ rationale: rationale || null,
82
+ signals,
83
+ catalogVariantIds: ids,
84
+ reason: summarize(status, variantId, signals),
85
+ };
86
+ }
87
+ function summarize(status, variantId, signals) {
88
+ if (status === "grounded")
89
+ return `Selection "${variantId}" is grounded in the catalog with a rationale.`;
90
+ if (status === "rejected")
91
+ return `Selection rejected: ${signals.filter((s) => s.severity === "error").map((s) => s.code).join(", ")}.`;
92
+ return `Selection accepted with review signals: ${signals.map((s) => s.code).join(", ")}.`;
93
+ }
94
+ /** Resolve the catalog directory shipped in the package (packages/intelligence/catalog). */
95
+ export function catalogDir() {
96
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
97
+ return path.resolve(moduleDir, "..", "..", "packages", "intelligence", "catalog");
98
+ }
99
+ /** Load the set of valid variant ids from the declarative catalog. */
100
+ export async function loadCatalogVariantIds(dir = catalogDir()) {
101
+ const raw = await readFile(path.join(dir, "variants.json"), "utf8");
102
+ const parsed = JSON.parse(raw);
103
+ const ids = (parsed.items ?? []).map((item) => item.id).filter((id) => typeof id === "string" && id.length > 0);
104
+ if (ids.length === 0)
105
+ throw new Error("No variant ids found in catalog variants.json");
106
+ return ids;
107
+ }
@@ -0,0 +1,71 @@
1
+ import { readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ // Display order — drives CREATIVE_SURFACE_HINTS and, downstream, surfaceSequence.
5
+ export const SURFACE_REGISTRY = [
6
+ { id: "feed", outcome: "add-feed", label: "Feed and content surface" },
7
+ { id: "comments", outcome: "add-comments", label: "Comments and replies" },
8
+ { id: "chat", outcome: "add-chat", label: "Chat inbox and threads" },
9
+ { id: "profile", outcome: "add-follow", label: "Profile and relationship graph" },
10
+ { id: "community", outcome: "add-community", label: "Community management and identity" },
11
+ { id: "notifications", outcome: "add-notifications", label: "Notifications and activation" },
12
+ ];
13
+ // Scan order for reducing an object list to its surfaces/outcomes. Kept distinct from the display
14
+ // order above to reproduce the pre-derivation if-chain output byte-for-byte (community was scanned
15
+ // before profile). Faithful-reproduction only; could be unified if order is proven immaterial.
16
+ const SURFACE_SCAN_ORDER = ["feed", "comments", "chat", "community", "profile", "notifications"];
17
+ const outcomeBySurface = new Map(SURFACE_REGISTRY.map((s) => [s.id, s.outcome]));
18
+ const VALID_SURFACES = new Set(SURFACE_REGISTRY.map((s) => s.id));
19
+ function catalogRoot() {
20
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
21
+ return path.resolve(moduleDir, "..", "..", "packages", "intelligence", "catalog");
22
+ }
23
+ // object id -> surface / block, in catalog declaration order. Read synchronously at module load so
24
+ // the SOCIAL_PLUS_OBJECTS export and the lookup functions stay synchronous (matches prior contract).
25
+ const objectSurface = new Map();
26
+ const objectBlock = new Map();
27
+ {
28
+ const filePath = path.join(catalogRoot(), "experience-objects.json");
29
+ const parsed = JSON.parse(readFileSync(filePath, "utf8"));
30
+ for (const item of parsed.items ?? []) {
31
+ if (typeof item.id !== "string")
32
+ continue;
33
+ if (typeof item.surface === "string") {
34
+ if (!VALID_SURFACES.has(item.surface)) {
35
+ throw new Error(`experience object "${item.id}" declares unknown surface "${item.surface}" (expected one of: ${[...VALID_SURFACES].join(", ")})`);
36
+ }
37
+ objectSurface.set(item.id, item.surface);
38
+ }
39
+ if (typeof item.block === "string") {
40
+ objectBlock.set(item.id, item.block);
41
+ }
42
+ }
43
+ }
44
+ // SDK-backed objects are exactly those placed on a surface; app-layer (knowledge/prediction) and
45
+ // in-development objects declare no surface and are excluded.
46
+ export const SOCIAL_PLUS_OBJECTS = new Set(objectSurface.keys());
47
+ export function surfaceIdsForObjects(objectIds) {
48
+ const present = new Set(objectIds);
49
+ const surfacesPresent = new Set();
50
+ for (const id of present) {
51
+ const surface = objectSurface.get(id);
52
+ if (surface)
53
+ surfacesPresent.add(surface);
54
+ }
55
+ return SURFACE_SCAN_ORDER.filter((sid) => surfacesPresent.has(sid));
56
+ }
57
+ export function outcomesForObjects(objectIds) {
58
+ return surfaceIdsForObjects(objectIds).map((sid) => outcomeBySurface.get(sid));
59
+ }
60
+ export function blockIdForObject(objectId) {
61
+ return objectBlock.get(objectId);
62
+ }
63
+ // Object ids bound to a surface, in catalog declaration order (used to build CREATIVE_SURFACE_HINTS).
64
+ export function surfaceObjectIds(surfaceId) {
65
+ const ids = [];
66
+ for (const [id, surface] of objectSurface) {
67
+ if (surface === surfaceId)
68
+ ids.push(id);
69
+ }
70
+ return ids;
71
+ }
package/dist/outcomes.js CHANGED
@@ -2,7 +2,7 @@ export function hasAnswer(answers, id) {
2
2
  const value = answers[id];
3
3
  return typeof value === "string" && value.trim() !== "";
4
4
  }
5
- const CLASSIFY_ORDER = [
5
+ export const CLASSIFY_ORDER = [
6
6
  "setup-push",
7
7
  "setup-live-data",
8
8
  "add-comments",
@@ -1531,7 +1531,7 @@ const unknown = {
1531
1531
  resolveVerification: () => [],
1532
1532
  resolveNotes: () => [],
1533
1533
  };
1534
- const outcomeRegistry = {
1534
+ export const outcomeRegistry = {
1535
1535
  "setup-sdk": setupSdk,
1536
1536
  "setup-push": setupPush,
1537
1537
  "setup-live-data": setupLiveData,