-
Notifications
You must be signed in to change notification settings - Fork 0
Update .gitignore and Complete Code Review #278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: codex/review-and-refactor-chatclient-component
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ node_modules/ | |
| .DS_Store | ||
|
|
||
| # Logs | ||
| *.log | ||
| npm-debug.log* | ||
| yarn-debug.log* | ||
| yarn-error.log* | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,148 @@ | ||||||||||||||||||||||||||||||||||||||||||
| // src/math_brain/service.ts | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||
| * @module mathBrainService | ||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||
| * This service is responsible for orchestrating the fetching and processing of | ||||||||||||||||||||||||||||||||||||||||||
| * astrological chart data. It acts as a replacement for the monolithic | ||||||||||||||||||||||||||||||||||||||||||
| * `lib/server/astrology-mathbrain.js` file, providing a modern, testable, | ||||||||||||||||||||||||||||||||||||||||||
| * and maintainable interface for the Math Brain v2 system. | ||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||
| normalizeSubjectData, | ||||||||||||||||||||||||||||||||||||||||||
| validateSubject, | ||||||||||||||||||||||||||||||||||||||||||
| buildHeaders, | ||||||||||||||||||||||||||||||||||||||||||
| fetchNatalChartComplete, | ||||||||||||||||||||||||||||||||||||||||||
| getTransits, | ||||||||||||||||||||||||||||||||||||||||||
| calculateSeismograph, | ||||||||||||||||||||||||||||||||||||||||||
| computeComposite, | ||||||||||||||||||||||||||||||||||||||||||
| } from './utils'; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| interface ChartDataPayload { | ||||||||||||||||||||||||||||||||||||||||||
| [key: string]: any; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| interface ChartDataResult { | ||||||||||||||||||||||||||||||||||||||||||
| success: boolean; | ||||||||||||||||||||||||||||||||||||||||||
| provenance: any; | ||||||||||||||||||||||||||||||||||||||||||
| person_a: any; | ||||||||||||||||||||||||||||||||||||||||||
| person_b?: any; | ||||||||||||||||||||||||||||||||||||||||||
| synastry?: any; | ||||||||||||||||||||||||||||||||||||||||||
| composite?: any; | ||||||||||||||||||||||||||||||||||||||||||
| woven_map?: any; | ||||||||||||||||||||||||||||||||||||||||||
| relationship_context?: any; | ||||||||||||||||||||||||||||||||||||||||||
| transitsByDate?: any; | ||||||||||||||||||||||||||||||||||||||||||
| [key: string]: any; // Allow other properties to match monolith's output | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| class MathBrainService { | ||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||
| * Fetches and processes all necessary astrological data for a given request payload. | ||||||||||||||||||||||||||||||||||||||||||
| * This is the primary entry point for the service. | ||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||
| * @param {ChartDataPayload} rawPayload - The raw request body from the API route. | ||||||||||||||||||||||||||||||||||||||||||
| * @returns {Promise<ChartDataResult>} The processed chart data, ready for the v2 orchestrator. | ||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||
| public async fetch(rawPayload: ChartDataPayload): Promise<ChartDataResult> { | ||||||||||||||||||||||||||||||||||||||||||
| const personA = normalizeSubjectData(rawPayload.personA || {}); | ||||||||||||||||||||||||||||||||||||||||||
| const validation = validateSubject(personA); | ||||||||||||||||||||||||||||||||||||||||||
| if (!validation.isValid) { | ||||||||||||||||||||||||||||||||||||||||||
| throw new Error(`Primary subject validation failed: ${validation.message}`); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const headers = buildHeaders(); | ||||||||||||||||||||||||||||||||||||||||||
| const pass = {}; | ||||||||||||||||||||||||||||||||||||||||||
| [ | ||||||||||||||||||||||||||||||||||||||||||
| 'active_points', 'active_aspects', 'houses_system_identifier', | ||||||||||||||||||||||||||||||||||||||||||
| 'sidereal_mode', 'perspective_type', 'wheel_only', 'wheel_format', | ||||||||||||||||||||||||||||||||||||||||||
| 'theme', 'language' | ||||||||||||||||||||||||||||||||||||||||||
| ].forEach((key) => { | ||||||||||||||||||||||||||||||||||||||||||
| if (rawPayload[key] !== undefined) pass[key] = rawPayload[key]; | ||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const personANatal = await fetchNatalChartComplete( | ||||||||||||||||||||||||||||||||||||||||||
| personA, | ||||||||||||||||||||||||||||||||||||||||||
| headers, | ||||||||||||||||||||||||||||||||||||||||||
| pass, | ||||||||||||||||||||||||||||||||||||||||||
| 'person_a', | ||||||||||||||||||||||||||||||||||||||||||
| rawPayload.mode || 'standard' | ||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const result: ChartDataResult = { | ||||||||||||||||||||||||||||||||||||||||||
| success: true, | ||||||||||||||||||||||||||||||||||||||||||
| provenance: {}, | ||||||||||||||||||||||||||||||||||||||||||
| person_a: { | ||||||||||||||||||||||||||||||||||||||||||
| details: personANatal.details, | ||||||||||||||||||||||||||||||||||||||||||
| chart: personANatal.chart, | ||||||||||||||||||||||||||||||||||||||||||
| aspects: personANatal.aspects, | ||||||||||||||||||||||||||||||||||||||||||
| assets: personANatal.assets || [], | ||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const win = rawPayload.window || null; | ||||||||||||||||||||||||||||||||||||||||||
| const start = win?.start; | ||||||||||||||||||||||||||||||||||||||||||
| const end = win?.end; | ||||||||||||||||||||||||||||||||||||||||||
| const step = win?.step || 'daily'; | ||||||||||||||||||||||||||||||||||||||||||
| const haveRange = Boolean(start && end); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (haveRange) { | ||||||||||||||||||||||||||||||||||||||||||
| const { transitsByDate, retroFlagsByDate, provenanceByDate } = await getTransits( | ||||||||||||||||||||||||||||||||||||||||||
| personA, | ||||||||||||||||||||||||||||||||||||||||||
| { startDate: start, endDate: end, step: step }, | ||||||||||||||||||||||||||||||||||||||||||
| headers, | ||||||||||||||||||||||||||||||||||||||||||
| pass | ||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||
| const seismographData = calculateSeismograph(transitsByDate, retroFlagsByDate, { | ||||||||||||||||||||||||||||||||||||||||||
| orbsProfile: rawPayload.orbs_profile || 'wm-tight-2025-11-v5' | ||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||
| result.person_a.chart.transitsByDate = seismographData.daily; | ||||||||||||||||||||||||||||||||||||||||||
| result.person_a.chart.provenanceByDate = provenanceByDate; | ||||||||||||||||||||||||||||||||||||||||||
| result.person_a.derived = { | ||||||||||||||||||||||||||||||||||||||||||
| seismograph_summary: seismographData.summary, | ||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| const hasPersonB = rawPayload.personB && Object.keys(rawPayload.personB).length > 0; | ||||||||||||||||||||||||||||||||||||||||||
| const mode = rawPayload.mode || ''; | ||||||||||||||||||||||||||||||||||||||||||
| const isSynastry = mode.includes('SYNASTRY'); | ||||||||||||||||||||||||||||||||||||||||||
| const isComposite = mode.includes('COMPOSITE'); | ||||||||||||||||||||||||||||||||||||||||||
| const isRelational = isSynastry || isComposite || hasPersonB; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (isRelational) { | ||||||||||||||||||||||||||||||||||||||||||
| if (!hasPersonB) { | ||||||||||||||||||||||||||||||||||||||||||
| throw new Error('Relational report requested but personB is missing.'); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| const personB = normalizeSubjectData(rawPayload.personB); | ||||||||||||||||||||||||||||||||||||||||||
| const validationB = validateSubject(personB); | ||||||||||||||||||||||||||||||||||||||||||
| if (!validationB.isValid) { | ||||||||||||||||||||||||||||||||||||||||||
| throw new Error(`Secondary subject validation failed: ${validationB.message}`); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| const personBNatal = await fetchNatalChartComplete( | ||||||||||||||||||||||||||||||||||||||||||
| personB, | ||||||||||||||||||||||||||||||||||||||||||
| headers, | ||||||||||||||||||||||||||||||||||||||||||
| pass, | ||||||||||||||||||||||||||||||||||||||||||
| 'person_b', | ||||||||||||||||||||||||||||||||||||||||||
| mode | ||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||
| result.person_b = { | ||||||||||||||||||||||||||||||||||||||||||
| details: personBNatal.details, | ||||||||||||||||||||||||||||||||||||||||||
| chart: personBNatal.chart, | ||||||||||||||||||||||||||||||||||||||||||
| aspects: personBNatal.aspects, | ||||||||||||||||||||||||||||||||||||||||||
| assets: personBNatal.assets || [], | ||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||
| if (isComposite) { | ||||||||||||||||||||||||||||||||||||||||||
| const composite = await computeComposite(personA, personB, pass, headers); | ||||||||||||||||||||||||||||||||||||||||||
| result.composite = { | ||||||||||||||||||||||||||||||||||||||||||
| aspects: composite.aspects, | ||||||||||||||||||||||||||||||||||||||||||
| data: composite.raw, | ||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
| }; | |
| }; | |
| // If a transit window is provided, compute composite transits and seismograph | |
| if (rawPayload.transitWindow) { | |
| // getTransits expects a chart and a window; composite.raw is the chart data | |
| const compositeTransits = await getTransits( | |
| composite.raw, | |
| rawPayload.transitWindow, | |
| headers, | |
| pass | |
| ); | |
| // calculateSeismograph expects a natal chart and a set of transits | |
| const compositeSeismograph = calculateSeismograph( | |
| composite.raw, | |
| compositeTransits | |
| ); | |
| result.composite.transits = compositeTransits; | |
| result.composite.seismograph = compositeSeismograph; | |
| } |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing synastry aspects calculation in the service. The original monolith handler computed synastry aspects when isSynastry is true, but this implementation only fetches natal charts for both subjects without computing the cross-chart aspects. This will result in incomplete data for synastry reports.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing handling for Person B transits in relational modes. When
isSynastryorisCompositeis true and transits are requested, the service should also compute transits for Person B, not just Person A. The original monolith computed transits for both subjects in synastry/composite transit modes.