From b901332df40baa2b55134ebb883a279d135ca228 Mon Sep 17 00:00:00 2001
From: DHCross <45954119+DHCross@users.noreply.github.com>
Date: Sat, 25 Apr 2026 11:48:11 -0500
Subject: [PATCH 1/7] Vary symbolic moment fallback phrasing by semantic seed
---
.../src/lib/raven/symbolicMomentFrontstage.ts | 78 +++++++++++++++----
1 file changed, 61 insertions(+), 17 deletions(-)
diff --git a/vessel/src/lib/raven/symbolicMomentFrontstage.ts b/vessel/src/lib/raven/symbolicMomentFrontstage.ts
index 44a37df6..4fd5328d 100644
--- a/vessel/src/lib/raven/symbolicMomentFrontstage.ts
+++ b/vessel/src/lib/raven/symbolicMomentFrontstage.ts
@@ -490,6 +490,21 @@ function formatList(items: readonly string[], conjunction: 'and' | 'or'): string
return `${items.slice(0, -1).join(', ')}, ${conjunction} ${items[items.length - 1]}`;
}
+
+
+function computeVariantSeed(input: string): number {
+ let hash = 0;
+ for (let index = 0; index < input.length; index += 1) {
+ hash = (hash * 31 + input.charCodeAt(index)) >>> 0;
+ }
+ return hash;
+}
+
+function pickVariant(options: readonly string[], seed: number): string {
+ if (options.length === 0) return '';
+ return options[seed % options.length];
+}
+
function pickVoiceDomains(domains: readonly string[]): string[] {
if (domains.length >= 4) {
return [domains[0], domains[1], domains[domains.length - 1]];
@@ -502,44 +517,72 @@ function pickSilhouetteDomains(domains: readonly string[]): string[] {
return domains.slice(-2);
}
-function buildVoiceSentence(primary: PressureSignature, chamber: string): string {
+function buildVoiceSentence(primary: PressureSignature, chamber: string, variantSeed: number): string {
const domains = pickVoiceDomains(getChamberDomainOptions(chamber));
const domainPhrase = formatList(domains, 'and');
switch (primary) {
case 'Amplification':
case 'FusedExpansion':
- return `Opening here tends to show through ${domainPhrase}. Whether it carries depends on the ground.`;
+ return pickVariant([
+ `Opening here tends to show through ${domainPhrase}. Whether it carries depends on the ground.`,
+ `This opening usually reaches you through ${domainPhrase}. What holds depends on the ground beneath it.`,
+ ], variantSeed);
case 'Compression':
case 'FusedCompression':
- return `Pressure here tends to narrow through ${domainPhrase}. Whether it carries depends on the ground.`;
+ return pickVariant([
+ `Pressure here tends to narrow through ${domainPhrase}. Whether it carries depends on the ground.`,
+ `The squeeze concentrates first through ${domainPhrase}. Its impact depends on the ground it meets.`,
+ ], variantSeed);
case 'Shear':
case 'SplitCurrent':
- return `Cross-pressure here tends to show through ${domainPhrase}. Whether it carries depends on the ground.`;
+ return pickVariant([
+ `Cross-pressure here tends to show through ${domainPhrase}. Whether it carries depends on the ground.`,
+ `Competing pulls surface through ${domainPhrase}. Whether this bites depends on the ground underneath.`,
+ ], variantSeed);
case 'Ignition':
- return `Heat here tends to move through ${domainPhrase}. Whether it carries depends on the ground.`;
+ return pickVariant([
+ `Heat here tends to move through ${domainPhrase}. Whether it carries depends on the ground.`,
+ `The spark runs through ${domainPhrase} first. Its consequence depends on what it lands on.`,
+ ], variantSeed);
case 'Dissolution':
- return `Clarity is softer here. The line can blur through ${domainPhrase}.`;
+ return pickVariant([
+ `Clarity is softer here. The line can blur through ${domainPhrase}.`,
+ `Edges soften in this chamber, and the line can blur through ${domainPhrase}.`,
+ ], variantSeed);
case 'DirectionlessLoad':
case 'Carrier':
default:
- return `The load is present here and tends to show through ${domainPhrase}. Whether it carries depends on the ground.`;
+ return pickVariant([
+ `The load is present here and tends to show through ${domainPhrase}. Whether it carries depends on the ground.`,
+ `A steady load is active here, usually through ${domainPhrase}. Whether it lands depends on the ground condition.`,
+ ], variantSeed);
}
}
-function buildSilhouetteSentence(chamber: string): string {
+function buildSilhouetteSentence(chamber: string, variantSeed: number): string {
const domains = pickSilhouetteDomains(getChamberDomainOptions(chamber));
const domainPhrase = formatList(domains, 'or');
- return `But if this does not land there first, it may be gathering more quietly through ${domainPhrase} instead.`;
+ return pickVariant([
+ `But if this does not land there first, it may be gathering more quietly through ${domainPhrase} instead.`,
+ `If it does not strike there first, the quieter build is likely moving through ${domainPhrase}.`,
+ ], variantSeed);
}
-function buildLandingSentence(chamber: string): string {
- return `This lands first in ${chamber} — ${getChamberAnchor(chamber)}.`;
+function buildLandingSentence(chamber: string, variantSeed: number): string {
+ return pickVariant([
+ `This lands first in ${chamber} — ${getChamberAnchor(chamber)}.`,
+ `${chamber} is the first contact line today — ${getChamberAnchor(chamber)}.`,
+ ], variantSeed);
}
-function buildVerificationPrompt(chamber: string): string {
+function buildVerificationPrompt(chamber: string, variantSeed: number): string {
const domains = getChamberDomainOptions(chamber).slice(0, 4);
- return `On the ground, this might touch ${formatList(domains, 'or')}. Is one of those close, or is this landing elsewhere?`;
+ const domainPhrase = formatList(domains, 'or');
+ return pickVariant([
+ `On the ground, this might touch ${domainPhrase}. Is one of those close, or is this landing elsewhere?`,
+ `In lived terms, does this show first in ${domainPhrase}, or is it concentrating somewhere else?`,
+ ], variantSeed);
}
function canonicalize(value: unknown): string {
@@ -705,16 +748,17 @@ export function buildStructuredSymbolicMomentReply(input: {
// Fallback builders if LLM output is unstructured
const fallbackForce = resolveForceSentence(primaryDriver, drivers);
const fallbackMeasurement = resolveMeasurementSentence(pressureSignatures[0], metrics, primaryDriver);
- const fallbackLanding = buildLandingSentence(chamber);
- const fallbackVoice = buildVoiceSentence(pressureSignatures[0], chamber);
- const fallbackSilhouette = buildSilhouetteSentence(chamber);
+ const variantSeed = computeVariantSeed(`${chamber}|${primaryDriver?.label ?? 'none'}|${pressureSignatures[0]}|${metrics.loadScore.toFixed(2)}|${metrics.directionScore.toFixed(2)}`);
+ const fallbackLanding = buildLandingSentence(chamber, variantSeed);
+ const fallbackVoice = buildVoiceSentence(pressureSignatures[0], chamber, variantSeed);
+ const fallbackSilhouette = buildSilhouetteSentence(chamber, variantSeed);
const fallbackZone1 = [fallbackForce, fallbackMeasurement, fallbackLanding, fallbackVoice, fallbackSilhouette].join(' ');
const zone1 = (apertureMatch && fieldEdgeMatch && voiceMatch)
? normalizeText(`${apertureMatch} ${fieldEdgeMatch} ${voiceMatch}`)
: fallbackZone1;
- const zone3 = inquiryMatch ? normalizeText(inquiryMatch) : buildVerificationPrompt(chamber);
+ const zone3 = inquiryMatch ? normalizeText(inquiryMatch) : buildVerificationPrompt(chamber, variantSeed);
const zone2 = buildSealedAudit({
chamber,
drivers,
From 13a96c31ff5c1435d56303a8335fefded9c8ce40 Mon Sep 17 00:00:00 2001
From: DHCross <45954119+DHCross@users.noreply.github.com>
Date: Thu, 23 Apr 2026 09:13:11 -0500
Subject: [PATCH 2/7] Add explicit counterpart Symbolic Moment actions
---
vessel/src/app/page.tsx | 17 ++++++++
vessel/src/components/ProfileVault.tsx | 40 +++++++++++++++++++
.../chat/CounterpartQuickActions.tsx | 13 ++++++
vessel/src/test/polyadic-chat-routing.test.ts | 2 +
4 files changed, 72 insertions(+)
diff --git a/vessel/src/app/page.tsx b/vessel/src/app/page.tsx
index 30fad71e..c01c6421 100644
--- a/vessel/src/app/page.tsx
+++ b/vessel/src/app/page.tsx
@@ -3456,6 +3456,14 @@ export default function App() {
>
Map Us · {profile.name}
+
);
})}
@@ -3898,6 +3906,7 @@ export default function App() {
soloFocusProfileId={soloFocusProfileId}
compact
onSoloMirror={(profile) => handleCounterpartSoloMirror(profile, `desktop_rail_mirror_${profile.id}`)}
+ onSymbolicMoment={(profile) => handleCounterpartSymbolicMoment(profile, `desktop_rail_symbolic_${profile.id}`)}
onMapPair={handleCounterpartMapPair}
onMapObserverPair={handleMapObserverPair}
onPolyadicMap={handlePolyadicMap}
@@ -4353,6 +4362,10 @@ export default function App() {
{/* Profile Vault */}
{
+ setIsVaultOpen(false);
+ handleCounterpartSymbolicMoment(profile, `vault_profile_symbolic_${profile.id}`);
+ }}
onOpenBlueprint={handleOpenProfileBlueprint}
onClearSession={() => {
archiveCurrentFlightRecorderRun();
@@ -4888,6 +4901,10 @@ export default function App() {
closeMobileControls();
handleCounterpartSoloMirror(profile, `mobile_chip_mirror_${profile.id}`);
}}
+ onSymbolicMoment={(profile) => {
+ closeMobileControls();
+ handleCounterpartSymbolicMoment(profile, `mobile_chip_symbolic_${profile.id}`);
+ }}
onMapPair={(profile) => {
closeMobileControls();
handleCounterpartMapPair(profile);
diff --git a/vessel/src/components/ProfileVault.tsx b/vessel/src/components/ProfileVault.tsx
index 22e0ffd7..3fd8b981 100644
--- a/vessel/src/components/ProfileVault.tsx
+++ b/vessel/src/components/ProfileVault.tsx
@@ -48,6 +48,7 @@ import { assessNatalGeometry, downloadNatalMarkdown } from '../lib/natalExport';
interface ProfileVaultProps {
readonly onProfileSelect: (profile: VaultProfile | null) => void;
readonly onStageProfile: (profile: VaultProfile | null, role?: StagingRole) => void;
+ readonly onRunSymbolicMoment?: (profile: VaultProfile) => void;
readonly onOpenBlueprint?: (profile: VaultProfile) => void | Promise;
readonly onClearSession?: () => void;
readonly activeProfile: VaultProfile | null;
@@ -272,6 +273,7 @@ function pickBestLocationCandidate(
export default function ProfileVault({
onProfileSelect,
onStageProfile,
+ onRunSymbolicMoment,
onOpenBlueprint,
onClearSession = () => { },
activeProfile,
@@ -2422,6 +2424,25 @@ export default function ProfileVault({
);
})()}
+