/**
* insight-layer-d.js
*
* Layer D – Insight Review
* ————————
*
* Purpose:
* Review what progress or development occurred during the completed Insight.
*
* Layer D must NOT:
* – continue the live coaching conversation
* – decide next framework steps
* – extract new evidence from a single turn
* – exaggerate progress
* – invent development
*/

(function () {
‘use strict’;

function clean(value) {
return String(value == null ? ” : value).trim();
}

function buildHeaders(config) {
const headers = { ‘Content-Type’: ‘application/json’ };

if (config.token) headers[‘X-CP-Token’] = config.token;
else if (config.restNonce) headers[‘X-WP-Nonce’] = config.restNonce;

return headers;
}

async function callAiJson(config, payload, fallback) {
try {
const res = await fetch(config.aiUrl, {
method: ‘POST’,
headers: buildHeaders(config),
body: JSON.stringify(payload)
});

if (!res.ok) throw new Error(`Layer D AI error ${res.status}`);

const json = await res.json();
const raw = clean(json.text || json.reply || json.content);
return JSON.parse(raw.replace(/“`json/g, ”).replace(/“`/g, ”).trim());
} catch (err) {
console.log(‘LAYER D JSON ERROR:’, err);
return fallback;
}
}

async function callAiText(config, payload, fallback) {
try {
const res = await fetch(config.aiUrl, {
method: ‘POST’,
headers: buildHeaders(config),
body: JSON.stringify(payload)
});

if (!res.ok) throw new Error(`Layer D AI error ${res.status}`);

const json = await res.json();
return clean(json.text || json.reply || json.content || fallback);
} catch (err) {
console.log(‘LAYER D TEXT ERROR:’, err);
return fallback;
}
}

/**
* D1 – Review Eligibility Assessment
*/
async function assessReviewEligibility(ctx) {
const config = ctx.config || {};

if (!config.aiUrl) {
return {
review_required: false,
development_summary: ”,
reason: ‘No AI endpoint available.’
};
}

const payload = {
model: ‘gpt-4o’,
temperature: 0,
messages: [
{
role: ‘system’,
content:
`You are D1 Review Eligibility Assessment.

Your role:
Decide whether the completed Insight conversation contains enough evidence for a meaningful review.

Return ONLY valid JSON:
{
“review_required”: true|false,
“development_summary”: “…”,
“reason”: “…”
}

Rules:
– Base this only on evidence from the completed Insight.
– A review is justified when there is meaningful awareness, clarity, tension, discovery, trait movement, or development.
– Do not invent progress.
– Do not reward length alone.
– If little meaningful development occurred, set review_required to false.
– Do not write the user-facing review.`
},
{
role: ‘user’,
content:
`COMPLETE INSIGHT CONVERSATION:
${JSON.stringify(ctx.thread || [])}

REFLECTIONS GENERATED:
${JSON.stringify(ctx.reflectionHistory || [])}

TRAIT UPDATE RECOMMENDATIONS:
${JSON.stringify(ctx.traitUpdates || [])}

PREVIOUS INSIGHT REVIEWS:
${JSON.stringify(ctx.previousInsightReviews || [])}

RELEVANT TRAIT HISTORY:
${JSON.stringify(ctx.relevantTraitHistory || [])}

INSIGHT SUMMARY:
${clean(ctx.insightSummary)}`
}
]
};

const parsed = await callAiJson(config, payload, {
review_required: false,
development_summary: ”,
reason: ”
});

return {
review_required: !!parsed.review_required,
development_summary: clean(parsed.development_summary),
reason: clean(parsed.reason)
};
}

/**
* D2 – Review Evidence Selection
*/
async function selectReviewEvidence(ctx, eligibility) {
const config = ctx.config || {};

if (!eligibility.review_required || !config.aiUrl) {
return { selected_evidence: [] };
}

const payload = {
model: ‘gpt-4o’,
temperature: 0,
messages: [
{
role: ‘system’,
content:
`You are D2 Review Evidence Selection.

Your role:
Select the evidence that should be used in the end-of-Insight review.

Return ONLY valid JSON:
{
“selected_evidence”: [
{
“type”: “awareness|clarity|tension|discovery|theme|trait_development”,
“evidence”: “…”,
“quote”: “…”
}
]
}

Rules:
– Select only evidence from the completed Insight.
– Prefer meaningful evidence over quantity.
– Do not include generic or weak material.
– Do not invent themes.
– Do not write the review.`
},
{
role: ‘user’,
content:
`D1 ELIGIBILITY:
${JSON.stringify(eligibility)}

COMPLETE INSIGHT CONVERSATION:
${JSON.stringify(ctx.thread || [])}

REFLECTION HISTORY:
${JSON.stringify(ctx.reflectionHistory || [])}

TRAIT UPDATE RECOMMENDATIONS:
${JSON.stringify(ctx.traitUpdates || [])}`
}
]
};

const parsed = await callAiJson(config, payload, { selected_evidence: [] });

return {
selected_evidence: Array.isArray(parsed.selected_evidence)
? parsed.selected_evidence
: []
};
}

/**
* D3 – Insight Review Writer
*/
async function writeInsightReview(ctx, eligibility, selectedEvidence) {
const config = ctx.config || {};

const fallback = clean(eligibility.development_summary) ||
‘You explored this Insight and shared your perspective on it.’;

if (!config.aiUrl) return fallback;

const payload = {
model: ‘gpt-4o’,
temperature: 0.3,
messages: [
{
role: ‘system’,
content:
`You are D3 Insight Review Writer.

Write the user-facing end-of-Insight review.

Rules:
– Focus primarily on the current Insight.
– Base every observation on selected evidence.
– Do not invent progress.
– Do not exaggerate development.
– Avoid generic encouragement.
– Do not introduce new coaching themes.
– Keep it concise.
– Use UK English.`
},
{
role: ‘user’,
content:
`SELECTED REVIEW EVIDENCE:
${JSON.stringify(selectedEvidence.selected_evidence || [])}

DEVELOPMENT SUMMARY:
${clean(eligibility.development_summary)}

PREVIOUS INSIGHT REVIEWS:
${JSON.stringify(ctx.previousInsightReviews || [])}

RELEVANT TRAIT HISTORY:
${JSON.stringify(ctx.relevantTraitHistory || [])}

INSIGHT SUMMARY:
${clean(ctx.insightSummary)}`
}
]
};

return callAiText(config, payload, fallback);
}

/**
* D4 – Minimal Closing Review
*/
async function writeMinimalClosingReview(ctx, eligibility) {
const config = ctx.config || {};

const fallback =
‘You explored this Insight and shared your perspective on it. While no major shift emerged during this conversation, your responses still help build a clearer picture of how you see this area.’;

if (!config.aiUrl) return fallback;

const payload = {
model: ‘gpt-4o’,
temperature: 0.2,
messages: [
{
role: ‘system’,
content:
`You are D4 Minimal Closing Review Writer.

Write a brief factual closing review when there is not enough evidence for a fuller review.

Rules:
– Do not exaggerate progress.
– Do not imply a major shift occurred.
– Remain factual.
– Keep it concise.
– Use UK English.`
},
{
role: ‘user’,
content:
`D1 ELIGIBILITY:
${JSON.stringify(eligibility)}

INSIGHT SUMMARY:
${clean(ctx.insightSummary)}

COMPLETE INSIGHT CONVERSATION:
${JSON.stringify(ctx.thread || [])}`
}
]
};

return callAiText(config, payload, fallback);
}

/**
* runLayerD()
*/
async function runLayerD(ctx) {
const eligibility = await assessReviewEligibility(ctx);

if (!eligibility.review_required) {
const review = await writeMinimalClosingReview(ctx, eligibility);

return {
review_required: false,
eligibility,
selected_evidence: [],
review,
review_type: ‘minimal’,

debug: {
layer: ‘D’,
decision: ‘D1’,
value: ‘minimal_review’,
reason: eligibility.reason
}
};
}

const selectedEvidence = await selectReviewEvidence(ctx, eligibility);
const review = await writeInsightReview(ctx, eligibility, selectedEvidence);

return {
review_required: true,
eligibility,
selected_evidence: selectedEvidence.selected_evidence || [],
review,
review_type: ‘full’,

debug: {
layer: ‘D’,
decision: ‘D3’,
value: ‘full_review’,
reason: eligibility.reason,
details: [
{
decision: ‘D2’,
value: `${(selectedEvidence.selected_evidence || []).length} evidence item(s) selected`
}
]
}
};
}

window.cpInsightLayerD = {
runLayerD,
assessReviewEligibility,
selectReviewEvidence,
writeInsightReview,
writeMinimalClosingReview
};
})();