diff --git a/vessel/package.json b/vessel/package.json index 22b00d04..9c438fcc 100644 --- a/vessel/package.json +++ b/vessel/package.json @@ -14,7 +14,7 @@ "pretest": "node sherlog-velocity/src/cli/guard-workspace.js", "test": "npm run typecheck && npm run test:smoke", "test:tts": "NODE_ENV=test tsx --tsconfig tsconfig.test.json --test src/test/tts.route.test.ts", - "test:smoke": "NODE_ENV=test tsx --tsconfig tsconfig.test.json --test src/test/api-smoke.test.ts src/test/chat-glossary.test.ts src/test/astrology-proxy.test.ts src/test/relational-legacy-repair.test.ts src/test/gemini-unified-pro.test.ts src/test/raven-context-repair.test.ts src/test/raven-turn-continuity.test.ts src/test/raven-creator-telemetry.test.ts src/test/blueprint-firewall.test.ts src/test/session-boundary-firewall.test.ts src/test/sst-osr-audit.test.ts src/test/instrument-ledger.test.ts src/app/api/raven-chat/__tests__/circumstanceDisclosure.test.ts src/app/api/raven-chat/__tests__/counterpartProvenance.test.ts src/app/api/raven-chat/__tests__/enrichmentPhase.test.ts src/app/api/raven-chat/__tests__/forecastIntent.test.ts src/app/api/raven-chat/__tests__/generationIntegrity.test.ts src/app/api/raven-chat/__tests__/intentDetection.test.ts src/app/api/raven-chat/__tests__/promptLines.test.ts src/app/api/raven-chat/__tests__/protocolRules.test.ts src/app/api/raven-chat/__tests__/recoveryMessages.test.ts src/app/api/raven-chat/__tests__/relationalPrep.test.ts src/app/api/raven-chat/__tests__/requestParsing.test.ts src/app/api/raven-chat/__tests__/sessionStateGuards.test.ts src/app/api/raven-chat/__tests__/slashCommandDispatcher.test.ts src/app/api/raven-chat/__tests__/turnContextResolver.test.ts src/app/api/raven-chat/__tests__/userBlockBuilder.test.ts src/lib/raven/__tests__/symbolicMomentVariants.test.ts", + "test:smoke": "NODE_ENV=test tsx --tsconfig tsconfig.test.json --test src/test/api-smoke.test.ts src/test/chat-glossary.test.ts src/test/astrology-proxy.test.ts src/test/relational-legacy-repair.test.ts src/test/gemini-unified-pro.test.ts src/test/raven-context-repair.test.ts src/test/raven-turn-continuity.test.ts src/test/raven-creator-telemetry.test.ts src/test/blueprint-firewall.test.ts src/test/session-boundary-firewall.test.ts src/test/sst-osr-audit.test.ts src/test/instrument-ledger.test.ts src/app/api/raven-chat/__tests__/circumstanceDisclosure.test.ts src/app/api/raven-chat/__tests__/counterpartProvenance.test.ts src/app/api/raven-chat/__tests__/enrichmentPhase.test.ts src/app/api/raven-chat/__tests__/forecastIntent.test.ts src/app/api/raven-chat/__tests__/generationIntegrity.test.ts src/app/api/raven-chat/__tests__/intentDetection.test.ts src/app/api/raven-chat/__tests__/promptLines.test.ts src/app/api/raven-chat/__tests__/protocolRules.test.ts src/app/api/raven-chat/__tests__/recoveryMessages.test.ts src/app/api/raven-chat/__tests__/relationalPrep.test.ts src/app/api/raven-chat/__tests__/requestParsing.test.ts src/app/api/raven-chat/__tests__/sessionStateGuards.test.ts src/app/api/raven-chat/__tests__/slashCommandDispatcher.test.ts src/app/api/raven-chat/__tests__/turnContextResolver.test.ts src/app/api/raven-chat/__tests__/userBlockBuilder.test.ts src/lib/raven/__tests__/symbolicMomentVariants.test.ts src/lib/raven/__tests__/readState.test.ts src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts", "librarian:index": "tsx scripts/librarian.ts", "e2e:flight-recorder": "node scripts/e2e-helpers/inspect-flight-recorder.mjs", "sherlog:init-context": "node sherlog-velocity/src/cli/init-context.js", diff --git a/vessel/sherlog-velocity/data/gap-history.jsonl b/vessel/sherlog-velocity/data/gap-history.jsonl index b71948d1..4834783a 100644 --- a/vessel/sherlog-velocity/data/gap-history.jsonl +++ b/vessel/sherlog-velocity/data/gap-history.jsonl @@ -817,3 +817,4 @@ {"version":1,"feature":"Refined Retrieval Seam Patch","feature_key":"refined-retrieval-seam-patch","timestamp":"2026-04-29T08:14:34.073Z","timestamp_epoch":1777450474,"day_epoch":1777420800,"gaps":["workspace_integrity","stale_context","architectural_limit_exceeded","complexity_hotspot","type_safety_risk","arch_monolith","hygiene_complexity_hotspot","hygiene_any_abuse"],"ranked_gaps":[{"gap":"workspace_integrity","base_weight":8,"salience_weight":8,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"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":"Black Feather Ledger","feature_key":"black-feather-ledger","timestamp":"2026-04-29T22:45:03.725Z","timestamp_epoch":1777502703,"day_epoch":1777420800,"gaps":["documentation","stale_context","architectural_limit_exceeded","complexity_hotspot","arch_monolith","hygiene_complexity_hotspot"],"ranked_gaps":[{"gap":"documentation","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":"complexity_hotspot","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_complexity_hotspot","base_weight":1,"salience_weight":1,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null}]} {"version":1,"feature":"Temporal Aperture Doctrine + Dashboard Aperture Transparency","feature_key":"temporal-aperture-doctrine-dashboard-aperture-transparency","timestamp":"2026-04-30T06:59:05.288Z","timestamp_epoch":1777532345,"day_epoch":1777507200,"gaps":["stale_context","type_safety_risk","architectural_limit_exceeded","complexity_hotspot","hygiene_any_abuse","arch_monolith","hygiene_complexity_hotspot"],"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":"type_safety_risk","base_weight":6,"salience_weight":6,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"architectural_limit_exceeded","base_weight":5,"salience_weight":5,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"complexity_hotspot","base_weight":4,"salience_weight":4,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null},{"gap":"hygiene_any_abuse","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_complexity_hotspot","base_weight":1,"salience_weight":1,"persistence_boost":0,"streak":0,"occurrences":0,"age_days":0,"last_seen":null}]} +{"version":1,"feature":"Current Task","feature_key":"current-task","timestamp":"2026-04-30T21:16:23.487Z","timestamp_epoch":1777583783,"day_epoch":1777507200,"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":10,"persistence_boost":3,"streak":5,"occurrences":8,"age_days":72,"last_seen":"2026-04-29T08:04:59.411Z"},{"gap":"architectural_limit_exceeded","base_weight":6,"salience_weight":9,"persistence_boost":3,"streak":5,"occurrences":10,"age_days":72,"last_seen":"2026-04-29T08:04:59.411Z"},{"gap":"complexity_hotspot","base_weight":5,"salience_weight":8,"persistence_boost":3,"streak":4,"occurrences":9,"age_days":72,"last_seen":"2026-04-29T08:04:59.411Z"},{"gap":"type_safety_risk","base_weight":4,"salience_weight":7,"persistence_boost":3,"streak":4,"occurrences":9,"age_days":72,"last_seen":"2026-04-29T08:04:59.411Z"},{"gap":"arch_monolith","base_weight":3,"salience_weight":6,"persistence_boost":3,"streak":5,"occurrences":10,"age_days":72,"last_seen":"2026-04-29T08:04:59.411Z"},{"gap":"hygiene_complexity_hotspot","base_weight":2,"salience_weight":5,"persistence_boost":3,"streak":4,"occurrences":9,"age_days":72,"last_seen":"2026-04-29T08:04:59.411Z"},{"gap":"hygiene_any_abuse","base_weight":1,"salience_weight":4,"persistence_boost":3,"streak":4,"occurrences":9,"age_days":72,"last_seen":"2026-04-29T08:04:59.411Z"}]} diff --git a/vessel/sherlog-velocity/data/self-model.json b/vessel/sherlog-velocity/data/self-model.json index 190431bf..3e7850d4 100644 --- a/vessel/sherlog-velocity/data/self-model.json +++ b/vessel/sherlog-velocity/data/self-model.json @@ -1,7 +1,7 @@ { "version": 1, - "generated_at": "2026-04-30T06:59:08.753Z", - "repo_root": "/Users/dancross/Dev/GitHub/Shipyard", + "generated_at": "2026-04-30T21:16:28.689Z", + "repo_root": "/home/runner/work/Shipyard/Shipyard", "source_roots": [ "vessel/src", "vessel/src/app", @@ -9,13 +9,13 @@ "vessel/src/lib/server" ], "summary": { - "total_modules": 404, - "total_edges": 954, - "fragile_file_count": 35, - "contract_anchor_count": 47, + "total_modules": 409, + "total_edges": 968, + "fragile_file_count": 19, + "contract_anchor_count": 49, "zone_coverage_pct": 100 }, - "narrative": "This codebase contains:\n- 138 lib files, 111 test files, 76 route files, 51 component files, 17 page files, 6 hook files, 5 source files\n- 954 internal dependency edges\n- 35 files with elevated fragility\n- 404 of 404 files mapped to declared zones (0 unmapped)\n- Contract anchor surfaces: intent_contract, governor_contract, repair_contract, scope_contract", + "narrative": "This codebase contains:\n- 140 lib files, 113 test files, 77 route files, 51 component files, 17 page files, 6 hook files, 5 source files\n- 968 internal dependency edges\n- 19 files with elevated fragility\n- 409 of 409 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", @@ -54,17 +54,130 @@ ], "export_count": 29, "import_count": 16, - "churn": 23, + "churn": 0, "fragility": { - "score": 7, + "score": 5, "label": "high" }, "zone": "Vessel Src Zone" }, + { + "path": "vessel/src/lib/vaultSync.ts", + "role": "lib", + "lines": 2163, + "exports": [ + "prepareForSignOut", + "resetSyncGuard", + "clearLocalVault", + "getVaultOwnerUid", + "stampVaultOwnerUid", + "buildAstroPosterForProfile", + "vaultProfileToBirthInput", + "getLocalVaultSnapshot", + "getRelationshipContextHint", + "upsertRelationshipHistoryEntry", + "applyCloudVaultToLocal", + "getLatestSavedLocation", + "getAllSavedLocations", + "rememberSavedLocation", + "loadPrimaryProfileInput", + "listVaultProfiles", + "getVaultProfileById", + "getPlannerVaultSnapshot", + "savePrimaryProfileInput", + "listPlannerReflections", + "getPlannerReflection", + "savePlannerReflection", + "listPlannerTasks", + "savePlannerTask", + "updatePlannerTaskState", + "upsertVaultProfile", + "deleteVaultProfile", + "setProfileCurrentLocation", + "promoteBirthLocationAsCurrent", + "getVaultPosterByProfileId", + "getBlueprintPosterRegenerationNotice", + "isBlueprintSparse", + "generatePosterForProfile", + "ensureVaultPosterForProfile", + "appendRuntimeEvents", + "scheduleBackgroundVaultSync", + "syncVaultNow", + "recoverVaultFromCloud", + "getConstitutionalCalibrations", + "upsertConstitutionalCalibration", + "KEYS", + "VAULT_SYNC_EVENT", + "StagingRole", + "DataProvenance", + "LivingStatus", + "BirthProfileInput", + "ProfileCurrentLocation", + "PlannerReflectionFit", + "PlannerReflection", + "PlannerTaskCategory", + "PlannerTaskState", + "PlannerTaskBlock", + "VaultProfile", + "VaultPoster", + "RuntimeSystemEvent", + "PlannerVaultSnapshot", + "SavedLocation", + "RelationshipParticipant", + "RelationshipHistoryEntry" + ], + "export_count": 59, + "import_count": 9, + "churn": 0, + "fragility": { + "score": 4, + "label": "medium" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/raven/constellationVault.ts", + "role": "lib", + "lines": 806, + "exports": [ + "getConstellationEntries", + "upsertConstellationEntry", + "removeConstellationEntry", + "buildWrapUpArtifacts", + "convertPoeticIndexCardToArtifact", + "storePoeticIndexCard", + "captureSingleMessageArtifacts", + "CONSTELLATION_VAULT_EVENT", + "SessionSummaryArtifact", + "InsightCardArtifact", + "SymbolLogic", + "LoadQuality", + "ForceTempo", + "ForceReading", + "SystemLoad", + "EngineSnapshot", + "VisibleLayer", + "DataLayer", + "PoeticIndexCardArtifact", + "CapturedArtifacts", + "ConstellationArtifact", + "ConstellationEntry", + "SessionMessageForConstellation", + "SessionStateForConstellation" + ], + "export_count": 24, + "import_count": 4, + "churn": 0, + "fragility": { + "score": 4, + "label": "medium" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", "role": "lib", - "lines": 1297, + "lines": 1371, "exports": [ "validateInternalSymbolicMomentStructure", "validateSymbolicMomentPreTestimony", @@ -90,11 +203,11 @@ "StructuredSymbolicMomentResult" ], "export_count": 22, - "import_count": 5, - "churn": 42, + "import_count": 6, + "churn": 0, "fragility": { - "score": 6, - "label": "high" + "score": 4, + "label": "medium" }, "zone": "Vessel Src Lib Zone" }, @@ -171,10 +284,102 @@ ], "export_count": 65, "import_count": 8, - "churn": 20, + "churn": 0, "fragility": { - "score": 6, - "label": "high" + "score": 4, + "label": "medium" + }, + "zone": "Vessel Src App Zone" + }, + { + "path": "vessel/src/app/api/raven-chat/llmProvider.ts", + "role": "route", + "lines": 902, + "exports": [ + "isThinkingModel", + "resolveGeminiEndpoint", + "geminiChatFetch", + "estimateLlmTokens", + "estimateLlmInputTokens", + "sleep", + "resetLimiterWindowIfNeeded", + "reserveLlmPermit", + "markLlmBackpressure", + "clearLlmBackpressure", + "callLLM", + "callLLMStream", + "hasConfiguredLlmKey", + "LLM_WINDOW_MS", + "LLM_RPM_LIMIT", + "LLM_TPM_LIMIT", + "LLM_MAX_INFLIGHT", + "LLM_FAILOVER_JITTER_MIN_MS", + "LLM_FAILOVER_JITTER_MAX_MS", + "MIN_EMERGENCY_OUTPUT_TOKENS", + "GEMINI_THINKING_OVERHEAD_TOKENS", + "llmLimiterState", + "GeminiEndpoint" + ], + "export_count": 23, + "import_count": 8, + "churn": 0, + "fragility": { + "score": 4, + "label": "medium" + }, + "zone": "Vessel Src App Zone" + }, + { + "path": "vessel/src/app/api/raven-chat/requestParsing.ts", + "role": "route", + "lines": 824, + "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": 0, + "fragility": { + "score": 4, + "label": "medium" }, "zone": "Vessel Src App Zone" }, @@ -231,10 +436,10 @@ ], "export_count": 45, "import_count": 11, - "churn": 20, + "churn": 0, "fragility": { - "score": 6, - "label": "high" + "score": 4, + "label": "medium" }, "zone": "Vessel Src App Zone" }, @@ -256,17 +461,17 @@ ], "export_count": 10, "import_count": 37, - "churn": 30, + "churn": 0, "fragility": { - "score": 5, - "label": "high" + "score": 3, + "label": "medium" }, "zone": "Vessel Src Zone" }, { "path": "vessel/src/lib/v3MathBrain.ts", "role": "lib", - "lines": 1213, + "lines": 1254, "exports": [ "buildV3MathTelemetry", "toV3MathPromptContext", @@ -284,193 +489,17 @@ ], "export_count": 13, "import_count": 0, - "churn": 16, + "churn": 0, "fragility": { - "score": 5, - "label": "high" + "score": 3, + "label": "medium" }, "zone": "Vessel Src Lib Zone" }, { - "path": "vessel/src/lib/raven/symbolicMomentComposer.ts", + "path": "vessel/src/lib/raven/doctrineManifest.ts", "role": "lib", - "lines": 1769, - "exports": [ - "resolveLoadTier", - "buildSymbolicMomentPayload", - "composeSymbolicMomentNarrative", - "sanitizeUserFacingNarrative", - "composeNamedStormNarrative", - "AspectType", - "ParsedDriver", - "NarrativeSignature", - "LunarContext", - "LocationContext", - "SymbolicMomentNarrative", - "LoadTier", - "NamedStormNarrative", - "SymbolicMomentPayload" - ], - "export_count": 14, - "import_count": 3, - "churn": 14, - "fragility": { - "score": 5, - "label": "high" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/app/page.tsx", - "role": "page", - "lines": 5709, - "exports": [ - "App" - ], - "export_count": 1, - "import_count": 44, - "churn": 35, - "fragility": { - "score": 5, - "label": "high" - }, - "zone": "Vessel Src App Zone" - }, - { - "path": "vessel/src/app/api/raven-chat/route.ts", - "role": "route", - "lines": 2831, - "exports": [ - "POST", - "maxDuration", - "dynamic" - ], - "export_count": 3, - "import_count": 69, - "churn": 80, - "fragility": { - "score": 5, - "label": "high" - }, - "zone": "Vessel Src App Zone" - }, - { - "path": "vessel/src/lib/vaultSync.ts", - "role": "lib", - "lines": 2163, - "exports": [ - "prepareForSignOut", - "resetSyncGuard", - "clearLocalVault", - "getVaultOwnerUid", - "stampVaultOwnerUid", - "buildAstroPosterForProfile", - "vaultProfileToBirthInput", - "getLocalVaultSnapshot", - "getRelationshipContextHint", - "upsertRelationshipHistoryEntry", - "applyCloudVaultToLocal", - "getLatestSavedLocation", - "getAllSavedLocations", - "rememberSavedLocation", - "loadPrimaryProfileInput", - "listVaultProfiles", - "getVaultProfileById", - "getPlannerVaultSnapshot", - "savePrimaryProfileInput", - "listPlannerReflections", - "getPlannerReflection", - "savePlannerReflection", - "listPlannerTasks", - "savePlannerTask", - "updatePlannerTaskState", - "upsertVaultProfile", - "deleteVaultProfile", - "setProfileCurrentLocation", - "promoteBirthLocationAsCurrent", - "getVaultPosterByProfileId", - "getBlueprintPosterRegenerationNotice", - "isBlueprintSparse", - "generatePosterForProfile", - "ensureVaultPosterForProfile", - "appendRuntimeEvents", - "scheduleBackgroundVaultSync", - "syncVaultNow", - "recoverVaultFromCloud", - "getConstitutionalCalibrations", - "upsertConstitutionalCalibration", - "KEYS", - "VAULT_SYNC_EVENT", - "StagingRole", - "DataProvenance", - "LivingStatus", - "BirthProfileInput", - "ProfileCurrentLocation", - "PlannerReflectionFit", - "PlannerReflection", - "PlannerTaskCategory", - "PlannerTaskState", - "PlannerTaskBlock", - "VaultProfile", - "VaultPoster", - "RuntimeSystemEvent", - "PlannerVaultSnapshot", - "SavedLocation", - "RelationshipParticipant", - "RelationshipHistoryEntry" - ], - "export_count": 59, - "import_count": 9, - "churn": 5, - "fragility": { - "score": 4, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/raven/constellationVault.ts", - "role": "lib", - "lines": 806, - "exports": [ - "getConstellationEntries", - "upsertConstellationEntry", - "removeConstellationEntry", - "buildWrapUpArtifacts", - "convertPoeticIndexCardToArtifact", - "storePoeticIndexCard", - "captureSingleMessageArtifacts", - "CONSTELLATION_VAULT_EVENT", - "SessionSummaryArtifact", - "InsightCardArtifact", - "SymbolLogic", - "LoadQuality", - "ForceTempo", - "ForceReading", - "SystemLoad", - "EngineSnapshot", - "VisibleLayer", - "DataLayer", - "PoeticIndexCardArtifact", - "CapturedArtifacts", - "ConstellationArtifact", - "ConstellationEntry", - "SessionMessageForConstellation", - "SessionStateForConstellation" - ], - "export_count": 24, - "import_count": 4, - "churn": 4, - "fragility": { - "score": 4, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/raven/doctrineManifest.ts", - "role": "lib", - "lines": 1055, + "lines": 1098, "exports": [ "getDoctrineManifestEntryBySourceFile", "getDoctrineManifestEntriesByBundle", @@ -494,9 +523,9 @@ ], "export_count": 19, "import_count": 1, - "churn": 8, + "churn": 0, "fragility": { - "score": 4, + "score": 3, "label": "medium" }, "zone": "Vessel Src Lib Zone" @@ -543,42 +572,42 @@ ], "export_count": 34, "import_count": 0, - "churn": 7, + "churn": 0, "fragility": { - "score": 4, + "score": 3, "label": "medium" }, "zone": "Vessel Src Lib Zone" }, { - "path": "vessel/src/lib/raven/persona-law.ts", + "path": "vessel/src/lib/raven/protocolEngine.ts", "role": "lib", - "lines": 482, + "lines": 1426, "exports": [ - "buildKernelPrompt", - "RAVEN_IDENTITY", - "CONSTITUTIONAL_AXIOMS", - "SIGNAL_PATH", - "VOICE_KERNEL", - "GROUNDING_AND_COMPRESSION_PROTOCOL", - "CONVERSATIONAL_PRINCIPLE", - "UX_CONSTITUTION", - "RESONANT_FIELD_DOCTRINE", - "SOVEREIGNTY_LAW", - "SOVEREIGNTY_VALIDATION", - "LANGUAGE_GOVERNOR", - "PATTERN_SURFACE_GOVERNOR", - "MIRROR_FLOW_TIERS", - "RAVEN_INSTRUMENT_RESPONSE_LAW", - "MAP_FIRST_SEQUENCING_LAW", - "EPISTEMIC_BRIDGE_AND_CITATION_LAW", - "EPISTEMIC_INTEGRITY_LAW" + "shouldUnlockInDepth", + "validateFrontstagePatternTitle", + "passesFrontstageValidation", + "detectSignals", + "resolveProtocolInjectionBudget", + "applyInjectionTokenBudget", + "injectProtocols", + "formatRetrievedDoctrineContext", + "formatInjectionForPrompt", + "TIER_CONTENT_POLICY", + "OutputDepthTier", + "FrontstagePatternValidation", + "DetectedSignal", + "ProtocolInjectionBudget", + "InjectionResult", + "RetrievedDoctrineSnippet", + "DoctrineAuthorityLabel", + "InjectionContext" ], "export_count": 18, - "import_count": 0, - "churn": 13, + "import_count": 5, + "churn": 0, "fragility": { - "score": 4, + "score": 3, "label": "medium" }, "zone": "Vessel Src Lib Zone" @@ -609,9 +638,38 @@ ], "export_count": 18, "import_count": 7, - "churn": 10, + "churn": 0, "fragility": { - "score": 4, + "score": 3, + "label": "medium" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/raven/symbolicMomentComposer.ts", + "role": "lib", + "lines": 1779, + "exports": [ + "resolveLoadTier", + "buildSymbolicMomentPayload", + "composeSymbolicMomentNarrative", + "sanitizeUserFacingNarrative", + "composeNamedStormNarrative", + "AspectType", + "ParsedDriver", + "NarrativeSignature", + "LunarContext", + "LocationContext", + "SymbolicMomentNarrative", + "LoadTier", + "NamedStormNarrative", + "SymbolicMomentPayload" + ], + "export_count": 14, + "import_count": 4, + "churn": 0, + "fragility": { + "score": 3, "label": "medium" }, "zone": "Vessel Src Lib Zone" @@ -665,393 +723,68 @@ "BirthTimeAuditEntry", "BirthTimeRecord" ], - "export_count": 43, - "import_count": 2, - "churn": 8, - "fragility": { - "score": 4, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/raven/__tests__/responseRenderer.test.ts", - "role": "test", - "lines": 814, - "export_count": 0, - "import_count": 1, - "churn": 16, - "fragility": { - "score": 4, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/components/AlignmentCorridor.tsx", - "role": "component", - "lines": 1581, - "exports": [ - "AlignmentCorridor", - "CorridorSynastryAspect", - "CorridorTransitDriverSet", - "CorridorTransitDrivers", - "RelationalFallbackNotice", - "OracleBalanceTagPayload", - "SubjectContext", - "SessionSignatureData" - ], - "export_count": 8, - "import_count": 5, - "churn": 14, - "fragility": { - "score": 4, - "label": "medium" - }, - "zone": "Vessel Src Zone" - }, - { - "path": "vessel/src/app/api/raven-chat/llmProvider.ts", - "role": "route", - "lines": 902, - "exports": [ - "isThinkingModel", - "resolveGeminiEndpoint", - "geminiChatFetch", - "estimateLlmTokens", - "estimateLlmInputTokens", - "sleep", - "resetLimiterWindowIfNeeded", - "reserveLlmPermit", - "markLlmBackpressure", - "clearLlmBackpressure", - "callLLM", - "callLLMStream", - "hasConfiguredLlmKey", - "LLM_WINDOW_MS", - "LLM_RPM_LIMIT", - "LLM_TPM_LIMIT", - "LLM_MAX_INFLIGHT", - "LLM_FAILOVER_JITTER_MIN_MS", - "LLM_FAILOVER_JITTER_MAX_MS", - "MIN_EMERGENCY_OUTPUT_TOKENS", - "GEMINI_THINKING_OVERHEAD_TOKENS", - "llmLimiterState", - "GeminiEndpoint" - ], - "export_count": 23, - "import_count": 8, - "churn": 5, - "fragility": { - "score": 4, - "label": "medium" - }, - "zone": "Vessel Src App Zone" - }, - { - "path": "vessel/src/app/api/raven-chat/requestParsing.ts", - "role": "route", - "lines": 824, - "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": 4, - "label": "medium" - }, - "zone": "Vessel Src App Zone" - }, - { - "path": "vessel/src/lib/wovenReportCore.ts", - "role": "lib", - "lines": 4637, - "exports": [ - "parseRetryAfterHeaderMs", - "deriveCognitiveArchitectureFromNatal", - "runTwoClockDriftModules", - "runSoloMirrorReport", - "runSoloBalanceMeterReport", - "runRelationalMirrorReport", - "runPolyadicMirrorReport", - "runRelationalBalanceMeterReport" - ], - "export_count": 8, - "import_count": 7, - "churn": 11, - "fragility": { - "score": 3, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/raven/fieldReportVoiceContract.ts", - "role": "lib", - "lines": 442, - "exports": [ - "findFieldReportVoiceContractViolations", - "hasFieldReportVoiceContractDrift", - "validateSymbolicImage" - ], - "export_count": 3, - "import_count": 0, - "churn": 17, - "fragility": { - "score": 3, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/raven/protocolEngine.ts", - "role": "lib", - "lines": 1426, - "exports": [ - "shouldUnlockInDepth", - "validateFrontstagePatternTitle", - "passesFrontstageValidation", - "detectSignals", - "resolveProtocolInjectionBudget", - "applyInjectionTokenBudget", - "injectProtocols", - "formatRetrievedDoctrineContext", - "formatInjectionForPrompt", - "TIER_CONTENT_POLICY", - "OutputDepthTier", - "FrontstagePatternValidation", - "DetectedSignal", - "ProtocolInjectionBudget", - "InjectionResult", - "RetrievedDoctrineSnippet", - "DoctrineAuthorityLabel", - "InjectionContext" - ], - "export_count": 18, - "import_count": 5, - "churn": 6, - "fragility": { - "score": 3, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/raven/sessionMachine.ts", - "role": "lib", - "lines": 751, - "exports": [ - "createSession", - "sessionReducer", - "getRecommendedPhase", - "checkGate", - "maybeAdvancePhase", - "detectResonance", - "detectCalibrationConfirmations", - "buildSessionContext", - "sealSession", - "REJECTED_READING_DIGEST_CAP", - "DISCUSSED_DRIVER_CAP", - "ASSISTANT_RENDER_HASH_CAP" - ], - "export_count": 12, - "import_count": 2, - "churn": 9, - "fragility": { - "score": 3, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/raven/__tests__/symbolicMomentComposer.test.ts", - "role": "test", - "lines": 427, - "export_count": 0, - "import_count": 1, - "churn": 14, - "fragility": { - "score": 3, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts", - "role": "test", - "lines": 460, - "export_count": 0, - "import_count": 2, - "churn": 32, - "fragility": { - "score": 3, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/black-feather/bflEngine.ts", - "role": "lib", - "lines": 504, - "exports": [ - "reduceToRange", - "computeBalanceMeter", - "canonicalJson", - "computeLockHash", - "computeBaselineSeed", - "generateLedger", - "SIGN_INDEX", - "SIGNS", - "PLANETS", - "PLANETARY_WEIGHTS", - "ASPECT_WEIGHTS", - "MAX_ORBS", - "ASPECT_NAMES", - "SOURCE_EXACTNESS", - "CANDIDATE_W", - "DEFAULT_ROUTE_CYCLE", - "ROUTE_CYCLE_VERSION", - "PUBLIC_BASELINE_SALT", - "RouteTag", - "DrawConfig", - "BalanceMeter", - "DreamWitness", - "Candidate", - "Panel", - "LockObject", - "LedgerEntry", - "EphemerisResult", - "GenerateOptions" - ], - "export_count": 28, - "import_count": 1, - "churn": 2, - "fragility": { - "score": 3, - "label": "medium" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/components/ProfileVault.tsx", - "role": "component", - "lines": 2755, - "exports": [ - "ProfileVault" - ], - "export_count": 1, - "import_count": 8, - "churn": 10, - "fragility": { - "score": 3, - "label": "medium" - }, - "zone": "Vessel Src Zone" - }, - { - "path": "vessel/src/components/chat/BalanceMeterPill.tsx", - "role": "component", - "lines": 510, - "exports": [ - "BalanceMeterPill" - ], - "export_count": 1, - "import_count": 4, - "churn": 13, - "fragility": { - "score": 3, - "label": "medium" - }, - "zone": "Vessel Src Zone" - }, - { - "path": "vessel/src/components/chat/DownloadSessionButton.tsx", - "role": "component", - "lines": 1578, - "exports": [ - "buildSessionDebugExportPayload", - "buildSessionPipelineDebugExportPayload", - "buildSessionExportPayload", - "DownloadSessionButton" - ], - "export_count": 4, + "export_count": 43, "import_count": 2, - "churn": 9, + "churn": 0, "fragility": { "score": 3, "label": "medium" }, - "zone": "Vessel Src Zone" + "zone": "Vessel Src Lib Zone" }, { - "path": "vessel/src/components/chat/SessionFlightRecorder.tsx", - "role": "component", - "lines": 1593, + "path": "vessel/src/lib/black-feather/bflEngine.ts", + "role": "lib", + "lines": 504, "exports": [ - "describeRuntimeEvent", - "SessionFlightRecorder", - "FlightRecorderArchiveRun" + "reduceToRange", + "computeBalanceMeter", + "canonicalJson", + "computeLockHash", + "computeBaselineSeed", + "generateLedger", + "SIGN_INDEX", + "SIGNS", + "PLANETS", + "PLANETARY_WEIGHTS", + "ASPECT_WEIGHTS", + "MAX_ORBS", + "ASPECT_NAMES", + "SOURCE_EXACTNESS", + "CANDIDATE_W", + "DEFAULT_ROUTE_CYCLE", + "ROUTE_CYCLE_VERSION", + "PUBLIC_BASELINE_SALT", + "RouteTag", + "DrawConfig", + "BalanceMeter", + "DreamWitness", + "Candidate", + "Panel", + "LockObject", + "LedgerEntry", + "EphemerisResult", + "GenerateOptions" ], - "export_count": 3, - "import_count": 8, - "churn": 11, + "export_count": 28, + "import_count": 1, + "churn": 0, "fragility": { "score": 3, "label": "medium" }, - "zone": "Vessel Src Zone" + "zone": "Vessel Src Lib Zone" }, { - "path": "vessel/src/app/api/raven-chat/enrichmentPhase.ts", - "role": "route", - "lines": 364, + "path": "vessel/src/app/page.tsx", + "role": "page", + "lines": 5709, "exports": [ - "runEnrichmentPhase", - "EnrichmentResult" + "App" ], - "export_count": 2, - "import_count": 19, - "churn": 13, + "export_count": 1, + "import_count": 44, + "churn": 0, "fragility": { "score": 3, "label": "medium" @@ -1059,69 +792,17 @@ "zone": "Vessel Src App Zone" }, { - "path": "vessel/src/app/api/raven-chat/promptLines.ts", + "path": "vessel/src/app/api/raven-chat/route.ts", "role": "route", - "lines": 436, + "lines": 2882, "exports": [ - "buildPromptLines", - "PromptLinesConfig", - "PromptLinesResult" + "POST", + "maxDuration", + "dynamic" ], "export_count": 3, - "import_count": 6, - "churn": 46, - "fragility": { - "score": 3, - "label": "medium" - }, - "zone": "Vessel Src App Zone" - }, - { - "path": "vessel/src/app/api/raven-chat/protocolRules.ts", - "role": "route", - "lines": 517, - "exports": [ - "detectCalibrationReAsk", - "needsProtocolRepair", - "buildRepairDirective", - "classifyLlmFailure", - "buildExpectedBlock", - "buildLlmFallbackReply", - "buildSymbolicMomentsUnavailableReply", - "buildDailyLimitReply", - "buildCognitiveStructureStatusReply", - "buildSealClosureReply", - "sanitizeRelationalMappingError", - "formatRelationalFallbackEndpointLabel", - "formatRetryWindowLabel", - "buildRelationalFallbackSnapshot", - "buildRelationalFallbackSnapshotFromReport", - "applyRelationalFallbackLead", - "needsConcreteRetry", - "parseLabeledMetric", - "getTelemetryRangeViolations", - "hasUnverifiedLiveLocationClaim" - ], - "export_count": 20, - "import_count": 14, - "churn": 11, - "fragility": { - "score": 3, - "label": "medium" - }, - "zone": "Vessel Src App Zone" - }, - { - "path": "vessel/src/app/api/raven-chat/userBlockBuilder.ts", - "role": "route", - "lines": 440, - "exports": [ - "buildUserBlocks", - "UserBlocksConfig" - ], - "export_count": 2, - "import_count": 14, - "churn": 18, + "import_count": 70, + "churn": 0, "fragility": { "score": 3, "label": "medium" @@ -1227,6 +908,29 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/wovenReportCore.ts", + "role": "lib", + "lines": 4637, + "exports": [ + "parseRetryAfterHeaderMs", + "deriveCognitiveArchitectureFromNatal", + "runTwoClockDriftModules", + "runSoloMirrorReport", + "runSoloBalanceMeterReport", + "runRelationalMirrorReport", + "runPolyadicMirrorReport", + "runRelationalBalanceMeterReport" + ], + "export_count": 8, + "import_count": 7, + "churn": 0, + "fragility": { + "score": 2, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/adviceLadderRuntime.ts", "role": "lib", @@ -1259,7 +963,7 @@ { "path": "vessel/src/lib/raven/affirmativeDomain.ts", "role": "lib", - "lines": 244, + "lines": 252, "exports": [ "getActiveOperations", "AUTHORITY_DOMAINS", @@ -1303,8 +1007,8 @@ "LeanWovenMapEnvelope" ], "export_count": 40, - "import_count": 0, - "churn": 5, + "import_count": 1, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -1314,7 +1018,7 @@ { "path": "vessel/src/lib/raven/affirmativeRuntime.ts", "role": "lib", - "lines": 542, + "lines": 563, "exports": [ "executeModule", "transitionGovernor", @@ -1330,7 +1034,7 @@ ], "export_count": 11, "import_count": 1, - "churn": 4, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -1370,15 +1074,32 @@ "zone": "Vessel Src Lib Zone" }, { - "path": "vessel/src/lib/raven/fieldReportRepairFallback.ts", + "path": "vessel/src/lib/raven/persona-law.ts", "role": "lib", - "lines": 247, + "lines": 482, "exports": [ - "buildFieldReportVoiceDriftFallback" + "buildKernelPrompt", + "RAVEN_IDENTITY", + "CONSTITUTIONAL_AXIOMS", + "SIGNAL_PATH", + "VOICE_KERNEL", + "GROUNDING_AND_COMPRESSION_PROTOCOL", + "CONVERSATIONAL_PRINCIPLE", + "UX_CONSTITUTION", + "RESONANT_FIELD_DOCTRINE", + "SOVEREIGNTY_LAW", + "SOVEREIGNTY_VALIDATION", + "LANGUAGE_GOVERNOR", + "PATTERN_SURFACE_GOVERNOR", + "MIRROR_FLOW_TIERS", + "RAVEN_INSTRUMENT_RESPONSE_LAW", + "MAP_FIRST_SEQUENCING_LAW", + "EPISTEMIC_BRIDGE_AND_CITATION_LAW", + "EPISTEMIC_INTEGRITY_LAW" ], - "export_count": 1, - "import_count": 3, - "churn": 18, + "export_count": 18, + "import_count": 0, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -1386,33 +1107,26 @@ "zone": "Vessel Src Lib Zone" }, { - "path": "vessel/src/lib/raven/localLexicon.ts", + "path": "vessel/src/lib/raven/sessionMachine.ts", "role": "lib", - "lines": 299, + "lines": 751, "exports": [ - "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" + "createSession", + "sessionReducer", + "getRecommendedPhase", + "checkGate", + "maybeAdvancePhase", + "detectResonance", + "detectCalibrationConfirmations", + "buildSessionContext", + "sealSession", + "REJECTED_READING_DIGEST_CAP", + "DISCUSSED_DRIVER_CAP", + "ASSISTANT_RENDER_HASH_CAP" ], - "export_count": 19, - "import_count": 0, - "churn": 8, + "export_count": 12, + "import_count": 2, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -1429,51 +1143,26 @@ "pickVariant", "computeSymbolicMomentSeed", "getVoiceVariants", - "getSilhouetteVariants", - "getLandingVariants", - "getVerificationVariants", - "listAllPressureSignatures", - "selectVoiceVariant", - "selectSilhouetteVariant", - "selectLandingVariant", - "selectVerificationVariant", - "assertCoreVariantSafe", - "PressureSignature", - "SymbolicMomentBuilder", - "SymbolicMomentSeedInput", - "SelectVoiceArgs", - "SelectSilhouetteArgs", - "SelectLandingArgs", - "SelectVerificationArgs" - ], - "export_count": 21, - "import_count": 1, - "churn": 6, - "fragility": { - "score": 2, - "label": "low" - }, - "zone": "Vessel Src Lib Zone" - }, - { - "path": "vessel/src/lib/raven/turnContinuity.ts", - "role": "lib", - "lines": 408, - "exports": [ - "buildCommittedMapPromptBlock", - "classifyTurnContinuityType", - "buildTurnContinuityPayload", - "buildTurnContinuityPromptBlock", - "TurnContinuityHistoryEntry", - "TurnContinuityType", - "TurnContinuityUserMove", - "TurnContinuityEmpathyMode", - "TurnContinuityAcknowledgmentPriority", - "TurnContinuityPayload" + "getSilhouetteVariants", + "getLandingVariants", + "getVerificationVariants", + "listAllPressureSignatures", + "selectVoiceVariant", + "selectSilhouetteVariant", + "selectLandingVariant", + "selectVerificationVariant", + "assertCoreVariantSafe", + "PressureSignature", + "SymbolicMomentBuilder", + "SymbolicMomentSeedInput", + "SelectVoiceArgs", + "SelectSilhouetteArgs", + "SelectLandingArgs", + "SelectVerificationArgs" ], - "export_count": 10, - "import_count": 2, - "churn": 8, + "export_count": 21, + "import_count": 1, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -1545,6 +1234,19 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/raven/__tests__/responseRenderer.test.ts", + "role": "test", + "lines": 814, + "export_count": 0, + "import_count": 1, + "churn": 0, + "fragility": { + "score": 2, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/blueprint/blueprintBuilder.ts", "role": "lib", @@ -1565,15 +1267,22 @@ "zone": "Vessel Src Lib Zone" }, { - "path": "vessel/src/components/shipyard/VelocityPanel.tsx", + "path": "vessel/src/components/AlignmentCorridor.tsx", "role": "component", - "lines": 875, + "lines": 1553, "exports": [ - "VelocityPanel" + "AlignmentCorridor", + "CorridorSynastryAspect", + "CorridorTransitDriverSet", + "CorridorTransitDrivers", + "RelationalFallbackNotice", + "OracleBalanceTagPayload", + "SubjectContext", + "SessionSignatureData" ], - "export_count": 1, - "import_count": 0, - "churn": 2, + "export_count": 8, + "import_count": 6, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -1581,15 +1290,15 @@ "zone": "Vessel Src Zone" }, { - "path": "vessel/src/components/reports/StructuralLoadScatter.tsx", + "path": "vessel/src/components/ProfileVault.tsx", "role": "component", - "lines": 525, + "lines": 2755, "exports": [ - "StructuralLoadScatter" + "ProfileVault" ], "export_count": 1, - "import_count": 1, - "churn": 12, + "import_count": 8, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -1597,15 +1306,15 @@ "zone": "Vessel Src Zone" }, { - "path": "vessel/src/components/reports/WovenMapTab.tsx", + "path": "vessel/src/components/shipyard/VelocityPanel.tsx", "role": "component", - "lines": 433, + "lines": 1012, "exports": [ - "WovenMapTab" + "VelocityPanel" ], "export_count": 1, - "import_count": 1, - "churn": 8, + "import_count": 0, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -1613,16 +1322,18 @@ "zone": "Vessel Src Zone" }, { - "path": "vessel/src/components/chat/ChatInput.tsx", + "path": "vessel/src/components/chat/DownloadSessionButton.tsx", "role": "component", - "lines": 699, + "lines": 1578, "exports": [ - "ChatInput", - "ChatInputHandle" + "buildSessionDebugExportPayload", + "buildSessionPipelineDebugExportPayload", + "buildSessionExportPayload", + "DownloadSessionButton" ], - "export_count": 2, - "import_count": 3, - "churn": 9, + "export_count": 4, + "import_count": 2, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -1630,12 +1341,17 @@ "zone": "Vessel Src Zone" }, { - "path": "vessel/src/components/chat/__tests__/DownloadSessionButton.test.ts", - "role": "test", - "lines": 538, - "export_count": 0, - "import_count": 3, - "churn": 7, + "path": "vessel/src/components/chat/SessionFlightRecorder.tsx", + "role": "component", + "lines": 1593, + "exports": [ + "describeRuntimeEvent", + "SessionFlightRecorder", + "FlightRecorderArchiveRun" + ], + "export_count": 3, + "import_count": 8, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -1645,14 +1361,14 @@ { "path": "vessel/src/app/planner/page.tsx", "role": "page", - "lines": 1366, + "lines": 1363, "exports": [ "dynamic", "PlannerPage" ], "export_count": 2, "import_count": 5, - "churn": 3, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -1694,13 +1410,14 @@ { "path": "vessel/src/app/api/raven-chat/astrologyApi.ts", "role": "route", - "lines": 487, + "lines": 575, "exports": [ "fetchWithTimeout", "raceWithBudget", "firstAddressText", "resolveLiveLocation", "fetchAstrologyContext", + "fetchNowPulseContext", "fetchPulseOverlay", "resolveRelocationAnchor", "resolveBirthLocationAnchor", @@ -1712,7 +1429,7 @@ "UPSTREAM_BUDGET_MS", "PULSE_CACHE_TTL_MS" ], - "export_count": 15, + "export_count": 16, "import_count": 9, "churn": 0, "fragility": { @@ -1722,26 +1439,34 @@ "zone": "Vessel Src App Zone" }, { - "path": "vessel/src/app/api/raven-chat/sherlogTelemetry.ts", + "path": "vessel/src/app/api/raven-chat/protocolRules.ts", "role": "route", - "lines": 221, + "lines": 517, "exports": [ - "parseSherlogSummaryText", - "formatCreatorMirrorVelocityStatus", - "formatCreatorMirrorRepair", - "readLatestSherlogTelemetryFromRunsRoot", - "readLatestSherlogTelemetry", - "buildOfflineCreatorMirrorTelemetry", - "resolvePrimaryCreatorOperatorLabel", - "isCreatorMirrorAuthorized", - "isCreatorModeTriggerMessage", - "isCreatorAstrologyV3OptInMessage", - "PRIMARY_CREATOR_EMAIL", - "PRIMARY_CREATOR_LABEL" + "detectCalibrationReAsk", + "needsProtocolRepair", + "buildRepairDirective", + "classifyLlmFailure", + "buildExpectedBlock", + "buildLlmFallbackReply", + "buildSymbolicMomentsUnavailableReply", + "buildDailyLimitReply", + "buildCognitiveStructureStatusReply", + "buildSealClosureReply", + "sanitizeRelationalMappingError", + "formatRelationalFallbackEndpointLabel", + "formatRetryWindowLabel", + "buildRelationalFallbackSnapshot", + "buildRelationalFallbackSnapshotFromReport", + "applyRelationalFallbackLead", + "needsConcreteRetry", + "parseLabeledMetric", + "getTelemetryRangeViolations", + "hasUnverifiedLiveLocationClaim" ], - "export_count": 12, - "import_count": 5, - "churn": 9, + "export_count": 20, + "import_count": 14, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -1781,7 +1506,7 @@ ], "export_count": 25, "import_count": 7, - "churn": 3, + "churn": 0, "fragility": { "score": 2, "label": "low" @@ -1820,32 +1545,13 @@ "lines": 562, "export_count": 0, "import_count": 4, - "churn": 4, + "churn": 0, "fragility": { "score": 1, "label": "low" }, "zone": "Vessel Src Zone" }, - { - "path": "vessel/src/lib/chatGlossary.ts", - "role": "lib", - "lines": 247, - "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", @@ -1858,25 +1564,7 @@ ], "export_count": 4, "import_count": 1, - "churn": 4, - "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, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -1894,7 +1582,7 @@ ], "export_count": 3, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -1924,25 +1612,6 @@ }, "zone": "Vessel Src Lib Zone" }, - { - "path": "vessel/src/lib/stripe.ts", - "role": "lib", - "lines": 42, - "exports": [ - "getStripe", - "STRIPE_ENABLED", - "STRIPE_PRO_PRICE_ID", - "STRIPE_WEBHOOK_SECRET" - ], - "export_count": 4, - "import_count": 0, - "churn": 8, - "fragility": { - "score": 1, - "label": "low" - }, - "zone": "Vessel Src Lib Zone" - }, { "path": "vessel/src/lib/raven/authorityLampRouter.ts", "role": "lib", @@ -2010,6 +1679,24 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/raven/fieldReportVoiceContract.ts", + "role": "lib", + "lines": 442, + "exports": [ + "findFieldReportVoiceContractViolations", + "hasFieldReportVoiceContractDrift", + "validateSymbolicImage" + ], + "export_count": 3, + "import_count": 0, + "churn": 0, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/geminiModelSelection.ts", "role": "lib", @@ -2041,6 +1728,40 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/raven/localLexicon.ts", + "role": "lib", + "lines": 299, + "exports": [ + "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": 19, + "import_count": 0, + "churn": 0, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/semanticDepth.ts", "role": "lib", @@ -2058,8 +1779,33 @@ "SemanticDepthSource", "SemanticDepthResolution" ], - "export_count": 11, - "import_count": 1, + "export_count": 11, + "import_count": 1, + "churn": 0, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/raven/turnContinuity.ts", + "role": "lib", + "lines": 462, + "exports": [ + "buildCommittedMapPromptBlock", + "classifyTurnContinuityType", + "buildTurnContinuityPayload", + "buildTurnContinuityPromptBlock", + "TurnContinuityHistoryEntry", + "TurnContinuityType", + "TurnContinuityUserMove", + "TurnContinuityEmpathyMode", + "TurnContinuityAcknowledgmentPriority", + "TurnContinuityPayload" + ], + "export_count": 10, + "import_count": 3, "churn": 0, "fragility": { "score": 1, @@ -2099,7 +1845,7 @@ ], "export_count": 1, "import_count": 4, - "churn": 4, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2130,7 +1876,7 @@ ], "export_count": 16, "import_count": 1, - "churn": 5, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2163,7 +1909,7 @@ ], "export_count": 18, "import_count": 0, - "churn": 2, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2189,12 +1935,25 @@ "zone": "Vessel Src Lib Zone" }, { - "path": "vessel/src/lib/raven/__tests__/fieldReportVoiceContract.test.ts", + "path": "vessel/src/lib/raven/__tests__/sst.test.ts", "role": "test", - "lines": 224, + "lines": 508, + "export_count": 0, + "import_count": 6, + "churn": 0, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/raven/__tests__/symbolicMomentComposer.test.ts", + "role": "test", + "lines": 436, "export_count": 0, "import_count": 1, - "churn": 12, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2202,12 +1961,12 @@ "zone": "Vessel Src Lib Zone" }, { - "path": "vessel/src/lib/raven/__tests__/sst.test.ts", + "path": "vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts", "role": "test", - "lines": 508, + "lines": 463, "export_count": 0, - "import_count": 6, - "churn": 3, + "import_count": 2, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2276,7 +2035,7 @@ ], "export_count": 11, "import_count": 0, - "churn": 2, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2289,30 +2048,13 @@ "lines": 401, "export_count": 0, "import_count": 2, - "churn": 4, + "churn": 0, "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", @@ -2371,7 +2113,7 @@ ], "export_count": 1, "import_count": 7, - "churn": 6, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2394,6 +2136,38 @@ }, "zone": "Vessel Src Zone" }, + { + "path": "vessel/src/components/reports/StructuralLoadScatter.tsx", + "role": "component", + "lines": 525, + "exports": [ + "StructuralLoadScatter" + ], + "export_count": 1, + "import_count": 1, + "churn": 0, + "fragility": { + "score": 1, + "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": 0, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src Zone" + }, { "path": "vessel/src/components/raven/insight-cards/InsightCardDisplay.tsx", "role": "component", @@ -2411,15 +2185,15 @@ "zone": "Vessel Src Zone" }, { - "path": "vessel/src/components/chat/AlignmentCorridorReadout.tsx", + "path": "vessel/src/components/chat/BalanceMeterPill.tsx", "role": "component", - "lines": 322, + "lines": 544, "exports": [ - "AlignmentCorridorReadout" + "BalanceMeterPill" ], "export_count": 1, - "import_count": 8, - "churn": 7, + "import_count": 4, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2427,15 +2201,16 @@ "zone": "Vessel Src Zone" }, { - "path": "vessel/src/components/chat/FlightRecorderSidebar.tsx", + "path": "vessel/src/components/chat/ChatInput.tsx", "role": "component", - "lines": 254, + "lines": 699, "exports": [ - "FlightRecorderSidebar" + "ChatInput", + "ChatInputHandle" ], - "export_count": 1, - "import_count": 5, - "churn": 8, + "export_count": 2, + "import_count": 3, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2452,7 +2227,20 @@ ], "export_count": 2, "import_count": 6, - "churn": 6, + "churn": 0, + "fragility": { + "score": 1, + "label": "low" + }, + "zone": "Vessel Src Zone" + }, + { + "path": "vessel/src/components/chat/__tests__/DownloadSessionButton.test.ts", + "role": "test", + "lines": 538, + "export_count": 0, + "import_count": 3, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2523,17 +2311,16 @@ "zone": "Vessel Src App Zone" }, { - "path": "vessel/src/app/api/raven-chat/generationIntegrity.ts", + "path": "vessel/src/app/api/raven-chat/enrichmentPhase.ts", "role": "route", - "lines": 270, + "lines": 364, "exports": [ - "resolveReplyIntegrity", - "ReplyIntegrityInput", - "ReplyIntegrityResolution" + "runEnrichmentPhase", + "EnrichmentResult" ], - "export_count": 3, - "import_count": 2, - "churn": 7, + "export_count": 2, + "import_count": 19, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2541,19 +2328,17 @@ "zone": "Vessel Src App Zone" }, { - "path": "vessel/src/app/api/raven-chat/operatorSwitchboard.ts", + "path": "vessel/src/app/api/raven-chat/promptLines.ts", "role": "route", - "lines": 266, + "lines": 445, "exports": [ - "resolveOperatorSwitchboardCommand", - "buildOperatorSwitchboardHelpMessage", - "OPERATOR_SWITCHBOARD_COMMANDS", - "OperatorSwitchboardCategory", - "OperatorSwitchboardCommand" + "buildPromptLines", + "PromptLinesConfig", + "PromptLinesResult" ], - "export_count": 5, - "import_count": 1, - "churn": 12, + "export_count": 3, + "import_count": 6, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2561,31 +2346,26 @@ "zone": "Vessel Src App Zone" }, { - "path": "vessel/src/app/api/raven-chat/systemBlockBuilder.ts", + "path": "vessel/src/app/api/raven-chat/sherlogTelemetry.ts", "role": "route", - "lines": 400, + "lines": 221, "exports": [ - "buildAuthorityHierarchyBlock", - "buildSystemBlocks", - "buildLivePrecedenceOverride", - "SystemBlocksConfig" + "parseSherlogSummaryText", + "formatCreatorMirrorVelocityStatus", + "formatCreatorMirrorRepair", + "readLatestSherlogTelemetryFromRunsRoot", + "readLatestSherlogTelemetry", + "buildOfflineCreatorMirrorTelemetry", + "resolvePrimaryCreatorOperatorLabel", + "isCreatorMirrorAuthorized", + "isCreatorModeTriggerMessage", + "isCreatorAstrologyV3OptInMessage", + "PRIMARY_CREATOR_EMAIL", + "PRIMARY_CREATOR_LABEL" ], - "export_count": 4, - "import_count": 12, - "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": 232, - "export_count": 0, - "import_count": 1, - "churn": 8, + "export_count": 12, + "import_count": 5, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2593,12 +2373,16 @@ "zone": "Vessel Src App Zone" }, { - "path": "vessel/src/app/api/raven-chat/__tests__/intentDetection.test.ts", - "role": "test", - "lines": 309, - "export_count": 0, - "import_count": 1, - "churn": 9, + "path": "vessel/src/app/api/raven-chat/userBlockBuilder.ts", + "role": "route", + "lines": 447, + "exports": [ + "buildUserBlocks", + "UserBlocksConfig" + ], + "export_count": 2, + "import_count": 15, + "churn": 0, "fragility": { "score": 1, "label": "low" @@ -2731,7 +2515,7 @@ "lines": 184, "export_count": 0, "import_count": 2, - "churn": 3, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -2783,7 +2567,7 @@ "lines": 55, "export_count": 0, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -2796,7 +2580,7 @@ "lines": 34, "export_count": 0, "import_count": 0, - "churn": 6, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -2874,7 +2658,7 @@ "lines": 31, "export_count": 0, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -2900,7 +2684,7 @@ "lines": 63, "export_count": 0, "import_count": 0, - "churn": 4, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3028,7 +2812,7 @@ { "path": "vessel/src/lib/bestAstrologyProxy.ts", "role": "lib", - "lines": 195, + "lines": 198, "exports": [ "normalizeBestAstrologyProxyRequest", "forwardBestAstrologyRequest" @@ -3042,6 +2826,25 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/chatGlossary.ts", + "role": "lib", + "lines": 242, + "exports": [ + "splitGlossaryText", + "CHAT_GLOSSARY", + "ChatGlossaryEntry", + "ChatGlossaryTextPart" + ], + "export_count": 4, + "import_count": 0, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/firebase.ts", "role": "lib", @@ -3089,7 +2892,7 @@ ], "export_count": 1, "import_count": 0, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3106,8 +2909,26 @@ "canBackfillBirthLocation", "mapFriendlyAuthErrorMessage" ], - "export_count": 4, - "import_count": 0, + "export_count": 4, + "import_count": 0, + "churn": 0, + "fragility": { + "score": 0, + "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": 0, "fragility": { "score": 0, @@ -3131,7 +2952,7 @@ ], "export_count": 8, "import_count": 0, - "churn": 6, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3209,7 +3030,26 @@ ], "export_count": 3, "import_count": 0, - "churn": 2, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, + { + "path": "vessel/src/lib/stripe.ts", + "role": "lib", + "lines": 42, + "exports": [ + "getStripe", + "STRIPE_ENABLED", + "STRIPE_PRO_PRICE_ID", + "STRIPE_WEBHOOK_SECRET" + ], + "export_count": 4, + "import_count": 0, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3299,7 +3139,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 5, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3340,7 +3180,7 @@ ], "export_count": 2, "import_count": 4, - "churn": 5, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3356,7 +3196,7 @@ ], "export_count": 1, "import_count": 0, - "churn": 5, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3373,7 +3213,7 @@ ], "export_count": 2, "import_count": 2, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3454,7 +3294,7 @@ ], "export_count": 6, "import_count": 3, - "churn": 3, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3518,6 +3358,27 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/raven/dashboardApertureValidation.ts", + "role": "lib", + "lines": 81, + "exports": [ + "validateDashboardApertureSurface", + "DashboardMetricDescriptor", + "DashboardZoneDescriptor", + "DashboardApertureSurface", + "DashboardValidationIssue", + "DashboardValidationResult" + ], + "export_count": 6, + "import_count": 1, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/degradedReplyBuilders.ts", "role": "lib", @@ -3531,7 +3392,7 @@ ], "export_count": 5, "import_count": 1, - "churn": 6, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3557,6 +3418,22 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/raven/fieldReportRepairFallback.ts", + "role": "lib", + "lines": 247, + "exports": [ + "buildFieldReportVoiceDriftFallback" + ], + "export_count": 1, + "import_count": 3, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/fieldScope.ts", "role": "lib", @@ -3588,7 +3465,7 @@ ], "export_count": 2, "import_count": 0, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3622,7 +3499,7 @@ ], "export_count": 3, "import_count": 0, - "churn": 6, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3661,7 +3538,7 @@ ], "export_count": 3, "import_count": 1, - "churn": 5, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3718,7 +3595,7 @@ ], "export_count": 6, "import_count": 0, - "churn": 5, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3737,7 +3614,7 @@ ], "export_count": 4, "import_count": 0, - "churn": 4, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3864,7 +3741,7 @@ { "path": "vessel/src/lib/raven/sealedArtifact.ts", "role": "lib", - "lines": 171, + "lines": 191, "exports": [ "hashGeometry", "buildProfileFingerprint", @@ -3876,8 +3753,8 @@ "SealedSymbolicArtifact" ], "export_count": 8, - "import_count": 1, - "churn": 4, + "import_count": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3912,7 +3789,7 @@ ], "export_count": 3, "import_count": 0, - "churn": 3, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3968,7 +3845,7 @@ { "path": "vessel/src/lib/raven/symbolicMomentIntent.ts", "role": "lib", - "lines": 259, + "lines": 260, "exports": [ "classifySymbolicMomentTurn", "hasStructuredSymbolicMomentArtifact", @@ -3979,7 +3856,7 @@ ], "export_count": 6, "import_count": 0, - "churn": 4, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -3998,7 +3875,7 @@ ], "export_count": 4, "import_count": 0, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -4063,6 +3940,31 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/raven/temporalAperture.ts", + "role": "lib", + "lines": 312, + "exports": [ + "resolveTemporalAperture", + "hasApertureDeclaration", + "ensureApertureDeclaration", + "validateApertureNarrative", + "serializeApertureForPrompt", + "TemporalAperture", + "TemporalApertureSource", + "TemporalApertureRange", + "TemporalApertureContext", + "TemporalApertureValidationResult" + ], + "export_count": 10, + "import_count": 0, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/tokenGovernor.ts", "role": "lib", @@ -4114,7 +4016,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 4, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -4234,7 +4136,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -4308,7 +4210,7 @@ ], "export_count": 3, "import_count": 3, - "churn": 3, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -4547,7 +4449,7 @@ ], "export_count": 6, "import_count": 2, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -4624,7 +4526,7 @@ "lines": 204, "export_count": 0, "import_count": 3, - "churn": 4, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -4709,6 +4611,19 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/raven/__tests__/dashboardApertureValidation.test.ts", + "role": "test", + "lines": 48, + "export_count": 0, + "import_count": 1, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/__tests__/doctrineManifest.test.ts", "role": "test", @@ -4748,6 +4663,19 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/raven/__tests__/fieldReportVoiceContract.test.ts", + "role": "test", + "lines": 224, + "export_count": 0, + "import_count": 1, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/__tests__/fieldScope.test.ts", "role": "test", @@ -4793,7 +4721,7 @@ "lines": 282, "export_count": 0, "import_count": 1, - "churn": 3, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -4806,7 +4734,7 @@ "lines": 99, "export_count": 0, "import_count": 2, - "churn": 3, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -4858,7 +4786,7 @@ "lines": 212, "export_count": 0, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5008,6 +4936,19 @@ }, "zone": "Vessel Src Lib Zone" }, + { + "path": "vessel/src/lib/raven/__tests__/temporalAperture.test.ts", + "role": "test", + "lines": 122, + "export_count": 0, + "import_count": 2, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Lib Zone" + }, { "path": "vessel/src/lib/raven/__tests__/tokenGovernor.test.ts", "role": "test", @@ -5024,10 +4965,10 @@ { "path": "vessel/src/lib/raven/__tests__/turnContinuity.test.ts", "role": "test", - "lines": 198, + "lines": 218, "export_count": 0, "import_count": 1, - "churn": 6, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5268,10 +5209,10 @@ { "path": "vessel/src/lib/__tests__/sealedArtifact.test.ts", "role": "test", - "lines": 287, + "lines": 314, "export_count": 0, "import_count": 2, - "churn": 4, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5281,7 +5222,7 @@ { "path": "vessel/src/lib/__tests__/v3MathBrain.test.ts", "role": "test", - "lines": 155, + "lines": 173, "export_count": 0, "import_count": 1, "churn": 0, @@ -5307,6 +5248,23 @@ }, "zone": "Vessel Src Zone" }, + { + "path": "vessel/src/hooks/useFlightRecorderData.ts", + "role": "hook", + "lines": 63, + "exports": [ + "useFlightRecorderData", + "FlightRecorderData" + ], + "export_count": 2, + "import_count": 4, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Zone" + }, { "path": "vessel/src/hooks/useTextMeasure.ts", "role": "hook", @@ -5381,7 +5339,7 @@ ], "export_count": 1, "import_count": 3, - "churn": 5, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5517,6 +5475,22 @@ }, "zone": "Vessel Src Zone" }, + { + "path": "vessel/src/components/chat/AlignmentCorridorReadout.tsx", + "role": "component", + "lines": 326, + "exports": [ + "AlignmentCorridorReadout" + ], + "export_count": 1, + "import_count": 8, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Zone" + }, { "path": "vessel/src/components/chat/ChatDashboardLayout.tsx", "role": "component", @@ -5591,7 +5565,7 @@ ], "export_count": 1, "import_count": 4, - "churn": 3, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5662,6 +5636,22 @@ }, "zone": "Vessel Src Zone" }, + { + "path": "vessel/src/components/chat/FlightRecorderSidebar.tsx", + "role": "component", + "lines": 254, + "exports": [ + "FlightRecorderSidebar" + ], + "export_count": 1, + "import_count": 5, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src Zone" + }, { "path": "vessel/src/components/chat/InstrumentMenu.tsx", "role": "component", @@ -5727,7 +5717,7 @@ ], "export_count": 5, "import_count": 0, - "churn": 5, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5776,7 +5766,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5808,7 +5798,7 @@ ], "export_count": 1, "import_count": 2, - "churn": 3, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5915,7 +5905,7 @@ "lines": 118, "export_count": 0, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5928,7 +5918,7 @@ "lines": 127, "export_count": 0, "import_count": 3, - "churn": 3, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -5989,7 +5979,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6015,7 +6005,7 @@ { "path": "vessel/src/components/__tests__/AlignmentCorridor.session.test.tsx", "role": "test", - "lines": 187, + "lines": 199, "export_count": 0, "import_count": 2, "churn": 0, @@ -6164,7 +6154,7 @@ ], "export_count": 1, "import_count": 2, - "churn": 4, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6316,7 +6306,7 @@ ], "export_count": 4, "import_count": 3, - "churn": 4, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6381,7 +6371,7 @@ ], "export_count": 1, "import_count": 2, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6461,7 +6451,7 @@ ], "export_count": 1, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6534,6 +6524,22 @@ }, "zone": "Vessel Src App Zone" }, + { + "path": "vessel/src/app/api/sherlog/dependency/route.ts", + "role": "route", + "lines": 28, + "exports": [ + "GET" + ], + "export_count": 1, + "import_count": 1, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src App Zone" + }, { "path": "vessel/src/app/api/sherlog/config/route.ts", "role": "route", @@ -6718,7 +6724,25 @@ ], "export_count": 2, "import_count": 2, - "churn": 3, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src App Zone" + }, + { + "path": "vessel/src/app/api/raven-chat/generationIntegrity.ts", + "role": "route", + "lines": 270, + "exports": [ + "resolveReplyIntegrity", + "ReplyIntegrityInput", + "ReplyIntegrityResolution" + ], + "export_count": 3, + "import_count": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6736,7 +6760,7 @@ ], "export_count": 3, "import_count": 1, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6761,6 +6785,26 @@ }, "zone": "Vessel Src App Zone" }, + { + "path": "vessel/src/app/api/raven-chat/operatorSwitchboard.ts", + "role": "route", + "lines": 266, + "exports": [ + "resolveOperatorSwitchboardCommand", + "buildOperatorSwitchboardHelpMessage", + "OPERATOR_SWITCHBOARD_COMMANDS", + "OperatorSwitchboardCategory", + "OperatorSwitchboardCommand" + ], + "export_count": 5, + "import_count": 1, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src App Zone" + }, { "path": "vessel/src/app/api/raven-chat/polyadicRouting.ts", "role": "route", @@ -6773,7 +6817,7 @@ ], "export_count": 4, "import_count": 2, - "churn": 3, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6811,7 +6855,7 @@ ], "export_count": 7, "import_count": 0, - "churn": 6, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6855,7 +6899,7 @@ ], "export_count": 5, "import_count": 10, - "churn": 4, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6905,7 +6949,7 @@ ], "export_count": 2, "import_count": 4, - "churn": 5, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6921,7 +6965,26 @@ ], "export_count": 1, "import_count": 1, - "churn": 4, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src App Zone" + }, + { + "path": "vessel/src/app/api/raven-chat/systemBlockBuilder.ts", + "role": "route", + "lines": 400, + "exports": [ + "buildAuthorityHierarchyBlock", + "buildSystemBlocks", + "buildLivePrecedenceOverride", + "SystemBlocksConfig" + ], + "export_count": 4, + "import_count": 12, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6948,15 +7011,15 @@ { "path": "vessel/src/app/api/raven-chat/upstreamContext.ts", "role": "route", - "lines": 167, + "lines": 189, "exports": [ "fetchUpstreamContext", "UpstreamContextConfig", "UpstreamContextResult" ], "export_count": 3, - "import_count": 8, - "churn": 6, + "import_count": 9, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -6995,7 +7058,7 @@ "lines": 208, "export_count": 0, "import_count": 1, - "churn": 5, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -7008,7 +7071,33 @@ "lines": 150, "export_count": 0, "import_count": 3, - "churn": 5, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src App Zone" + }, + { + "path": "vessel/src/app/api/raven-chat/__tests__/generationIntegrity.test.ts", + "role": "test", + "lines": 232, + "export_count": 0, + "import_count": 1, + "churn": 0, + "fragility": { + "score": 0, + "label": "low" + }, + "zone": "Vessel Src App Zone" + }, + { + "path": "vessel/src/app/api/raven-chat/__tests__/intentDetection.test.ts", + "role": "test", + "lines": 309, + "export_count": 0, + "import_count": 1, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -7018,10 +7107,10 @@ { "path": "vessel/src/app/api/raven-chat/__tests__/promptLines.test.ts", "role": "test", - "lines": 165, + "lines": 177, "export_count": 0, "import_count": 1, - "churn": 5, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -7034,7 +7123,7 @@ "lines": 168, "export_count": 0, "import_count": 1, - "churn": 5, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -7047,7 +7136,7 @@ "lines": 304, "export_count": 0, "import_count": 5, - "churn": 5, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -7073,7 +7162,7 @@ "lines": 176, "export_count": 0, "import_count": 1, - "churn": 3, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -7099,7 +7188,7 @@ "lines": 52, "export_count": 0, "import_count": 1, - "churn": 4, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -7112,7 +7201,7 @@ "lines": 72, "export_count": 0, "import_count": 0, - "churn": 3, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -7135,10 +7224,10 @@ { "path": "vessel/src/app/api/raven-chat/__tests__/userBlockBuilder.test.ts", "role": "test", - "lines": 287, + "lines": 304, "export_count": 0, "import_count": 2, - "churn": 3, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -7171,7 +7260,7 @@ ], "export_count": 2, "import_count": 6, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -7269,7 +7358,7 @@ ], "export_count": 1, "import_count": 6, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -7285,7 +7374,7 @@ ], "export_count": 1, "import_count": 2, - "churn": 4, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -7331,7 +7420,7 @@ ], "export_count": 2, "import_count": 2, - "churn": 2, + "churn": 0, "fragility": { "score": 0, "label": "low" @@ -8091,6 +8180,11 @@ "to": "./adviceLadder", "resolved_to": "vessel/src/lib/raven/adviceLadder.ts" }, + { + "from": "vessel/src/lib/raven/affirmativeDomain.ts", + "to": "./temporalAperture", + "resolved_to": "vessel/src/lib/raven/temporalAperture.ts" + }, { "from": "vessel/src/lib/raven/affirmativeRuntime.ts", "to": "./affirmativeDomain", @@ -8171,6 +8265,11 @@ "to": "./relationshipMapping", "resolved_to": "vessel/src/lib/raven/relationshipMapping.ts" }, + { + "from": "vessel/src/lib/raven/dashboardApertureValidation.ts", + "to": "./temporalAperture", + "resolved_to": "vessel/src/lib/raven/temporalAperture.ts" + }, { "from": "vessel/src/lib/raven/degradedReplyBuilders.ts", "to": "./corridorSnapshot", @@ -8286,6 +8385,11 @@ "to": "../v3MathBrain", "resolved_to": "vessel/src/lib/v3MathBrain.ts" }, + { + "from": "vessel/src/lib/raven/sealedArtifact.ts", + "to": "./temporalAperture", + "resolved_to": "vessel/src/lib/raven/temporalAperture.ts" + }, { "from": "vessel/src/lib/raven/semanticDepth.ts", "to": "./localLexicon", @@ -8316,6 +8420,11 @@ "to": "./symbolicMomentTranslation", "resolved_to": "vessel/src/lib/raven/symbolicMomentTranslation.ts" }, + { + "from": "vessel/src/lib/raven/symbolicMomentComposer.ts", + "to": "./temporalAperture", + "resolved_to": "vessel/src/lib/raven/temporalAperture.ts" + }, { "from": "vessel/src/lib/raven/symbolicMomentComposer.ts", "to": "./frontstageLinter", @@ -8341,6 +8450,11 @@ "to": "./frontstageBackstageGuard", "resolved_to": "vessel/src/lib/raven/frontstageBackstageGuard.ts" }, + { + "from": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", + "to": "./temporalAperture", + "resolved_to": "vessel/src/lib/raven/temporalAperture.ts" + }, { "from": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", "to": "../v3MathBrain", @@ -8366,6 +8480,11 @@ "to": "../ravenPersona", "resolved_to": "vessel/src/lib/ravenPersona.ts" }, + { + "from": "vessel/src/lib/raven/turnContinuity.ts", + "to": "./temporalAperture", + "resolved_to": "vessel/src/lib/raven/temporalAperture.ts" + }, { "from": "vessel/src/lib/raven/turnContinuity.ts", "to": "./relationalIntent", @@ -8846,6 +8965,11 @@ "to": "../relationshipMapping", "resolved_to": "vessel/src/lib/raven/relationshipMapping.ts" }, + { + "from": "vessel/src/lib/raven/__tests__/dashboardApertureValidation.test.ts", + "to": "../dashboardApertureValidation", + "resolved_to": "vessel/src/lib/raven/dashboardApertureValidation.ts" + }, { "from": "vessel/src/lib/raven/__tests__/doctrineManifest.test.ts", "to": "../doctrineManifest", @@ -9036,6 +9160,16 @@ "to": "../telemetryInterpretation", "resolved_to": "vessel/src/lib/raven/telemetryInterpretation.ts" }, + { + "from": "vessel/src/lib/raven/__tests__/temporalAperture.test.ts", + "to": "../temporalAperture", + "resolved_to": "vessel/src/lib/raven/temporalAperture.ts" + }, + { + "from": "vessel/src/lib/raven/__tests__/temporalAperture.test.ts", + "to": "../symbolicMomentIntent", + "resolved_to": "vessel/src/lib/raven/symbolicMomentIntent.ts" + }, { "from": "vessel/src/lib/raven/__tests__/tokenGovernor.test.ts", "to": "../tokenGovernor", @@ -9371,6 +9505,11 @@ "to": "@/lib/ui/commandHelper", "resolved_to": "vessel/src/lib/ui/commandHelper.ts" }, + { + "from": "vessel/src/components/AlignmentCorridor.tsx", + "to": "@/lib/raven/temporalAperture", + "resolved_to": "vessel/src/lib/raven/temporalAperture.ts" + }, { "from": "vessel/src/components/AstroPosterCard.tsx", "to": "../lib/vaultSync", @@ -10576,6 +10715,11 @@ "to": "../lib", "resolved_to": "vessel/src/app/api/sherlog/lib.ts" }, + { + "from": "vessel/src/app/api/sherlog/dependency/route.ts", + "to": "../lib", + "resolved_to": "vessel/src/app/api/sherlog/lib.ts" + }, { "from": "vessel/src/app/api/sherlog/config/route.ts", "to": "../lib", @@ -11541,6 +11685,11 @@ "to": "@/lib/raven/frontstageBackstageGuard", "resolved_to": "vessel/src/lib/raven/frontstageBackstageGuard.ts" }, + { + "from": "vessel/src/app/api/raven-chat/route.ts", + "to": "@/lib/raven/temporalAperture", + "resolved_to": "vessel/src/lib/raven/temporalAperture.ts" + }, { "from": "vessel/src/app/api/raven-chat/sealGuard.ts", "to": "../../../lib/raven/types", @@ -11806,6 +11955,11 @@ "to": "@/lib/raven/sealedArtifact", "resolved_to": "vessel/src/lib/raven/sealedArtifact.ts" }, + { + "from": "vessel/src/app/api/raven-chat/upstreamContext.ts", + "to": "@/lib/raven/temporalAperture", + "resolved_to": "vessel/src/lib/raven/temporalAperture.ts" + }, { "from": "vessel/src/app/api/raven-chat/upstreamContext.ts", "to": "@/lib/v3MathBrain", @@ -11906,6 +12060,11 @@ "to": "../../../lib/raven/symbolicMomentComposer", "resolved_to": "vessel/src/lib/raven/symbolicMomentComposer.ts" }, + { + "from": "vessel/src/app/api/raven-chat/userBlockBuilder.ts", + "to": "../../../lib/raven/temporalAperture", + "resolved_to": "vessel/src/lib/raven/temporalAperture.ts" + }, { "from": "vessel/src/app/api/raven-chat/__tests__/circumstanceDisclosure.test.ts", "to": "../circumstanceDisclosure", @@ -12250,248 +12409,136 @@ "fragile_files": [ { "path": "vessel/src/hooks/useOracleChat.ts", - "score": 7, - "label": "high", - "lines": 2554, - "churn": 23 - }, - { - "path": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", - "score": 6, - "label": "high", - "lines": 1297, - "churn": 42 - }, - { - "path": "vessel/src/app/api/raven-chat/intentDetection.ts", - "score": 6, - "label": "high", - "lines": 1270, - "churn": 20 - }, - { - "path": "vessel/src/app/api/raven-chat/sessionState.ts", - "score": 6, - "label": "high", - "lines": 1201, - "churn": 20 - }, - { - "path": "vessel/src/test/api-smoke.test.ts", - "score": 5, - "label": "high", - "lines": 3556, - "churn": 30 - }, - { - "path": "vessel/src/lib/v3MathBrain.ts", - "score": 5, - "label": "high", - "lines": 1213, - "churn": 16 - }, - { - "path": "vessel/src/lib/raven/symbolicMomentComposer.ts", - "score": 5, - "label": "high", - "lines": 1769, - "churn": 14 - }, - { - "path": "vessel/src/app/page.tsx", - "score": 5, - "label": "high", - "lines": 5709, - "churn": 35 - }, - { - "path": "vessel/src/app/api/raven-chat/route.ts", "score": 5, "label": "high", - "lines": 2831, - "churn": 80 + "lines": 2554, + "churn": 0 }, { "path": "vessel/src/lib/vaultSync.ts", "score": 4, "label": "medium", "lines": 2163, - "churn": 5 + "churn": 0 }, { "path": "vessel/src/lib/raven/constellationVault.ts", "score": 4, "label": "medium", "lines": 806, - "churn": 4 - }, - { - "path": "vessel/src/lib/raven/doctrineManifest.ts", - "score": 4, - "label": "medium", - "lines": 1055, - "churn": 8 - }, - { - "path": "vessel/src/lib/raven/instrumentLedger.ts", - "score": 4, - "label": "medium", - "lines": 535, - "churn": 7 - }, - { - "path": "vessel/src/lib/raven/persona-law.ts", - "score": 4, - "label": "medium", - "lines": 482, - "churn": 13 - }, - { - "path": "vessel/src/lib/raven/responseRenderer.ts", - "score": 4, - "label": "medium", - "lines": 874, - "churn": 10 - }, - { - "path": "vessel/src/lib/raven/types.ts", - "score": 4, - "label": "medium", - "lines": 419, - "churn": 8 + "churn": 0 }, { - "path": "vessel/src/lib/raven/__tests__/responseRenderer.test.ts", + "path": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", "score": 4, "label": "medium", - "lines": 814, - "churn": 16 + "lines": 1371, + "churn": 0 }, { - "path": "vessel/src/components/AlignmentCorridor.tsx", + "path": "vessel/src/app/api/raven-chat/intentDetection.ts", "score": 4, "label": "medium", - "lines": 1581, - "churn": 14 + "lines": 1270, + "churn": 0 }, { "path": "vessel/src/app/api/raven-chat/llmProvider.ts", "score": 4, "label": "medium", "lines": 902, - "churn": 5 + "churn": 0 }, { "path": "vessel/src/app/api/raven-chat/requestParsing.ts", "score": 4, "label": "medium", "lines": 824, - "churn": 3 - }, - { - "path": "vessel/src/lib/wovenReportCore.ts", - "score": 3, - "label": "medium", - "lines": 4637, - "churn": 11 - }, - { - "path": "vessel/src/lib/raven/fieldReportVoiceContract.ts", - "score": 3, - "label": "medium", - "lines": 442, - "churn": 17 - }, - { - "path": "vessel/src/lib/raven/protocolEngine.ts", - "score": 3, - "label": "medium", - "lines": 1426, - "churn": 6 + "churn": 0 }, { - "path": "vessel/src/lib/raven/sessionMachine.ts", - "score": 3, + "path": "vessel/src/app/api/raven-chat/sessionState.ts", + "score": 4, "label": "medium", - "lines": 751, - "churn": 9 + "lines": 1201, + "churn": 0 }, { - "path": "vessel/src/lib/raven/__tests__/symbolicMomentComposer.test.ts", + "path": "vessel/src/test/api-smoke.test.ts", "score": 3, "label": "medium", - "lines": 427, - "churn": 14 + "lines": 3556, + "churn": 0 }, { - "path": "vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts", + "path": "vessel/src/lib/v3MathBrain.ts", "score": 3, "label": "medium", - "lines": 460, - "churn": 32 + "lines": 1254, + "churn": 0 }, { - "path": "vessel/src/lib/black-feather/bflEngine.ts", + "path": "vessel/src/lib/raven/doctrineManifest.ts", "score": 3, "label": "medium", - "lines": 504, - "churn": 2 + "lines": 1098, + "churn": 0 }, { - "path": "vessel/src/components/ProfileVault.tsx", + "path": "vessel/src/lib/raven/instrumentLedger.ts", "score": 3, "label": "medium", - "lines": 2755, - "churn": 10 + "lines": 535, + "churn": 0 }, { - "path": "vessel/src/components/chat/BalanceMeterPill.tsx", + "path": "vessel/src/lib/raven/protocolEngine.ts", "score": 3, "label": "medium", - "lines": 510, - "churn": 13 + "lines": 1426, + "churn": 0 }, { - "path": "vessel/src/components/chat/DownloadSessionButton.tsx", + "path": "vessel/src/lib/raven/responseRenderer.ts", "score": 3, "label": "medium", - "lines": 1578, - "churn": 9 + "lines": 874, + "churn": 0 }, { - "path": "vessel/src/components/chat/SessionFlightRecorder.tsx", + "path": "vessel/src/lib/raven/symbolicMomentComposer.ts", "score": 3, "label": "medium", - "lines": 1593, - "churn": 11 + "lines": 1779, + "churn": 0 }, { - "path": "vessel/src/app/api/raven-chat/enrichmentPhase.ts", + "path": "vessel/src/lib/raven/types.ts", "score": 3, "label": "medium", - "lines": 364, - "churn": 13 + "lines": 419, + "churn": 0 }, { - "path": "vessel/src/app/api/raven-chat/promptLines.ts", + "path": "vessel/src/lib/black-feather/bflEngine.ts", "score": 3, "label": "medium", - "lines": 436, - "churn": 46 + "lines": 504, + "churn": 0 }, { - "path": "vessel/src/app/api/raven-chat/protocolRules.ts", + "path": "vessel/src/app/page.tsx", "score": 3, "label": "medium", - "lines": 517, - "churn": 11 + "lines": 5709, + "churn": 0 }, { - "path": "vessel/src/app/api/raven-chat/userBlockBuilder.ts", + "path": "vessel/src/app/api/raven-chat/route.ts", "score": 3, "label": "medium", - "lines": 440, - "churn": 18 + "lines": 2882, + "churn": 0 } ], "dependency_hubs": [ @@ -12612,6 +12659,12 @@ "governor_contract" ] }, + { + "path": "vessel/src/lib/raven/temporalAperture.ts", + "anchors": [ + "intent_contract" + ] + }, { "path": "vessel/src/lib/raven/tokenGovernor.ts", "anchors": [ @@ -12642,6 +12695,12 @@ "governor_contract" ] }, + { + "path": "vessel/src/lib/raven/__tests__/temporalAperture.test.ts", + "anchors": [ + "intent_contract" + ] + }, { "path": "vessel/src/lib/raven/__tests__/tokenGovernor.test.ts", "anchors": [ @@ -12836,8 +12895,8 @@ } ], "zone_ownership": { - "total": 404, - "covered": 404, + "total": 409, + "covered": 409, "unmapped": 0, "zones": [ { @@ -12868,12 +12927,12 @@ { "name": "Vessel Src App Zone", "belief": "TODO: Describe what this zone governs.", - "file_count": 112 + "file_count": 113 }, { "name": "Vessel Src Lib Zone", "belief": "TODO: Describe what this zone governs.", - "file_count": 187 + "file_count": 191 }, { "name": "Vessel Src Zone", @@ -12895,64 +12954,64 @@ "churn_window_days": 14, "churn_hotspots": [ { - "file": "vessel/src/app/api/raven-chat/route.ts", - "commits": 80 + "file": ".replit_integration_files/server/replit_integrations/batch/index.ts", + "commits": 1 }, { - "file": "vessel/src/app/api/raven-chat/promptLines.ts", - "commits": 46 + "file": ".replit_integration_files/server/replit_integrations/batch/utils.ts", + "commits": 1 }, { - "file": "vessel/src/lib/raven/symbolicMomentFrontstage.ts", - "commits": 42 + "file": ".replit_integration_files/server/replit_integrations/chat/index.ts", + "commits": 1 }, { - "file": "vessel/src/app/page.tsx", - "commits": 35 + "file": ".replit_integration_files/server/replit_integrations/chat/routes.ts", + "commits": 1 }, { - "file": "vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts", - "commits": 32 + "file": ".replit_integration_files/server/replit_integrations/chat/storage.ts", + "commits": 1 }, { - "file": "vessel/src/test/api-smoke.test.ts", - "commits": 30 + "file": ".replit_integration_files/server/replit_integrations/image/client.ts", + "commits": 1 }, { - "file": "vessel/src/hooks/useOracleChat.ts", - "commits": 23 + "file": ".replit_integration_files/server/replit_integrations/image/index.ts", + "commits": 1 }, { - "file": "vessel/src/app/api/raven-chat/intentDetection.ts", - "commits": 20 + "file": ".replit_integration_files/server/replit_integrations/image/routes.ts", + "commits": 1 }, { - "file": "vessel/src/app/api/raven-chat/sessionState.ts", - "commits": 20 + "file": ".replit_integration_files/shared/models/chat.ts", + "commits": 1 }, { - "file": "vessel/src/app/api/raven-chat/userBlockBuilder.ts", - "commits": 18 + "file": "Research/audits/audit_bundle.ts", + "commits": 1 }, { - "file": "vessel/src/lib/raven/fieldReportRepairFallback.ts", - "commits": 18 + "file": "Research/hurricane_retrodiction/scripts/reproduce_michael.js", + "commits": 1 }, { - "file": "vessel/src/lib/raven/fieldReportVoiceContract.ts", - "commits": 17 + "file": "Research/hurricane_retrodiction/scripts/verify_michael_live.js", + "commits": 1 }, { - "file": "vessel/src/lib/raven/__tests__/responseRenderer.test.ts", - "commits": 16 + "file": "Research/scripts/research_correlation.js", + "commits": 1 }, { - "file": "vessel/src/lib/v3MathBrain.ts", - "commits": 16 + "file": "Research/scripts/research_mood_correlation.js", + "commits": 1 }, { - "file": "vessel/src/components/AlignmentCorridor.tsx", - "commits": 14 + "file": "Research/tests_and_simulations/generate_regression_freeze_frame.test.js", + "commits": 1 } ] } diff --git a/vessel/src/app/api/raven-chat/route.ts b/vessel/src/app/api/raven-chat/route.ts index 4899326f..81fbaa39 100644 --- a/vessel/src/app/api/raven-chat/route.ts +++ b/vessel/src/app/api/raven-chat/route.ts @@ -149,6 +149,16 @@ import { buildNatalHousesByPlanet } from '@/lib/raven/natalHousesByPlanet'; import { isStreamReadTimeoutError, readStreamChunkWithTimeout } from '@/lib/streamReadTimeout'; import { sanitizeFrontstageBackstageLeak } from '@/lib/raven/frontstageBackstageGuard'; import { ensureApertureDeclaration, resolveTemporalAperture } from '@/lib/raven/temporalAperture'; +import { + computeReadState, + type ReadState, + type AspectSnapshot, +} from '@/lib/raven/readState'; +import { + appendRead, + getMostRecentRead, + getReadsForDate, +} from '@/lib/server/readHistory'; export const maxDuration = 200; @@ -170,6 +180,8 @@ const CHAMBER_FOCUS_PATTERN = /\b(chamber)\b/i; const HOUSE_FOCUS_PATTERN = /\b(house|h\d{1,2}|1st|2nd|3rd|4th|5th|6th|7th|8th|9th|10th|11th|12th)\b/i; const PLANET_FOCUS_PATTERN = /\b(sun|moon|mercury|venus|mars|jupiter|saturn|uranus|neptune|pluto|chiron|node)\b/i; const BACKSTAGE_LEAK_PATTERN = /\b(keep the same diagnostic lane|sharpen that map|swap driver set|relationship mode rule)\b/gi; +// Matches "Body1 aspect Body2" driver labels for aspect snapshot extraction. +const ASPECT_LABEL_PATTERN = /^([A-Za-z\s]+)\s+(square|opposition|conjunction|trine|sextile|quincunx|semisquare|semisextile|sesquiquadrate)\s+([A-Za-z\s]+)$/i; function normalizeFrontstageForHash(input: string): string { return input @@ -2624,6 +2636,42 @@ async function runRavenChatPipeline(request: Request): Promise { contact: lunarPhaseContext.closestMoonContact || null, } : null; + // ── Read-State Awareness ────────────────────────────────────── + // Derive a stable chart identifier from birth data fields so read + // history is scoped to the chart (not just the user). + const nowUtc = new Date().toISOString(); + const chartFingerprint = createHash('sha256') + .update( + `${telemetryProfile.birthDate ?? ''}|${telemetryProfile.birthTime ?? ''}|` + + `${telemetryProfile.latitude ?? ''}|${telemetryProfile.longitude ?? ''}`, + ) + .digest('hex') + .slice(0, 16); + + // User's local date in their timezone (falls back to UTC if unknown). + const effectiveTimezone = + liveLocation?.timezone || + telemetryProfile.currentTimezone || + telemetryProfile.timezone || + 'UTC'; + const userLocalDate = new Date(nowUtc).toLocaleDateString('en-CA', { + timeZone: effectiveTimezone, + }); // 'en-CA' produces YYYY-MM-DD + + // Load read history (silently degrades to "first read" on Firestore errors). + const [todayReads, mostRecentReadEntry] = await Promise.all([ + getReadsForDate(uid, chartFingerprint, userLocalDate), + getMostRecentRead(uid, chartFingerprint), + ]); + + const readState: ReadState = computeReadState( + todayReads, + mostRecentReadEntry, + nowUtc, + temporalAperture.aperture, + ); + // ───────────────────────────────────────────────────────────── + const structuredMoment = buildStructuredSymbolicMomentReply({ reply: finalReply, telemetry: astrology, @@ -2633,6 +2681,7 @@ async function runRavenChatPipeline(request: Request): Promise { : undefined, lunar, location, + readState, includeFootnote: true, apertureContext: temporalAperture, }); @@ -2671,6 +2720,39 @@ async function runRavenChatPipeline(request: Request): Promise { ); } else { finalReply = structuredMoment.reply; + + // Persist read history entry for future read-state computation. + // Fire-and-forget: errors must not block the response path. + const proseOutputHash = createHash('sha256') + .update(finalReply) + .digest('hex') + .slice(0, 16); + const primaryAspects: AspectSnapshot[] = ( + astrology?.anchor?.topDrivers ?? [] + ).slice(0, 5).flatMap((driver) => { + const m = ASPECT_LABEL_PATTERN.exec(driver.label.trim()); + if (!m) return []; + return [{ + body1: m[1].trim(), + body2: m[3].trim(), + aspect_type: m[2].toLowerCase(), + orb: driver.orb, + }]; + }); + appendRead({ + read_id: `read_${crypto.randomUUID()}`, + user_id: uid, + chart_id: chartFingerprint, + timestamp_utc: nowUtc, + user_local_date: userLocalDate, + aperture: temporalAperture.aperture, + sealed_geometry_hash: structuredMoment.zone2?.sealed_hash ?? '', + primary_chamber: structuredMoment.zone2?.primary_chamber ?? '', + primary_aspects: primaryAspects, + prose_output_hash: proseOutputHash, + }).catch(() => { + // Swallowed: persistence failure must not affect the read path. + }); } // Preserve frontstage prose on signal void: use the integrity-checked LLM // reply rather than the cold SIGNAL_VOID_REPLY string (invariant #2). diff --git a/vessel/src/lib/raven/__tests__/readState.test.ts b/vessel/src/lib/raven/__tests__/readState.test.ts new file mode 100644 index 00000000..64607b81 --- /dev/null +++ b/vessel/src/lib/raven/__tests__/readState.test.ts @@ -0,0 +1,321 @@ +/** + * Read-State Awareness — Regression Tests + * + * Validates that: + * - First-ever reads produce no continuity language + * - First-of-day reads are framed as opening reads + * - Continuation reads carry real diffs + * - The validator blocks fabricated continuity on first reads + * - The validator flags missing continuity on continuation reads + */ +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + computeReadState, + computeContinuityDiff, + generateContinuityLanguage, + validateReadStateConsistency, + isFirstRead, + type ReadHistoryEntry, +} from '../readState'; + +// ───────────────────────────────────────────────────────── +// Fixtures +// ───────────────────────────────────────────────────────── + +function makeEntry(overrides: Partial = {}): ReadHistoryEntry { + return { + read_id: 'read_test_001', + user_id: 'user_test', + chart_id: 'chart_test', + timestamp_utc: '2026-04-30T14:33:00Z', + user_local_date: '2026-04-30', + aperture: 'NOW_PULSE', + sealed_geometry_hash: 'abc123', + primary_chamber: 'The Horizon', + primary_aspects: [ + { body1: 'Saturn', body2: 'Sun', aspect_type: 'square', orb: 1.8 }, + ], + prose_output_hash: 'prose001', + ...overrides, + }; +} + +// ───────────────────────────────────────────────────────── +// computeReadState +// ───────────────────────────────────────────────────────── + +test('computeReadState returns first-read-ever when no history exists', () => { + const state = computeReadState([], null, '2026-04-30T16:08:00Z', 'NOW_PULSE'); + assert.equal(state.is_first_read_ever, true); + assert.equal(state.is_first_read_today, true); + assert.equal(state.is_continuation, false); + assert.equal(state.prior_read, null); + assert.equal(isFirstRead(state), true); +}); + +test('computeReadState returns first-read-today when prior reads exist from other days', () => { + const yesterdayEntry = makeEntry({ + timestamp_utc: '2026-04-29T14:33:00Z', + user_local_date: '2026-04-29', + }); + const state = computeReadState([], yesterdayEntry, '2026-04-30T08:17:00Z', 'NOW_PULSE'); + assert.equal(state.is_first_read_ever, false); + assert.equal(state.is_first_read_today, true); + assert.equal(state.is_continuation, false); + assert.equal(state.prior_read, null); + assert.equal(isFirstRead(state), true); +}); + +test('computeReadState returns continuation when prior read exists from today', () => { + const morningRead = makeEntry({ + timestamp_utc: '2026-04-30T14:33:00Z', + user_local_date: '2026-04-30', + }); + const state = computeReadState([morningRead], morningRead, '2026-04-30T16:08:00Z', 'NOW_PULSE'); + assert.equal(state.is_first_read_ever, false); + assert.equal(state.is_first_read_today, false); + assert.equal(state.is_continuation, true); + assert.equal(state.same_aperture_continuation, true); + assert.equal(state.cross_aperture_comparison, false); + assert.ok(state.prior_read !== null); + // 14:33 UTC → 16:08 UTC = 95 minutes + assert.ok(Math.abs(state.prior_read!.minutes_elapsed - 95) < 1); + assert.equal(isFirstRead(state), false); +}); + +test('computeReadState detects cross-aperture continuation', () => { + const morningRead = makeEntry({ + timestamp_utc: '2026-04-30T14:33:00Z', + user_local_date: '2026-04-30', + aperture: 'NOW_PULSE', + }); + const state = computeReadState( + [morningRead], + morningRead, + '2026-04-30T16:08:00Z', + 'SYMBOLIC_WEATHER', + ); + assert.equal(state.is_continuation, true); + assert.equal(state.same_aperture_continuation, false); + assert.equal(state.cross_aperture_comparison, true); +}); + +test('computeReadState uses the most recent entry from today reads', () => { + const read1 = makeEntry({ + read_id: 'read_001', + timestamp_utc: '2026-04-30T10:00:00Z', + user_local_date: '2026-04-30', + }); + const read2 = makeEntry({ + read_id: 'read_002', + timestamp_utc: '2026-04-30T14:33:00Z', + user_local_date: '2026-04-30', + }); + // todayReads sorted oldest-first + const state = computeReadState([read1, read2], read2, '2026-04-30T16:08:00Z', 'NOW_PULSE'); + assert.equal(state.prior_read?.read_id, 'read_002'); +}); + +// ───────────────────────────────────────────────────────── +// computeContinuityDiff +// ───────────────────────────────────────────────────────── + +test('computeContinuityDiff identifies tightening orb', () => { + const prior = { + aspects: [{ body1: 'Saturn', body2: 'Sun', aspect_type: 'square', orb: 1.8 }], + moon_sign: 'Gemini', + primary_chamber: 'The Horizon', + }; + const current = { + aspects: [{ body1: 'Saturn', body2: 'Sun', aspect_type: 'square', orb: 0.9 }], + moon_sign: 'Gemini', + primary_chamber: 'The Horizon', + }; + const diff = computeContinuityDiff(current, prior, 95); + assert.equal(diff.tightening.length, 1); + assert.equal(diff.loosening.length, 0); + assert.ok(Math.abs(diff.tightening[0].delta - 0.9) < 0.01); + assert.equal(diff.moon_sign_changed, false); + assert.equal(diff.chamber_shifted, false); +}); + +test('computeContinuityDiff identifies loosening orb', () => { + const prior = { + aspects: [{ body1: 'Venus', body2: 'Pluto', aspect_type: 'trine', orb: 0.3 }], + moon_sign: 'Cancer', + primary_chamber: 'The Gate', + }; + const current = { + aspects: [{ body1: 'Venus', body2: 'Pluto', aspect_type: 'trine', orb: 0.8 }], + moon_sign: 'Cancer', + primary_chamber: 'The Gate', + }; + const diff = computeContinuityDiff(current, prior, 60); + assert.equal(diff.loosening.length, 1); + assert.ok(Math.abs(diff.loosening[0].delta - 0.5) < 0.01); +}); + +test('computeContinuityDiff detects Moon sign change', () => { + const prior = { + aspects: [], + moon_sign: 'Gemini', + primary_chamber: 'The Horizon', + }; + const current = { + aspects: [], + moon_sign: 'Cancer', + primary_chamber: 'The Horizon', + }; + const diff = computeContinuityDiff(current, prior, 90); + assert.equal(diff.moon_sign_changed, true); + assert.equal(diff.moon_sign_from, 'Gemini'); + assert.equal(diff.moon_sign_to, 'Cancer'); +}); + +test('computeContinuityDiff detects new and departed aspects', () => { + const prior = { + aspects: [{ body1: 'Saturn', body2: 'Sun', aspect_type: 'square', orb: 1.8 }], + moon_sign: null, + primary_chamber: null, + }; + const current = { + aspects: [{ body1: 'Mars', body2: 'Mercury', aspect_type: 'opposition', orb: 0.5 }], + moon_sign: null, + primary_chamber: null, + }; + const diff = computeContinuityDiff(current, prior, 95); + assert.equal(diff.new_aspects.length, 1); + assert.equal(diff.departed_aspects.length, 1); + assert.equal(diff.new_aspects[0].body1, 'Mars'); + assert.equal(diff.departed_aspects[0].body1, 'Saturn'); +}); + +// ───────────────────────────────────────────────────────── +// generateContinuityLanguage +// ───────────────────────────────────────────────────────── + +test('generateContinuityLanguage reports "essentially where it was" when field is stable within 30min', () => { + const diff = { + tightening: [], + loosening: [], + stable: [{ body1: 'Saturn', body2: 'Sun', aspect_type: 'square', orb: 1.8 }], + new_aspects: [], + departed_aspects: [], + moon_sign_changed: false, + moon_sign_from: null, + moon_sign_to: null, + chamber_shifted: false, + chamber_from: null, + chamber_to: null, + minutes_elapsed: 15, + }; + const language = generateContinuityLanguage(diff, '2026-04-30T14:33:00Z'); + assert.match(language, /essentially where it was/i); + assert.match(language, /confirmation/i); +}); + +test('generateContinuityLanguage describes tightening when orb has closed', () => { + const diff = { + tightening: [{ aspect: { body1: 'Saturn', body2: 'Sun', aspect_type: 'square', orb: 0.9 }, delta: 0.9 }], + loosening: [], + stable: [], + new_aspects: [], + departed_aspects: [], + moon_sign_changed: false, + moon_sign_from: null, + moon_sign_to: null, + chamber_shifted: false, + chamber_from: null, + chamber_to: null, + minutes_elapsed: 95, + }; + const language = generateContinuityLanguage(diff, '2026-04-30T14:33:00Z'); + assert.match(language, /tightened/i); + assert.match(language, /Saturn/); + assert.match(language, /0\.9 degrees/i); +}); + +// ───────────────────────────────────────────────────────── +// validateReadStateConsistency +// ───────────────────────────────────────────────────────── + +test('validator blocks fabricated continuity on first-ever read', () => { + const proseOutput = ` + Reading this moment — Apr 30, 8:00 AM CDT. + The line has tightened since last check. Saturn still presses. + `; + const state = computeReadState([], null, '2026-04-30T13:00:00Z', 'NOW_PULSE'); + const result = validateReadStateConsistency(proseOutput, state); + assert.equal(result.passes, false); + assert.equal(result.failureType, 'FABRICATED_CONTINUITY_ON_FIRST_READ'); +}); + +test('validator blocks fabricated continuity on first-read-today', () => { + const proseOutput = ` + Reading this moment — Apr 30, 8:17 AM CDT. + Changed since last check: No new signal. + `; + const yesterday = makeEntry({ timestamp_utc: '2026-04-29T14:00:00Z', user_local_date: '2026-04-29' }); + const state = computeReadState([], yesterday, '2026-04-30T13:17:00Z', 'NOW_PULSE'); + const result = validateReadStateConsistency(proseOutput, state); + assert.equal(result.passes, false); + assert.equal(result.failureType, 'FABRICATED_CONTINUITY_ON_FIRST_READ'); +}); + +test('validator passes clean first read prose', () => { + const proseOutput = ` + Reading this moment — Apr 30, 8:00 AM CDT. + A steady line is active. Saturn presses with weight. + The Moon is in Gemini, waxing crescent. + This lands on your Horizon. + `; + const state = computeReadState([], null, '2026-04-30T13:00:00Z', 'NOW_PULSE'); + const result = validateReadStateConsistency(proseOutput, state); + assert.equal(result.passes, true); +}); + +test('validator flags continuation read missing continuity language', () => { + const proseOutput = ` + Reading this moment — Apr 30, 4:08 PM CDT. + A steady line is active. Saturn presses with weight. + The Moon is in Gemini, waxing crescent. + `; + const morningRead = makeEntry({ timestamp_utc: '2026-04-30T14:33:00Z', user_local_date: '2026-04-30' }); + const state = computeReadState([morningRead], morningRead, '2026-04-30T16:08:00Z', 'NOW_PULSE'); + const result = validateReadStateConsistency(proseOutput, state); + assert.equal(result.passes, false); + assert.equal(result.failureType, 'CONTINUATION_READ_MISSING_CONTINUITY_LANGUAGE'); +}); + +test('validator passes continuation read with real continuity language', () => { + const proseOutput = ` + Reading this moment — Apr 30, 4:08 PM CDT. + The line that was steady at 2:33 has tightened. Saturn still presses on the Sun, + but the orb has closed by 0.9 degrees — what was approaching is now closer to exact. + The Moon has moved into Cancer since the last reading, shifting tone. + This still sits on your Horizon. + `; + const morningRead = makeEntry({ timestamp_utc: '2026-04-30T14:33:00Z', user_local_date: '2026-04-30' }); + const state = computeReadState([morningRead], morningRead, '2026-04-30T16:08:00Z', 'NOW_PULSE'); + const result = validateReadStateConsistency(proseOutput, state); + assert.equal(result.passes, true); +}); + +test('validator does not require continuity language when elapsed < 5 minutes', () => { + const recentRead = makeEntry({ timestamp_utc: '2026-04-30T14:33:00Z', user_local_date: '2026-04-30' }); + // Only 3 minutes elapsed + const state = computeReadState( + [recentRead], + recentRead, + '2026-04-30T14:36:00Z', + 'NOW_PULSE', + ); + const proseOutput = ` + Reading this moment — Apr 30, 2:36 PM CDT. + A steady line is active. Saturn presses. + `; + const result = validateReadStateConsistency(proseOutput, state); + assert.equal(result.passes, true); +}); diff --git a/vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts b/vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts index ae238b4d..02789ac9 100644 --- a/vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts +++ b/vessel/src/lib/raven/__tests__/symbolicMomentFrontstage.test.ts @@ -63,6 +63,15 @@ test('buildStructuredSymbolicMomentReply assembles named-storm Zone 1 prose, sea ], }), includeFootnote: true, + // No readState = first read: "Changed since last check" must be absent. + readState: { + is_first_read_ever: true, + is_first_read_today: true, + is_continuation: false, + prior_read: null, + same_aperture_continuation: false, + cross_aperture_comparison: false, + }, }); assert.equal(structured.signalVoid, false); @@ -74,7 +83,9 @@ test('buildStructuredSymbolicMomentReply assembles named-storm Zone 1 prose, sea assert.match(structured.zone1, /\*\*Moon Tone:\*\* unavailable from the current payload\./); assert.doesNotMatch(structured.zone1, /Moon active|present and changing|hour-hand has shifted/i); assert.match(structured.zone1, /This lands in \*\*The Horizon\*\* — travel, study, belief, higher meaning, and distance\./); - assert.match(structured.zone1, /\*\*Changed since last check:\*\* No new signal\./); + // On a first read there is no prior read to compare against. + // The "Changed since last check" block must be ABSENT — it would fabricate continuity. + assert.doesNotMatch(structured.zone1, /\*\*Changed since last check:\*\*/); // Verification is the final prompt. assert.match(structured.zone3 ?? '', /^(?:On the ground, does this resemble|Is this landing as|Does this feel more like)\b/); assert.match(structured.zone3 ?? '', /, or none of these\?$/); @@ -100,6 +111,9 @@ test('buildStructuredSymbolicMomentReply assembles named-storm Zone 1 prose, sea assert.equal(structured.payload?.landingZones[0].chamber, 'The Horizon'); assert.equal(structured.payload?.peakDrivers[0].orb, 0.3); assert.match(structured.zone2?.sealed_hash ?? '', /^[a-f0-9]{64}$/i); + // Zone 2 carries the read state snapshot. + assert.equal(structured.zone2?.read_state?.is_first_read_ever, true); + assert.equal(structured.zone2?.read_state?.is_continuation, false); }); test('buildStructuredSymbolicMomentReply carries plain translation for dense Symbolic Moment drivers', () => { @@ -270,6 +284,23 @@ test('buildStructuredSymbolicMomentReply rewrites technical change labels into h topDrivers: [{ label: 'Venus trine Pluto', orb: 0.3 }], }), previousDelta: 'Current symbolic vector maintains prior telemetry with lunar modulation.', + // Must be a continuation read for the "Changed since last check" block to appear. + readState: { + is_first_read_ever: false, + is_first_read_today: false, + is_continuation: true, + prior_read: { + read_id: 'read_prev', + timestamp_utc: '2026-04-24T08:00:00Z', + aperture: 'NOW_PULSE', + minutes_elapsed: 60, + sealed_geometry_hash: 'prev_hash', + primary_chamber: 'The Horizon', + primary_aspects: [], + }, + same_aperture_continuation: true, + cross_aperture_comparison: false, + }, }); assert.equal(structured.signalVoid, false); @@ -293,6 +324,23 @@ test('buildStructuredSymbolicMomentReply surfaces Moon sign, phase, and stronges feel: 'sorting through what has happened.', }, previousDelta: 'Same signal. New tone.', + // Continuation read so the block is included. + readState: { + is_first_read_ever: false, + is_first_read_today: false, + is_continuation: true, + prior_read: { + read_id: 'read_prev', + timestamp_utc: '2026-04-24T06:00:00Z', + aperture: 'NOW_PULSE', + minutes_elapsed: 120, + sealed_geometry_hash: 'prev_hash', + primary_chamber: 'The Horizon', + primary_aspects: [], + }, + same_aperture_continuation: true, + cross_aperture_comparison: false, + }, }); assert.equal(structured.signalVoid, false); diff --git a/vessel/src/lib/raven/readState.ts b/vessel/src/lib/raven/readState.ts new file mode 100644 index 00000000..b2e67a0b --- /dev/null +++ b/vessel/src/lib/raven/readState.ts @@ -0,0 +1,399 @@ +/** + * Read-State Awareness — Pure domain types and functions. + * + * Tracks whether a read is the user's first ever, the first of today, + * or a continuation within the same day, and computes the structural + * diff between the current geometry and the prior read. + * + * No Firestore I/O here — this module is purely functional so it can + * be tested without infrastructure dependencies. + */ + +import type { TemporalAperture } from './temporalAperture'; + +// ───────────────────────────────────────────────────────── +// History Entry — stored in Firestore via ReadHistory +// ───────────────────────────────────────────────────────── + +export type AspectSnapshot = { + body1: string; + body2: string; + aspect_type: string; + orb: number; +}; + +export type ReadHistoryEntry = { + read_id: string; + user_id: string; + chart_id: string; + timestamp_utc: string; // ISO 8601 + user_local_date: string; // YYYY-MM-DD in user's timezone + aperture: TemporalAperture; + sealed_geometry_hash: string; + primary_chamber: string; + primary_aspects: AspectSnapshot[]; + prose_output_hash: string; +}; + +// ───────────────────────────────────────────────────────── +// Read State — computed before each read +// ───────────────────────────────────────────────────────── + +export type PriorReadContext = { + read_id: string; + timestamp_utc: string; + aperture: TemporalAperture; + minutes_elapsed: number; + sealed_geometry_hash: string; + primary_chamber: string; + primary_aspects: AspectSnapshot[]; +}; + +export type ReadState = { + is_first_read_ever: boolean; + is_first_read_today: boolean; + is_continuation: boolean; + prior_read: PriorReadContext | null; + same_aperture_continuation: boolean; + cross_aperture_comparison: boolean; +}; + +// ───────────────────────────────────────────────────────── +// Continuity Diff — aspect-level delta between reads +// ───────────────────────────────────────────────────────── + +export type AspectChange = { + aspect: AspectSnapshot; + delta: number; // positive = orb narrowed (tightening), negative = orb widened (loosening) +}; + +export type ContinuityDiff = { + tightening: AspectChange[]; + loosening: AspectChange[]; + stable: AspectSnapshot[]; + new_aspects: AspectSnapshot[]; + departed_aspects: AspectSnapshot[]; + moon_sign_changed: boolean; + moon_sign_from: string | null; + moon_sign_to: string | null; + chamber_shifted: boolean; + chamber_from: string | null; + chamber_to: string | null; + minutes_elapsed: number; +}; + +// ───────────────────────────────────────────────────────── +// Validation +// ───────────────────────────────────────────────────────── + +export type ReadStateValidationResult = { + passes: boolean; + failureType?: 'FABRICATED_CONTINUITY_ON_FIRST_READ' | 'CONTINUATION_READ_MISSING_CONTINUITY_LANGUAGE'; +}; + +// ───────────────────────────────────────────────────────── +// computeReadState — pure; takes pre-loaded history slices +// ───────────────────────────────────────────────────────── + +/** + * Derives the ReadState for an upcoming read. + * + * @param todayReads All read history entries for this chart on today's local date, + * sorted oldest-first. + * @param mostRecentRead The single most-recent read entry for this chart across all + * time, or null if no prior reads exist. + * @param currentTimestampUtc ISO 8601 UTC timestamp of the current read. + * @param currentAperture The aperture being requested now. + */ +export function computeReadState( + todayReads: ReadHistoryEntry[], + mostRecentRead: ReadHistoryEntry | null, + currentTimestampUtc: string, + currentAperture: TemporalAperture, +): ReadState { + const isFirstReadEver = mostRecentRead === null; + const isFirstReadToday = todayReads.length === 0; + const isContinuation = !isFirstReadToday; + + if (!isContinuation) { + return { + is_first_read_ever: isFirstReadEver, + is_first_read_today: isFirstReadToday, + is_continuation: false, + prior_read: null, + same_aperture_continuation: false, + cross_aperture_comparison: false, + }; + } + + // Most recent read from today (last entry in the sorted list) + const mostRecentToday = todayReads[todayReads.length - 1]; + const minutesElapsed = + (new Date(currentTimestampUtc).getTime() - new Date(mostRecentToday.timestamp_utc).getTime()) / + (1000 * 60); + + const sameApertureContinuation = mostRecentToday.aperture === currentAperture; + + const priorRead: PriorReadContext = { + read_id: mostRecentToday.read_id, + timestamp_utc: mostRecentToday.timestamp_utc, + aperture: mostRecentToday.aperture, + minutes_elapsed: minutesElapsed, + sealed_geometry_hash: mostRecentToday.sealed_geometry_hash, + primary_chamber: mostRecentToday.primary_chamber, + primary_aspects: mostRecentToday.primary_aspects, + }; + + return { + is_first_read_ever: false, + is_first_read_today: false, + is_continuation: true, + prior_read: priorRead, + same_aperture_continuation: sameApertureContinuation, + cross_aperture_comparison: !sameApertureContinuation, + }; +} + +// ───────────────────────────────────────────────────────── +// computeContinuityDiff — compares aspect snapshots +// ───────────────────────────────────────────────────────── + +type SimpleGeometry = { + aspects: AspectSnapshot[]; + moon_sign?: string | null; + primary_chamber?: string | null; +}; + +function sameAspect(a: AspectSnapshot, b: AspectSnapshot): boolean { + return ( + a.body1.toLowerCase() === b.body1.toLowerCase() && + a.body2.toLowerCase() === b.body2.toLowerCase() && + a.aspect_type.toLowerCase() === b.aspect_type.toLowerCase() + ); +} + +export function computeContinuityDiff( + current: SimpleGeometry, + prior: SimpleGeometry, + minutesElapsed: number, +): ContinuityDiff { + const sharedCurrent = current.aspects.filter((a) => + prior.aspects.some((p) => sameAspect(p, a)), + ); + + const tightening: AspectChange[] = []; + const loosening: AspectChange[] = []; + const stable: AspectSnapshot[] = []; + + for (const currentAspect of sharedCurrent) { + const priorAspect = prior.aspects.find((p) => sameAspect(p, currentAspect)); + if (!priorAspect) continue; + + const orbDelta = priorAspect.orb - currentAspect.orb; // positive = tightening + if (Math.abs(orbDelta) < 0.1) { + stable.push(currentAspect); + } else if (orbDelta > 0) { + tightening.push({ aspect: currentAspect, delta: orbDelta }); + } else { + loosening.push({ aspect: currentAspect, delta: Math.abs(orbDelta) }); + } + } + + const newAspects = current.aspects.filter( + (a) => !prior.aspects.some((p) => sameAspect(p, a)), + ); + + const departedAspects = prior.aspects.filter( + (p) => !current.aspects.some((a) => sameAspect(a, p)), + ); + + const moonSignChanged = + Boolean(current.moon_sign) && + Boolean(prior.moon_sign) && + current.moon_sign !== prior.moon_sign; + + const chamberShifted = + Boolean(current.primary_chamber) && + Boolean(prior.primary_chamber) && + current.primary_chamber !== prior.primary_chamber; + + return { + tightening, + loosening, + stable, + new_aspects: newAspects, + departed_aspects: departedAspects, + moon_sign_changed: moonSignChanged, + moon_sign_from: prior.moon_sign ?? null, + moon_sign_to: current.moon_sign ?? null, + chamber_shifted: chamberShifted, + chamber_from: prior.primary_chamber ?? null, + chamber_to: current.primary_chamber ?? null, + minutes_elapsed: minutesElapsed, + }; +} + +// ───────────────────────────────────────────────────────── +// generateContinuityLanguage — diff → natural prose +// ───────────────────────────────────────────────────────── + +function formatElapsed(minutes: number): string { + if (minutes < 60) return `${Math.round(minutes)} minutes`; + const hours = minutes / 60; + if (hours < 2) return 'about an hour'; + return `${Math.round(hours)} hours`; +} + +function formatPriorTime(isoTimestamp: string): string { + try { + return new Date(isoTimestamp).toLocaleTimeString('en-US', { + hour: 'numeric', + minute: '2-digit', + hour12: true, + timeZone: 'UTC', + }); + } catch { + return 'earlier'; + } +} + +function describeAspect(a: AspectSnapshot): string { + return `${a.body1} ${a.aspect_type} ${a.body2}`; +} + +export function generateContinuityLanguage( + diff: ContinuityDiff, + priorTimestampUtc: string, +): string { + const elapsed = formatElapsed(diff.minutes_elapsed); + const priorTime = formatPriorTime(priorTimestampUtc); + + // Nothing material changed + if ( + diff.tightening.length === 0 && + diff.loosening.length === 0 && + diff.new_aspects.length === 0 && + !diff.moon_sign_changed + ) { + if (diff.minutes_elapsed < 30) { + return `${elapsed} on, the field is essentially where it was. There isn't new news, just confirmation of the line.`; + } + return `The field is steady — what was here ${elapsed} ago is still here.`; + } + + const phrases: string[] = []; + + if (diff.tightening.length > 0) { + const primary = diff.tightening[0]; + phrases.push( + `The line that was steady at ${priorTime} has tightened. ` + + `${primary.aspect.body1} still presses ${primary.aspect.body2}, but the orb has ` + + `closed by ${primary.delta.toFixed(1)} degrees.`, + ); + } else if (diff.loosening.length > 0) { + const primary = diff.loosening[0]; + phrases.push( + `The ${primary.aspect.body1}-${primary.aspect.body2} contact is loosening — ` + + `${primary.delta.toFixed(1)} degrees wider than at ${priorTime}.`, + ); + } + + if (diff.moon_sign_changed && diff.moon_sign_to) { + phrases.push( + `The Moon has moved into ${diff.moon_sign_to} since ${priorTime}, shifting tone.`, + ); + } + + if (diff.new_aspects.length > 0) { + phrases.push(`A new line is forming: ${describeAspect(diff.new_aspects[0])}.`); + } + + if (diff.departed_aspects.length > 0 && phrases.length === 0) { + const d = diff.departed_aspects[0]; + phrases.push( + `The ${d.body1}-${d.body2} contact that was present at ${priorTime} has moved out of range.`, + ); + } + + return phrases.join(' '); +} + +// ───────────────────────────────────────────────────────── +// validateReadStateConsistency — post-generation guard +// ───────────────────────────────────────────────────────── + +const FABRICATED_CONTINUITY_PATTERNS = [ + /since\s+the\s+last\s+(read|reading|check)/i, + /the\s+line\s+(has|was)\s+(tightened|loosened|narrowed|widened)/i, + /changed\s+since\s+last/i, + /(\d+)\s+(minutes?|hours?)\s+(ago|on)/i, + /has\s+moved\s+into/i, +]; + +const CONTINUITY_INDICATOR_PATTERNS = [ + /since/i, + /at\s+\d+:\d+/i, + /earlier/i, + /the\s+line\s+(has|that)/i, + /tightened|loosened|narrowed/i, + /still\s+(holds|sits|presses)/i, +]; + +export function validateReadStateConsistency( + proseOutput: string, + state: ReadState, +): ReadStateValidationResult { + // First reads must NOT fabricate continuity + if (state.is_first_read_ever || state.is_first_read_today) { + for (const pattern of FABRICATED_CONTINUITY_PATTERNS) { + if (pattern.test(proseOutput)) { + return { + passes: false, + failureType: 'FABRICATED_CONTINUITY_ON_FIRST_READ', + }; + } + } + } + + // Continuation reads (same aperture, >5 min elapsed) must reference prior state + if ( + state.is_continuation && + state.same_aperture_continuation && + state.prior_read && + state.prior_read.minutes_elapsed > 5 + ) { + const hasContinuity = CONTINUITY_INDICATOR_PATTERNS.some((p) => + p.test(proseOutput), + ); + if (!hasContinuity) { + return { + passes: false, + failureType: 'CONTINUATION_READ_MISSING_CONTINUITY_LANGUAGE', + }; + } + } + + return { passes: true }; +} + +// ───────────────────────────────────────────────────────── +// isFirstRead — convenience predicate +// ───────────────────────────────────────────────────────── + +/** + * Returns true when the read state represents a first read (ever or today). + * On first reads the "Changed since last check" block must be omitted. + */ +export function isFirstRead(state: ReadState): boolean { + return state.is_first_read_ever || state.is_first_read_today; +} + +/** + * Variant of isFirstRead that defaults to `true` (first-read behavior) + * when no ReadState is available. Use this in validators and other + * downstream code so the "no readState" path is always consistent with + * the composer's default suppression logic. + */ +export function isFirstReadOrDefault(state: ReadState | null | undefined): boolean { + return state != null ? isFirstRead(state) : true; +} diff --git a/vessel/src/lib/raven/symbolicMomentComposer.ts b/vessel/src/lib/raven/symbolicMomentComposer.ts index f5b7f39c..e572fcbe 100644 --- a/vessel/src/lib/raven/symbolicMomentComposer.ts +++ b/vessel/src/lib/raven/symbolicMomentComposer.ts @@ -67,6 +67,7 @@ import { PLANET_CONSEQUENCE, } from './symbolicMomentTranslation'; import type { TemporalAperture, TemporalApertureRange, TemporalApertureSource } from './temporalAperture'; +import { isFirstRead, type ReadState } from './readState'; export type AspectType = | 'conjunction' @@ -118,7 +119,7 @@ export type SymbolicMomentNarrative = { moonTone: string; landingPlace: string; plainMeaning: string; - changeSinceLastCheck: string; + changeSinceLastCheck: string | null; reply: string; zone1: string; zone3: string; @@ -1687,8 +1688,9 @@ export function composeSymbolicMomentNarrative(input: { lunar?: LunarContext | null; location?: LocationContext | null; previousDelta?: string | null; + readState?: ReadState | null; }): SymbolicMomentNarrative { - const { chamber, drivers, primarySignature, lunar, location, previousDelta } = input; + const { chamber, drivers, primarySignature, lunar, location, previousDelta, readState } = input; const loadTier = resolveLoadTier(input.loadScore, input.volatility); // DEPRECATED: Template composition. Use buildSymbolicMomentPayload() + prompt layer instead. @@ -1705,7 +1707,19 @@ export function composeSymbolicMomentNarrative(input: { const moonTone = composeMoonTone(lunar, isRepeat); const landing = composeLanding(chamber); const plainMeaning = stripJargon(composePlainTranslation(drivers, chamber, primarySignature, loadTier)); - const changeSinceLastCheck = normalizeChangeSinceLastCheck(previousDelta); + + // Determine whether to include the "Changed since last check" block. + // On a first read (ever or today) there is no prior read to compare against, + // so fabricating continuity language would be misleading. + // When readState is null and previousDelta is provided, treat as continuation + // for backward compatibility (explicit override path). + const suppressContinuity = readState != null + ? isFirstRead(readState) + : previousDelta == null; + + const changeSinceLastCheck = suppressContinuity + ? null + : normalizeChangeSinceLastCheck(previousDelta); const stamp = location ? `${location.city}${location.state ? `, ${location.state}` : ''} · ${location.time}` : ''; @@ -1716,7 +1730,7 @@ export function composeSymbolicMomentNarrative(input: { `**Plain Meaning:** ${plainMeaning}`, `**Moon Tone:** ${moonTone}`, landing, - `**Changed since last check:** ${changeSinceLastCheck}` + ...(changeSinceLastCheck !== null ? [`**Changed since last check:** ${changeSinceLastCheck}`] : []), ].filter(Boolean); if (input.includeAstrologicalNote) { diff --git a/vessel/src/lib/raven/symbolicMomentFrontstage.ts b/vessel/src/lib/raven/symbolicMomentFrontstage.ts index 56f29e6e..7e0bf991 100644 --- a/vessel/src/lib/raven/symbolicMomentFrontstage.ts +++ b/vessel/src/lib/raven/symbolicMomentFrontstage.ts @@ -26,6 +26,7 @@ import { type TemporalApertureContext, } from './temporalAperture'; import { ASPECT_DEFINITIONS, type V3MathPromptContext } from '../v3MathBrain'; +import { isFirstRead, isFirstReadOrDefault, type ReadState } from './readState'; export type StructuredMomentType = 'transit' | 'solar_return' | 'progression' | 'composite'; @@ -63,6 +64,14 @@ export type SymbolicMomentGeometryClusterEntry = { orb_limit: number; }; +export type SealedReadStateSnapshot = { + is_first_read_ever: boolean; + is_first_read_today: boolean; + is_continuation: boolean; + minutes_since_prior: number | null; + same_aperture_continuation: boolean; +}; + export type SealedSymbolicMomentAudit = { sealed_at_utc: string; aperture: TemporalApertureContext['aperture']; @@ -75,6 +84,7 @@ export type SealedSymbolicMomentAudit = { resonance_state: 'Pending / Unreviewed'; sealed_hash: string; classification: null; + read_state: SealedReadStateSnapshot | null; }; export type SymbolicMomentPreTestimonyValidation = { @@ -802,7 +812,18 @@ function buildSealedAudit(input: { pressureSignatures: PressureSignature[]; momentType: StructuredMomentType; apertureContext: TemporalApertureContext; + readState?: ReadState | null; }): SealedSymbolicMomentAudit { + const readStateSnapshot: SealedReadStateSnapshot | null = input.readState + ? { + is_first_read_ever: input.readState.is_first_read_ever, + is_first_read_today: input.readState.is_first_read_today, + is_continuation: input.readState.is_continuation, + minutes_since_prior: input.readState.prior_read?.minutes_elapsed ?? null, + same_aperture_continuation: input.readState.same_aperture_continuation, + } + : null; + const baseAudit = { sealed_at_utc: new Date().toISOString(), aperture: input.apertureContext.aperture, @@ -814,6 +835,7 @@ function buildSealedAudit(input: { moment_type: input.momentType, resonance_state: 'Pending / Unreviewed' as const, classification: null, + read_state: readStateSnapshot, }; return { @@ -836,8 +858,13 @@ function buildFootnoteSection(drivers: readonly DriverRecord[]): string | null { ].join('\n'); } -export function validateInternalSymbolicMomentStructure(text: string): boolean { - return REQUIRED_STRUCTURAL_PATTERNS.every((pattern) => pattern.test(text)); +export function validateInternalSymbolicMomentStructure(text: string, readState?: ReadState | null): boolean { + // On first reads the "Changed since last check" block must be absent. + // Defaults to first-read behavior when no readState is provided. + const patternsToCheck = isFirstReadOrDefault(readState) + ? REQUIRED_STRUCTURAL_PATTERNS.filter((p) => !p.source.includes('Changed since last check')) + : REQUIRED_STRUCTURAL_PATTERNS; + return patternsToCheck.every((pattern) => pattern.test(text)); } export function validateSymbolicMomentPreTestimony(text: string): SymbolicMomentPreTestimonyValidation { @@ -953,6 +980,7 @@ export function validateSymbolicMomentFrontstageSequence(input: { zone1: string; zone3: string | null; apertureContext?: TemporalApertureContext; + readState?: ReadState | null; }): SymbolicMomentPreTestimonyValidation { const zone1 = input.zone1.trim(); const zone3 = input.zone3?.trim() || ''; @@ -988,7 +1016,12 @@ export function validateSymbolicMomentFrontstageSequence(input: { } const blocks = zone1.split(/\n\s*\n/).map((block) => block.trim()).filter(Boolean); - if (blocks.length < 4) { + + // First reads omit the continuity block, so the minimum block count is lower. + // Defaults to first-read behavior when no readState is provided. + const firstRead = isFirstReadOrDefault(input.readState); + const minBlockCount = firstRead ? 3 : 4; + if (blocks.length < minBlockCount) { return { passes: false, failureType: 'STRUCTURAL_TEMPLATE_VIOLATION' }; } @@ -1006,9 +1039,13 @@ export function validateSymbolicMomentFrontstageSequence(input: { return { passes: false, failureType: 'STRUCTURAL_TEMPLATE_VIOLATION' }; } - const changeBlock = blocks.find((block) => /^\*\*Changed since last check:\*\*/i.test(block)); - if (!changeBlock) { - return { passes: false, failureType: 'STRUCTURAL_TEMPLATE_VIOLATION' }; + // The "Changed since last check" block is required on continuation reads + // and must be absent on first reads (absence of a fabricated block is correct). + if (!firstRead) { + const changeBlock = blocks.find((block) => /^\*\*Changed since last check:\*\*/i.test(block)); + if (!changeBlock) { + return { passes: false, failureType: 'STRUCTURAL_TEMPLATE_VIOLATION' }; + } } if (!ZONE3_ALLOWED_OPENERS.some((pattern) => pattern.test(zone3)) || !zone3.endsWith('?')) { @@ -1037,6 +1074,7 @@ export function buildStructuredSymbolicMomentReply(input: { lunar?: LunarContext | null; location?: { city: string; state?: string; time: string } | null; previousDelta?: string | null; + readState?: ReadState | null; includeFootnote?: boolean; apertureContext?: TemporalApertureContext; }): StructuredSymbolicMomentResult { @@ -1113,6 +1151,7 @@ export function buildStructuredSymbolicMomentReply(input: { lunar, location: input.location, previousDelta: input.previousDelta, + readState: input.readState, }); narrative.reply = ensureApertureDeclaration(narrative.reply, apertureContext); @@ -1124,8 +1163,9 @@ export function buildStructuredSymbolicMomentReply(input: { zone1: narrative.zone1, zone3: narrative.zone3, apertureContext, + readState: input.readState, }); - if (!validateInternalSymbolicMomentStructure(narrative.reply) || !validation.passes || !frontstageSequenceValidation.passes) { + if (!validateInternalSymbolicMomentStructure(narrative.reply, input.readState) || !validation.passes || !frontstageSequenceValidation.passes) { const heldReply = ensureApertureDeclaration(SIGNAL_VOID_REPLY, apertureContext); return { reply: heldReply, @@ -1167,6 +1207,7 @@ export function buildStructuredSymbolicMomentReply(input: { pressureSignatures, momentType: input.momentType ?? 'transit', apertureContext, + readState: input.readState, }); return { diff --git a/vessel/src/lib/server/readHistory.ts b/vessel/src/lib/server/readHistory.ts new file mode 100644 index 00000000..37dfe60f --- /dev/null +++ b/vessel/src/lib/server/readHistory.ts @@ -0,0 +1,115 @@ +/** + * Read History — server-authoritative persistent store for symbolic-moment + * read events, backed by Firestore Admin SDK. + * + * Documents are stored under: + * raven_read_history/{userId_chartId}/{readId} + * + * Indexed queries: + * - Most-recent read for a chart (getMostRecentRead) + * - All reads for a chart on a given local date (getReadsForDate) + */ +import { getFirebaseAdminDb } from '../firebaseAdmin'; +import type { ReadHistoryEntry } from '../raven/readState'; + +const COLLECTION = 'raven_read_history'; + +function partitionId(userId: string, chartId: string): string { + const safeUid = userId.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 128); + const safeChart = chartId.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 128); + return `${safeUid}__${safeChart}`; +} + +function docId(entry: ReadHistoryEntry): string { + const safeId = entry.read_id.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 128); + return safeId; +} + +/** + * Append a new read history entry to Firestore. + * Silently swallows errors — a write failure must never block the read path. + */ +export async function appendRead(entry: ReadHistoryEntry): Promise { + const db = getFirebaseAdminDb(); + if (!db) return; + try { + const partition = partitionId(entry.user_id, entry.chart_id); + await db + .collection(COLLECTION) + .doc(partition) + .collection('entries') + .doc(docId(entry)) + .set(entry); + } catch (err) { + console.warn('[readHistory] appendRead failed', { + userId: entry.user_id.slice(0, 8), + chartId: entry.chart_id.slice(0, 8), + error: err instanceof Error ? err.message : String(err), + }); + } +} + +/** + * Returns the single most-recent read entry for this chart across all time, + * or null if no prior reads exist. + */ +export async function getMostRecentRead( + userId: string, + chartId: string, +): Promise { + const db = getFirebaseAdminDb(); + if (!db) return null; + try { + const partition = partitionId(userId, chartId); + const snap = await db + .collection(COLLECTION) + .doc(partition) + .collection('entries') + .orderBy('timestamp_utc', 'desc') + .limit(1) + .get(); + if (snap.empty) return null; + return snap.docs[0].data() as ReadHistoryEntry; + } catch (err) { + console.warn('[readHistory] getMostRecentRead failed', { + userId: userId.slice(0, 8), + chartId: chartId.slice(0, 8), + error: err instanceof Error ? err.message : String(err), + }); + return null; + } +} + +/** + * Returns all read history entries for this chart on a given local date + * (YYYY-MM-DD in the user's local timezone), sorted oldest-first. + * Returns an empty array on error. + */ +export async function getReadsForDate( + userId: string, + chartId: string, + localDate: string, +): Promise { + const db = getFirebaseAdminDb(); + if (!db) return []; + try { + const partition = partitionId(userId, chartId); + const snap = await db + .collection(COLLECTION) + .doc(partition) + .collection('entries') + .where('user_local_date', '==', localDate) + .orderBy('timestamp_utc', 'asc') + .get(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return snap.docs.map((doc: any) => doc.data() as ReadHistoryEntry); + } catch (err) { + console.warn('[readHistory] getReadsForDate failed', { + userId: userId.slice(0, 8), + chartId: chartId.slice(0, 8), + localDate, + error: err instanceof Error ? err.message : String(err), + }); + return []; + } +}