/**
* 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
};
})();