import assert from "node:assert/strict"; import test from "node:test"; import { consultationMethodologyForDomains, markdownSection, METHODOLOGY_SECTION_MAX_CHARS, METHODOLOGY_TOTAL_MAX_CHARS, } from "../src/lib/consultation-methodology.ts"; import { consultationDomainIds } from "../src/lib/consultation-domain-registry.ts"; import { resolveLiveJyotishSkill } from "../src/lib/skill-package-registry.ts"; test("the route's own strict checklist reaches the answer, not just the package listing", () => { const methodology = consultationMethodologyForDomains(["career"]); assert.ok(methodology, "career must resolve a methodology"); const career = methodology.sections.find((section) => section.title.includes("career-timing-strict")); assert.ok(career, "the career strict route must be delivered as its own section"); assert.match(career.source, /strict-workflow-router\.md$/); // The checklist is only useful if the specific instructions arrive with it. assert.match(career.text, /D10/); assert.match(career.text, /Opportunity contact/); assert.ok( methodology.sections.some((section) => section.title.includes("Shared mandatory baseline")), "every route is read against the shared baseline", ); assert.ok( methodology.sections.some((section) => /Full-Spectrum Invocation Contract/.test(section.text)), "the skill's full-spectrum contract must reach the web model", ); assert.deepEqual(methodology.domains_without_strict_checklist, []); }); test("a route the skill declares no checklist for is reported, not filled in with another route's", () => { const methodology = consultationMethodologyForDomains(["education"]); assert.ok(methodology); assert.deepEqual(methodology.domains_without_strict_checklist, ["education"]); assert.ok( !methodology.sections.some((section) => section.title.includes("timing-strict") || section.title.includes("verification-strict")), "no strict section may be substituted for a route that has none", ); assert.ok( methodology.sections.some((section) => section.title.includes("Shared mandatory baseline")), "the baseline still applies", ); assert.ok( methodology.sections.some((section) => section.title.includes("Full-spectrum")), "full-spectrum invocation still applies when a domain has no named checklist", ); }); test("health uses the skill's health-timing-strict checklist", () => { const methodology = consultationMethodologyForDomains(["health"]); assert.ok(methodology); assert.deepEqual(methodology.domains_without_strict_checklist, []); const health = methodology.sections.find((section) => section.title.includes("health-timing-strict")); assert.ok(health); assert.match(health.text, /D6/); assert.match(health.text, /D30/); }); test("a multi-domain plan carries every executed route's checklist once", () => { const methodology = consultationMethodologyForDomains(["career", "timing", "career"]); assert.ok(methodology); const titles = methodology.sections.map((section) => section.title); assert.equal(titles.filter((title) => title.includes("career-timing-strict")).length, 1); assert.equal(titles.filter((title) => title.includes("event-timing-strict")).length, 1); }); test("no plan can spend the answer's context on method", () => { for (const domain of consultationDomainIds) { const methodology = consultationMethodologyForDomains([domain]); assert.ok(methodology, `${domain} must resolve`); const total = methodology.sections.reduce((sum, section) => sum + section.text.length, 0); assert.ok( total <= METHODOLOGY_TOTAL_MAX_CHARS, `${domain} delivered ${total} chars, over the ${METHODOLOGY_TOTAL_MAX_CHARS} budget`, ); for (const section of methodology.sections) { assert.ok(section.text.length <= METHODOLOGY_SECTION_MAX_CHARS); } } }); test("the widest legal plan still fits the budget", () => { const methodology = consultationMethodologyForDomains(["career", "marriage", "wealth", "timing"]); assert.ok(methodology); const total = methodology.sections.reduce((sum, section) => sum + section.text.length, 0); assert.ok(total <= METHODOLOGY_TOTAL_MAX_CHARS, `delivered ${total} chars`); }); test("further reading offers the references the skill names, and only ones that exist", () => { const methodology = consultationMethodologyForDomains(["career"]); assert.ok(methodology); assert.ok(methodology.further_reading.length > 0, "the skill names references worth reading"); assert.ok( methodology.further_reading.includes("references/strict-workflow-router.md"), "the router the skill points at must be reachable on purpose", ); for (const path of methodology.further_reading) { assert.match(path, /^references\//); assert.ok(!path.includes(".."), "no path may escape the package"); } assert.ok( methodology.further_reading.length < 100, "the index exists to replace the package listing, not to reproduce it", ); }); test("the delivered method is quoted from the live skill tree", () => { const methodology = consultationMethodologyForDomains(["career"]); assert.ok(methodology); assert.equal(methodology.skill, "jyotish-vedic-astrology"); assert.equal(methodology.version, resolveLiveJyotishSkill().version); assert.equal(methodology.version.includes("/"), false); }); test("a section is found by heading text so the router may be renumbered", () => { const source = [ "# Doc", "## 3. `career-timing-strict`", "body one", "## 4. next", "body two", ].join("\n"); const section = markdownSection(source, "career-timing-strict"); assert.ok(section); assert.match(section, /body one/); assert.ok(!section.includes("body two"), "a section stops at the next heading"); assert.equal(markdownSection(source, "absent-route"), null); });