diff --git a/AGENTS.md b/AGENTS.md index fe36b3796..29692fe2b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,37 +1,62 @@ -# Agent Guide - -## Project Structure (Read First) - -This is a monorepo. The layout is non-obvious — read carefully before searching for files. - -``` -Shipyard/ ← repo root (tooling only, NOT the app) -├── package.json ← sherlog/script runner; all scripts delegate to vessel/ -├── Taskfile.yml ← top-level task runner -├── vessel/ ← THE NEXT.JS APP (start here for all UI/API work) -│ ├── package.json ← app dependencies (npm install runs here) -│ ├── next.config.ts ← Next.js config -│ ├── tailwind.config.js ← Tailwind config -│ ├── tsconfig.json ← TypeScript config -│ ├── src/ ← all app source (components, lib, app, api routes) -│ ├── public/ ← static assets, OpenAPI specs, ai-plugin.json -│ ├── firestore.rules ← Firebase security rules -│ ├── docs/ ← implementation briefs, architecture notes -│ └── sherlog-velocity/ ← sherlog tooling (separate sub-package) +Yes. The current guide is already solid, but it has one weakness: it gives agents a lot of rules without a clear priority ladder. I’d make it more “execution-contract” than “reference doc,” so an AI agent knows exactly what to do first, what never to do, and what proof is required before claiming success. The uploaded guide already covers the key terrain: `vessel/` as the actual app, Sherlog preflight, no scheduled workflows, branch discipline, workspace cleanup, and the completion contract. + +Here’s a tightened version. + +````md +# AGENTS.md — Shipyard Operating Contract + +This repository is a Vercel + Firebase monorepo. Treat this file as binding instructions for AI agents, coding assistants, and automated contributors. + +The goal is not merely to change code. The goal is to preserve repository integrity, avoid accidental deployments, keep Sherlog telemetry useful, and leave a verifiable handoff trail. + +## 0. Non-Negotiable Priority Order + +When instructions conflict, follow this order: + +1. User’s explicit request for the current task. +2. This AGENTS.md file. +3. Existing repo architecture and local docs. +4. Prior AI suggestions, comments, or assumptions. + +Do not invent missing requirements. Do not create branches, push code, enable workflows, or open PRs unless the user explicitly asks. + +## 1. Repository Shape + +This is a monorepo. The app is not at the repo root. + +```text +Shipyard/ ← repo root; tooling and coordination only +├── package.json ← script runner; delegates to vessel/ +├── Taskfile.yml ← repo-level task runner +├── AGENTS.md ← this operating contract +├── vessel/ ← THE NEXT.JS APP +│ ├── package.json ← app dependencies +│ ├── next.config.ts +│ ├── tailwind.config.js +│ ├── tsconfig.json +│ ├── src/ ← app source: UI, API routes, lib +│ ├── public/ ← static assets and public specs +│ ├── firestore.rules +│ ├── docs/ ← implementation briefs and architecture notes +│ └── sherlog-velocity/ ← Sherlog tooling sub-package └── scripts/ ← repo-level utilities -``` +```` -**Rules that follow from this:** -- All UI and API changes live under `vessel/src/`. -- `cd vessel && npm run typecheck` is the local verification command. -- The repo-root `package.json` has no app code — it just shells into `vessel/`. -- Tailwind, Next.js, TypeScript configs are all inside `vessel/`, not at repo root. -- Do not confuse `vessel/vessel/` (build artifact dir) with `vessel/` (the app). +Working rule: - -## Sherlog Preflight (Required) +All app UI, API, and library changes belong under `vessel/src/`. -Before proposing plans, estimates, or implementation order for a feature, run: +Do not confuse `vessel/` with generated or nested build artifacts such as `vessel/vessel/`. + +## 2. Required Startup Sequence + +Before planning, estimating, or implementing a feature, run the workspace repair guard first: + +```bash +npm run sherlog:repair-workspace -- --apply --json +``` + +Then run Sherlog preflight: ```bash npm run sherlog:verify -- --json @@ -40,71 +65,276 @@ npm run sherlog:gaps -- --feature "Feature Name" --json npm run sherlog:prompt -- "Feature Name" ``` -Use `/docs/sherlog-next-steps.md` and `/docs/why-sherlog.md` as the local operating guide. +Use: + +```text +/docs/sherlog-next-steps.md +/docs/why-sherlog.md +``` + +as the local operating guide for Sherlog interpretation. -### Workspace Integrity (Antigravity Check) +If the task is read-only, documentation-only, or an emergency diagnostic where Sherlog cannot run, state that clearly in the handoff. Do not pretend the preflight passed. -If AI agent worktrees (Codex, Claude, etc.) have linked to this repo, your workspace may be "poisoned": -- `.git/config` may contain `[extensions] worktreeConfig = true` -- Workspace files may have accumulated `chat.tools.terminal.autoApprove` entries +## 3. Workspace Integrity + +AI worktrees can poison this repo by leaving behind editor or git state. Watch for: + +```text +.git/config entries such as: +[extensions] + worktreeConfig = true + +workspace files containing: +chat.tools.terminal.autoApprove +``` + +The repair command should be run before work begins: -**Before you start any task, run:** ```bash npm run sherlog:repair-workspace -- --apply --json ``` -This prevents mysterious "Antigravity breakage" where editor behavior degrades only for this repository. +Local app entrypoints already run `sherlog:guard-workspace` before `dev`, `build`, `typecheck`, and `test`. If the guard hard-fails, stop and report the reason. Do not bypass it. + +Before handoff, remove agent-created worktrees under: + +```text +.codex/worktrees/ +.claude/worktrees/ +/private/tmp/shipyard-ci-* +``` + +unless the user explicitly asked to preserve one. + +## 4. Verification Commands + +For app work, verify from inside `vessel/`: + +```bash +cd vessel +npm run typecheck +npm run build +``` + +For targeted tests, run the narrowest relevant test first, then broader verification if the change touches shared code. -Local app entrypoints now run `sherlog:guard-workspace` automatically before `dev`, `build`, `typecheck`, and `test`. The guard auto-repairs safe drift and hard-fails if dirty managed agent worktrees still remain linked. - +Do not claim success unless verification actually ran and passed. -## CRITICAL: Automated Workflows Policy +If verification cannot run, say why. Examples: -**DO NOT** enable automated GitHub Actions workflows (e.g., cron schedules or continuous automated maintenance jobs). -Our account has a strictly enforced budget of 2,000 Actions minutes per month on the free tier. Scheduled workflows consume minutes 24/7 even when not needed and can quickly lead to account lockouts. +```text +typecheck not run: dependency install missing +build not run: task was documentation-only +test not run: no relevant test script found +``` + +## 5. Automated Workflow Policy + +Do not enable scheduled or continuous automated GitHub Actions workflows. + +The account has a strict 2,000 Actions-minutes/month free-tier budget. Scheduled workflows consume minutes even when no human needs them. + +Forbidden unless the user explicitly asks: + +```yaml +on: + schedule: + - cron: ... +``` -**Key Workflows to Watch For:** -- `sherlog-scheduled.yml` (daily maintenance) -- `sherlog-health.yml` (automated health checks) -- Any workflow utilizing a `schedule:` trigger (`cron`) +Watch especially for: + +```text +sherlog-scheduled.yml +sherlog-health.yml +any workflow using schedule: +``` + +Allowed only by explicit human request: -**Manual Activation (when needed):** -Instead of automated schedules, workflows should only be triggered manually via `workflow_dispatch`. If a human requests a workflow run, use: ```bash gh workflow enable "" gh workflow run "" --ref main ``` -Users must explicitly opt-in to automation. You are explicitly forbidden from reverting these files back to automated schedules. +Prefer `workflow_dispatch` over cron. + +Never revert a workflow back to scheduled automation as a “fix.” + +## 6. Branching and Deployment Discipline + +Every remote branch push may create a Vercel preview and may require Firebase authorized-domain overhead. + +Default behavior: + +Stay on the current branch. + +Do not create a branch unless the user explicitly asks or the task cannot safely proceed on the current branch. + +If a branch is necessary, create exactly one branch: + +```text +ai/ +``` + +Do not create multiple speculative branches. + +Do not push just to test. Verify locally first. -## Linear issue key hygiene +Before investigating a failing deployment, confirm it belongs to the branch you are working on. If it belongs to another branch, stop and report the mismatch. -- Treat Linear issue keys as optional metadata, not as a hard requirement for branches, commits, or PR titles. -- If the task context already includes a real `WOV-*` key and it helps traceability, carry it through into branch, commit, or PR metadata. -- Do not invent issue keys. +## 7. Git Discipline -## Branching and deployment discipline +Do not leave behind strings of micro-commits. -This is a Vercel + Firebase project. Every remote branch push creates a preview deployment and adds Firebase authorized-domain overhead. +Use logical commits that preserve meaningful development history. -- Stay on the current branch by default. Do not create or push branches unless explicitly asked. -- If branching is necessary, create exactly one branch named `ai/`. Never create multiple speculative branches. -- Never trigger preview deployments just to test. Verify locally first with `npm run typecheck` and `npm run build` inside `vessel/`. -- If a failing deployment belongs to another branch, stop and report the branch mismatch instead of investigating unrelated previews. -- Before claiming success, report: branch name, commit SHA, whether anything was pushed, whether any preview deployment was created, and local verification results. +Repository standard: -## Git & workspace discipline +Interactive Rebase → Rebase and Merge -- Clean up detached worktrees before you finish a task. Agent-created worktrees under `.codex/worktrees/`, `.claude/worktrees/`, and `/private/tmp/shipyard-ci-*` are not allowed to linger after task completion. -- Do not leave strings of micro-commits behind on your branch. Consolidate your own work into logical commits before handoff. -- The repository standard is **Interactive Rebase -> Rebase and Merge**. Do not use or recommend **Squash and Merge** because it destroys the commit-resolution detail Sherlog uses for velocity and blast-radius telemetry. -- Sherlog is diagnostic infrastructure, not repository-control infrastructure. It may read git history and emit Sherlog-owned artifacts, but it must not manage branches, worktrees, or `.code-workspace` files unless a human explicitly asks for Sherlog maintenance. +Do not recommend Squash and Merge. Squashing destroys commit-resolution detail Sherlog uses for velocity and blast-radius telemetry. -## Completion & submission contract +Linear issue keys are optional metadata. If the task already includes a real `WOV-*` key, preserve it where useful. Do not invent issue keys. -- Do not describe a task as "fixed", "submitted", or "done" unless you can name the exact repository state that proves it. -- "Fixed" means the file edits exist locally and the relevant verification ran. -- "Submitted" means a verifiable git artifact exists: at minimum a local commit SHA; if the user asked for delivery upstream, also state whether it was pushed and to which branch. -- "Ready for review" means the work was pushed and you can name the branch; if a PR exists, provide that fact too. -- Never let prose stand in for repository state. If nothing was committed, say explicitly: changes are local only, not committed. If nothing was pushed, say explicitly: committed locally only, not pushed. -- Before handoff on any code-changing task, report all of the following in one place: changed files, verification run and result, branch name, commit SHA (or "no commit"), pushed yes/no, preview deployment yes/no, PR yes/no. +## 8. Sherlog Boundaries + +Sherlog is diagnostic infrastructure. + +Sherlog may: + +```text +read git history +emit Sherlog-owned artifacts +identify gaps, risks, and blast radius +support planning and verification +``` + +Sherlog must not: + +```text +manage branches +create worktrees +rewrite workspace files +alter .code-workspace files +control repository state +``` + +unless a human explicitly requests Sherlog maintenance. + +## 9. Coding Conduct + +Before editing: + +Read the relevant files. + +Do not rely on filename guesses when a local search is available. + +Prefer small, direct changes over broad rewrites. + +Preserve existing architecture unless the user explicitly asks for a redesign. + +Do not hide behavior behind silent fallbacks when the domain requires auditability. If a fallback changes meaning, expose it in code, tests, or logs. + +For Raven/Symbolic Moment work specifically: + +Do not leak compiler or section markup into user-visible output. + +Do not pre-classify SST states before testimony. + +Do not use WB, ABE, OSR, Mixed, or Inconclusive in pre-testimony frontstage prose. + +Do not ask leading verification questions. + +Do not convert geometry into claimed lived events. + +Maintain the separation: + +```text +pre-testimony: sealed geometry + symbolic pressure + placement inquiry +post-testimony: resonance classification + diagnostic logging +``` + +## 10. Completion Vocabulary + +Use these words precisely. + +“Fixed” means: + +```text +file edits exist locally +relevant verification ran +verification passed or failure is clearly reported +``` + +“Submitted” means: + +```text +a verifiable git artifact exists +at minimum, a local commit SHA +if upstream delivery was requested, also pushed branch and PR status +``` + +“Ready for review” means: + +```text +work was pushed +branch is named +PR status is stated +verification result is reported +``` + +Do not say “done,” “fixed,” “submitted,” or “ready” unless the repository state proves it. + +## 11. Required Handoff Report + +Every code-changing task must end with one handoff block: + +```text +Changed files: +- path/to/file +- path/to/file + +Verification: +- npm run typecheck: pass/fail/not run +- npm run build: pass/fail/not run +- tests: pass/fail/not run + +Repository state: +- Branch: +- Commit SHA: +- Pushed: yes/no +- Preview deployment created: yes/no +- PR: yes/no + +Notes: +- Known limitations +- Follow-up risks +- Anything intentionally left local only +``` + +If nothing was committed, write: + +```text +Commit SHA: no commit +``` + +If nothing was pushed, write: + +```text +Pushed: no +``` + +If no preview was created, write: + +```text +Preview deployment created: no +``` + +Never let prose substitute for repository state. + +``` + +The main improvement is that this version makes the agent’s decision tree harder to game. It distinguishes startup, verification, branching, workflow safety, and handoff proof. It also folds in the Raven/Symbolic Moment firewall directly, because that is now one of the repo’s high-risk zones: a coder can otherwise “fix phrasing” while accidentally reintroducing pre-testimony classification or outcome-language. +``` diff --git a/RaveniOS/RaveniOS/Design/RavenDesignTokens.swift b/RaveniOS/RaveniOS/Design/RavenDesignTokens.swift index 0c4d12efe..770f3177f 100644 --- a/RaveniOS/RaveniOS/Design/RavenDesignTokens.swift +++ b/RaveniOS/RaveniOS/Design/RavenDesignTokens.swift @@ -333,3 +333,41 @@ enum RavenMotion { static let landingPromptSpringBounce: Double = 0.20 static let landingPromptSpringDelay: Double = 0.35 } + +// MARK: - Typography +// +// Named font scale for non-spatial views (Chat, Vault, sheets). +// Spatial labels in SkyMapView continue to use .system(size:design:monospaced) +// directly for fine-grained pixel control; this ramp targets the UI chrome. + +enum RavenTypography { + /// Screen/section title — chat header name, nav titles. + static func title() -> Font { .system(size: 17, weight: .semibold) } + + /// Primary UI body — mode display names, list row headlines. + static func body() -> Font { .system(size: 15, weight: .regular) } + + /// Secondary label — phase labels, profile names in header, subtitles. + static func caption() -> Font { .system(size: 12, weight: .regular) } + + /// Monospaced metadata — coords, timestamps, stat values. + static func mono(size: CGFloat = 11, weight: Font.Weight = .regular) -> Font { + .system(size: size, weight: weight, design: .monospaced) + } +} + +extension View { + /// Raven title style: 17pt semibold. + func ravenTitle() -> some View { self.font(RavenTypography.title()) } + + /// Raven body style: 15pt regular. + func ravenBody() -> some View { self.font(RavenTypography.body()) } + + /// Raven caption style: 12pt regular. + func ravenCaption() -> some View { self.font(RavenTypography.caption()) } + + /// Raven monospaced style: configurable size, default 11pt. + func ravenMono(size: CGFloat = 11, weight: Font.Weight = .regular) -> some View { + self.font(RavenTypography.mono(size: size, weight: weight)) + } +} diff --git a/RaveniOS/RaveniOS/RaveniOSApp.swift b/RaveniOS/RaveniOS/RaveniOSApp.swift index 952b247bc..551700637 100644 --- a/RaveniOS/RaveniOS/RaveniOSApp.swift +++ b/RaveniOS/RaveniOS/RaveniOSApp.swift @@ -6,6 +6,7 @@ struct RaveniOSApp: App { init() { FirebaseApp.configure() + configureTabBarAppearance() } var body: some Scene { @@ -13,4 +14,34 @@ struct RaveniOSApp: App { ContentView() } } + + // MARK: - Tab Bar Theming + + /// Applies cosmos dark chrome to the tab bar using UITabBarAppearance. + /// Mirrors RavenPalette.cosmosBackground (0.04, 0.04, 0.10) and ravenAmber + /// (hue 0.08, sat 0.60, bri 0.80) for selected glyph tint. + /// + /// Configured at app start so the appearance is in place before the first + /// render — avoids a flash of the system default white bar. + /// + /// Note: EarthView overlays the TabView with zIndex(2) and ignoresSafeArea(), + /// so the tab bar sits beneath it during Earth mode and is not affected. + private func configureTabBarAppearance() { + let cosmos = UIColor(red: 0.04, green: 0.04, blue: 0.10, alpha: 0.97) + let amber = UIColor(hue: 0.08, saturation: 0.60, brightness: 0.80, alpha: 1.0) + let dim = UIColor.white.withAlphaComponent(0.35) + + let appearance = UITabBarAppearance() + appearance.configureWithOpaqueBackground() + appearance.backgroundColor = cosmos + + let stacked = appearance.stackedLayoutAppearance + stacked.selected.iconColor = amber + stacked.selected.titleTextAttributes = [.foregroundColor: amber] + stacked.normal.iconColor = dim + stacked.normal.titleTextAttributes = [.foregroundColor: dim] + + UITabBar.appearance().standardAppearance = appearance + UITabBar.appearance().scrollEdgeAppearance = appearance + } } diff --git a/RaveniOS/RaveniOS/Views/ChatView.swift b/RaveniOS/RaveniOS/Views/ChatView.swift index 23dcfb746..1b68a0c55 100644 --- a/RaveniOS/RaveniOS/Views/ChatView.swift +++ b/RaveniOS/RaveniOS/Views/ChatView.swift @@ -25,7 +25,7 @@ struct ChatView: View { inputBar } } - .background(Color(.systemBackground)) + .background(RavenPalette.cosmosBackground.ignoresSafeArea()) .onTapGesture { inputFocused = false } .sheet(isPresented: $showModeSelector) { ModeSelectorView(selectedMode: $selectedMode, vaultVM: vaultVM) @@ -43,25 +43,28 @@ struct ChatView: View { VStack(alignment: .leading, spacing: 3) { HStack(spacing: 6) { Text("Raven Calder") - .font(.headline) + .ravenTitle() + .foregroundStyle(.white) // Connection state dot — only visible when degraded or offline if chatVM.connectionState != .connected { Circle() - .fill(chatVM.connectionState == .degraded ? Color.yellow : Color.red) + .fill(chatVM.connectionState == .degraded + ? Color.yellow + : Color.red) .frame(width: 7, height: 7) } } HStack(spacing: 6) { Text(phaseLabel) - .font(.caption) - .foregroundStyle(.secondary) + .ravenCaption() + .foregroundStyle(.white.opacity(0.45)) if let profile = vaultVM.activeProfile { Text("·") - .foregroundStyle(.secondary) - .font(.caption) + .ravenCaption() + .foregroundStyle(.white.opacity(0.30)) Text(profile.name) - .font(.caption) - .foregroundStyle(.secondary) + .ravenCaption() + .foregroundStyle(.white.opacity(0.45)) } } } @@ -70,12 +73,14 @@ struct ChatView: View { ModePill(mode: selectedMode) { showModeSelector = true } - // TTS toggle + // TTS toggle — amber when active, dim when off Button { chatVM.toggleTTS() } label: { Image(systemName: chatVM.isTTSEnabled ? "speaker.wave.2.fill" : "speaker.slash") - .foregroundStyle(chatVM.isTTSEnabled ? .blue : .secondary) + .foregroundStyle(chatVM.isTTSEnabled + ? RavenPalette.ravenAmber + : .white.opacity(0.35)) } .buttonStyle(.plain) // New session @@ -83,13 +88,18 @@ struct ChatView: View { chatVM.startNewSession() } label: { Image(systemName: "arrow.counterclockwise") - .foregroundStyle(.secondary) + .foregroundStyle(.white.opacity(0.35)) } .buttonStyle(.plain) } .padding(.horizontal) .padding(.vertical, 10) - .background(.ultraThinMaterial) + .background(RavenPalette.cosmosBackground.opacity(0.96)) + .overlay(alignment: .bottom) { + Rectangle() + .fill(Color.white.opacity(0.07)) + .frame(height: 0.5) + } } // MARK: - Message List @@ -143,23 +153,22 @@ struct ChatView: View { Spacer(minLength: 60) Image(systemName: selectedMode.iconName) .font(.system(size: 48)) - .foregroundStyle(.secondary) + .foregroundStyle(RavenPalette.ravenAmber.opacity(0.60)) Text(selectedMode.displayName) - .font(.title3) + .ravenTitle() + .foregroundStyle(.white.opacity(0.80)) if let profile = vaultVM.activeProfile { Text("Reading for \(profile.name)") - .font(.subheadline) - .foregroundStyle(.secondary) + .ravenCaption() + .foregroundStyle(.white.opacity(0.45)) } else if selectedMode.requiresProfile { - VStack(spacing: 8) { - Text("Add a profile in the Vault first") - .font(.subheadline) - .foregroundStyle(.secondary) - } + Text("Add a profile in the Vault first") + .ravenCaption() + .foregroundStyle(.white.opacity(0.45)) } else { Text(selectedMode.subtitle) - .font(.subheadline) - .foregroundStyle(.secondary) + .ravenCaption() + .foregroundStyle(.white.opacity(0.45)) .multilineTextAlignment(.center) .padding(.horizontal) } @@ -176,10 +185,16 @@ struct ChatView: View { TextField("Say something...", text: $inputText, axis: .vertical) .textFieldStyle(.plain) .lineLimit(1...5) + .ravenBody() + .foregroundStyle(.white) .padding(.horizontal, 12) .padding(.vertical, 10) - .background(Color(.secondarySystemBackground)) + .background(Color.white.opacity(0.08)) .clipShape(RoundedRectangle(cornerRadius: 20)) + .overlay( + RoundedRectangle(cornerRadius: 20) + .stroke(Color.white.opacity(0.12), lineWidth: 0.5) + ) .focused($inputFocused) .onSubmit { submitMessage() } @@ -188,33 +203,36 @@ struct ChatView: View { } label: { Image(systemName: chatVM.isLoading ? "stop.circle.fill" : "arrow.up.circle.fill") .font(.system(size: 32)) - .foregroundStyle(canSend ? .blue : .secondary) + .foregroundStyle(canSend ? RavenPalette.sendActive : .white.opacity(0.25)) } .disabled(!canSend) .buttonStyle(.plain) } .padding(.horizontal) .padding(.vertical, 8) - .background(.ultraThinMaterial) + .background(RavenPalette.cosmosBackground.opacity(0.96)) + .overlay(alignment: .top) { + Rectangle() + .fill(Color.white.opacity(0.07)) + .frame(height: 0.5) + } } // MARK: - Offline Banner - /// Persistent strip shown while there is no network connection. - /// Dismissed automatically when connection restores and the queued message sends. private var offlineBanner: some View { HStack(spacing: 8) { Image(systemName: "wifi.slash") .font(.footnote) - .foregroundStyle(.secondary) + .foregroundStyle(.white.opacity(0.45)) Text("No signal — will send when you're back online") - .font(.footnote) - .foregroundStyle(.secondary) + .ravenCaption() + .foregroundStyle(.white.opacity(0.45)) Spacer() } .padding(.horizontal) .padding(.vertical, 7) - .background(Color(.secondarySystemBackground)) + .background(Color.white.opacity(0.06)) .transition(.move(edge: .top).combined(with: .opacity)) } @@ -225,44 +243,46 @@ struct ChatView: View { Image(systemName: error.requiresReauth ? "person.crop.circle.badge.exclamationmark" : "exclamationmark.triangle.fill") - .foregroundStyle(error.requiresReauth ? .red : .orange) + .foregroundStyle(error.requiresReauth + ? Color.red + : RavenPalette.ravenAmber) Text(error.message) - .font(.footnote) + .ravenCaption() + .foregroundStyle(.white.opacity(0.85)) .fixedSize(horizontal: false, vertical: true) Spacer() - // Retry button — only for retryable errors if error.isRetryable { Button { Task { await chatVM.retryPendingMessage() } } label: { Text("Try again") - .font(.footnote.bold()) - .foregroundStyle(.primary) + .ravenCaption() + .fontWeight(.semibold) + .foregroundStyle(.white) .padding(.horizontal, 10) .padding(.vertical, 5) .background( - Capsule().fill(Color(.tertiarySystemBackground)) + Capsule().fill(Color.white.opacity(0.12)) ) } .buttonStyle(.plain) } - // Dismiss Button { withAnimation { chatVM.chatError = nil } } label: { Image(systemName: "xmark") .font(.footnote) - .foregroundStyle(.secondary) + .foregroundStyle(.white.opacity(0.45)) } .buttonStyle(.plain) } .padding(.horizontal) .padding(.vertical, 10) - .background(Color(.systemYellow).opacity(0.12)) + .background(RavenPalette.ravenAmber.opacity(0.10)) .transition(.move(edge: .bottom).combined(with: .opacity)) } @@ -275,10 +295,10 @@ struct ChatView: View { private var phaseLabel: String { switch chatVM.currentPhase { case .calibration: return "Calibration" - case .tension: return "Tension" + case .tension: return "Tension" case .integration: return "Integration" - case .vector: return "Vector" - case .seal: return "Sealed" + case .vector: return "Vector" + case .seal: return "Sealed" } } @@ -301,9 +321,10 @@ struct MessageBubble: View { if message.role == .user { Spacer(minLength: 60) } VStack(alignment: message.role == .user ? .trailing : .leading, spacing: 4) { Text(message.text) + .ravenBody() .padding(.horizontal, 14) .padding(.vertical, 10) - .background(bubbleColor) + .background(bubbleBackground) .foregroundStyle(textColor) .clipShape(RoundedRectangle(cornerRadius: 18)) if let tag = message.balanceTag { @@ -312,11 +333,11 @@ struct MessageBubble: View { if message.isFallback { HStack(spacing: 4) { Image(systemName: "arrow.trianglehead.2.clockwise") - .font(.caption2) + .ravenMono(size: 10) Text("System throttled — retry in a moment") - .font(.caption2) + .ravenMono(size: 10) } - .foregroundStyle(.secondary) + .foregroundStyle(.white.opacity(0.35)) .padding(.horizontal, 8) } } @@ -324,11 +345,16 @@ struct MessageBubble: View { } } - private var bubbleColor: Color { - message.role == .user ? .blue : Color(.secondarySystemBackground) + private var bubbleBackground: Color { + message.role == .user + ? RavenPalette.ravenAmber.opacity(0.85) + : Color.white.opacity(0.09) } + private var textColor: Color { - message.role == .user ? .white : .primary + message.role == .user + ? Color(red: 0.08, green: 0.05, blue: 0.02) + : .white.opacity(0.90) } } @@ -343,8 +369,8 @@ struct BalanceTagView: View { .fill(magnitudeColor) .frame(width: 8, height: 8) Text("\(tag.tierLabel) · \(tag.balanceLabel)") - .font(.caption2) - .foregroundStyle(.secondary) + .ravenMono(size: 10) + .foregroundStyle(.white.opacity(0.40)) } .padding(.horizontal, 8) } @@ -352,10 +378,10 @@ struct BalanceTagView: View { private var magnitudeColor: Color { switch tag.tierLabel { case "Calm": return .green - case "Moderate": return .yellow + case "Moderate": return RavenPalette.ravenAmber case "High": return .orange case "Intense": return .red - default: return .gray + default: return .white.opacity(0.30) } } } @@ -369,14 +395,14 @@ struct TypingIndicator: View { HStack(spacing: 4) { ForEach(0..<3, id: \.self) { i in Circle() - .fill(Color.secondary) + .fill(Color.white.opacity(0.35)) .frame(width: 8, height: 8) .scaleEffect(1 + 0.4 * sin(phase + Double(i) * .pi / 1.5)) } } .padding(.horizontal, 14) .padding(.vertical, 10) - .background(Color(.secondarySystemBackground)) + .background(Color.white.opacity(0.09)) .clipShape(RoundedRectangle(cornerRadius: 18)) .onAppear { withAnimation(.linear(duration: 1).repeatForever(autoreverses: false)) { diff --git a/RaveniOS/RaveniOS/Views/SessionSealedCard.swift b/RaveniOS/RaveniOS/Views/SessionSealedCard.swift index 44475312a..4e892571c 100644 --- a/RaveniOS/RaveniOS/Views/SessionSealedCard.swift +++ b/RaveniOS/RaveniOS/Views/SessionSealedCard.swift @@ -10,48 +10,49 @@ struct SessionSealedCard: View { var body: some View { VStack(spacing: 0) { - // Card VStack(spacing: 20) { // Header VStack(spacing: 8) { Image(systemName: "seal.fill") .font(.system(size: 36)) - .foregroundStyle(.secondary) + .foregroundStyle(RavenPalette.ravenAmber.opacity(0.75)) Text("Session Sealed") - .font(.title3) - .fontWeight(.semibold) + .ravenTitle() + .foregroundStyle(.white) Text("This reading has completed its arc.") - .font(.subheadline) - .foregroundStyle(.secondary) + .ravenCaption() + .foregroundStyle(.white.opacity(0.50)) } - Divider() + Rectangle() + .fill(Color.white.opacity(0.10)) + .frame(height: 0.5) // Stats HStack(spacing: 0) { - statCell(label: "Turns", value: "\(session.turnCount)") - Divider().frame(height: 40) + statCell(label: "Turns", value: "\(session.turnCount)") + Rectangle().fill(Color.white.opacity(0.10)).frame(width: 0.5, height: 40) statCell(label: "Resonance", value: "\(session.resonanceHits)") - Divider().frame(height: 40) - statCell(label: "Phase", value: phaseLabel) + Rectangle().fill(Color.white.opacity(0.10)).frame(width: 0.5, height: 40) + statCell(label: "Phase", value: phaseLabel) } // Open threads if !session.openThreads.isEmpty { VStack(alignment: .leading, spacing: 8) { Text("Open Threads") - .font(.caption) - .fontWeight(.semibold) - .foregroundStyle(.secondary) + .ravenMono(size: 10, weight: .semibold) + .foregroundStyle(.white.opacity(0.40)) .textCase(.uppercase) ForEach(session.openThreads, id: \.self) { thread in HStack(alignment: .top, spacing: 8) { Image(systemName: "arrow.right") - .font(.caption) - .foregroundStyle(.secondary) + .ravenMono(size: 10) + .foregroundStyle(RavenPalette.ravenAmber.opacity(0.60)) .padding(.top, 2) Text(thread) - .font(.subheadline) + .ravenBody() + .foregroundStyle(.white.opacity(0.80)) } } } @@ -64,25 +65,44 @@ struct SessionSealedCard: View { exportSession() } label: { Label("Export Session", systemImage: "square.and.arrow.up") + .ravenBody() .frame(maxWidth: .infinity) + .padding(.vertical, 12) + .background(Color.white.opacity(0.08)) + .foregroundStyle(.white.opacity(0.80)) + .clipShape(RoundedRectangle(cornerRadius: 12)) + .overlay( + RoundedRectangle(cornerRadius: 12) + .stroke(Color.white.opacity(0.12), lineWidth: 0.5) + ) } - .buttonStyle(.bordered) - .controlSize(.large) + .buttonStyle(.plain) Button { onStartNew() } label: { Label("Start New Session", systemImage: "arrow.counterclockwise") + .ravenBody() + .fontWeight(.semibold) .frame(maxWidth: .infinity) + .padding(.vertical, 12) + .background(RavenPalette.ravenAmber.opacity(0.85)) + .foregroundStyle(Color(red: 0.08, green: 0.05, blue: 0.02)) + .clipShape(RoundedRectangle(cornerRadius: 12)) } - .buttonStyle(.borderedProminent) - .controlSize(.large) + .buttonStyle(.plain) } } .padding(24) - .background(Color(.secondarySystemBackground)) - .clipShape(RoundedRectangle(cornerRadius: 20)) - .shadow(color: .black.opacity(0.08), radius: 12, y: 4) + .background( + RoundedRectangle(cornerRadius: 20, style: .continuous) + .fill(Color(red: 0.06, green: 0.06, blue: 0.14)) + .overlay( + RoundedRectangle(cornerRadius: 20, style: .continuous) + .stroke(Color.white.opacity(0.10), lineWidth: 0.5) + ) + ) + .shadow(color: RavenPalette.ravenAmber.opacity(0.08), radius: 16, y: 6) .padding(.horizontal) } } @@ -92,11 +112,11 @@ struct SessionSealedCard: View { private func statCell(label: String, value: String) -> some View { VStack(spacing: 4) { Text(value) - .font(.title2) - .fontWeight(.semibold) + .ravenMono(size: 20, weight: .semibold) + .foregroundStyle(.white) Text(label) - .font(.caption) - .foregroundStyle(.secondary) + .ravenMono(size: 10) + .foregroundStyle(.white.opacity(0.40)) } .frame(maxWidth: .infinity) } @@ -104,10 +124,10 @@ struct SessionSealedCard: View { private var phaseLabel: String { switch session.phase { case .calibration: return "Cal." - case .tension: return "Tension" + case .tension: return "Tension" case .integration: return "Integ." - case .vector: return "Vector" - case .seal: return "Seal" + case .vector: return "Vector" + case .seal: return "Seal" } } diff --git a/RaveniOS/RaveniOS/Views/Sheets/ModeSelectorView.swift b/RaveniOS/RaveniOS/Views/Sheets/ModeSelectorView.swift index 833236797..af89151b4 100644 --- a/RaveniOS/RaveniOS/Views/Sheets/ModeSelectorView.swift +++ b/RaveniOS/RaveniOS/Views/Sheets/ModeSelectorView.swift @@ -105,7 +105,7 @@ struct ModeModeRow: View { HStack(alignment: .top, spacing: 14) { Image(systemName: mode.iconName) .font(.title2) - .foregroundStyle(isAvailable ? .blue : .secondary) + .foregroundStyle(isAvailable ? RavenPalette.ravenAmber : .secondary) .frame(width: 30) .padding(.top, 2) @@ -128,7 +128,7 @@ struct ModeModeRow: View { if isSelected { Image(systemName: "checkmark.circle.fill") - .foregroundStyle(.blue) + .foregroundStyle(RavenPalette.ravenAmber) .padding(.top, 2) } } @@ -170,8 +170,8 @@ struct ModePill: View { } .padding(.horizontal, 10) .padding(.vertical, 5) - .background(Color.blue.opacity(0.12)) - .foregroundStyle(.blue) + .background(RavenPalette.ravenAmber.opacity(0.12)) + .foregroundStyle(RavenPalette.ravenAmber) .clipShape(Capsule()) } .buttonStyle(.plain) diff --git a/RaveniOS/RaveniOS/Views/Today/TodayScreenView.swift b/RaveniOS/RaveniOS/Views/Today/TodayScreenView.swift index 8f20dc715..77b4454dc 100644 --- a/RaveniOS/RaveniOS/Views/Today/TodayScreenView.swift +++ b/RaveniOS/RaveniOS/Views/Today/TodayScreenView.swift @@ -31,7 +31,7 @@ struct TodayScreenView: View { } .padding(16) } - .background(Color.black.ignoresSafeArea()) + .background(RavenPalette.cosmosBackground.ignoresSafeArea()) .navigationTitle("Today") } } @@ -86,7 +86,7 @@ private struct SymbolicMomentCard: View { HStack(spacing: 6) { ForEach(0..<5) { index in Circle() - .fill(index < moment.magnitude ? Color.cyan : Color.white.opacity(0.2)) + .fill(index < moment.magnitude ? RavenPalette.ravenAmber : Color.white.opacity(0.2)) .frame(width: 9, height: 9) } } @@ -115,7 +115,7 @@ private struct BalanceMeterView: View { ZStack(alignment: .leading) { Capsule().fill(Color.white.opacity(0.12)) Capsule() - .fill(Color.cyan.opacity(0.9)) + .fill(RavenPalette.ravenAmber.opacity(0.85)) .frame(width: geometry.size.width * telemetry.load) } } @@ -236,10 +236,14 @@ private struct IdentityLoadSelector: View { .padding(.vertical, 10) } .buttonStyle(.plain) - .foregroundStyle(selectedLoad == loadType ? Color.black : Color.white.opacity(0.85)) + .foregroundStyle(selectedLoad == loadType + ? Color(red: 0.08, green: 0.05, blue: 0.02) + : Color.white.opacity(0.85)) .background( RoundedRectangle(cornerRadius: 11, style: .continuous) - .fill(selectedLoad == loadType ? Color.cyan : Color.white.opacity(0.08)) + .fill(selectedLoad == loadType + ? RavenPalette.ravenAmber + : Color.white.opacity(0.08)) ) } } @@ -252,12 +256,12 @@ private struct IdentityLoadSelector: View { private var panelBackground: some View { RoundedRectangle(cornerRadius: 16, style: .continuous) - .fill(Color(red: 0.08, green: 0.09, blue: 0.12)) + .fill(Color(red: 0.06, green: 0.06, blue: 0.14)) .overlay( RoundedRectangle(cornerRadius: 16, style: .continuous) .stroke(Color.white.opacity(0.08), lineWidth: 1) ) - .shadow(color: Color.cyan.opacity(0.10), radius: 8, x: 0, y: 0) + .shadow(color: RavenPalette.ravenAmber.opacity(0.08), radius: 8, x: 0, y: 0) } #Preview { diff --git a/RaveniOS/RaveniOS/Views/VaultView.swift b/RaveniOS/RaveniOS/Views/VaultView.swift index 3cb55543e..c1eec7380 100644 --- a/RaveniOS/RaveniOS/Views/VaultView.swift +++ b/RaveniOS/RaveniOS/Views/VaultView.swift @@ -186,12 +186,11 @@ struct ProfileRow: View { .font(.headline) if profile.isPrimary { Text("PRIMARY") - .font(.caption2) - .fontWeight(.semibold) + .ravenMono(size: 10, weight: .semibold) .padding(.horizontal, 6) .padding(.vertical, 2) - .background(Color.blue.opacity(0.15)) - .foregroundStyle(.blue) + .background(RavenPalette.ravenAmber.opacity(0.15)) + .foregroundStyle(RavenPalette.ravenAmber) .clipShape(Capsule()) } } @@ -209,7 +208,7 @@ struct ProfileRow: View { Spacer() if isActive { Image(systemName: "checkmark.circle.fill") - .foregroundStyle(.blue) + .foregroundStyle(RavenPalette.ravenAmber) } } .padding(.vertical, 4) diff --git a/RaveniOS/UI_REVIEW.md b/RaveniOS/UI_REVIEW.md new file mode 100644 index 000000000..2fe3ab361 --- /dev/null +++ b/RaveniOS/UI_REVIEW.md @@ -0,0 +1,68 @@ +# RaveniOS — UI Review (Task #21) + +## Screen Summaries + +**SkyMapView (Map tab)** +The spatial navigation canvas. Fully token-driven: `RavenPalette.cosmosBackground` fill, all sizes from `RavenLayout`, all motion from `RavenMotion`, all glow from `RavenGlow`. This is the gold standard that every other screen should aspire to match. + +**RavenOpeningView (Map tab – first launch)** +Entry splash before the map reveals. Uses `RavenPalette.openingBackground`, `ravenAmber` glow, and `sendActive` on the send button. Well-themed; only minor typography literals remain (hard-coded `size: 18/16` instead of tokens). + +**ChatView (Chat tab)** +The biggest offender. Background, banners, bubbles, header, input bar all fall back to `systemBackground` / `secondarySystemBackground` / `ultraThinMaterial`. None of the palette, typography, or accent colors come from the design tokens. Effectively a default SwiftUI chat template dropped inside a cosmos app. + +**VaultView (Vault tab)** +Standard `NavigationStack + List(insetGrouped)`. System-white background with default List chrome. The "PRIMARY" badge and active-profile checkmark both use `.blue` instead of `ravenAmber`. Otherwise structurally fine — it's a data entry surface, so a fully opaque cosmos background here is less critical than in Chat. + +**ProfileDetailView (sheet)** +Pure system `List` form. Same structural issue as VaultView. Blue accent on `.green`/`.blue` status labels. Navigation title and toolbar buttons are unstyled defaults. + +**SessionSealedCard (inline in Chat)** +Card uses `Color(.secondarySystemBackground)` — will appear white/light on top of the cosmos chat background, breaking the dark-field aesthetic. The `.borderedProminent` CTA button defaults to blue. Stats and open-thread list use system fonts throughout. + +**ModeSelectorView (sheet) + ModePill (Chat header)** +`ModePill` uses `.blue` accent; `ModeModeRow` uses `.blue` for icon and selected checkmark. Both should use `ravenAmber` or a token accent. + +**TodayScreenView (not currently in TabView)** +Uses `Color.black` background (close, but not `cosmosBackground`) and `Color.cyan` as the primary accent throughout — a different aesthetic register from the amber/violet cosmos palette. Panel background is a raw `Color(red:green:blue:)` literal rather than a token. + +--- + +## Token-vs-View Matrix + +| Token / constant | Defined | Used in SkyMap | Used in Chat | Used in Vault | Used in SessionCard | Used in Today | +|---|---|---|---|---|---|---| +| `RavenPalette.cosmosBackground` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ (uses Color.black) | +| `RavenPalette.ravenAmber` | ✅ | ✅ | ❌ (uses .blue) | ❌ (uses .blue) | ❌ | ❌ (uses .cyan) | +| `RavenPalette.sendActive` | ✅ | ✅ (OpeningView) | ❌ (uses .blue) | — | — | — | +| `RavenLayout.*` spacing | ✅ | ✅ | ❌ (hard-coded 10/12/24) | ❌ | ❌ (hard-coded 24/20) | ❌ | +| `RavenMotion.*` | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | +| Tab bar appearance | — | — | ❌ (system default) | ❌ | — | — | + +--- + +## Ranked Fix List (highest impact first) + +1. **ChatView shell background** — `Color(.systemBackground)` makes the entire Chat tab appear white. Replace with `RavenPalette.cosmosBackground`. Single line, highest visual impact. *(done in this pass)* + +2. **Tab bar appearance** — System translucent tab bar looks out of place against the cosmos void. Apply `UITabBarAppearance` with dark cosmos chrome and `ravenAmber` selected-item tint. *(done in this pass)* + +3. **ChatView accent colors** — TTS button, send button, message bubbles, input field all use `.blue` or system fills. Swap to `ravenAmber` / `sendActive` / cosmos-tinted backgrounds. *(done in this pass)* + +4. **SessionSealedCard background** — White card atop cosmos background is the most visually jarring contrast moment. Replace with a dark cosmos panel. *(done in this pass)* + +5. **Typography ramp in Chat** — `.headline` / `.caption` / `.subheadline` scattered without a token anchor. Introduce `RavenTypography` helpers (appended to `RavenDesignTokens.swift`) and apply to Chat header and bubble metadata. *(done in this pass)* + +6. **ModePill + ModeModeRow accent** — `.blue` icon/checkmark/pill tint. Swap to `ravenAmber`. *(done in this pass)* + +7. **VaultView badge/checkmark** — "PRIMARY" badge and active-profile checkmark use `.blue`. Swap to `ravenAmber`. *(done in this pass)* + +8. **TodayScreenView palette** — `Color.cyan` accent and `Color.black` background diverge from cosmos register. Swap to token colors. *(deferred — TodayScreenView is not in the active TabView yet; low runtime impact)* + +--- + +## Out of scope (this pass) +- NavigationStack background tinting on Vault/ProfileDetail (requires `UINavigationBarAppearance` — lower priority than Chat) +- AddProfileView form theming +- Spacing literals in SkyMapView (already token-driven; no literals found) +- Animation additions or overhauls diff --git a/vessel/docs/CAPTAINS_LOG.md b/vessel/docs/CAPTAINS_LOG.md index ff1fecd35..4f0658df0 100644 --- a/vessel/docs/CAPTAINS_LOG.md +++ b/vessel/docs/CAPTAINS_LOG.md @@ -4,6 +4,44 @@ Development journal for Raven Calder / Woven Map system. --- +## 2026-04-26 — Stripe Bypass Mechanism (Tester Key) + +**Session Focus:** Adding a developer/tester bypass code for ARCHITECT tier access without Stripe payment. + +### The Problem +- Developer (owner) was hitting the "Advanced reads require the Architect tier" paywall despite being the system owner +- Needed a shareable bypass code for testers/friends without requiring Stripe subscription + +### The Fix +Added `TESTER_ACCESS_KEY` environment variable mechanism: +1. **Server-side validation** (`src/lib/server/userTier.ts`): Checks `x-tester-key` header against `TESTER_ACCESS_KEY` env var +2. **Client-side activation** (`src/lib/TierContext.tsx`): `activateTesterKey()` stores key in localStorage, auto-injects as header +3. **UI entry** (`src/app/pricing/page.tsx`): Existing tester key input field on pricing page + +### Configuration +- **Owner email bypass:** Set `FULL_ACCESS_EMAILS="nathal@gmail.com"` and `NEXT_PUBLIC_FULL_ACCESS_EMAILS="nathal@gmail.com"` for automatic ARCHITECT access without any code entry +- **Tester key (for others):** Set `TESTER_ACCESS_KEY="shipyard-2026"` in `.env.local` for shareable bypass code +- **Production:** Add both `FULL_ACCESS_EMAILS` and `TESTER_ACCESS_KEY` as environment variables in Vercel project settings +- **Usage (tester key):** Navigate to `/pricing`, enter the code, submit + +### Alternative Bypasses (Already Configured) +- `OWNER_UID`: Automatic ARCHITECT access when Firebase UID matches (already set in `.env.local`) +- `FULL_ACCESS_EMAILS`: Email-based bypass (now configured for nathal@gmail.com) +- `RAVEN_DEV_AUTH_BYPASS=1`: Dev-mode bypass (non-production only) + +### Files Changed +- `.env.local` — Added `TESTER_ACCESS_KEY="shipyard-2026"`, `FULL_ACCESS_EMAILS="nathal@gmail.com"`, `NEXT_PUBLIC_FULL_ACCESS_EMAILS="nathal@gmail.com"` +- No code changes needed — mechanism already implemented in existing tier system + +### Verification Status +- [x] Env var added to `.env.local` +- [x] Dev server restarted to load new env var +- [ ] Manual verification: Enter code on pricing page and confirm ARCHITECT access + +> **Insight:** The bypass mechanism was already architecturally sound — it just needed the environment variable to be configured. This is a configuration fix, not a code fix. + +--- + ## 2026-03-04 — Shipyard Dev Wrapper (Repomix + Codemap, Dev-Only) **Session Focus:** Restore a lightweight Shipyard-style dev cockpit without reintroducing production route pollution. diff --git a/vessel/docs/SST_Classification_Protocol.md b/vessel/docs/SST_Classification_Protocol.md index ec5d38553..93c8fe9a5 100644 --- a/vessel/docs/SST_Classification_Protocol.md +++ b/vessel/docs/SST_Classification_Protocol.md @@ -10,21 +10,22 @@ This document is interpretive. Weight tiers, orb gates, and formulas are governe Raven operates under one load-bearing rule: **name the map first, classify the landing later.** -Pre-testimony, Raven may translate geometry into pressure-signature language (compression, ignition, dissolution, amplification, fog, heat, restraint, fusion, friction). Raven may name the chamber emphasis, the timing frame, and the named sky feeding the pattern. +Pre-testimony, Raven may translate sealed geometry into pressure-signature language (compression, ignition, dissolution, amplification, fog, heat, restraint, fusion, friction). Raven may name the chamber landing range, the timing frame, the direct face, the shadowed or inverted face, and the named sky feeding the pattern. Pre-testimony, Raven may not: - assert a lived outcome as already true - ask the user to confirm a predicted feeling - pre-load any SST classification into the opening read +- expose WB, ABE, OSR, Mixed, Inconclusive, Within Boundary, At Boundary Edge, or Outside Symbolic Range in frontstage prose before testimony -This separation is what keeps the system falsifiable. A pre-written WB description waiting to be matched is a Texas Sharpshooter target in slow motion. +This separation is what keeps the system falsifiable. A pre-written planet-specific WB/ABE/OSR prediction library waiting to be matched is a Texas Sharpshooter target in slow motion. ## Three-Zone Delivery Protocol Every Symbolic Moment read is delivered in three zones. ### Zone 1 — Frontstage Voice -Translated pressure language. Names the field, the chamber, the pressure signatures, and the named sky. Does not forecast lived outcome. Does not ask for validation. +Translated pressure language. Names sealed geometry, symbolic pressure, chamber landing range, direct face, shadowed/inverted face, and the named sky. Does not forecast lived outcome. Does not ask for validation. ### Zone 2 — Backstage Sealed Geometry Structured log of what was committed before testimony. Minimum fields: @@ -38,17 +39,19 @@ Structured log of what was committed before testimony. Minimum fields: This zone is tamper-evident. Once sealed, it does not update based on testimony. Classification writes to a separate downstream field. ### Zone 3 — Verification Prompts -Collects placement data, not confirmation of a prediction. Prompts are phrased to surface the classification rather than prime it. +Collects placement data, not confirmation of a prediction. Prompts are phrased to give the later classifier usable testimony without priming agreement. Preferred forms: - "Which chamber is taking the load first: work, body, mood, responsibility, relationship, or something else?" -- "Is this landing as direct pressure, inversion, sideways displacement, fog, or near-absence?" +- "Name the closest landing: direct pressure, inversion, sideways displacement, fog, or near-absence." - "What changed first: pace, feeling tone, role burden, clarity, or motivation?" +- "Name the closest landing: direct pressure, sideways displacement, numb workaround, or none of these." Avoid: - "Does it feel like [specific outcome]?" - "Are you experiencing [pre-written description]?" - Any form that lets the user answer with yes/no confirmation of a pre-loaded WB. +- Any prompt that asks the witness to agree with Raven instead of locating the contact point. ## SST Classification States @@ -104,4 +107,4 @@ Raven's register must match the temporal scope of the reading. A daily cluster a - **Implement Structured Zone 2 Logging:** - Introduce a serialized JSON object for the exact geometry constraints sealed before user report. - **Expand `SSTClass` type**: - - Support and recognize "Mixed" and "Inconclusive" in active memory structures alongside WB, ABE, OSR. \ No newline at end of file + - Support and recognize "Mixed" and "Inconclusive" in active memory structures alongside WB, ABE, OSR. diff --git a/vessel/docs/raven-calder/symbolic-moment-protocol-v2.md b/vessel/docs/raven-calder/symbolic-moment-protocol-v2.md index 894572fc8..e0c1fa243 100644 --- a/vessel/docs/raven-calder/symbolic-moment-protocol-v2.md +++ b/vessel/docs/raven-calder/symbolic-moment-protocol-v2.md @@ -11,13 +11,13 @@ Symbolic Moment readings function as a falsifiable, Socratic mirror. They do not Every Symbolic Moment reading must adhere to this three-zone structure to maintain the "Sealed Geometry" integrity. ### Zone 1: Frontstage Voice -The interpretive reading shown to the user. It follows the **Force → Measurement → Landing → Voice → Silhouette Rule** sequence. +The interpretive reading shown to the user. It names sealed geometry, symbolic pressure, chamber landing range, direct face, shadowed/inverted face, and a placement inquiry. It does not include compiler section tags, raw JSON, unresolved placeholders, or backstage labels. ### Zone 2: Backstage Sealed Geometry A machine-readable JSON object containing the raw technical basis of the reading. It is logged and hashed *before* the user provides testimony. ### Zone 3: Verification Prompt -A structured request for grounded placement. It asks the user where the described load is manifesting without leading them toward a specific "correct" answer. +A structured request for grounded placement. It asks where the described load registers without leading the user toward agreement, a predicted feeling, or a specific "correct" answer. The user is not being tested; the symbol is. --- @@ -39,7 +39,7 @@ A structured request for grounded placement. It asks the user where the describe - **DO NOT** use textbook house glossaries. 8. **"Not Alone in the Room" Rule**: If the primary driver is a soft aspect (trine/sextile) but heavy outer-planet loads (conjunctions/oppositions) are active in the same cluster, the voice must contextualize the soft opening within the heavier field. -9. **"Symbolic Grounding" Rule**: Avoid "dashboard" outputs (e.g., "moderate, narrowing") as standalone voice. Use them to calibrate the description of the *force* (e.g., "value, desire, and attraction moving near a larger undercurrent of pressure"). +9. **"Symbolic Grounding" Rule**: Avoid "dashboard" outputs (e.g., "moderate, narrowing") as standalone voice. Use them only backstage to calibrate image-bearing force language. 10. **"Domain Variety" Rule**: When referencing chamber domains, use different handles for the same concept across the Voice and Silhouette sentences to avoid redundant cadence. 11. **"The Opening is Serious" Rule**: If there's a trine (light) but also heavy outer-planet loads, the trine must be read as an "opening that asks to be taken seriously" (weighty opening), not just "easy reach". @@ -48,33 +48,33 @@ A structured request for grounded placement. It asks the user where the describe ## Zone 2 Rules: Sealed Geometry Schema Zone 2 must be created before Zone 3 and logged backstage. It is never mutated after user testimony. -**Required Fields:** +**Active Code Schema:** - `sealed_at_utc`: Timestamp of generation. - `geometry_cluster`: The specific planetary configurations involved. - `primary_chamber`: The dominant chamber for the reading. -- `chamber_anchor`: The lived-meaning anchor used in Zone 1. - `pressure_signatures`: Array of active signatures (Compression, Shear, etc.). -- `transmission_condition`: The flow state (Carries, Stalls, etc.). - `moment_type`: The structural classification. -- `timing_frame`: The duration of the trigger. - `resonance_state`: Initialized as `"Pending / Unreviewed"`. - `classification`: Initialized as `null`. - `sealed_hash`: SHA-256 computed from the canonical JSON (excluding the `sealed_hash` field). +Code is the source of truth for active sealed fields. Doctrine may describe future or broader fields, but frontstage delivery must not expose missing schema fields as placeholders. + --- ## Zone 3 Rules: Verification & Placement 1. **Ask for placement, not confirmation**: Do not ask "Is this true?" or "Do you agree?" -2. **Domain Options**: Pull 2–4 specific domain options from `CHAMBER_DOMAIN_MAP`. -3. **The Escape Path**: Always include an "or elsewhere" path. +2. **Domain Options**: Pull specific domain options from the active chamber registry or local lexicon. +3. **The Escape Path**: Always include an "elsewhere," "absence," or "none of these" path. 4. **No Yes/No**: Avoid binary confirmation questions. 5. **No Decoding**: Do not ask the user to interpret Raven’s terminology. 6. **No Implication**: Do not imply the manifestation has already happened. +7. **No Pre-Testimony SST Labels**: Do not use WB, ABE, OSR, Mixed, Inconclusive, Within Boundary, At Boundary Edge, or Outside Symbolic Range before user report. --- ## Pressure-Signature Vocabulary -Use only the following approved terms to describe structural load: +Use only the following backstage/translation terms to describe structural load. In frontstage voice, translate them into image-bearing language rather than exposing them as dashboard residue: - **Compression**: narrowing, tightening, weight, pressure, containment - **Ignition**: heat, friction, push, urgency, activation @@ -88,18 +88,14 @@ Use only the following approved terms to describe structural load: --- ## Corrected Math Doctrine -1. **Tiered Planetary Weights**: - - **Architects (1.5x)**: Pluto, Neptune, Uranus - - **Auditors (1.2x)**: Saturn, Jupiter - - **Movers (1.0x)**: Sun, Mars, Venus, Mercury -2. **Gravitational Inheritance**: `effective_weight = max(transiting_weight, natal_weight)`. (e.g., A Moon-to-Pluto contact inherits Pluto-scale gravity). -3. **The Surgical Gate**: - - **Major Aspects**: orb ≤ 3° (unless production config overrides). - - **Minor Aspects**: orb ≤ 1° (unless production config overrides). - - Orb decay applies only *after* the aspect passes the gate. +The active constants live in `vessel/src/lib/v3MathBrain.ts`; if this document conflicts with that file, code wins. + +Current active anchors: +1. **Tiered Planetary Weights**: Architects (Uranus, Neptune, Pluto) use 1.5x; Auditors (Jupiter, Saturn) use 1.2x; Movers (Sun, Mars, Venus, Mercury, Moon) use 1.0x; Chiron currently uses 0.8x. Structural pivots are weighted in `PLANET_TIERS`. +2. **Gravitational Inheritance**: `wp = max(weight_transiting, weight_stationed)`. +3. **Aspect Gates**: Orb limits are per-aspect constants in `ASPECT_DEFINITIONS`; do not replace them with a generic major/minor gate. 4. **Aspect Logic**: Do not collapse validity and strength into one curve. -5. **Dominance-Based Magnitude**: - `magnitude = 5 * tanh(0.4 * (peak + 0.25 * rest))` +5. **Magnitude Formula**: The current formula is centralized in `SCORING_CONSTANTS`. --- @@ -112,7 +108,7 @@ Use only the following approved terms to describe structural load: --- ## SST Classification & Post-Testimony -Classification happens **only after testimony**. Pre-generating WB/ABE/OSR descriptions is strictly forbidden (Texas Sharpshooter Risk). +Classification happens **only after testimony**. Pre-generating planet-specific WB/ABE/OSR prediction libraries or descriptions is strictly forbidden (Texas Sharpshooter Risk). Before testimony, these labels stay backstage only. ### SST States: - **WB**: Within Boundary @@ -153,10 +149,10 @@ A reading fails validation if it: ### The Core (Node 8) **Corrected Read:** -“A live friction line is active today. The pressure is brief, sharp, and carrying heat. This lands first in The Core — shared consequence and what is bonded. Friction here tends to gather around obligation, exchange, or what cannot be cleanly separated. Whether it reaches the ground is open. But if this does not land as direct pressure around shared consequence, it may be showing as a bind underneath the visible exchange.” +“A live friction line is active today. The pressure is brief and sharp. This lands first in The Core — shared consequence and what is bonded. Friction here tends to gather around obligation, exchange, or what cannot be cleanly separated. Whether it reaches the ground is open. If no direct pressure appears there, mark that as quiet ground rather than forcing the omen.” **Verification:** -“On the ground, this might touch shared obligation, something bonded, or what feels irrevocable. Is one of those close, or is this landing elsewhere?” +“Name the first contact point: shared obligation, something bonded, another lane, or none of these.” ### The Horizon (Node 9) **Corrected Read:** @@ -164,10 +160,10 @@ A reading fails validation if it: The first landing is The Horizon — the far-view room of belief, direction, planning, and the larger arc. Something may be opening there, but not lightly. Pluto and Jupiter are fused underneath it, so growth carries weight; Neptune across Pluto adds fog around what is really driving the change. -This is not a closed field. It is a field where an opening asks to be taken seriously. The line may show through plans, perspective, study, distance, timing, or a question about where the road is actually leading.” +This is not a closed field. It is a line where an opening asks to be taken seriously. The placement may be plans, perspective, study, distance, timing, or no ground contact today.” **Verification:** -“On the ground, does this resemble an opening with weight behind it, a foggier question about direction, or neither?” +“Name the closest landing: opening with weight behind it, a foggier direction question, another lane, or none of these.” --- diff --git a/vessel/sherlog-velocity/data/gap-history.jsonl b/vessel/sherlog-velocity/data/gap-history.jsonl index 7ab726964..a1cac9d5f 100644 --- a/vessel/sherlog-velocity/data/gap-history.jsonl +++ b/vessel/sherlog-velocity/data/gap-history.jsonl @@ -801,3 +801,4 @@ {"version":1,"feature":"Symbolic Moment Structure Fix","feature_key":"symbolic-moment-structure-fix","timestamp":"2026-04-25T02:52:19.718Z","timestamp_epoch":1777085539,"day_epoch":1777075200,"gaps":["workspace_integrity","stale_context","architectural_limit_exceeded","type_safety_risk","arch_monolith","hygiene_any_abuse"],"ranked_gaps":[{"gap":"workspace_integrity","base_weight":6,"salience_weight":6,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"stale_context","base_weight":5,"salience_weight":5,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"architectural_limit_exceeded","base_weight":4,"salience_weight":4,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"type_safety_risk","base_weight":3,"salience_weight":3,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"arch_monolith","base_weight":2,"salience_weight":2,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"hygiene_any_abuse","base_weight":1,"salience_weight":1,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null}]} {"version":1,"feature":"Antigravity","feature_key":"antigravity","timestamp":"2026-04-26T19:11:47.177Z","timestamp_epoch":1777230707,"day_epoch":1777161600,"gaps":["workspace_integrity","stale_context"],"ranked_gaps":[{"gap":"workspace_integrity","base_weight":2,"salience_weight":2.43,"persistence_boost":0.43,"streak":1,"occurrences":1,"age_days":1,"last_seen":"2026-04-24T20:25:58.637Z"},{"gap":"stale_context","base_weight":1,"salience_weight":1.43,"persistence_boost":0.43,"streak":1,"occurrences":1,"age_days":1,"last_seen":"2026-04-24T20:25:58.637Z"}]} {"version":1,"feature":"Vault profile markdown export","feature_key":"vault-profile-markdown-export","timestamp":"2026-04-26T19:42:17.467Z","timestamp_epoch":1777232537,"day_epoch":1777161600,"gaps":["stale_context","architectural_limit_exceeded","complexity_hotspot","type_safety_risk","arch_monolith","hygiene_complexity_hotspot","hygiene_any_abuse"],"ranked_gaps":[{"gap":"stale_context","base_weight":7,"salience_weight":7,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"architectural_limit_exceeded","base_weight":6,"salience_weight":6,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"complexity_hotspot","base_weight":5,"salience_weight":5,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"type_safety_risk","base_weight":4,"salience_weight":4,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"arch_monolith","base_weight":3,"salience_weight":3,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"hygiene_complexity_hotspot","base_weight":2,"salience_weight":2,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"hygiene_any_abuse","base_weight":1,"salience_weight":1,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null}]} +{"version":1,"feature":"Raven Symbolic Moment Tightening Sweep","feature_key":"raven-symbolic-moment-tightening-sweep","timestamp":"2026-04-27T03:55:54.840Z","timestamp_epoch":1777262154,"day_epoch":1777248000,"gaps":["stale_context","architectural_limit_exceeded","complexity_hotspot","type_safety_risk","arch_monolith","hygiene_complexity_hotspot","hygiene_any_abuse"],"ranked_gaps":[{"gap":"stale_context","base_weight":7,"salience_weight":7,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"architectural_limit_exceeded","base_weight":6,"salience_weight":6,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"complexity_hotspot","base_weight":5,"salience_weight":5,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"type_safety_risk","base_weight":4,"salience_weight":4,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"arch_monolith","base_weight":3,"salience_weight":3,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"hygiene_complexity_hotspot","base_weight":2,"salience_weight":2,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"hygiene_any_abuse","base_weight":1,"salience_weight":1,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null}]} diff --git a/vessel/sherlog-velocity/data/self-model.json b/vessel/sherlog-velocity/data/self-model.json index e3f93a452..2042d8f28 100644 --- a/vessel/sherlog-velocity/data/self-model.json +++ b/vessel/sherlog-velocity/data/self-model.json @@ -1,6 +1,6 @@ { "version": 1, - "generated_at": "2026-04-26T19:42:18.997Z", + "generated_at": "2026-04-27T03:56:05.676Z", "repo_root": "/Users/dancross/Dev/GitHub/Shipyard", "source_roots": [ "vessel/src", @@ -9,18 +9,18 @@ "vessel/src/lib/server" ], "summary": { - "total_modules": 361, - "total_edges": 871, - "fragile_file_count": 21, + "total_modules": 371, + "total_edges": 892, + "fragile_file_count": 22, "contract_anchor_count": 45, "zone_coverage_pct": 100 }, - "narrative": "This codebase contains:\n- 115 lib files, 100 test files, 71 route files, 50 component files, 16 page files, 6 hook files, 3 source files\n- 871 internal dependency edges\n- 21 files with elevated fragility\n- 361 of 361 files mapped to declared zones (0 unmapped)\n- Contract anchor surfaces: intent_contract, governor_contract, repair_contract, scope_contract", + "narrative": "This codebase contains:\n- 122 lib files, 102 test files, 72 route files, 50 component files, 16 page files, 6 hook files, 3 source files\n- 892 internal dependency edges\n- 22 files with elevated fragility\n- 371 of 371 files mapped to declared zones (0 unmapped)\n- Contract anchor surfaces: intent_contract, governor_contract, repair_contract, scope_contract", "modules": [ { "path": "vessel/src/hooks/useOracleChat.ts", "role": "hook", - "lines": 2494, + "lines": 2674, "exports": [ "generateGreeting", "normalizeBlindMirrorValidation", @@ -54,17 +54,92 @@ ], "export_count": 29, "import_count": 16, - "churn": 13, + "churn": 25, "fragility": { "score": 7, "label": "high" }, "zone": "Vessel Src Zone" }, + { + "path": "vessel/src/app/api/raven-chat/intentDetection.ts", + "role": "route", + "lines": 1115, + "exports": [ + "isReflectionControlMessage", + "isTuneRefinementRequest", + "isAstrologyLanguageRequest", + "isGuidanceExplicitlyRequested", + "isMetaDiagnosticRequest", + "hasCrisisOrOverwhelmSignal", + "guidanceAllowedForTurn", + "isHighValenceEmotionalDisclosure", + "hasAffectWitnessAcknowledgement", + "hasDynamicAtmosphereClaim", + "hasBirthTimestampVerificationAsk", + "hasNavigationalClose", + "detectDeferredResonanceCheck", + "hasStagingMomentumSignal", + "findLastUserMessage", + "shouldMaintainRelationalMappingContext", + "shouldResumeRelationalMappingAfterStageConfirmation", + "shouldAutoPromoteRelationalMapping", + "pickSoloCounterpartFromMessage", + "pickSymbolicMomentTargetFromMessage", + "isRelationalIntentMessage", + "isStagingStatusQuestion", + "missedStagingStatusAnswer", + "hasUngroundedCounterpartDynamics", + "hasPrematureRelationalIntakePrompt", + "hasCognitiveStructureStatusDrift", + "isOperatorAnchorContext", + "hasObserverScopeMismatch", + "hasBlueprintPlacementMissingSign", + "userRequestedExplicitReportFormat", + "hasUnexpectedReportFormatting", + "hasRelationalMissingSections", + "hasInstrumentResponseSections", + "hasSoloMirrorStructuredSections", + "hasUnpromptedReflectionEnvelope", + "hasDisallowedClockTerminology", + "hasAcknowledgementPreamble", + "hasCorrectionReplay", + "hasFollowUpMapShift", + "hasConcreteAnchorDrift", + "findRecentConcreteAnchorMessage", + "hasConcreteAnchorDriftWithContext", + "isSignalDecayReport", + "hasSignalDecayAcknowledgement", + "hasFieldReportScaffoldLeakPhrasing", + "hasUnpromptedCognitiveStatusDisclosure", + "hasRelationalTelemetryInternals", + "isDirectAddressOverrideRequest", + "isDiagnosticConversationalQuery", + "isDeceasedProfile", + "normalizeProfileIdentity", + "escapeRegExp", + "findLastAssistantMessage", + "BIRTH_RECORD_AUDIT_QUESTION_PATTERN", + "BIRTH_TIMESTAMP_VERIFICATION_PATTERN", + "BIRTH_TIMESTAMP_CONFIRM_ASK_PATTERN", + "RESONANCE_CHECK_QUESTION_PATTERN", + "RESONANCE_DEFER_PIVOT_PATTERN", + "NEW_TASK_PIVOT_PATTERN", + "CALIBRATION_QUESTION_PATTERNS" + ], + "export_count": 60, + "import_count": 8, + "churn": 17, + "fragility": { + "score": 6, + "label": "high" + }, + "zone": "Vessel Src App Zone" + }, { "path": "vessel/src/app/api/raven-chat/sessionState.ts", "role": "route", - "lines": 1149, + "lines": 1153, "exports": [ "buildTelemetryBrief", "resolveTierLabel", @@ -114,7 +189,7 @@ ], "export_count": 45, "import_count": 11, - "churn": 13, + "churn": 15, "fragility": { "score": 6, "label": "high" @@ -124,7 +199,7 @@ { "path": "vessel/src/test/api-smoke.test.ts", "role": "test", - "lines": 3543, + "lines": 3545, "exports": [ "readLatestSherlogTelemetryFromRunsRoot", "isCreatorModeTriggerMessage", @@ -139,7 +214,7 @@ ], "export_count": 10, "import_count": 37, - "churn": 17, + "churn": 21, "fragility": { "score": 5, "label": "high" @@ -147,90 +222,71 @@ "zone": "Vessel Src Zone" }, { - "path": "vessel/src/app/page.tsx", - "role": "page", - "lines": 5739, + "path": "vessel/src/lib/v3MathBrain.ts", + "role": "lib", + "lines": 1222, "exports": [ - "App" + "buildV3MathTelemetry", + "toV3MathPromptContext", + "buildTransitReadTrace", + "ASPECT_DEFINITIONS", + "PLANET_TIERS", + "MAGNITUDE_EXCLUDED_ASPECTS", + "SCORING_CONSTANTS", + "AnchorReason", + "CoherenceAnchor", + "DailyTelemetry", + "V3MathTelemetry", + "V3MathPromptContext", + "TransitReadTrace" ], - "export_count": 1, - "import_count": 45, - "churn": 29, + "export_count": 13, + "import_count": 0, + "churn": 16, "fragility": { "score": 5, "label": "high" }, - "zone": "Vessel Src App Zone" + "zone": "Vessel Src Lib Zone" }, { - "path": "vessel/src/app/api/raven-chat/intentDetection.ts", - "role": "route", - "lines": 1110, + "path": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", + "role": "lib", + "lines": 954, "exports": [ - "isReflectionControlMessage", - "isTuneRefinementRequest", - "isAstrologyLanguageRequest", - "isGuidanceExplicitlyRequested", - "isMetaDiagnosticRequest", - "hasCrisisOrOverwhelmSignal", - "guidanceAllowedForTurn", - "isHighValenceEmotionalDisclosure", - "hasAffectWitnessAcknowledgement", - "hasDynamicAtmosphereClaim", - "hasBirthTimestampVerificationAsk", - "hasNavigationalClose", - "detectDeferredResonanceCheck", - "hasStagingMomentumSignal", - "findLastUserMessage", - "shouldMaintainRelationalMappingContext", - "shouldResumeRelationalMappingAfterStageConfirmation", - "shouldAutoPromoteRelationalMapping", - "pickSoloCounterpartFromMessage", - "pickSymbolicMomentTargetFromMessage", - "isRelationalIntentMessage", - "isStagingStatusQuestion", - "missedStagingStatusAnswer", - "hasUngroundedCounterpartDynamics", - "hasPrematureRelationalIntakePrompt", - "hasCognitiveStructureStatusDrift", - "isOperatorAnchorContext", - "hasObserverScopeMismatch", - "hasBlueprintPlacementMissingSign", - "userRequestedExplicitReportFormat", - "hasUnexpectedReportFormatting", - "hasRelationalMissingSections", - "hasInstrumentResponseSections", - "hasSoloMirrorStructuredSections", - "hasUnpromptedReflectionEnvelope", - "hasDisallowedClockTerminology", - "hasAcknowledgementPreamble", - "hasCorrectionReplay", - "hasFollowUpMapShift", - "hasConcreteAnchorDrift", - "findRecentConcreteAnchorMessage", - "hasConcreteAnchorDriftWithContext", - "isSignalDecayReport", - "hasSignalDecayAcknowledgement", - "hasFieldReportScaffoldLeakPhrasing", - "hasUnpromptedCognitiveStatusDisclosure", - "hasRelationalTelemetryInternals", - "isDirectAddressOverrideRequest", - "isDiagnosticConversationalQuery", - "isDeceasedProfile", - "normalizeProfileIdentity", - "escapeRegExp", - "findLastAssistantMessage", - "BIRTH_RECORD_AUDIT_QUESTION_PATTERN", - "BIRTH_TIMESTAMP_VERIFICATION_PATTERN", - "BIRTH_TIMESTAMP_CONFIRM_ASK_PATTERN", - "RESONANCE_CHECK_QUESTION_PATTERN", - "RESONANCE_DEFER_PIVOT_PATTERN", - "NEW_TASK_PIVOT_PATTERN", - "CALIBRATION_QUESTION_PATTERNS" + "validateInternalSymbolicMomentStructure", + "validateSymbolicMomentPreTestimony", + "assertSafeSymbolicMomentFrontstage", + "buildStructuredSymbolicMomentReply", + "tightenSymbolicMomentFrontstage", + "buildChamberReference", + "StructuredMomentType", + "PressureSignature", + "SymbolicMomentFailureType", + "SymbolicMomentGeometryClusterEntry", + "SealedSymbolicMomentAudit", + "SymbolicMomentPreTestimonyValidation", + "StructuredSymbolicMomentResult" ], - "export_count": 60, - "import_count": 8, - "churn": 12, + "export_count": 13, + "import_count": 4, + "churn": 28, + "fragility": { + "score": 5, + "label": "high" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/app/page.tsx", + "role": "page", + "lines": 5910, + "exports": [ + "App" + ], + "export_count": 1, + "import_count": 45, + "churn": 41, "fragility": { "score": 5, "label": "high" @@ -240,49 +296,21 @@ { "path": "vessel/src/app/api/raven-chat/route.ts", "role": "route", - "lines": 2301, + "lines": 2334, "exports": [ "POST", "maxDuration", "dynamic" ], "export_count": 3, - "import_count": 59, - "churn": 40, + "import_count": 60, + "churn": 57, "fragility": { "score": 5, "label": "high" }, "zone": "Vessel Src App Zone" }, - { - "path": "vessel/src/lib/v3MathBrain.ts", - "role": "lib", - "lines": 1222, - "exports": [ - "buildV3MathTelemetry", - "toV3MathPromptContext", - "buildTransitReadTrace", - "ASPECT_DEFINITIONS", - "PLANET_TIERS", - "MAGNITUDE_EXCLUDED_ASPECTS", - "SCORING_CONSTANTS", - "AnchorReason", - "CoherenceAnchor", - "DailyTelemetry", - "V3MathTelemetry", - "V3MathPromptContext", - "TransitReadTrace" - ], - "export_count": 13, - "import_count": 0, - "churn": 11, - "fragility": { - "score": 4, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, { "path": "vessel/src/lib/vaultSync.ts", "role": "lib", @@ -349,128 +377,13 @@ ], "export_count": 58, "import_count": 9, - "churn": 6, - "fragility": { - "score": 4, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/raven/responseRenderer.ts", - "role": "lib", - "lines": 867, - "exports": [ - "buildAffectWitnessReply", - "buildRelationalLensShiftNotice", - "buildPolyadicTransparencyNotice", - "isAstrologyLanguageRequest", - "isAstrologyExplanationRequest", - "guidanceAllowedForTurn", - "userRequestedExplicitMetrics", - "isOverlongTuneReply", - "distillTuneReply", - "applyDeterministicReplyHardening", - "applyFrontstageStyleGuard", - "applySoloScopeHardening", - "applyDeterministicRepairFallback", - "hasTexasSharpshooterDrift", - "hasOpenEndedDiagnosticQuestion", - "stripOpenEndedDiagnosticQuestions", - "hasRawTelemetryReadout", - "DeterministicRepairFallbackContext" - ], - "export_count": 18, - "import_count": 7, - "churn": 9, - "fragility": { - "score": 4, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", - "role": "lib", - "lines": 759, - "exports": [ - "validateInternalSymbolicMomentStructure", - "validateSymbolicMomentPreTestimony", - "assertSafeSymbolicMomentFrontstage", - "buildStructuredSymbolicMomentReply", - "tightenSymbolicMomentFrontstage", - "buildChamberReference", - "StructuredMomentType", - "PressureSignature", - "SymbolicMomentFailureType", - "SymbolicMomentGeometryClusterEntry", - "SealedSymbolicMomentAudit", - "SymbolicMomentPreTestimonyValidation", - "StructuredSymbolicMomentResult" - ], - "export_count": 13, - "import_count": 3, - "churn": 15, + "churn": 3, "fragility": { "score": 4, "label": "medium" }, "zone": "Vessel Src Lib Zone" }, - { - "path": "vessel/src/app/api/raven-chat/requestParsing.ts", - "role": "route", - "lines": 801, - "exports": [ - "normalizeRelationalContext", - "inferRelationalContext", - "hasFullChartCoordinates", - "toCoreProfile", - "asTrimmedText", - "isChatRole", - "asPromptMode", - "toApertureMode", - "extractLiveLocationQuery", - "hasUSStateHint", - "countryCodeHint", - "summarizeProfileArchitecture", - "parseBirthDateParts", - "parseBirthTimeParts", - "profileInputToBlueprintShape", - "toCognitiveVoiceContext", - "isValidCoordinatePair", - "hasAnyCoordinateAnchor", - "parseChatRequest", - "sanitizeProfile", - "sanitizeConstitutionalCalibrationRecord", - "mergeHydratedProfile", - "needsVaultHydration", - "selectVaultProfileForHydration", - "hydrateProfilesFromVault", - "pickVaultSavedLocationAnchor", - "hydrateProfileFromVault", - "hasPersistedCurrentLocation", - "hasLiveCoordinateData", - "asObjectRecord", - "toIsoDateFromParts", - "toIsoTimeFromParts", - "toNumericText", - "normalizeCountryCode", - "inferCountryCodeFromLabel", - "isGovernorState", - "hasBirthContext", - "US_STATE_CODES", - "US_STATE_NAMES" - ], - "export_count": 39, - "import_count": 12, - "churn": 4, - "fragility": { - "score": 4, - "label": "medium" - }, - "zone": "Vessel Src App Zone" - }, { "path": "vessel/src/lib/wovenReportCore.ts", "role": "lib", @@ -487,9 +400,9 @@ ], "export_count": 8, "import_count": 7, - "churn": 12, + "churn": 15, "fragility": { - "score": 3, + "score": 4, "label": "medium" }, "zone": "Vessel Src Lib Zone" @@ -497,12 +410,14 @@ { "path": "vessel/src/lib/raven/constellationVault.ts", "role": "lib", - "lines": 744, + "lines": 806, "exports": [ "getConstellationEntries", "upsertConstellationEntry", "removeConstellationEntry", "buildWrapUpArtifacts", + "convertPoeticIndexCardToArtifact", + "storePoeticIndexCard", "captureSingleMessageArtifacts", "CONSTELLATION_VAULT_EVENT", "SessionSummaryArtifact", @@ -522,14 +437,101 @@ "SessionMessageForConstellation", "SessionStateForConstellation" ], - "export_count": 22, - "import_count": 2, - "churn": 0, + "export_count": 24, + "import_count": 4, + "churn": 4, + "fragility": { + "score": 4, + "label": "medium" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/raven/responseRenderer.ts", + "role": "lib", + "lines": 867, + "exports": [ + "buildAffectWitnessReply", + "buildRelationalLensShiftNotice", + "buildPolyadicTransparencyNotice", + "isAstrologyLanguageRequest", + "isAstrologyExplanationRequest", + "guidanceAllowedForTurn", + "userRequestedExplicitMetrics", + "isOverlongTuneReply", + "distillTuneReply", + "applyDeterministicReplyHardening", + "applyFrontstageStyleGuard", + "applySoloScopeHardening", + "applyDeterministicRepairFallback", + "hasTexasSharpshooterDrift", + "hasOpenEndedDiagnosticQuestion", + "stripOpenEndedDiagnosticQuestions", + "hasRawTelemetryReadout", + "DeterministicRepairFallbackContext" + ], + "export_count": 18, + "import_count": 7, + "churn": 9, + "fragility": { + "score": 4, + "label": "medium" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/app/api/raven-chat/requestParsing.ts", + "role": "route", + "lines": 801, + "exports": [ + "normalizeRelationalContext", + "inferRelationalContext", + "hasFullChartCoordinates", + "toCoreProfile", + "asTrimmedText", + "isChatRole", + "asPromptMode", + "toApertureMode", + "extractLiveLocationQuery", + "hasUSStateHint", + "countryCodeHint", + "summarizeProfileArchitecture", + "parseBirthDateParts", + "parseBirthTimeParts", + "profileInputToBlueprintShape", + "toCognitiveVoiceContext", + "isValidCoordinatePair", + "hasAnyCoordinateAnchor", + "parseChatRequest", + "sanitizeProfile", + "sanitizeConstitutionalCalibrationRecord", + "mergeHydratedProfile", + "needsVaultHydration", + "selectVaultProfileForHydration", + "hydrateProfilesFromVault", + "pickVaultSavedLocationAnchor", + "hydrateProfileFromVault", + "hasPersistedCurrentLocation", + "hasLiveCoordinateData", + "asObjectRecord", + "toIsoDateFromParts", + "toIsoTimeFromParts", + "toNumericText", + "normalizeCountryCode", + "inferCountryCodeFromLabel", + "isGovernorState", + "hasBirthContext", + "US_STATE_CODES", + "US_STATE_NAMES" + ], + "export_count": 39, + "import_count": 12, + "churn": 3, "fragility": { - "score": 3, + "score": 4, "label": "medium" }, - "zone": "Vessel Src Lib Zone" + "zone": "Vessel Src App Zone" }, { "path": "vessel/src/lib/raven/doctrineManifest.ts", @@ -556,7 +558,25 @@ ], "export_count": 17, "import_count": 0, - "churn": 7, + "churn": 8, + "fragility": { + "score": 3, + "label": "medium" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/raven/fieldReportVoiceContract.ts", + "role": "lib", + "lines": 403, + "exports": [ + "findFieldReportVoiceContractViolations", + "hasFieldReportVoiceContractDrift", + "validateSymbolicImage" + ], + "export_count": 3, + "import_count": 0, + "churn": 17, "fragility": { "score": 3, "label": "medium" @@ -605,7 +625,7 @@ ], "export_count": 34, "import_count": 0, - "churn": 4, + "churn": 6, "fragility": { "score": 3, "label": "medium" @@ -636,7 +656,7 @@ ], "export_count": 16, "import_count": 0, - "churn": 8, + "churn": 10, "fragility": { "score": 3, "label": "medium" @@ -676,7 +696,7 @@ { "path": "vessel/src/components/AlignmentCorridor.tsx", "role": "component", - "lines": 1431, + "lines": 1436, "exports": [ "AlignmentCorridor", "CorridorSynastryAspect", @@ -689,7 +709,7 @@ ], "export_count": 8, "import_count": 5, - "churn": 9, + "churn": 12, "fragility": { "score": 3, "label": "medium" @@ -699,13 +719,13 @@ { "path": "vessel/src/components/ProfileVault.tsx", "role": "component", - "lines": 2755, + "lines": 2795, "exports": [ "ProfileVault" ], "export_count": 1, "import_count": 8, - "churn": 8, + "churn": 12, "fragility": { "score": 3, "label": "medium" @@ -715,7 +735,7 @@ { "path": "vessel/src/app/api/raven-chat/promptLines.ts", "role": "route", - "lines": 527, + "lines": 412, "exports": [ "buildPromptLines", "PromptLinesConfig", @@ -723,7 +743,7 @@ ], "export_count": 3, "import_count": 5, - "churn": 29, + "churn": 43, "fragility": { "score": 3, "label": "medium" @@ -758,7 +778,7 @@ ], "export_count": 20, "import_count": 14, - "churn": 8, + "churn": 11, "fragility": { "score": 3, "label": "medium" @@ -785,7 +805,7 @@ ], "export_count": 12, "import_count": 3, - "churn": 2, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -941,7 +961,7 @@ ], "export_count": 40, "import_count": 0, - "churn": 3, + "churn": 5, "fragility": { "score": 2, "label": "low" @@ -967,7 +987,7 @@ ], "export_count": 11, "import_count": 1, - "churn": 2, + "churn": 3, "fragility": { "score": 2, "label": "low" @@ -1009,13 +1029,13 @@ { "path": "vessel/src/lib/raven/fieldReportRepairFallback.ts", "role": "lib", - "lines": 679, + "lines": 159, "exports": [ "buildFieldReportVoiceDriftFallback" ], "export_count": 1, - "import_count": 3, - "churn": 8, + "import_count": 2, + "churn": 15, "fragility": { "score": 2, "label": "low" @@ -1023,17 +1043,33 @@ "zone": "Vessel Src Lib Zone" }, { - "path": "vessel/src/lib/raven/fieldReportVoiceContract.ts", + "path": "vessel/src/lib/raven/localLexicon.ts", "role": "lib", - "lines": 403, + "lines": 299, "exports": [ - "findFieldReportVoiceContractViolations", - "hasFieldReportVoiceContractDrift", - "validateSymbolicImage" + "getChamberDomain", + "getChamberDomainOptions", + "getChamberAnchor", + "getChamberHouseNumber", + "getChamberByHouseNumber", + "formatChamberDomainRegistry", + "buildRavenLexiconBridge", + "RAVEN_PLANETARY_ANCHORS", + "RAVEN_PRESSURE_SIGNATURES", + "RAVEN_ASPECT_ANCHORS", + "RAVEN_PIOS_TERMS", + "RAVEN_HOUSE_BRIDGE", + "CHAMBER_DOMAIN_OPTIONS_MAP", + "CHAMBER_DOMAIN_MAP", + "CHAMBER_ANCHOR_MAP", + "CHAMBER_HOUSE_NUMBER_MAP", + "RAVEN_LOCAL_SKY_FRAME", + "RavenHouseBridge", + "ChamberName" ], - "export_count": 3, + "export_count": 19, "import_count": 0, - "churn": 10, + "churn": 8, "fragility": { "score": 2, "label": "low" @@ -1067,6 +1103,31 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/raven/symbolicMomentComposer.ts", + "role": "lib", + "lines": 1254, + "exports": [ + "resolveLoadTier", + "composeSymbolicMomentNarrative", + "sanitizeUserFacingNarrative", + "composeNamedStormNarrative", + "AspectType", + "ParsedDriver", + "NarrativeSignature", + "LoadTier", + "SymbolicMomentNarrative", + "NamedStormNarrative" + ], + "export_count": 10, + "import_count": 2, + "churn": 4, + "fragility": { + "score": 2, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/types.ts", "role": "lib", @@ -1196,7 +1257,20 @@ "lines": 757, "export_count": 0, "import_count": 1, - "churn": 10, + "churn": 11, + "fragility": { + "score": 2, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts", + "role": "test", + "lines": 320, + "export_count": 0, + "import_count": 2, + "churn": 21, "fragility": { "score": 2, "label": "low" @@ -1231,7 +1305,23 @@ ], "export_count": 1, "import_count": 0, - "churn": 1, + "churn": 2, + "fragility": { + "score": 2, + "label": "low" + }, + "zone": "Vessel Src Zone" + }, + { + "path": "vessel/src/components/reports/WovenMapTab.tsx", + "role": "component", + "lines": 433, + "exports": [ + "WovenMapTab" + ], + "export_count": 1, + "import_count": 1, + "churn": 9, "fragility": { "score": 2, "label": "low" @@ -1247,7 +1337,7 @@ ], "export_count": 1, "import_count": 4, - "churn": 9, + "churn": 12, "fragility": { "score": 2, "label": "low" @@ -1266,7 +1356,7 @@ ], "export_count": 4, "import_count": 2, - "churn": 3, + "churn": 5, "fragility": { "score": 2, "label": "low" @@ -1276,14 +1366,14 @@ { "path": "vessel/src/components/chat/RavenStructuredReply.tsx", "role": "component", - "lines": 615, + "lines": 633, "exports": [ "parseRavenStructuredReply", "RavenStructuredReply" ], "export_count": 2, "import_count": 6, - "churn": 8, + "churn": 10, "fragility": { "score": 2, "label": "low" @@ -1386,6 +1476,23 @@ }, "zone": "Vessel Src App Zone" }, + { + "path": "vessel/src/app/api/raven-chat/enrichmentPhase.ts", + "role": "route", + "lines": 345, + "exports": [ + "runEnrichmentPhase", + "EnrichmentResult" + ], + "export_count": 2, + "import_count": 19, + "churn": 8, + "fragility": { + "score": 2, + "label": "low" + }, + "zone": "Vessel Src App Zone" + }, { "path": "vessel/src/app/api/raven-chat/llmProvider.ts", "role": "route", @@ -1414,7 +1521,7 @@ ], "export_count": 20, "import_count": 8, - "churn": 1, + "churn": 2, "fragility": { "score": 2, "label": "low" @@ -1441,7 +1548,7 @@ ], "export_count": 12, "import_count": 5, - "churn": 7, + "churn": 9, "fragility": { "score": 2, "label": "low" @@ -1491,14 +1598,14 @@ { "path": "vessel/src/app/api/raven-chat/userBlockBuilder.ts", "role": "route", - "lines": 257, + "lines": 255, "exports": [ "buildUserBlocks", "UserBlocksConfig" ], "export_count": 2, "import_count": 12, - "churn": 13, + "churn": 15, "fragility": { "score": 2, "label": "low" @@ -1524,7 +1631,7 @@ "lines": 497, "export_count": 0, "import_count": 2, - "churn": 2, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -1544,10 +1651,29 @@ }, "zone": "Vessel Src Zone" }, + { + "path": "vessel/src/lib/chatGlossary.ts", + "role": "lib", + "lines": 241, + "exports": [ + "splitGlossaryText", + "CHAT_GLOSSARY", + "ChatGlossaryEntry", + "ChatGlossaryTextPart" + ], + "export_count": 4, + "import_count": 0, + "churn": 7, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/natalExport.ts", "role": "lib", - "lines": 567, + "lines": 575, "exports": [ "assessNatalGeometry", "generateNatalMarkdown", @@ -1556,7 +1682,25 @@ ], "export_count": 4, "import_count": 1, - "churn": 3, + "churn": 6, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/planner.ts", + "role": "lib", + "lines": 320, + "exports": [ + "buildPlannerResponse", + "SoloBalanceMeterResult", + "PlannerResponse" + ], + "export_count": 3, + "import_count": 2, + "churn": 7, "fragility": { "score": 1, "label": "low" @@ -1650,40 +1794,7 @@ ], "export_count": 16, "import_count": 0, - "churn": 0, - "fragility": { - "score": 1, - "label": "low" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/raven/localLexicon.ts", - "role": "lib", - "lines": 279, - "exports": [ - "getChamberDomain", - "getChamberDomainOptions", - "getChamberAnchor", - "getChamberHouseNumber", - "formatChamberDomainRegistry", - "buildRavenLexiconBridge", - "RAVEN_PLANETARY_ANCHORS", - "RAVEN_PRESSURE_SIGNATURES", - "RAVEN_ASPECT_ANCHORS", - "RAVEN_PIOS_TERMS", - "RAVEN_HOUSE_BRIDGE", - "CHAMBER_DOMAIN_OPTIONS_MAP", - "CHAMBER_DOMAIN_MAP", - "CHAMBER_ANCHOR_MAP", - "CHAMBER_HOUSE_NUMBER_MAP", - "RAVEN_LOCAL_SKY_FRAME", - "RavenHouseBridge", - "ChamberName" - ], - "export_count": 18, - "import_count": 0, - "churn": 4, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -1734,7 +1845,7 @@ ], "export_count": 10, "import_count": 2, - "churn": 5, + "churn": 6, "fragility": { "score": 1, "label": "low" @@ -1773,7 +1884,7 @@ ], "export_count": 1, "import_count": 4, - "churn": 4, + "churn": 5, "fragility": { "score": 1, "label": "low" @@ -1804,7 +1915,40 @@ ], "export_count": 16, "import_count": 1, - "churn": 3, + "churn": 4, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/raven/poetic-codex/types.ts", + "role": "lib", + "lines": 327, + "exports": [ + "SYMBOL_LOGIC_MAP", + "VOICE_CALIBRATION", + "TONE_DERIVATION_RULES", + "MOVEMENT_VERBS", + "SHADOW_DETECTION_TRIGGERS", + "INVERSION_SIGNATURES", + "VisibleLayer", + "SymbolLogic", + "LoadQuality", + "ForceTempo", + "ToneDerivation", + "ForceReading", + "SystemLoad", + "EngineSnapshot", + "DataLayer", + "CardStatus", + "PoeticIndexCard", + "CardGenerationInput" + ], + "export_count": 18, + "import_count": 0, + "churn": 2, "fragility": { "score": 1, "label": "low" @@ -1835,7 +1979,7 @@ "lines": 197, "export_count": 0, "import_count": 1, - "churn": 8, + "churn": 12, "fragility": { "score": 1, "label": "low" @@ -1848,20 +1992,7 @@ "lines": 508, "export_count": 0, "import_count": 6, - "churn": 2, - "fragility": { - "score": 1, - "label": "low" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts", - "role": "test", - "lines": 200, - "export_count": 0, - "import_count": 2, - "churn": 11, + "churn": 3, "fragility": { "score": 1, "label": "low" @@ -1930,13 +2061,43 @@ ], "export_count": 11, "import_count": 0, - "churn": 1, + "churn": 2, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/__tests__/natalExport.test.ts", + "role": "test", + "lines": 401, + "export_count": 0, + "import_count": 2, + "churn": 5, "fragility": { "score": 1, "label": "low" }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/hooks/useFlightRecorderData.ts", + "role": "hook", + "lines": 63, + "exports": [ + "useFlightRecorderData", + "FlightRecorderData" + ], + "export_count": 2, + "import_count": 4, + "churn": 7, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src Zone" + }, { "path": "vessel/src/components/Auth.tsx", "role": "component", @@ -1995,7 +2156,7 @@ ], "export_count": 1, "import_count": 7, - "churn": 2, + "churn": 5, "fragility": { "score": 1, "label": "low" @@ -2027,7 +2188,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 3, + "churn": 6, "fragility": { "score": 1, "label": "low" @@ -2035,15 +2196,31 @@ "zone": "Vessel Src Zone" }, { - "path": "vessel/src/components/reports/WovenMapTab.tsx", + "path": "vessel/src/components/raven/insight-cards/InsightCardDisplay.tsx", "role": "component", - "lines": 433, + "lines": 405, "exports": [ - "WovenMapTab" + "InsightCardDisplay" ], "export_count": 1, - "import_count": 1, - "churn": 5, + "import_count": 2, + "churn": 0, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src Zone" + }, + { + "path": "vessel/src/components/chat/AlignmentCorridorReadout.tsx", + "role": "component", + "lines": 322, + "exports": [ + "AlignmentCorridorReadout" + ], + "export_count": 1, + "import_count": 8, + "churn": 7, "fragility": { "score": 1, "label": "low" @@ -2067,13 +2244,29 @@ }, "zone": "Vessel Src Zone" }, + { + "path": "vessel/src/components/chat/FlightRecorderSidebar.tsx", + "role": "component", + "lines": 254, + "exports": [ + "FlightRecorderSidebar" + ], + "export_count": 1, + "import_count": 5, + "churn": 8, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src Zone" + }, { "path": "vessel/src/components/chat/__tests__/DownloadSessionButton.test.ts", "role": "test", "lines": 461, "export_count": 0, "import_count": 3, - "churn": 3, + "churn": 4, "fragility": { "score": 1, "label": "low" @@ -2107,7 +2300,7 @@ ], "export_count": 6, "import_count": 4, - "churn": 0, + "churn": 2, "fragility": { "score": 1, "label": "low" @@ -2144,16 +2337,43 @@ "zone": "Vessel Src App Zone" }, { - "path": "vessel/src/app/api/raven-chat/enrichmentPhase.ts", + "path": "vessel/src/app/api/raven-chat/generationIntegrity.ts", "role": "route", - "lines": 345, + "lines": 278, "exports": [ - "runEnrichmentPhase", - "EnrichmentResult" + "resolveReplyIntegrity", + "ReplyIntegrityInput", + "ReplyIntegrityResolution" ], - "export_count": 2, - "import_count": 19, - "churn": 5, + "export_count": 3, + "import_count": 2, + "churn": 8, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src App Zone" + }, + { + "path": "vessel/src/app/api/raven-chat/__tests__/generationIntegrity.test.ts", + "role": "test", + "lines": 281, + "export_count": 0, + "import_count": 1, + "churn": 9, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src App Zone" + }, + { + "path": "vessel/src/app/api/raven-chat/__tests__/intentDetection.test.ts", + "role": "test", + "lines": 242, + "export_count": 0, + "import_count": 1, + "churn": 8, "fragility": { "score": 1, "label": "low" @@ -2273,7 +2493,7 @@ "lines": 184, "export_count": 0, "import_count": 2, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -2309,10 +2529,10 @@ { "path": "vessel/src/test/polyadic-chat-routing.test.ts", "role": "test", - "lines": 113, + "lines": 122, "export_count": 0, "import_count": 2, - "churn": 0, + "churn": 3, "fragility": { "score": 0, "label": "low" @@ -2325,7 +2545,7 @@ "lines": 55, "export_count": 0, "import_count": 1, - "churn": 1, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -2403,7 +2623,7 @@ "lines": 66, "export_count": 0, "import_count": 4, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -2416,7 +2636,7 @@ "lines": 31, "export_count": 0, "import_count": 1, - "churn": 1, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -2442,7 +2662,7 @@ "lines": 51, "export_count": 0, "import_count": 0, - "churn": 2, + "churn": 3, "fragility": { "score": 0, "label": "low" @@ -2481,7 +2701,7 @@ "lines": 84, "export_count": 0, "import_count": 1, - "churn": 0, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -2525,7 +2745,7 @@ ], "export_count": 3, "import_count": 2, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -2584,25 +2804,6 @@ }, "zone": "Vessel Src Lib Zone" }, - { - "path": "vessel/src/lib/chatGlossary.ts", - "role": "lib", - "lines": 241, - "exports": [ - "splitGlossaryText", - "CHAT_GLOSSARY", - "ChatGlossaryEntry", - "ChatGlossaryTextPart" - ], - "export_count": 4, - "import_count": 0, - "churn": 6, - "fragility": { - "score": 0, - "label": "low" - }, - "zone": "Vessel Src Lib Zone" - }, { "path": "vessel/src/lib/firebase.ts", "role": "lib", @@ -2676,28 +2877,10 @@ }, "zone": "Vessel Src Lib Zone" }, - { - "path": "vessel/src/lib/planner.ts", - "role": "lib", - "lines": 320, - "exports": [ - "buildPlannerResponse", - "SoloBalanceMeterResult", - "PlannerResponse" - ], - "export_count": 3, - "import_count": 2, - "churn": 5, - "fragility": { - "score": 0, - "label": "low" - }, - "zone": "Vessel Src Lib Zone" - }, { "path": "vessel/src/lib/ravenPersona.ts", "role": "lib", - "lines": 165, + "lines": 168, "exports": [ "buildRavenSystemPrompt", "compactText", @@ -2710,7 +2893,7 @@ ], "export_count": 8, "import_count": 0, - "churn": 2, + "churn": 6, "fragility": { "score": 0, "label": "low" @@ -2788,7 +2971,7 @@ ], "export_count": 3, "import_count": 0, - "churn": 1, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -2798,16 +2981,18 @@ { "path": "vessel/src/lib/stripe.ts", "role": "lib", - "lines": 34, + "lines": 40, "exports": [ "getStripe", "STRIPE_ENABLED", - "STRIPE_PRICE_ID", + "STRIPE_PRO_PRICE_ID", + "STRIPE_SOLO_REPORT_PRICE_ID", + "STRIPE_RELATIONAL_REPORT_PRICE_ID", "STRIPE_WEBHOOK_SECRET" ], - "export_count": 4, + "export_count": 6, "import_count": 0, - "churn": 0, + "churn": 4, "fragility": { "score": 0, "label": "low" @@ -2865,7 +3050,7 @@ ], "export_count": 8, "import_count": 0, - "churn": 0, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -2897,7 +3082,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 3, + "churn": 4, "fragility": { "score": 0, "label": "low" @@ -2954,7 +3139,7 @@ ], "export_count": 1, "import_count": 0, - "churn": 1, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -2991,7 +3176,7 @@ ], "export_count": 5, "import_count": 0, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3033,7 +3218,7 @@ ], "export_count": 6, "import_count": 3, - "churn": 1, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -3090,7 +3275,7 @@ ], "export_count": 8, "import_count": 2, - "churn": 0, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -3110,7 +3295,7 @@ ], "export_count": 5, "import_count": 1, - "churn": 5, + "churn": 6, "fragility": { "score": 0, "label": "low" @@ -3168,7 +3353,7 @@ ], "export_count": 3, "import_count": 0, - "churn": 5, + "churn": 6, "fragility": { "score": 0, "label": "low" @@ -3193,6 +3378,22 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/raven/natalHousesByPlanet.ts", + "role": "lib", + "lines": 151, + "exports": [ + "buildNatalHousesByPlanet" + ], + "export_count": 1, + "import_count": 0, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/personaLawGovernors.ts", "role": "lib", @@ -3227,7 +3428,7 @@ ], "export_count": 6, "import_count": 0, - "churn": 3, + "churn": 5, "fragility": { "score": 0, "label": "low" @@ -3246,7 +3447,7 @@ ], "export_count": 4, "import_count": 0, - "churn": 3, + "churn": 4, "fragility": { "score": 0, "label": "low" @@ -3304,7 +3505,7 @@ ], "export_count": 6, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3329,7 +3530,7 @@ ], "export_count": 10, "import_count": 0, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3347,7 +3548,7 @@ ], "export_count": 3, "import_count": 0, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3357,7 +3558,7 @@ { "path": "vessel/src/lib/raven/sealedArtifact.ts", "role": "lib", - "lines": 149, + "lines": 171, "exports": [ "hashGeometry", "buildProfileFingerprint", @@ -3370,7 +3571,7 @@ ], "export_count": 8, "import_count": 1, - "churn": 1, + "churn": 4, "fragility": { "score": 0, "label": "low" @@ -3468,7 +3669,7 @@ ], "export_count": 3, "import_count": 0, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3487,7 +3688,31 @@ ], "export_count": 4, "import_count": 0, - "churn": 1, + "churn": 2, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/raven/symbolicMomentTranslation.ts", + "role": "lib", + "lines": 255, + "exports": [ + "formatChamberLabel", + "chamberLifeDomain", + "chamberShortForm", + "phraseForAspect", + "PLANET_CONSEQUENCE", + "ASPECT_QUALITY", + "COMMON_ASPECT_PHRASE", + "CHAMBER_META", + "BANNED_FRONTSTAGE_TERMS" + ], + "export_count": 9, + "import_count": 0, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3521,7 +3746,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 0, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -3579,7 +3804,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 2, + "churn": 4, "fragility": { "score": 0, "label": "low" @@ -3699,7 +3924,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 1, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -3716,7 +3941,46 @@ ], "export_count": 2, "import_count": 3, - "churn": 2, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/raven/poetic-codex/adaptive-prompt.ts", + "role": "lib", + "lines": 377, + "exports": [ + "buildAdaptivePrompt", + "ADAPTIVE_CODEX_PROMPT" + ], + "export_count": 2, + "import_count": 2, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/raven/poetic-codex/helpers.ts", + "role": "lib", + "lines": 171, + "exports": [ + "deriveTone", + "getVoiceCalibration", + "suggestSymbolLogic", + "detectShadowMaterial", + "identifyShadowType", + "extractShadowGeometry", + "generateCardId" + ], + "export_count": 7, + "import_count": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3726,15 +3990,37 @@ { "path": "vessel/src/lib/raven/insight-cards/prompt.ts", "role": "lib", - "lines": 49, + "lines": 77, "exports": [ "buildInsightUserPrompt", "INSIGHT_CARD_SYSTEM_PROMPT", "InsightGenerationInput" ], "export_count": 3, - "import_count": 2, - "churn": 2, + "import_count": 3, + "churn": 3, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/raven/insight-cards/resonanceEcologyCodex.ts", + "role": "lib", + "lines": 141, + "exports": [ + "getBlend", + "getBlendsByDriver", + "getBlendsByElement", + "getBlendById", + "LIGHT_LEDGER", + "Sign", + "ResonanceBlend" + ], + "export_count": 7, + "import_count": 0, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3763,16 +4049,18 @@ { "path": "vessel/src/lib/raven/insight-cards/types.ts", "role": "lib", - "lines": 29, + "lines": 46, "exports": [ "KINETIC_SYMBOLS", "InsightDomain", "KineticMode", "CoherenceLevel", "Orientation", + "VesselGeometry", + "WeatherTelemetry", "InsightCard" ], - "export_count": 6, + "export_count": 8, "import_count": 0, "churn": 0, "fragility": { @@ -3869,7 +4157,7 @@ "lines": 91, "export_count": 0, "import_count": 2, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3908,7 +4196,7 @@ "lines": 91, "export_count": 0, "import_count": 3, - "churn": 0, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -3960,7 +4248,7 @@ "lines": 66, "export_count": 0, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3986,7 +4274,7 @@ "lines": 282, "export_count": 0, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -4006,6 +4294,19 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/raven/__tests__/natalHousesByPlanet.test.ts", + "role": "test", + "lines": 103, + "export_count": 0, + "import_count": 1, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/__tests__/persona-law.test.ts", "role": "test", @@ -4064,7 +4365,7 @@ "lines": 174, "export_count": 0, "import_count": 2, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -4077,7 +4378,7 @@ "lines": 59, "export_count": 0, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -4136,6 +4437,19 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/raven/__tests__/symbolicMomentComposer.test.ts", + "role": "test", + "lines": 329, + "export_count": 0, + "import_count": 1, + "churn": 4, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/__tests__/symbolicMomentIntent.test.ts", "role": "test", @@ -4168,7 +4482,7 @@ "lines": 60, "export_count": 0, "import_count": 1, - "churn": 0, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -4181,7 +4495,7 @@ "lines": 97, "export_count": 0, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -4406,19 +4720,6 @@ }, "zone": "Vessel Src Lib Zone" }, - { - "path": "vessel/src/lib/__tests__/natalExport.test.ts", - "role": "test", - "lines": 365, - "export_count": 0, - "import_count": 2, - "churn": 2, - "fragility": { - "score": 0, - "label": "low" - }, - "zone": "Vessel Src Lib Zone" - }, { "path": "vessel/src/lib/__tests__/relocationSandbox.test.ts", "role": "test", @@ -4448,10 +4749,10 @@ { "path": "vessel/src/lib/__tests__/sealedArtifact.test.ts", "role": "test", - "lines": 227, + "lines": 287, "export_count": 0, "import_count": 2, - "churn": 1, + "churn": 4, "fragility": { "score": 0, "label": "low" @@ -4464,7 +4765,7 @@ "lines": 155, "export_count": 0, "import_count": 1, - "churn": 1, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -4474,29 +4775,12 @@ { "path": "vessel/src/hooks/useElevenLabsVoice.ts", "role": "hook", - "lines": 226, + "lines": 246, "exports": [ "useElevenLabsVoice" ], "export_count": 1, "import_count": 1, - "churn": 0, - "fragility": { - "score": 0, - "label": "low" - }, - "zone": "Vessel Src Zone" - }, - { - "path": "vessel/src/hooks/useFlightRecorderData.ts", - "role": "hook", - "lines": 48, - "exports": [ - "useFlightRecorderData", - "FlightRecorderData" - ], - "export_count": 2, - "import_count": 4, "churn": 2, "fragility": { "score": 0, @@ -4578,7 +4862,7 @@ ], "export_count": 1, "import_count": 3, - "churn": 3, + "churn": 5, "fragility": { "score": 0, "label": "low" @@ -4668,7 +4952,7 @@ { "path": "vessel/src/components/raven/PoeticIndexCardDisplay.tsx", "role": "component", - "lines": 126, + "lines": 140, "exports": [ "PoeticIndexCardDisplay" ], @@ -4681,22 +4965,6 @@ }, "zone": "Vessel Src Zone" }, - { - "path": "vessel/src/components/raven/insight-cards/InsightCardDisplay.tsx", - "role": "component", - "lines": 400, - "exports": [ - "InsightCardDisplay" - ], - "export_count": 1, - "import_count": 2, - "churn": 0, - "fragility": { - "score": 0, - "label": "low" - }, - "zone": "Vessel Src Zone" - }, { "path": "vessel/src/components/raven/insight-cards/InsightCardPanel.tsx", "role": "component", @@ -4713,22 +4981,6 @@ }, "zone": "Vessel Src Zone" }, - { - "path": "vessel/src/components/chat/AlignmentCorridorReadout.tsx", - "role": "component", - "lines": 322, - "exports": [ - "AlignmentCorridorReadout" - ], - "export_count": 1, - "import_count": 8, - "churn": 5, - "fragility": { - "score": 0, - "label": "low" - }, - "zone": "Vessel Src Zone" - }, { "path": "vessel/src/components/chat/ChatDashboardLayout.tsx", "role": "component", @@ -4813,13 +5065,13 @@ { "path": "vessel/src/components/chat/CounterpartQuickActions.tsx", "role": "component", - "lines": 94, + "lines": 107, "exports": [ "CounterpartQuickActions" ], "export_count": 1, "import_count": 2, - "churn": 0, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -4874,22 +5126,6 @@ }, "zone": "Vessel Src Zone" }, - { - "path": "vessel/src/components/chat/FlightRecorderSidebar.tsx", - "role": "component", - "lines": 217, - "exports": [ - "FlightRecorderSidebar" - ], - "export_count": 1, - "import_count": 5, - "churn": 2, - "fragility": { - "score": 0, - "label": "low" - }, - "zone": "Vessel Src Zone" - }, { "path": "vessel/src/components/chat/InstrumentMenu.tsx", "role": "component", @@ -4955,7 +5191,7 @@ ], "export_count": 5, "import_count": 0, - "churn": 2, + "churn": 3, "fragility": { "score": 0, "label": "low" @@ -4988,7 +5224,7 @@ ], "export_count": 2, "import_count": 2, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -4998,13 +5234,13 @@ { "path": "vessel/src/components/chat/ScopeModeChips.tsx", "role": "component", - "lines": 132, + "lines": 192, "exports": [ "ScopeModeChips" ], "export_count": 1, "import_count": 1, - "churn": 0, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -5020,7 +5256,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5036,7 +5272,7 @@ ], "export_count": 1, "import_count": 2, - "churn": 2, + "churn": 3, "fragility": { "score": 0, "label": "low" @@ -5140,10 +5376,10 @@ { "path": "vessel/src/components/chat/__tests__/ScopeModeChips.test.tsx", "role": "test", - "lines": 50, + "lines": 118, "export_count": 0, "import_count": 1, - "churn": 0, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -5169,7 +5405,7 @@ "lines": 36, "export_count": 0, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5217,7 +5453,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 1, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -5275,7 +5511,7 @@ ], "export_count": 1, "import_count": 3, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5392,7 +5628,7 @@ ], "export_count": 1, "import_count": 2, - "churn": 0, + "churn": 3, "fragility": { "score": 0, "label": "low" @@ -5501,7 +5737,7 @@ { "path": "vessel/src/app/api/vault/export/route.ts", "role": "route", - "lines": 170, + "lines": 132, "exports": [ "GET", "runtime", @@ -5509,8 +5745,8 @@ "maxDuration" ], "export_count": 4, - "import_count": 1, - "churn": 2, + "import_count": 3, + "churn": 4, "fragility": { "score": 0, "label": "low" @@ -5559,7 +5795,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5655,7 +5891,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 1, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -5893,26 +6129,9 @@ "parseSymbolicMomentDateRange", "MONTH_NAME_TO_INDEX" ], - "export_count": 7, - "import_count": 2, - "churn": 0, - "fragility": { - "score": 0, - "label": "low" - }, - "zone": "Vessel Src App Zone" - }, - { - "path": "vessel/src/app/api/raven-chat/entityGuard.ts", - "role": "route", - "lines": 50, - "exports": [ - "applyCounterpartEntityGuard", - "CounterpartEntityGuardResult" - ], - "export_count": 2, + "export_count": 7, "import_count": 2, - "churn": 1, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5920,17 +6139,16 @@ "zone": "Vessel Src App Zone" }, { - "path": "vessel/src/app/api/raven-chat/generationIntegrity.ts", + "path": "vessel/src/app/api/raven-chat/entityGuard.ts", "role": "route", - "lines": 259, + "lines": 50, "exports": [ - "resolveReplyIntegrity", - "ReplyIntegrityInput", - "ReplyIntegrityResolution" + "applyCounterpartEntityGuard", + "CounterpartEntityGuardResult" ], - "export_count": 3, + "export_count": 2, "import_count": 2, - "churn": 4, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -5968,7 +6186,7 @@ ], "export_count": 5, "import_count": 1, - "churn": 4, + "churn": 5, "fragility": { "score": 0, "label": "low" @@ -5987,7 +6205,7 @@ ], "export_count": 4, "import_count": 2, - "churn": 2, + "churn": 3, "fragility": { "score": 0, "label": "low" @@ -6047,7 +6265,7 @@ ], "export_count": 5, "import_count": 10, - "churn": 2, + "churn": 3, "fragility": { "score": 0, "label": "low" @@ -6123,14 +6341,14 @@ { "path": "vessel/src/app/api/raven-chat/systemBlockBuilder.ts", "role": "route", - "lines": 341, + "lines": 375, "exports": [ "buildSystemBlocks", "SystemBlocksConfig" ], "export_count": 2, "import_count": 12, - "churn": 2, + "churn": 4, "fragility": { "score": 0, "label": "low" @@ -6165,7 +6383,7 @@ ], "export_count": 3, "import_count": 8, - "churn": 3, + "churn": 5, "fragility": { "score": 0, "label": "low" @@ -6204,7 +6422,7 @@ "lines": 114, "export_count": 0, "import_count": 1, - "churn": 2, + "churn": 3, "fragility": { "score": 0, "label": "low" @@ -6224,39 +6442,13 @@ }, "zone": "Vessel Src App Zone" }, - { - "path": "vessel/src/app/api/raven-chat/__tests__/generationIntegrity.test.ts", - "role": "test", - "lines": 175, - "export_count": 0, - "import_count": 1, - "churn": 5, - "fragility": { - "score": 0, - "label": "low" - }, - "zone": "Vessel Src App Zone" - }, - { - "path": "vessel/src/app/api/raven-chat/__tests__/intentDetection.test.ts", - "role": "test", - "lines": 233, - "export_count": 0, - "import_count": 1, - "churn": 6, - "fragility": { - "score": 0, - "label": "low" - }, - "zone": "Vessel Src App Zone" - }, { "path": "vessel/src/app/api/raven-chat/__tests__/promptLines.test.ts", "role": "test", "lines": 101, "export_count": 0, "import_count": 1, - "churn": 2, + "churn": 3, "fragility": { "score": 0, "label": "low" @@ -6269,7 +6461,7 @@ "lines": 64, "export_count": 0, "import_count": 1, - "churn": 0, + "churn": 3, "fragility": { "score": 0, "label": "low" @@ -6295,7 +6487,7 @@ "lines": 113, "export_count": 0, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6321,7 +6513,7 @@ "lines": 45, "export_count": 0, "import_count": 1, - "churn": 0, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -6344,10 +6536,10 @@ { "path": "vessel/src/app/api/raven-chat/__tests__/userBlockBuilder.test.ts", "role": "test", - "lines": 163, + "lines": 237, "export_count": 0, "import_count": 2, - "churn": 3, + "churn": 4, "fragility": { "score": 0, "label": "low" @@ -6370,6 +6562,23 @@ }, "zone": "Vessel Src App Zone" }, + { + "path": "vessel/src/app/api/poetic-codex/route.ts", + "role": "route", + "lines": 266, + "exports": [ + "POST", + "GET" + ], + "export_count": 2, + "import_count": 6, + "churn": 2, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src App Zone" + }, { "path": "vessel/src/app/api/planner/route.ts", "role": "route", @@ -6455,13 +6664,13 @@ { "path": "vessel/src/app/api/insight-card/route.ts", "role": "route", - "lines": 168, + "lines": 207, "exports": [ "POST" ], "export_count": 1, - "import_count": 5, - "churn": 2, + "import_count": 6, + "churn": 3, "fragility": { "score": 0, "label": "low" @@ -6477,7 +6686,7 @@ ], "export_count": 1, "import_count": 2, - "churn": 0, + "churn": 3, "fragility": { "score": 0, "label": "low" @@ -6493,7 +6702,7 @@ ], "export_count": 1, "import_count": 3, - "churn": 1, + "churn": 2, "fragility": { "score": 0, "label": "low" @@ -7298,6 +7507,16 @@ "to": "../sessionSummaryTelemetry", "resolved_to": "vessel/src/lib/sessionSummaryTelemetry.ts" }, + { + "from": "vessel/src/lib/raven/constellationVault.ts", + "to": "./poetic-codex/types", + "resolved_to": "vessel/src/lib/raven/poetic-codex/types.ts" + }, + { + "from": "vessel/src/lib/raven/constellationVault.ts", + "to": "./poetic-codex/types", + "resolved_to": "vessel/src/lib/raven/poetic-codex/types.ts" + }, { "from": "vessel/src/lib/raven/corridorSnapshot.ts", "to": "../v3MathBrain", @@ -7328,11 +7547,6 @@ "to": "./geometricalScaffoldingFootnotes", "resolved_to": "vessel/src/lib/raven/geometricalScaffoldingFootnotes.ts" }, - { - "from": "vessel/src/lib/raven/fieldReportRepairFallback.ts", - "to": "./symbolicMomentIntent", - "resolved_to": "vessel/src/lib/raven/symbolicMomentIntent.ts" - }, { "from": "vessel/src/lib/raven/fieldReportVoiceContext.ts", "to": "./localLexicon", @@ -7438,6 +7652,16 @@ "to": "./types", "resolved_to": "vessel/src/lib/raven/types.ts" }, + { + "from": "vessel/src/lib/raven/symbolicMomentComposer.ts", + "to": "./localLexicon", + "resolved_to": "vessel/src/lib/raven/localLexicon.ts" + }, + { + "from": "vessel/src/lib/raven/symbolicMomentComposer.ts", + "to": "./symbolicMomentTranslation", + "resolved_to": "vessel/src/lib/raven/symbolicMomentTranslation.ts" + }, { "from": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", "to": "./geometricalScaffoldingFootnotes", @@ -7448,6 +7672,11 @@ "to": "./localLexicon", "resolved_to": "vessel/src/lib/raven/localLexicon.ts" }, + { + "from": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", + "to": "./symbolicMomentComposer", + "resolved_to": "vessel/src/lib/raven/symbolicMomentComposer.ts" + }, { "from": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", "to": "../v3MathBrain", @@ -7668,6 +7897,26 @@ "to": "./chamberRegistry", "resolved_to": "vessel/src/lib/raven/sst/chamberRegistry.ts" }, + { + "from": "vessel/src/lib/raven/poetic-codex/adaptive-prompt.ts", + "to": "./types", + "resolved_to": "vessel/src/lib/raven/poetic-codex/types.ts" + }, + { + "from": "vessel/src/lib/raven/poetic-codex/adaptive-prompt.ts", + "to": "./helpers", + "resolved_to": "vessel/src/lib/raven/poetic-codex/helpers.ts" + }, + { + "from": "vessel/src/lib/raven/poetic-codex/helpers.ts", + "to": "./types", + "resolved_to": "vessel/src/lib/raven/poetic-codex/types.ts" + }, + { + "from": "vessel/src/lib/raven/poetic-codex/helpers.ts", + "to": "./types", + "resolved_to": "vessel/src/lib/raven/poetic-codex/types.ts" + }, { "from": "vessel/src/lib/raven/insight-cards/prompt.ts", "to": "./types", @@ -7678,6 +7927,11 @@ "to": "./sessionContext", "resolved_to": "vessel/src/lib/raven/insight-cards/sessionContext.ts" }, + { + "from": "vessel/src/lib/raven/insight-cards/prompt.ts", + "to": "./resonanceEcologyCodex", + "resolved_to": "vessel/src/lib/raven/insight-cards/resonanceEcologyCodex.ts" + }, { "from": "vessel/src/lib/raven/insight-cards/sessionContext.ts", "to": "@/hooks/useOracleChat", @@ -7863,6 +8117,11 @@ "to": "../lunarPhaseContext", "resolved_to": "vessel/src/lib/raven/lunarPhaseContext.ts" }, + { + "from": "vessel/src/lib/raven/__tests__/natalHousesByPlanet.test.ts", + "to": "../natalHousesByPlanet", + "resolved_to": "vessel/src/lib/raven/natalHousesByPlanet.ts" + }, { "from": "vessel/src/lib/raven/__tests__/persona-law.test.ts", "to": "../persona-law", @@ -7953,6 +8212,11 @@ "to": "../stagedProfileSnapshot", "resolved_to": "vessel/src/lib/raven/stagedProfileSnapshot.ts" }, + { + "from": "vessel/src/lib/raven/__tests__/symbolicMomentComposer.test.ts", + "to": "../symbolicMomentComposer", + "resolved_to": "vessel/src/lib/raven/symbolicMomentComposer.ts" + }, { "from": "vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts", "to": "../symbolicMomentFrontstage", @@ -9383,6 +9647,16 @@ "to": "../../../../lib/firebaseAdmin", "resolved_to": "vessel/src/lib/firebaseAdmin.ts" }, + { + "from": "vessel/src/app/api/vault/export/route.ts", + "to": "../../../../lib/natalExport", + "resolved_to": "vessel/src/lib/natalExport.ts" + }, + { + "from": "vessel/src/app/api/vault/export/route.ts", + "to": "../../../../lib/vaultSync", + "resolved_to": "vessel/src/lib/vaultSync.ts" + }, { "from": "vessel/src/app/api/vault/enrich-profile/route.ts", "to": "../../../../lib/wovenReportCore", @@ -10378,6 +10652,11 @@ "to": "@/lib/raven/symbolicMomentFrontstage", "resolved_to": "vessel/src/lib/raven/symbolicMomentFrontstage.ts" }, + { + "from": "vessel/src/app/api/raven-chat/route.ts", + "to": "@/lib/raven/natalHousesByPlanet", + "resolved_to": "vessel/src/lib/raven/natalHousesByPlanet.ts" + }, { "from": "vessel/src/app/api/raven-chat/route.ts", "to": "@/lib/streamReadTimeout", @@ -10818,6 +11097,36 @@ "to": "../../../lib/wovenReportCore", "resolved_to": "vessel/src/lib/wovenReportCore.ts" }, + { + "from": "vessel/src/app/api/poetic-codex/route.ts", + "to": "@/app/api/raven-chat/llmProvider", + "resolved_to": "vessel/src/app/api/raven-chat/llmProvider.ts" + }, + { + "from": "vessel/src/app/api/poetic-codex/route.ts", + "to": "@/lib/server/dailyUsageQuota", + "resolved_to": "vessel/src/lib/server/dailyUsageQuota.ts" + }, + { + "from": "vessel/src/app/api/poetic-codex/route.ts", + "to": "@/lib/raven/poetic-codex/adaptive-prompt", + "resolved_to": "vessel/src/lib/raven/poetic-codex/adaptive-prompt.ts" + }, + { + "from": "vessel/src/app/api/poetic-codex/route.ts", + "to": "@/lib/raven/poetic-codex/types", + "resolved_to": "vessel/src/lib/raven/poetic-codex/types.ts" + }, + { + "from": "vessel/src/app/api/poetic-codex/route.ts", + "to": "@/lib/raven/poetic-codex/helpers", + "resolved_to": "vessel/src/lib/raven/poetic-codex/helpers.ts" + }, + { + "from": "vessel/src/app/api/poetic-codex/route.ts", + "to": "@/lib/raven/constellationVault", + "resolved_to": "vessel/src/lib/raven/constellationVault.ts" + }, { "from": "vessel/src/app/api/planner/route.ts", "to": "../../../lib/ravenPersona", @@ -10878,6 +11187,11 @@ "to": "@/lib/raven/insight-cards/sessionContext", "resolved_to": "vessel/src/lib/raven/insight-cards/sessionContext.ts" }, + { + "from": "vessel/src/app/api/insight-card/route.ts", + "to": "@/lib/raven/insight-cards/resonanceEcologyCodex", + "resolved_to": "vessel/src/lib/raven/insight-cards/resonanceEcologyCodex.ts" + }, { "from": "vessel/src/app/api/checkout/route.ts", "to": "../../../lib/stripe", @@ -10999,113 +11313,120 @@ "path": "vessel/src/hooks/useOracleChat.ts", "score": 7, "label": "high", - "lines": 2494, - "churn": 13 + "lines": 2674, + "churn": 25 + }, + { + "path": "vessel/src/app/api/raven-chat/intentDetection.ts", + "score": 6, + "label": "high", + "lines": 1115, + "churn": 17 }, { "path": "vessel/src/app/api/raven-chat/sessionState.ts", "score": 6, "label": "high", - "lines": 1149, - "churn": 13 + "lines": 1153, + "churn": 15 }, { "path": "vessel/src/test/api-smoke.test.ts", "score": 5, "label": "high", - "lines": 3543, - "churn": 17 + "lines": 3545, + "churn": 21 }, { - "path": "vessel/src/app/page.tsx", + "path": "vessel/src/lib/v3MathBrain.ts", "score": 5, "label": "high", - "lines": 5739, - "churn": 29 + "lines": 1222, + "churn": 16 }, { - "path": "vessel/src/app/api/raven-chat/intentDetection.ts", + "path": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", "score": 5, "label": "high", - "lines": 1110, - "churn": 12 + "lines": 954, + "churn": 28 }, { - "path": "vessel/src/app/api/raven-chat/route.ts", + "path": "vessel/src/app/page.tsx", "score": 5, "label": "high", - "lines": 2301, - "churn": 40 + "lines": 5910, + "churn": 41 }, { - "path": "vessel/src/lib/v3MathBrain.ts", - "score": 4, - "label": "medium", - "lines": 1222, - "churn": 11 + "path": "vessel/src/app/api/raven-chat/route.ts", + "score": 5, + "label": "high", + "lines": 2334, + "churn": 57 }, { "path": "vessel/src/lib/vaultSync.ts", "score": 4, "label": "medium", "lines": 2159, - "churn": 6 + "churn": 3 }, { - "path": "vessel/src/lib/raven/responseRenderer.ts", + "path": "vessel/src/lib/wovenReportCore.ts", "score": 4, "label": "medium", - "lines": 867, - "churn": 9 + "lines": 4637, + "churn": 15 }, { - "path": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", + "path": "vessel/src/lib/raven/constellationVault.ts", "score": 4, "label": "medium", - "lines": 759, - "churn": 15 + "lines": 806, + "churn": 4 }, { - "path": "vessel/src/app/api/raven-chat/requestParsing.ts", + "path": "vessel/src/lib/raven/responseRenderer.ts", "score": 4, "label": "medium", - "lines": 801, - "churn": 4 + "lines": 867, + "churn": 9 }, { - "path": "vessel/src/lib/wovenReportCore.ts", - "score": 3, + "path": "vessel/src/app/api/raven-chat/requestParsing.ts", + "score": 4, "label": "medium", - "lines": 4637, - "churn": 12 + "lines": 801, + "churn": 3 }, { - "path": "vessel/src/lib/raven/constellationVault.ts", + "path": "vessel/src/lib/raven/doctrineManifest.ts", "score": 3, "label": "medium", - "lines": 744, - "churn": 0 + "lines": 617, + "churn": 8 }, { - "path": "vessel/src/lib/raven/doctrineManifest.ts", + "path": "vessel/src/lib/raven/fieldReportVoiceContract.ts", "score": 3, "label": "medium", - "lines": 617, - "churn": 7 + "lines": 403, + "churn": 17 }, { "path": "vessel/src/lib/raven/instrumentLedger.ts", "score": 3, "label": "medium", "lines": 535, - "churn": 4 + "churn": 6 }, { "path": "vessel/src/lib/raven/persona-law.ts", "score": 3, "label": "medium", "lines": 410, - "churn": 8 + "churn": 10 }, { "path": "vessel/src/lib/raven/protocolEngine.ts", @@ -11118,35 +11439,35 @@ "path": "vessel/src/components/AlignmentCorridor.tsx", "score": 3, "label": "medium", - "lines": 1431, - "churn": 9 + "lines": 1436, + "churn": 12 }, { "path": "vessel/src/components/ProfileVault.tsx", "score": 3, "label": "medium", - "lines": 2755, - "churn": 8 + "lines": 2795, + "churn": 12 }, { "path": "vessel/src/app/api/raven-chat/promptLines.ts", "score": 3, "label": "medium", - "lines": 527, - "churn": 29 + "lines": 412, + "churn": 43 }, { "path": "vessel/src/app/api/raven-chat/protocolRules.ts", "score": 3, "label": "medium", "lines": 513, - "churn": 8 + "churn": 11 } ], "dependency_hubs": [ { "target": "vessel/src/lib/vaultSync.ts", - "inbound_count": 49 + "inbound_count": 50 }, { "target": "vessel/src/lib/raven/types.ts", @@ -11472,8 +11793,8 @@ } ], "zone_ownership": { - "total": 361, - "covered": 361, + "total": 371, + "covered": 371, "unmapped": 0, "zones": [ { @@ -11504,12 +11825,12 @@ { "name": "Vessel Src App Zone", "belief": "TODO: Describe what this zone governs.", - "file_count": 103 + "file_count": 104 }, { "name": "Vessel Src Lib Zone", "belief": "TODO: Describe what this zone governs.", - "file_count": 155 + "file_count": 164 }, { "name": "Vessel Src Zone", @@ -11532,63 +11853,63 @@ "churn_hotspots": [ { "file": "vessel/src/app/api/raven-chat/route.ts", - "commits": 40 + "commits": 57 }, { "file": "vessel/src/app/api/raven-chat/promptLines.ts", - "commits": 29 + "commits": 43 }, { "file": "vessel/src/app/page.tsx", - "commits": 29 - }, - { - "file": "vessel/src/test/api-smoke.test.ts", - "commits": 17 + "commits": 41 }, { "file": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", - "commits": 15 + "commits": 28 }, { - "file": "vessel/src/app/api/raven-chat/userBlockBuilder.ts", - "commits": 13 + "file": "vessel/src/hooks/useOracleChat.ts", + "commits": 25 }, { - "file": "vessel/src/hooks/useOracleChat.ts", - "commits": 13 + "file": "vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts", + "commits": 21 }, { - "file": "vessel/src/app/api/raven-chat/sessionState.ts", - "commits": 13 + "file": "vessel/src/test/api-smoke.test.ts", + "commits": 21 }, { "file": "vessel/src/app/api/raven-chat/intentDetection.ts", - "commits": 12 + "commits": 17 }, { - "file": "vessel/src/lib/wovenReportCore.ts", - "commits": 12 + "file": "vessel/src/lib/raven/fieldReportVoiceContract.ts", + "commits": 17 }, { - "file": "vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts", - "commits": 11 + "file": "vessel/src/lib/v3MathBrain.ts", + "commits": 16 }, { - "file": "vessel/src/lib/v3MathBrain.ts", - "commits": 11 + "file": "vessel/src/app/api/raven-chat/userBlockBuilder.ts", + "commits": 15 }, { - "file": "vessel/src/lib/raven/fieldReportVoiceContract.ts", - "commits": 10 + "file": "vessel/src/app/api/raven-chat/sessionState.ts", + "commits": 15 + }, + { + "file": "vessel/src/lib/raven/fieldReportRepairFallback.ts", + "commits": 15 }, { - "file": "vessel/src/lib/raven/__tests__/responseRenderer.test.ts", - "commits": 10 + "file": "vessel/src/lib/wovenReportCore.ts", + "commits": 15 }, { - "file": "vessel/src/lib/raven/responseRenderer.ts", - "commits": 9 + "file": "vessel/src/components/ProfileVault.tsx", + "commits": 12 } ] } diff --git a/vessel/src/app/api/raven-chat/__tests__/generationIntegrity.test.ts b/vessel/src/app/api/raven-chat/__tests__/generationIntegrity.test.ts index dbe20693f..b358739a3 100644 --- a/vessel/src/app/api/raven-chat/__tests__/generationIntegrity.test.ts +++ b/vessel/src/app/api/raven-chat/__tests__/generationIntegrity.test.ts @@ -225,3 +225,56 @@ test('does not apply the counterpart-omission hard fail on non-relational turns' assert.equal(result.generated, true); assert.equal(result.acceptedReplySource, 'llm_stream'); }); + +test('labels stream-stall fallbacks with Clouded Skies on solo turns', () => { + const result = resolveReplyIntegrity({ + reply: '', + relationalRequested: false, + anchorName: 'DH Cross', + activeCounterpartName: null, + relationalFallback: null, + providerFinishReason: 'stream_stall', + providerCompleted: false, + }); + + assert.equal(result.generated, false); + assert.equal(result.isFallback, true); + assert.equal(result.droppedReplyReason, 'empty_generation'); + assert.equal(result.systemNotice, 'GENERATION_INCOMPLETE'); + assert.match(result.reply, /Clouded Skies/); + assert.match(result.reply, /Response incomplete/); +}); + +test('labels stream-stall fallbacks with Clouded Skies on relational turns', () => { + const result = resolveReplyIntegrity({ + reply: '', + relationalRequested: true, + anchorName: 'DH Cross', + activeCounterpartName: 'Alex', + relationalFallback: null, + providerFinishReason: 'stream_stall', + providerCompleted: false, + }); + + assert.equal(result.generated, false); + assert.equal(result.isFallback, true); + assert.equal(result.droppedReplyReason, 'empty_generation'); + assert.equal(result.systemNotice, 'RELATIONAL_GENERATION_INCOMPLETE'); + assert.match(result.reply, /Clouded Skies/); + assert.match(result.reply, /Relationship Mapping did not complete/i); +}); + +test('does not label normal incomplete generations with Clouded Skies (only stalls do)', () => { + const result = resolveReplyIntegrity({ + reply: '', + relationalRequested: false, + anchorName: 'DH Cross', + activeCounterpartName: null, + relationalFallback: null, + providerFinishReason: '', + providerCompleted: false, + }); + + assert.equal(result.generated, false); + assert.doesNotMatch(result.reply, /Clouded Skies/); +}); diff --git a/vessel/src/app/api/raven-chat/__tests__/userBlockBuilder.test.ts b/vessel/src/app/api/raven-chat/__tests__/userBlockBuilder.test.ts index 2d01bb1dd..852dfd011 100644 --- a/vessel/src/app/api/raven-chat/__tests__/userBlockBuilder.test.ts +++ b/vessel/src/app/api/raven-chat/__tests__/userBlockBuilder.test.ts @@ -160,4 +160,77 @@ test('buildUserBlocks emits a dedicated relationalAngleIntegrity block when asce assert.match(blocks.relationalAngleIntegrity || '', /do not share the same ascendant interface/i); assert.match(blocks.relationalAngleIntegrity || '', /Treat ascendant or rising-sign language as shared only when this integrity line explicitly says they match/i); -}); \ No newline at end of file +}); + +test('creator mirror offline telemetry still allows creator-mode help after acknowledgment', () => { + const blocks = buildUserBlocks({ + profile: { name: 'DH Cross' }, + primaryArchitectureSummary: 'stable architecture', + sealedCognitiveArchitecture: null, + blueprintNavigationScopeActive: false, + cognitiveCalibrationScopeActive: false, + constitutionalCalibrationBlock: '', + modeContract: MODE_CONTRACTS.CHAT, + blueprintSliceContext: null, + liveLocation: null, + liveLocationQuery: null, + telemetryProfile: { name: 'DH Cross' }, + hasKnownLocation: true, + stagedRosterSummary: 'none', + stagedProfileSnapshot: { + rosterNames: [], + activeCounterpartName: null, + contextOnlyNames: [], + }, + stagedTurnPolicyLine: 'No staged counterpart this turn.', + stagedArchitectureSummary: 'none', + operatorIsAnchor: true, + operatorLabel: 'DH Cross', + anchorLabel: 'DH Cross', + relationalMappingRequested: false, + counterpartIsDeceased: false, + effectiveRelationalContext: null, + relationalSharedStormReport: null, + relationalSharedStormError: null, + session: { + id: 'session-1', + turnCount: 1, + resonanceHits: 0, + missCount: 0, + openThreads: [], + isSealed: false, + calibration: { + locationConfirmed: true, + birthDataConfirmed: true, + blueprintConfirmed: true, + }, + phase: 'calibration', + phaseCapsules: [], + startedAt: new Date().toISOString(), + phaseEnteredAt: 0, + } as any, + history: [], + message: 'Why is Raven not replying in creator mode?', + upstreamResonance: null, + telemetryBrief: 'Telemetry brief unavailable.', + astrology: null, + creatorMirrorTelemetry: { + sensorStatus: 'offline', + runRef: null, + summary: 'No telemetry run available.', + architecturalGaps: ['sensor_array_offline'], + velocityStatus: 'offline', + recommendedRepairs: ['restore sensor runs'], + kernelSkillContext: null, + websiteSkillContext: null, + offlineReason: 'No Sherlog runs found.', + }, + fieldReportVoiceContext: null, + lunarPhaseContext: null, + circumstanceDisclosure: null, + } as any); + + assert.match(blocks.creatorMirrorTelemetry || '', /Acknowledge the sensor array is unavailable in one plain sentence/i); + assert.match(blocks.creatorMirrorTelemetry || '', /then continue helping in creator mode using known contracts/i); + assert.match(blocks.creatorMirrorTelemetry || '', /Do not refuse the turn solely because the sensor array is offline/i); +}); diff --git a/vessel/src/app/api/raven-chat/generationIntegrity.ts b/vessel/src/app/api/raven-chat/generationIntegrity.ts index ddb6cdaf8..1f89f4475 100644 --- a/vessel/src/app/api/raven-chat/generationIntegrity.ts +++ b/vessel/src/app/api/raven-chat/generationIntegrity.ts @@ -107,6 +107,14 @@ function hasBannedClosingQuestions(text: string): boolean { ); } +const STREAM_STALL_FINISH_REASON = "stream_stall"; +const CLOUDED_SKIES_LABEL = + "Clouded Skies — the channel went quiet before a full reading locked. The geometry is intact; only the rendering paused."; + +function isStreamStall(finishReason?: string | null): boolean { + return (finishReason || "").trim().toLowerCase() === STREAM_STALL_FINISH_REASON; +} + function buildIncompleteReply( input: ReplyIntegrityInput, reason: string, diff --git a/vessel/src/app/api/raven-chat/route.ts b/vessel/src/app/api/raven-chat/route.ts index 825861310..cb1eec54a 100644 --- a/vessel/src/app/api/raven-chat/route.ts +++ b/vessel/src/app/api/raven-chat/route.ts @@ -1922,6 +1922,7 @@ export async function POST(request: Request) { let accumulatedReply = ''; let providerFinishReason = ''; let providerCompleted = false; + let hasFirstChunk = false; let providerInterrupted = false; let providerInterruptionReason = ''; let finalReply = ''; @@ -1982,7 +1983,6 @@ export async function POST(request: Request) { buffer += decoder.decode(value, { stream: true }); const lines = buffer.split('\n'); buffer = lines.pop() || ''; - for (const line of lines) { const trimmed = line.trim(); if (trimmed === '') continue; @@ -1993,6 +1993,7 @@ export async function POST(request: Request) { if (trimmed.startsWith('data: ')) { try { const parsed = JSON.parse(trimmed.slice(6)); + // OpenAI content format handling const choice = parsed.choices?.[0]; const content = choice?.delta?.content; const finishReason = typeof choice?.finish_reason === 'string' @@ -2003,6 +2004,7 @@ export async function POST(request: Request) { } if (content) { accumulatedReply += content; + hasFirstChunk = true; } } catch (err) { // ignore JSON parse errors @@ -2028,6 +2030,7 @@ export async function POST(request: Request) { // Ignore cancellation failures } } + finalReply = accumulatedReply; currentIsRelational = relationalMappingRequested diff --git a/vessel/src/app/api/raven-chat/userBlockBuilder.ts b/vessel/src/app/api/raven-chat/userBlockBuilder.ts index d56cd5558..e94e8a5ac 100644 --- a/vessel/src/app/api/raven-chat/userBlockBuilder.ts +++ b/vessel/src/app/api/raven-chat/userBlockBuilder.ts @@ -64,11 +64,9 @@ function buildCreatorMirrorTelemetryBlock(creatorMirrorTelemetry: CreatorMirrorT : ''; if (creatorMirrorTelemetry.sensorStatus === 'offline') { - const offlineReason = compactText( - creatorMirrorTelemetry.offlineReason || 'Sherlog telemetry unavailable.', - 260, - ); - return `Sherlog creator-mirror telemetry: OFFLINE. Reason: ${offlineReason} Acknowledge the outage briefly, then continue in creator mode using available kernel/website context and the operator's request. Use explicit assumptions where needed and avoid pretending the telemetry is live.${kernelContextBlock}${websiteContextBlock}`; + const offlineReason = creatorMirrorTelemetry.offlineReason?.trim() + || 'No Sherlog runs found at velocity-artifacts/sherlog-runs.'; + return `Sherlog creator-mirror telemetry: OFFLINE. Reason: ${offlineReason} Acknowledge the sensor array is unavailable in one plain sentence, then continue helping in creator mode using known contracts, prompt architecture, and the user’s request. Do not claim live telemetry, and do not refuse the turn solely because the sensor array is offline.${kernelContextBlock}${websiteContextBlock}`; } return `Sherlog creator-mirror telemetry: ${compactText({ diff --git a/vessel/src/app/page.tsx b/vessel/src/app/page.tsx index 30fad71e1..9249814d4 100644 --- a/vessel/src/app/page.tsx +++ b/vessel/src/app/page.tsx @@ -2168,6 +2168,7 @@ export default function App() { })(); return () => { cancelled = true; + stop(); }; }, [messages, voiceMode, sendText, audioFullOutputEnabled, alignmentCorridorState, isLoading]); @@ -3037,6 +3038,7 @@ export default function App() { desc: string, options?: { forcePrimaryScope?: boolean; + stagedOnlyScope?: boolean; profileOverride?: VaultProfile | null; source?: string; }, @@ -3069,11 +3071,19 @@ export default function App() { }).catch(() => { }); return; } + if (options?.stagedOnlyScope) { + void sendMessage(safeDesc, { + stagedContextsOverride: observerStagedProfiles.map((p) => ({ profile: p, role: 'OBSERVER' as const })), + targetModeOverride: 'FIELD_REPORT', + structuredReadingOptInOverride: structuredFieldReport, + }).catch(() => { }); + return; + } void sendScopedMessage(safeDesc, { targetModeOverride: 'FIELD_REPORT', structuredReadingOptInOverride: structuredFieldReport, }).catch(() => { }); - }, [armCorridorLoadingMode, primeAlignmentCorridor, requestReadArm, sendMessage, sendScopedMessage]); + }, [armCorridorLoadingMode, observerStagedProfiles, primeAlignmentCorridor, requestReadArm, sendMessage, sendScopedMessage]); const handleCounterpartSoloMirror = useCallback((profile: VaultProfile, source: string) => { appendClientRuntimeEvent('COUNTERPART_QUICK_ACTION_SELECTED', { @@ -3339,6 +3349,15 @@ export default function App() { announceCopyResult('Copied Raven response.', messageId); } }; + + const replayAssistantMessage = (text: string) => { + stop(); + const spoken = normalizeReflectionSpeechText(text); + if (spoken) { + void sendText(spoken); + } + }; + if (authLoading) { return (
@@ -3456,6 +3475,14 @@ export default function App() { > Map Us · {profile.name} + ); })} @@ -3898,6 +3925,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} @@ -4181,7 +4209,9 @@ export default function App() { Symbolic Moment Target

- A counterpart is staged. Choose whose chart should anchor the symbolic moment, or map both together. + {observerStagedProfiles.length === 1 + ? `${observerStagedProfiles[0].name} is staged. Choose who or what to read in this moment.` + : `${observerStagedProfiles.length} profiles staged. Choose the focus or read them together.`}

+ )} + {observerStagedProfiles.length > 0 && ( + + )} +
); })} diff --git a/vessel/src/hooks/useElevenLabsVoice.ts b/vessel/src/hooks/useElevenLabsVoice.ts index 1250e24e4..8d1318453 100644 --- a/vessel/src/hooks/useElevenLabsVoice.ts +++ b/vessel/src/hooks/useElevenLabsVoice.ts @@ -125,9 +125,30 @@ export function useElevenLabsVoice({ } const unlocked = context.state === 'running'; + + // Pre-build the reverb chain and push a silent sample through it so the + // ConvolverNode has allocated its kernel before the first TTS response + // arrives. Without this warm-up, the first sendText() pays for impulse + // generation + convolver cold-start while audio is already trying to play, + // which manifests as the first response "choking out". + if (unlocked) { + try { + const { dry, convolver } = getReverbChain(context); + const warmBuf = context.createBuffer(1, 1, context.sampleRate); + const warmSrc = context.createBufferSource(); + warmSrc.buffer = warmBuf; + warmSrc.connect(dry); + warmSrc.connect(convolver); + warmSrc.start(0); + warmSrc.onended = () => { warmSrc.disconnect(); }; + } catch { + // best-effort — reverb will lazy-init on first sendText if this fails + } + } + setIsUnlocked(unlocked); return unlocked; - }, [getOrCreateContext]); + }, [getOrCreateContext, getReverbChain]); const stop = useCallback(() => { if (abortControllerRef.current) { diff --git a/vessel/src/hooks/useOracleChat.ts b/vessel/src/hooks/useOracleChat.ts index 11fcfdf2a..b5ed85294 100644 --- a/vessel/src/hooks/useOracleChat.ts +++ b/vessel/src/hooks/useOracleChat.ts @@ -1305,6 +1305,33 @@ function extractApiErrorMessage(errText: string): string | null { return normalized.length > 200 ? `${normalized.slice(0, 197)}…` : normalized; } +const NETWORK_RETRY_DELAYS_MS = [350, 900, 1800] as const; +const ONLINE_SIGNAL_WAIT_MS = 4000; + +function sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +async function waitForOnlineSignal(timeoutMs = ONLINE_SIGNAL_WAIT_MS): Promise { + if (typeof window === 'undefined' || typeof navigator === 'undefined') return; + if (navigator.onLine !== false) return; + await new Promise((resolve) => { + const onOnline = () => { + cleanup(); + resolve(); + }; + const timeout = window.setTimeout(() => { + cleanup(); + resolve(); + }, timeoutMs); + const cleanup = () => { + window.removeEventListener('online', onOnline); + window.clearTimeout(timeout); + }; + window.addEventListener('online', onOnline, { once: true }); + }); +} + function normalizeUpgradeGatePayload(value: unknown): UpgradeGatePayload | null { const row = asRecord(value); if (!row) return null; @@ -1550,6 +1577,9 @@ export function useOracleChat({ activeProfile, stagedContexts, activeMode, isIni // Incremented by restoreSession/clearMessages to invalidate any in-flight request. // Captured at request start; compared before writing any state from the response. const requestGenerationRef = useRef(0); + // Tracks the in-flight assistant message so the outer catch can distinguish a + // pre-CHUNK failure (show error bubble) from a post-stream enrichment failure + // (reply already rendered — log only, don't append a redundant error bubble). const setUsageOverrideEnabled = useCallback((enabled: boolean) => { setUsageOverrideEnabledState(enabled); }, []); @@ -1753,24 +1783,46 @@ export function useOracleChat({ activeProfile, stagedContexts, activeMode, isIni return response; }; + const performRequestWithNetworkRecovery = async ( + primaryHistory: ChatMessage[], + fallbackHistory?: ChatMessage[], + ): Promise<{ response: Response; usedFallbackHistory: boolean }> => { + let lastNetworkError: unknown = null; + const candidates = fallbackHistory ? [primaryHistory, fallbackHistory] : [primaryHistory]; + for (let attempt = 0; attempt <= NETWORK_RETRY_DELAYS_MS.length; attempt += 1) { + for (const candidate of candidates) { + try { + return { + response: await performRequest(candidate), + usedFallbackHistory: Boolean(fallbackHistory && candidate === fallbackHistory), + }; + } catch (error: unknown) { + if (!isLikelyNetworkLoadFailure(error)) throw error; + lastNetworkError = error; + console.error( + '[Raven] channel fetch failed (attempt %d/%d, online: %s):', + attempt + 1, + NETWORK_RETRY_DELAYS_MS.length + 1, + typeof navigator !== 'undefined' ? String(navigator.onLine) : 'unknown', + error, + ); + } + } + if (attempt < NETWORK_RETRY_DELAYS_MS.length) { + await waitForOnlineSignal(); + await sleep(NETWORK_RETRY_DELAYS_MS[attempt]); + } + } + throw lastNetworkError ?? new Error('Network request failed'); + }; + setRequestPhase('dispatched'); - let didCompactRetry = false; + const networkFallbackHistory = historyBase.length > compactHistoryBase.length ? compactHistoryBase : undefined; + const requestResult = await performRequestWithNetworkRecovery(historyBase, networkFallbackHistory); + let response = requestResult.response; + let didCompactRetry = requestResult.usedFallbackHistory; let didGatewayRetry = false; let gatewayRetryStatus: number | null = null; - let response: Response; - try { - response = await performRequest(historyBase); - } catch (error: unknown) { - if (historyBase.length > compactHistoryBase.length && isLikelyNetworkLoadFailure(error)) { - didCompactRetry = true; - response = await performRequest(compactHistoryBase); - } else if (isLikelyNetworkLoadFailure(error)) { - // Retry once on transient network failure even when history is already compact - response = await performRequest(historyBase); - } else { - throw error; - } - } if (response.status === 413 && !didCompactRetry && historyBase.length > compactHistoryBase.length) { didCompactRetry = true; @@ -1812,9 +1864,11 @@ export function useOracleChat({ activeProfile, stagedContexts, activeMode, isIni } throw new Error('UPGRADE_REQUIRED'); } - const parsedError = typeof errData?.error === 'string' && errData.error.trim() - ? errData.error.trim() - : extractApiErrorMessage(errText); + const parsedError = (typeof errData?.message === 'string' && errData.message.trim()) + ? errData.message.trim() + : (typeof errData?.error === 'string' && errData.error.trim()) + ? errData.error.trim() + : extractApiErrorMessage(errText); const msg = response.status === 401 ? 'Session expired. Please sign out and sign back in.' : parsedError @@ -1900,11 +1954,44 @@ export function useOracleChat({ activeProfile, stagedContexts, activeMode, isIni } catch { // Ignore cancellation failures after a broken stream. } - throw toRavenRequestExecutionError(error, { - phase: 'stream', - assistantMessageId, - assistantMessageText, + } + + if (data.generated === false || data.systemNotice === 'MODE_DRIFT_BLOCKED' || data.systemNotice === 'RELATIONAL_GENERATION_INCOMPLETE' || data.systemNotice === 'GENERATION_INCOMPLETE') { + assistantMessageText = data.reply || assistantMessageText; + data.reply = assistantMessageText; + setMessages((prev) => { + const idx = prev.findIndex((m) => m.id === assistantMessageId); + if (idx !== -1) { + const copy = [...prev]; + copy[idx] = { ...copy[idx], text: assistantMessageText }; + return copy; + } + return prev; }); + } else { + data.reply = assistantMessageText; + } + const serverTag = data.balanceTag ?? null; + const fieldReport = sanitizeFieldReportVoiceContext(data.fieldReport); + const corridorSnapshot = sanitizeCorridorSnapshot(data.corridorSnapshot); + const nextPulseCache = sanitizePulseCache(data.pulseCache); + const nextSymbolicWeatherCache = sanitizeSymbolicWeatherCache(data.symbolicWeatherCache); + const { action: vaultAction, cleanText: textWithoutVaultAction } = extractVaultAction(data.reply); + const {tag: inlineTag, cleanText} = extractBalanceTag(textWithoutVaultAction, serverTag?.scope || streamingBalanceTag?.scope); + const effectiveBalanceTag = serverTag ?? inlineTag ?? null; + + let vaultNote = ''; + if (vaultAction) { + try { + const created = await applyVaultAction(vaultAction); + if (created) { + vaultNote = created.status === 'created' + ? `\n\n✅ Added **${created.profile.name}** to your vault with natal + cognitive architecture.` + : `\n\n✅ Synced **${created.profile.name}** with existing vault record (natal + cognitive architecture refreshed).`; + } + } catch (vaultError) { + console.error('[Raven] vault action enrichment failed (degrading gracefully):', vaultError); + } } const sawReplyPayload = data && typeof data === 'object' && Object.prototype.hasOwnProperty.call(data, 'reply'); @@ -2325,6 +2412,22 @@ export function useOracleChat({ activeProfile, stagedContexts, activeMode, isIni assistantMessageId: ravenExecutionError?.assistantMessageId || undefined, }); } + + // If the streamed reply already rendered visible text, this error came from + // post-stream enrichment (vault sync, blind-mirror, telemetry side-effects). + // The user already saw a complete answer — don't append a redundant error + // bubble on top of it. Upgrade gates still surface (they steer routing). + const replyAlreadyRendered = !upgradeGate + && inflightAssistant?.hasText === true; + if (replyAlreadyRendered) { + console.error('[Raven] post-stream enrichment failed (reply already rendered, suppressing error bubble):', error); + return; + } + if (isNetwork) { + console.error('[Raven] channel failure — all retry attempts exhausted:', error); + } else if (!upgradeGate && !is413) { + console.error('[Raven] request failure:', error); + } if ( !upgradeGate && ( @@ -2339,7 +2442,7 @@ export function useOracleChat({ activeProfile, stagedContexts, activeMode, isIni : is413 ? 'Your message is too long for Raven to process. Please shorten it.' : isNetwork - ? 'The connection to Raven was interrupted. Please check your network and try again.' + ? 'Raven hit a temporary channel issue. Please try again.' : upgradeGate ? upgradeGate.message : `A dark cloud obscures my vision. (${errorMessage})`; @@ -2353,7 +2456,6 @@ export function useOracleChat({ activeProfile, stagedContexts, activeMode, isIni : (upgradeGate ? 'System · Upgrade' : undefined), ...(upgradeGate ? { upgradeGate } : {}), }; - if (ravenExecutionError?.phase === 'postprocess' && ravenExecutionError.assistantMessageText.trim()) { return; } @@ -2382,6 +2484,7 @@ export function useOracleChat({ activeProfile, stagedContexts, activeMode, isIni return [...withoutGhost, fallbackMessage]; }); } finally { + inflightAssistantRef.current = null; inflightRef.current = false; inflightAssistantRef.current = null; setIsLoading(false); diff --git a/vessel/src/lib/raven/__tests__/symbolicMomentComposer.test.ts b/vessel/src/lib/raven/__tests__/symbolicMomentComposer.test.ts index 40b70d5b9..76ca4abfb 100644 --- a/vessel/src/lib/raven/__tests__/symbolicMomentComposer.test.ts +++ b/vessel/src/lib/raven/__tests__/symbolicMomentComposer.test.ts @@ -58,11 +58,13 @@ test('composeSymbolicMomentNarrative produces the canonical Mercury-Uranus-Venus // pressure/numbness/fog/ignition/misfire/absence options. assert.equal( narrative.zone3, - 'Is this landing as pressure, numbness, fog, ignition, misfire, or absence?', + 'Name the closest landing: pressure, numbness, fog, ignition, misfire, or none of these.', ); // The leading "does this resemble [predicted outcome]?" form is // explicitly forbidden in pre-testimony reads. assert.doesNotMatch(narrative.zone3, /^On the ground, does this resemble /); + assert.doesNotMatch(narrative.zone3, /\b(?:WB|ABE|OSR|Mixed|Inconclusive)\b/); + assert.match(narrative.zone3, /\bnone of these\b/); // Astrological note appended in prose. assert.match(narrative.reply, /\*\*Astrological note:\*\*/); // Astrological-note phrasing is sourced from the restored @@ -313,6 +315,19 @@ test('a hidden template is still a leak if the brackets show: composer never shi } }); +test('pre-testimony verification keeps SST labels out and preserves null path', () => { + const narrative = composeSymbolicMomentNarrative({ + chamber: 'The Grove', + drivers: [{ left: 'mars', right: 'saturn', aspect: 'square' }], + primarySignature: 'Carrier', + includeAstrologicalNote: false, + }); + + assert.doesNotMatch(narrative.zone3, /\b(?:WB|ABE|OSR|Mixed|Inconclusive)\b/); + assert.doesNotMatch(narrative.zone3, /\bdoes this feel\b/i); + assert.match(narrative.zone3, /\bnone of these\b/); +}); + test('UnresolvedNarrativeTokenError class identity is exposed for caller catch blocks', () => { // The route layer (symbolicMomentFrontstage.buildStructuredSymbolic- // MomentReply) catches this specific error and emits Signal Void. diff --git a/vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts b/vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts index 5ec7196e2..e450f4cf6 100644 --- a/vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts +++ b/vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts @@ -81,8 +81,8 @@ test('buildStructuredSymbolicMomentReply assembles named-storm Zone 1 prose, sea assert.match(structured.zone1, /mark this as quiet ground\. Do not force the omen\./); assert.match(structured.zone1, /\*\*Resonance State:\*\* Pending \/ Unreviewed\./); // Verification is the final prompt. - assert.match(structured.zone3 ?? '', /^On the ground, does this resemble /); - assert.match(structured.zone3 ?? '', /, or none of these\?$/); + assert.match(structured.zone3 ?? '', /^Name the closest landing: /); + assert.match(structured.zone3 ?? '', /, or none of these\.$/); // No legacy
markup leaks into user-visible reply. assert.doesNotMatch(structured.reply, /
{ + const structured = buildStructuredSymbolicMomentReply({ + reply: 'The 8th house is active today.', + telemetry: buildTelemetry({ + magnitude: 3.2, + directionScore: -2.3, + loadScore: 3.8, + support: 0.2, + friction: 1.4, + topDrivers: [{ label: 'Sun square Sun', orb: 0.1 }], + }), + }); + + assert.equal(structured.signalVoid, false); + assert.match(structured.zone3 ?? '', /^Name the closest landing: /); + assert.match(structured.zone3 ?? '', /\bnone of these\.$/); + assert.doesNotMatch(structured.zone3 ?? '', /\b(?:WB|ABE|OSR|Mixed|Inconclusive|Within Boundary|At Boundary Edge|Outside Symbolic Range)\b/); + assert.doesNotMatch(structured.zone3 ?? '', /\b(?:does this feel|is that where|tell me what is actually happening)\b/i); +}); + test('validateSymbolicMomentPreTestimony rejects the Core failure mode', () => { const failedRead = `The pressure lands first in The Core. The Core is carrying a brief hard-angle load around shared consequence and exchange. Sun square Sun: live day-scale friction. Tell me what is actually happening in shared load, debt, fusion, or exchange in The Core right now.`; diff --git a/vessel/src/lib/raven/fieldReportRepairFallback.ts b/vessel/src/lib/raven/fieldReportRepairFallback.ts index 56ef81b17..e4f912cff 100644 --- a/vessel/src/lib/raven/fieldReportRepairFallback.ts +++ b/vessel/src/lib/raven/fieldReportRepairFallback.ts @@ -20,10 +20,9 @@ function buildFootnoteSection(driverLabels: string[], driverList?: string): stri ? `Astrologically, the load is clustering around ${rawLabelList}. That is the named sky feeding the bind rather than a generic pressure with no source.` : ''; return [ - '
', + '**Astrological note:**', clusterLine, formattedDriverLabels.map((label) => `- ${label}`).join('\n'), - '
', ].filter(Boolean).join('\n'); } @@ -101,7 +100,7 @@ export function buildFieldReportVoiceDriftFallback( const magnitude = input.telemetry?.anchor?.magnitude ?? 0; const strengthLabel = magnitude > 3 ? 'heavy' : magnitude > 1.5 ? 'noticeable' : 'quiet'; - const leanLabel = (input.telemetry?.anchor?.directionScore ?? 0) < 0 ? 'inward' : (input.telemetry?.anchor?.directionScore ?? 0) > 0 ? 'outward' : 'mixed'; + const leanLabel = (input.telemetry?.anchor?.directionScore ?? 0) < 0 ? 'inward' : (input.telemetry?.anchor?.directionScore ?? 0) > 0 ? 'outward' : 'crossed'; const houseLabel = typeof likelyLane.houseNumber === 'number' ? `${formatOrdinalHouse(likelyLane.houseNumber)}` @@ -110,36 +109,26 @@ export function buildFieldReportVoiceDriftFallback( let voiceText = ''; if (driverLabels.length === 0) { - voiceText = 'Nothing stands out strongly right now. The day may feel active in small ways without one clear emotional or practical center.'; + voiceText = 'Nothing stands out strongly right now. The trace stays small, without one clear practical center.'; } else if (leanLabel === 'inward') { - voiceText = 'The atmosphere feels more load-bearing than fluid. Pressure gathers inward rather than spreading out, which may bring a sense of weight or contraction.'; + voiceText = 'The pressure gathers inward rather than spreading out. The contact point should stay named as placement, not as a claimed state.'; } else if (leanLabel === 'outward') { - voiceText = 'The day feels expansive but scattered. Energy presses outward, which can manifest as momentum or urgency depending on what it meets.'; + voiceText = 'The line presses outward and may open more than one route. The ground has to say where it lands.'; } else { - voiceText = 'Pressure moves in more than one direction at once. This often surfaces as mixed signals or competing demands, where neither side clearly wins.'; + voiceText = 'Pressure moves in more than one direction at once. Keep the read with the placement data until testimony separates the route.'; } - const checkText = `Does this pressure show up most clearly in ${likelyLane.verificationLabel}?`; + const checkText = `Name the first contact point: ${likelyLane.verificationLabel}; another lane; none of these.`; - const skySection = `
-The main active force right now: ${mainForce}. -
`; + const skySection = `The main active force right now: ${mainForce}.`; - const readingSection = `
-This Symbolic Moment carries a ${strengthLabel} signature and leans ${leanLabel}. -
`; + const readingSection = `This Symbolic Moment carries a ${strengthLabel} signature and leans ${leanLabel}.`; - const chamberSection = `
-The pressure lands in the ${houseLabel}${chamberLabel}. -
`; + const chamberSection = `The pressure lands in the ${houseLabel}${chamberLabel}.`; - const voiceSection = `
-${voiceText} -
`; + const voiceSection = voiceText; - const checkSection = `
-${checkText} -
`; + const checkSection = checkText; const footnoteSection = buildFootnoteSection(input.driverLabels, driverList); diff --git a/vessel/src/lib/raven/symbolicMomentComposer.ts b/vessel/src/lib/raven/symbolicMomentComposer.ts index cb5bef7bb..0d4b47eae 100644 --- a/vessel/src/lib/raven/symbolicMomentComposer.ts +++ b/vessel/src/lib/raven/symbolicMomentComposer.ts @@ -9,8 +9,8 @@ * configuration a storm. * 4. Manifestation language must stay conditional ("points toward", * "may resemble", "if it registers"). Never declarative forecast. - * 5. Weight language is load-gated. "Carrying real weight" only when - * the sealed loadScore actually justifies it. + * 5. Weight language is load-gated and image-bearing. Do not expose + * "carrying real weight" as a standalone classifier phrase. * 6. Direct and shadowed faces must be derived from the actual * planets in the cluster, not generic "disruption / clarity". * 7. If any required narrative fragment fails to resolve, the @@ -364,9 +364,9 @@ export type LoadTier = 'low' | 'moderate' | 'high' | 'very_high'; * Resolve the load tier from sealed loadScore + optional volatility. * Per Raven doctrine: storm/weight language must be earned, not default. * - low (< 1.5) → thread, hum, line — quiet day - * - moderate (1.5–2.4) → crossing, pressure line, omen + * - moderate (1.5–2.4) → crossing, active line * - high (2.5–2.9) → planet-specific noun (Wire, Pressure, Weight) - * - very_high (≥ 3.0) → planet-specific noun, "carrying real weight" + * - very_high (≥ 3.0) → planet-specific noun, image-bearing weight * phrasing eligible */ export function resolveLoadTier(loadScore?: number, volatility?: number): LoadTier { @@ -414,6 +414,8 @@ const PRE_TESTIMONY_SST_PATTERNS: ReadonlyArray<{ pattern: RegExp; label: string { pattern: /\bAt\s+Boundary\s+Edge\b/i, label: '"At Boundary Edge" classification leak' }, { pattern: /\bOutside\s+Symbolic\s+Range\b/i, label: '"Outside Symbolic Range" classification leak' }, { pattern: /\bMixed\s*\/\s*Inconclusive\b/i, label: '"Mixed / Inconclusive" classification leak' }, + { pattern: /\bMixed\b/, label: '"Mixed" classification leak' }, + { pattern: /\bInconclusive\b/, label: '"Inconclusive" classification leak' }, { pattern: /\bthis\s+confirms\s+(?:WB|ABE|OSR)\b/i, label: 'classification confirmation leak' }, ]); @@ -428,8 +430,13 @@ const MANIFESTATION_CERTAINTY_PATTERNS: ReadonlyArray<{ pattern: RegExp; label: { pattern: /\bis\s+forcing\b/i, label: '"is forcing" manifestation leak' }, { pattern: /\bis\s+producing\b/i, label: '"is producing" manifestation leak' }, { pattern: /\bis\s+making\s+simple\s+things\s+harder\b/i, label: 'manifestation overreach' }, + { pattern: /\bsimple\s+things\s+are\s+harder\b/i, label: 'manifestation overreach' }, + { pattern: /\byou\s+feel\b/i, label: '"you feel" manifestation leak' }, { pattern: /\byou\s+are\s+experiencing\b/i, label: '"you are experiencing" manifestation leak' }, + { pattern: /\byou\s+may\s+notice\b/i, label: '"you may notice" manifestation leak' }, + { pattern: /\bthis\s+will\b/i, label: '"this will" forecast leak' }, { pattern: /\bwill\s+disrupt\b/i, label: '"will disrupt" forecast leak' }, + { pattern: /\btell\s+me\s+what\s+is\s+actually\s+happening\b/i, label: 'coercive verification leak' }, ]); /** @@ -1029,7 +1036,8 @@ function composeResonanceHold(drivers: readonly ParsedDriver[], chamber: string) * - Dissolution: * "Is this landing as fog, blur, drift, or absence?" * - Carrier / DirectionlessLoad / default: - * "Does this feel direct, inverted, sideways, mixed, or absent?" + * "Name the closest landing: direct pressure, sideways displacement, + * numb workaround, or none of these." * * `drivers` and `chamber` are reserved for future placement-prompt * variants (e.g. chamber-specific room lists). They are accepted but @@ -1044,10 +1052,10 @@ function composeVerification( primarySignature === 'Amplification' || primarySignature === 'FusedExpansion' ) { - return 'Is this landing as opening, lightness, momentum, or absence?'; + return 'Name the closest landing: opening, lightness, momentum, or none of these.'; } if (primarySignature === 'Dissolution') { - return 'Is this landing as fog, blur, drift, or absence?'; + return 'Name the closest landing: fog, blur, drift, or none of these.'; } if ( primarySignature === 'Compression' @@ -1056,9 +1064,9 @@ function composeVerification( || primarySignature === 'SplitCurrent' || primarySignature === 'Ignition' ) { - return 'Is this landing as pressure, numbness, fog, ignition, misfire, or absence?'; + return 'Name the closest landing: pressure, numbness, fog, ignition, misfire, or none of these.'; } - return 'Does this feel direct, inverted, sideways, mixed, or absent?'; + return 'Name the closest landing: direct pressure, sideways displacement, numb workaround, or none of these.'; } function noteConsequence(planet: string): string { @@ -1123,9 +1131,9 @@ export function composeSymbolicMomentNarrative(input: { drivers: readonly ParsedDriver[]; primarySignature: NarrativeSignature; /** - * Sealed loadScore from the V3 math layer. Used to gate "carrying - * real weight" and storm-class title language. Required for full - * fidelity; treated as 0 when omitted (forces low-tier framing). + * Sealed loadScore from the V3 math layer. Used to gate weight + * phrasing and storm-class title language. Required for full fidelity; + * treated as 0 when omitted (forces low-tier framing). */ loadScore?: number; /** diff --git a/vessel/src/lib/raven/symbolicMomentFrontstage.ts b/vessel/src/lib/raven/symbolicMomentFrontstage.ts index 067988abe..e9af98932 100644 --- a/vessel/src/lib/raven/symbolicMomentFrontstage.ts +++ b/vessel/src/lib/raven/symbolicMomentFrontstage.ts @@ -1,6 +1,5 @@ import { createHash } from 'node:crypto'; -import { formatGeometricalScaffoldingLabel } from './geometricalScaffoldingFootnotes'; import { getChamberAnchor, getChamberByHouseNumber, @@ -571,6 +570,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]]; @@ -583,44 +597,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 { @@ -678,20 +720,6 @@ function buildSealedAudit(input: { }; } -function extractSection(reply: string, id: 'footnote' | 'verification'): string | null { - const match = reply.match(new RegExp(`
[\\s\\S]*?<\\/section>`, 'i')); - return match?.[0] ?? null; -} - -function buildFootnoteSection(drivers: readonly DriverRecord[]): string | null { - if (drivers.length === 0) return null; - return [ - '
', - drivers.slice(0, 3).map((driver) => `- ${formatGeometricalScaffoldingLabel(driver.label)}`).join('\n'), - '
', - ].join('\n'); -} - export function validateInternalSymbolicMomentStructure(text: string): boolean { const normalized = normalizeText(text); return REQUIRED_STRUCTURAL_PATTERNS.every((pattern) => pattern.test(normalized)); diff --git a/vessel/src/lib/v3MathBrain.ts b/vessel/src/lib/v3MathBrain.ts index 3c703f977..fb3509838 100644 --- a/vessel/src/lib/v3MathBrain.ts +++ b/vessel/src/lib/v3MathBrain.ts @@ -221,7 +221,7 @@ export const MAGNITUDE_EXCLUDED_ASPECTS = new Set(['semisextile', 'sesquiquadrat // Change these to recalibrate — do not bury overrides in scoring or voice paths. // // ANGULAR AMPLIFICATION is not a separate multiplier: the PLANET_TIERS weights -// for angles (ASC=1.0, MC=0.9, DSC=0.8, IC=0.7) serve as the amplifiers via +// for angles (ASC=1.5, MC=1.2, DSC=1.0, IC=0.8) serve as the amplifiers via // the Gravitational Inheritance rule in scoreAspect(). If 1.5× angular boost // is ever desired, add it here and apply in scoreAspect(), not ad hoc. // diff --git a/vessel/src/test/api-smoke.test.ts b/vessel/src/test/api-smoke.test.ts index 9e0fa8b04..837960ffb 100644 --- a/vessel/src/test/api-smoke.test.ts +++ b/vessel/src/test/api-smoke.test.ts @@ -2466,11 +2466,12 @@ test('field-report voice-drift fallback returns a real symbolic-moment read inst guidanceAllowed: false, }); - assert.match(fallback, /Today may feel heavier or more consequential than usual\./i); - assert.match(fallback, /work through resistance first/i); - assert.match(fallback, /small moments feel heavier/i); - assert.match(fallback, /
[\s\S]*Mars square Saturn[\s\S]*Moon opposition Pluto[\s\S]*<\/section>/i); - assert.match(fallback, /
[\s\S]*work or public responsibility feel heavier or more consequential/i); + assert.match(fallback, /This Symbolic Moment carries a quiet signature/i); + assert.match(fallback, /The pressure lands in the 10th house — Calling\./i); + assert.match(fallback, /Name the first contact point: work or public responsibility; another lane; none of these\./i); + assert.match(fallback, /\*\*Astrological note:\*\*[\s\S]*Mars square Saturn[\s\S]*Moon opposition Pluto/i); + assert.doesNotMatch(fallback, /
{ const quickActionsSource = readFileSync(new URL('../components/chat/CounterpartQuickActions.tsx', import.meta.url), 'utf8'); assert.match(pageSource, /Map Us · \{profile\.name\}/); + assert.match(pageSource, /Moment · \{profile\.name\}/); assert.match(quickActionsSource, /Map With \{profile\.name\}/); + assert.match(quickActionsSource, /Moment: \{profile\.name\}/); assert.doesNotMatch(pageSource, /Map \+ \{profile\.name\}/); assert.doesNotMatch(quickActionsSource, /Map Me \+ \{profile\.name\}/); });