Improve audit pipeline and outreach review
This commit is contained in:
@@ -5,6 +5,15 @@ import test from "node:test";
|
||||
|
||||
const actionPath = path.join(process.cwd(), "convex", "auditGenerationAction.ts");
|
||||
const actionSource = existsSync(actionPath) ? readFileSync(actionPath, "utf8") : "";
|
||||
const toneGuidelinesPath = path.join(
|
||||
process.cwd(),
|
||||
"lib",
|
||||
"ai",
|
||||
"customer-tone-guidelines.ts",
|
||||
);
|
||||
const toneGuidelinesSource = existsSync(toneGuidelinesPath)
|
||||
? readFileSync(toneGuidelinesPath, "utf8")
|
||||
: "";
|
||||
const generationSourcePath = path.join(process.cwd(), "convex", "auditGeneration.ts");
|
||||
const generationSource = existsSync(generationSourcePath)
|
||||
? readFileSync(generationSourcePath, "utf8")
|
||||
@@ -129,6 +138,12 @@ test("action starts, queries evidence, and runs stage pipeline", () => {
|
||||
test("action includes all required audit stages", () => {
|
||||
for (const stage of [
|
||||
"classification",
|
||||
"localSeoSpecialist",
|
||||
"conversionUxSpecialist",
|
||||
"visualTrustSpecialist",
|
||||
"critiqueSpecialist",
|
||||
"performanceAccessibilitySpecialist",
|
||||
"evidenceVerifier",
|
||||
"multimodalAudit",
|
||||
"germanCopy",
|
||||
"qualityReview",
|
||||
@@ -142,6 +157,159 @@ test("action includes all required audit stages", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("specialist fan-out runs after evidence input and before German copy", () => {
|
||||
const evidenceInputIndex = actionSource.indexOf("const evidenceInput = buildAuditEvidenceInput");
|
||||
const fanOutIndex = actionSource.indexOf("Promise.all(\n specialistStageConfigs.map");
|
||||
const verifierIndex = actionSource.indexOf('currentStep = "evidenceVerifier"');
|
||||
const germanCopyIndex = actionSource.indexOf('currentStep = "germanCopy"');
|
||||
|
||||
assert.notEqual(evidenceInputIndex, -1, "Action should build evidence input.");
|
||||
assert.notEqual(germanCopyIndex, -1, "Action should still run German copy.");
|
||||
assert.notEqual(fanOutIndex, -1, "Action should fan out specialist stage configs.");
|
||||
assert.notEqual(verifierIndex, -1, "Action should run the evidence verifier.");
|
||||
assert.equal(
|
||||
fanOutIndex > evidenceInputIndex && fanOutIndex < germanCopyIndex,
|
||||
true,
|
||||
"Specialist fan-out should run after evidence input and before German copy.",
|
||||
);
|
||||
assert.equal(
|
||||
verifierIndex > fanOutIndex && verifierIndex < germanCopyIndex,
|
||||
true,
|
||||
"Evidence verifier should run after specialist fan-out and before German copy.",
|
||||
);
|
||||
});
|
||||
|
||||
test("specialist stages use specialist schemas and verified findings feed German copy", () => {
|
||||
assert.equal(
|
||||
hasStageCall("auditSpecialistResultSchema"),
|
||||
true,
|
||||
"Specialist stages should call generateObject with auditSpecialistResultSchema.",
|
||||
);
|
||||
assert.equal(
|
||||
hasStageCall("auditEvidenceVerificationSchema"),
|
||||
true,
|
||||
"Verifier stage should call generateObject with auditEvidenceVerificationSchema.",
|
||||
);
|
||||
assert.match(
|
||||
actionSource,
|
||||
/(?:const|let)\s+verifiedFindings\s*[:=]/,
|
||||
"Action should derive verifiedFindings before synthesis.",
|
||||
);
|
||||
assert.match(
|
||||
actionSource,
|
||||
/verifiedResult?\.?object|verifiedFindingIds/,
|
||||
"Verifier output should use compact finding IDs instead of echoing full findings.",
|
||||
);
|
||||
assert.match(
|
||||
actionSource,
|
||||
/verifiedFindingIds\.has\(candidate\.findingId\)/,
|
||||
"Action should map verifier-approved IDs back to original specialist findings.",
|
||||
);
|
||||
assert.match(
|
||||
actionSource,
|
||||
/buildGermanCopyPrompt\(\s*verifiedFindingsText/,
|
||||
"German copy should be generated from verified findings text.",
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
actionSource,
|
||||
/buildGermanCopyPrompt\(\s*classificationSummary\s*,/,
|
||||
"German copy should no longer use raw classification summary as its primary finding input.",
|
||||
);
|
||||
});
|
||||
|
||||
test("critique specialist translates impeccable critique guidance into the audit fan-out", () => {
|
||||
assert.match(
|
||||
actionSource,
|
||||
/stage:\s*["']critiqueSpecialist["']/,
|
||||
"Action should include a dedicated critique specialist stage.",
|
||||
);
|
||||
assert.match(
|
||||
actionSource,
|
||||
/impeccable-critique/,
|
||||
"Critique specialist should anchor findings to the impeccable critique skill id.",
|
||||
);
|
||||
assert.match(
|
||||
actionSource,
|
||||
/kognitive Last|Nielsen|AI-Slop|Informationsarchitektur/,
|
||||
"Critique specialist should include critique guidance beyond generic visual trust.",
|
||||
);
|
||||
});
|
||||
|
||||
test("German copy prompt uses first-contact email tone guidelines without a new AI stage", () => {
|
||||
const buildPromptSource = extractFunctionSource("buildGermanCopyPrompt");
|
||||
|
||||
assert.doesNotMatch(
|
||||
buildPromptSource,
|
||||
/Ich-Ich Kontext/,
|
||||
"German copy prompt should not force formulaic Ich-Ich copy.",
|
||||
);
|
||||
assert.match(
|
||||
actionSource,
|
||||
/buildCustomerTonePromptSection/,
|
||||
"German copy prompt should inject shared customer tone guidelines.",
|
||||
);
|
||||
assert.match(
|
||||
buildPromptSource,
|
||||
/evidence:\s*AuditEvidence/,
|
||||
"German copy prompt should accept explicit evidence context.",
|
||||
);
|
||||
assert.match(
|
||||
actionSource,
|
||||
/buildGermanCopyPrompt\([\s\S]*verifiedFindingsText[\s\S]*multimodalSummary[\s\S]*evidenceInput[\s\S]*\)/,
|
||||
"German copy prompt should receive the explicit evidence context at the callsite.",
|
||||
);
|
||||
assert.match(
|
||||
toneGuidelinesSource,
|
||||
/kollegial direkt/,
|
||||
"Tone guidelines should lock the selected sender posture.",
|
||||
);
|
||||
assert.match(
|
||||
toneGuidelinesSource,
|
||||
/maximal zwei verifizierte Befunde|max\. zwei verifizierte Befunde/,
|
||||
"Tone guidelines should keep outreach emails to at most two verified findings.",
|
||||
);
|
||||
assert.match(
|
||||
toneGuidelinesSource,
|
||||
/kein Mini-Audit/,
|
||||
"Tone guidelines should explicitly forbid mini-audit emails.",
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
actionSource,
|
||||
/tone(?:Review|Rewrite|Specialist)|emailToneSpecialist|copyToneSpecialist/,
|
||||
"Tone work should not add another model-backed generation stage.",
|
||||
);
|
||||
});
|
||||
|
||||
test("quality review blocks when model review or German copy guard fails", () => {
|
||||
const qualityPromptSource = extractFunctionSource("buildQualityReviewPrompt");
|
||||
|
||||
assert.match(
|
||||
actionSource,
|
||||
/qualityPassed\s*=\s*qualityResult\.object\.isValid\s*&&\s*guardResult\.passed/,
|
||||
"qualityPassed should require both model review validity and German copy guard.",
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
actionSource,
|
||||
/qualityPassed\s*=\s*guardResult\.passed\s*;/,
|
||||
"qualityPassed must not ignore the model quality review.",
|
||||
);
|
||||
assert.match(
|
||||
qualityPromptSource,
|
||||
/echte Erstmail von Matthias/,
|
||||
"Quality review should apply the selected first-contact email rubric.",
|
||||
);
|
||||
assert.match(
|
||||
qualityPromptSource,
|
||||
/KI-Verkaufstext/,
|
||||
"Quality review should reject AI-like sales copy.",
|
||||
);
|
||||
assert.match(
|
||||
qualityPromptSource,
|
||||
/verified findings|verifizierte Befunde/i,
|
||||
"Quality review should keep concrete claims tied to verified findings.",
|
||||
);
|
||||
});
|
||||
|
||||
test("action handles post-start failure paths in action-level catch", () => {
|
||||
assert.equal(
|
||||
hasPattern(
|
||||
@@ -377,18 +545,18 @@ test("action runs german copy guard and blocks outreach-ready on validation fail
|
||||
assert.equal(
|
||||
hasPattern(
|
||||
actionSource,
|
||||
/qualityPassed\s*=\s*guardResult\.passed/,
|
||||
/qualityPassed\s*=\s*qualityResult\.object\.isValid\s*&&\s*guardResult\.passed/,
|
||||
),
|
||||
true,
|
||||
"Only deterministic German copy guard failures should hard-block the audit run.",
|
||||
"Model QA and deterministic German copy guard failures should hard-block the audit run.",
|
||||
);
|
||||
assert.equal(
|
||||
hasPattern(
|
||||
actionSource,
|
||||
/qualityPassed\s*=\s*qualityResult\.object\.isValid\s*&&\s*guardResult\.passed/,
|
||||
/qualityPassed\s*=\s*guardResult\.passed\s*;/,
|
||||
),
|
||||
false,
|
||||
"Subjective model QA warnings should not be combined with guardResult for terminal failure.",
|
||||
"Action must not ignore the model QA validity flag.",
|
||||
);
|
||||
assert.equal(
|
||||
hasPattern(actionSource, /internal\.leads\.reviewUpdateInternal/),
|
||||
|
||||
Reference in New Issue
Block a user