import { ActivityType, DepthLevel, BloomLevel, PlanConstraints, TranslationPolicy, CurriculumPlan, PlanningGraph, PlanningNode, DependencyEdge, ConceptSpiralEncounter, SessionZpdStatus, PrerequisiteDecision, UnitPlan, WalkingSkeleton, MasteryGate, ConceptPrerequisiteEdge, LoTimeEstimate, PlanValidationResult, SessionPlan, LessonPlan, DiagnosticQuizInput, ActivityLab, SlideDeck, CodeLab, DiagnosticQuiz, LearningObjectiveRow, ActivitySeqRow, ResourceMapRow, ArtifactContractRow } from './schemas/index.js'; export { ActionableRepairAction, ActionableRepairActionSchema, ActionableRepairPrompt, ActionableRepairPromptSchema, ActiveLearningWorkflow, ActiveLearningWorkflowSchema, ActivityLabSchema, ActivitySeqRowSchema, ActivityStepSchema, ActivityTypeSchema, ArtifactContractRowSchema, AssessmentMapRow, AssessmentMapRowSchema, AssessmentObjective, AssessmentObjectiveSchema, BellRinger, BellRingerDay, BellRingerDaySchema, BellRingerInput, BellRingerSchema, BloomLevelSchema, BronzeTier, BronzeTierSchema, CERConclusion, CERConclusionSchema, CardTierEnum, ChoiceBoard, ChoiceBoardInput, ChoiceBoardRubricRowSchema, ChoiceBoardSchema, ChoiceRuleSchema, ChoiceSquare, ChoiceSquareSchema, CodeLabSchema, CodeSnippet, CodeSnippetSchema, CompetencyRubricRow, CompetencyRubricRowSchema, ComputationalThinking, ComputationalThinkingSchema, ConceptPrerequisiteEdgeSchema, ConceptSpiralEncounterSchema, CoreConcept, CoreConceptSchema, CourseObjective, CourseObjectiveSchema, CoverageReport, CoverageReportSchema, CurriculumArtifact, CurriculumArtifactSchema, CurriculumPlanSchema, CurriculumQualityReport, CurriculumQualityReportSchema, DependencyEdgeSchema, DepthAssignment, DepthAssignmentSchema, DepthLevelSchema, DiagnosticQuestion, DiagnosticQuestionInput, DiagnosticQuestionSchema, DiagnosticQuizSchema, EDPPhaseEnum, EntryLevelSchema, ExitTicket, ExitTicketBugHunt, ExitTicketBugHuntSchema, ExitTicketMetacognitionSchema, ExitTicketQuickItemSchema, ExitTicketRecallPromptSchema, ExitTicketSchema, ExperimentalDesignSchema, Extension, ExtensionChallengeSchema, ExtensionSchema, FiveEFlowPhaseSchema, FiveEPhaseEnum, Glossary, GlossaryInput, GlossaryQuickRefRowSchema, GlossarySchema, GlossaryTerm, GlossaryTermSchema, GoldTier, GoldTierSchema, GraphicOrganizer, GraphicOrganizerInput, GraphicOrganizerItem, GraphicOrganizerItemSchema, GraphicOrganizerSchema, Handout, HandoutSchema, HandoutSection, HandoutSectionSchema, InstructionSection, InstructionSectionSchema, InstructionStep, InstructionStepSchema, JudgeCriterion, JudgeCriterionSchema, LabTierTask, LabTierTaskSchema, LearningObjectiveInput, LearningObjectiveInputSchema, LearningObjectiveRowSchema, LessonFlowPhase, LessonFlowPhaseSchema, LessonPlan5E, LessonPlan5ESchema, LessonPlanEDP, LessonPlanEDPSchema, LessonPlanSchema, LessonSectionSchema, LoTimeEstimateSchema, MacroPedagogyPlanAuditReport, MacroPedagogyPlanAuditSchema, MarpSlide, MarpSlideSchema, MasteryGateSchema, MentorCheatsheetSchema, MilestoneInput, MilestoneInputSchema, Misconception, MisconceptionSchema, NodeKindSchema, OrganizerTypeEnum, PackedEntry, PackedEntrySchema, PhaseInput, PhaseInputSchema, PlanConstraintsSchema, PlanValidationIssue, PlanValidationIssueSchema, PlanValidationResultSchema, PlannerInput, PlannerInputSchema, PlanningGraphSchema, PlanningNodeSchema, PlanningPhase, PrerequisiteDecisionEntry, PrerequisiteDecisionEntrySchema, PrerequisiteDecisionSchema, ProductGoalSchema, ProgressiveHints, ProgressiveHintsSchema, ProjectGraph, ProjectGraphAuditReport, ProjectGraphAuditSchema, ProjectGraphSchema, ProjectInstruction, ProjectInstructionSchema, ProjectProfile, ProjectProfileSchema, ProjectRoadmap, QualityAuditVerdict, QualityAuditVerdictSchema, QuizOption, QuizOptionSchema, ResourceMapRowSchema, ReviewGame, ReviewGameExportRowSchema, ReviewGameInput, ReviewGameQuestion, ReviewGameQuestionSchema, ReviewGameSchema, RoadmapInput, RoadmapInputSchema, RotationStation, RotationStationSchema, Rubric, RubricCriteria, RubricCriteriaSchema, RubricSchema, ScaffoldDecision, ScaffoldDecisionEntry, ScaffoldDecisionEntrySchema, ScaffoldDecisionSchema, ScienceLab, ScienceLabInput, ScienceLabSchema, ScoringRubricRowSchema, SelfLab, SelfLabSchema, SelfPacedBundle, SelfPacedBundleSchema, SelfPacedChallenge, SelfPacedChallengeSchema, SessionPlanSchema, SessionZpdStatusSchema, SilverTier, SilverTierSchema, SlideDeckSchema, StandardizedTermRowSchema, StationRecordRowSchema, StationRotation, StationRotationInput, StationRotationSchema, StationTypeEnum, TaskCard, TaskCardSchema, TaskCards, TaskCardsInput, TaskCardsSchema, TeacherGuide, TeacherGuideSchema, TeachingScriptPhase, TeachingScriptPhaseSchema, TierLevelEnum, TierObjectiveSchema, TieredPractice, TieredPracticeSchema, TranslationPolicySchema, TroubleshootingEntry, TroubleshootingEntrySchema, TroubleshootingRow, TroubleshootingRowSchema, UnitPlanSchema, UserJourneySchema, WalkingSkeletonSchema, Worksheet, WorksheetItem, WorksheetItemSchema, WorksheetItemTypeEnum, WorksheetPart, WorksheetPartSchema, WorksheetSchema, ZpdVerdict, ZpdVerdictSchema, validateCurriculumPlan } from './schemas/index.js'; import { A as AIProviderName, M as ModelResolutionOptions } from './provider-factory-Bv-eIkhg.js'; export { N as NVIDIA_MODELS, g as getAIModel } from './provider-factory-Bv-eIkhg.js'; export { ActivityPromptInput, AsyncLLMJudgeInput, AuditCurriculumPlanInput, AuditCurriculumQualityInput, AuditProjectGraphInput, CodeLabPromptInput, CurriculumPlanJudgePromptInput, DEFAULT_ENABLED_PROVIDERS, DiagnosticQuizPromptInput, ExtensionPromptInput, GenerateActivityInput, GenerateCodeLabInput, GenerateDiagnosticQuizInput, GenerateExtensionInput, GenerateHandoutInput, GenerateLessonMasterInput, GenerateProjectInstructionInput, GenerateSelfLabInput, GenerateSlidesInput, GenerateTeacherGuideInput, GenerateWorksheetInput, HandoutPromptInput, HtmlDeckSlidePromptInput, JudgeEvaluationResult, JudgePromptInput, LLMJudgeEngine, LessonPromptInput, MarpMarkdownSlidePromptInput, ModelPolicyResolution, ModelPolicyResolver, ModelProviderKey, MultiProviderPolicyResolution, ProjectGraphJudgePromptInput, ProjectInstructionPromptInput, SLIDE_CANONICAL_METHODOLOGY, SelfLabPromptInput, SlidesPromptInput, StreamDiagnosticQuizInput, StreamLessonMasterInput, StreamSelfLabInput, TeacherGuidePromptInput, WorksheetPromptInput, activityTools, analystTools, assessorTools, auditCurriculumPlanFlow, auditCurriculumQualityFlow, auditProjectGraphFlow, buildActivityPrompt, buildCodeLabPrompt, buildCurriculumPlanJudgePrompt, buildDiagnosticQuizPrompt, buildExtensionPrompt, buildHandoutPrompt, buildHtmlDeckSlidePrompt, buildJudgePrompt, buildLessonMasterPrompt, buildMarpMarkdownSlidePrompt, buildProjectGraphJudgePrompt, buildProjectInstructionPrompt, buildSelfLabPrompt, buildSlidesPrompt, buildTeacherGuidePrompt, buildWorksheetPrompt, contentTools, designerTools, generateActivityFlow, generateCodeLabFlow, generateDiagnosticQuizFlow, generateExtensionFlow, generateHandoutFlow, generateLessonMasterFlow, generateProjectInstructionFlow, generateSelfLabFlow, generateSlidesFlow, generateTeacherGuideFlow, generateWorksheetFlow, illustratorTools, packagerTools, researcherTools, reviewerTools, streamCurriculumAIInferenceWithTools, streamDiagnosticQuizFlow, streamLessonMasterFlow, streamSelfLabFlow, techSmeTools } from './ai/index.js'; import { S as StreamRunnerOptions, C as ChunkType } from './streamRunner-BzlJrAGZ.js'; export { A as AggregatedToolCall, a as ChatMessage, D as DEFAULT_ARTIFACT_STREAM_IDLE_MS, d as DEFAULT_ARTIFACT_STREAM_TOTAL_MS, F as FallbackTarget, I as IdleAbort, f as StreamAbortController, T as ToolDefinition, l as ToolExecutionResult, m as ToolExecutor, n as ToolLoopConfig, j as createIdleAbortController, h as createStreamAbortController, e as extractThoughtAndContent, g as getDesignatedFallbackChain, c as getDesignatedFallbackConfig, b as isModelAllowed, i as isProviderEnabled, r as resolveApiKey, k as runCurriculumAIInference, s as streamCurriculumAIInference } from './streamRunner-BzlJrAGZ.js'; export { ArtifactLintReport, ConvertedSotBundle, GenerateProjectInstructionOptions, GenerateRoadmapCurriculumOptions, GenerateSelfPacedBundleInput, LintIssue, ProjectInstructionResult, RoadmapCurriculumOutput, SelfPacedBundleOutput, convertRoadmapToFoundationSot, generateProjectInstruction, generateRoadmapCurriculum, generateSelfPacedBundle, importRoadmapToProject, lintAndSanitizeArtifact, serializeActivityToMarkdown, serializeCodeLabToMarkdown, serializeDiagnosticQuizToMarkdown, serializeHandoutToMarkdown, serializeLessonToMarkdown, serializeProjectInstructionToMarkdown, serializeSelfLabToMarkdown, validateMarkdownTables, validateMermaidSyntax } from './pipeline/index.js'; export { A as AutoRepairOptions, a as AutoRepairResult, B as BundleTier, G as GenerateMilestoneBundleOptions, M as MilestoneCurriculumBundle, g as generateMilestoneCurriculumBundle, w as withAutoRepair } from './milestoneBundleGenerator-EHPiS8b9.js'; import { I as ICurriculumStorage, P as ProjectStatusReport, S as SmartResumeContext, Q as QualityAuditReport } from './types-Bgk-C4K2.js'; export { b as ArtifactLifecycleInfo, A as ArtifactLifecycleState, L as LessonArtifactSummary, c as PipelineState, R as ReviewRecord, a as SotDocument, T as TaskLifecycleState } from './types-Bgk-C4K2.js'; export { FileSystemCurriculumAdapter, FileSystemStorageOptions, STANDARD_SOT_FILES, StorageFactoryOptions, SupabaseCurriculumAdapter, SupabaseStorageConfig, atomicWriteFileSync, computeContentHash, createCurriculumStorage } from './storage/index.js'; import { F as FrameworkPack, C as CoverageGateReport } from './standardsCoverageGate-49pJq5t8.js'; export { B as BloomHintSchema, a as ClassificationSchema, m as CoverageGateInput, h as FrameworkMapping, d as FrameworkMappingSchema, f as FrameworkPackManifest, b as FrameworkPackManifestSchema, e as FrameworkPackSchema, g as FrameworkStatement, c as FrameworkStatementSchema, G as GradeBandSchema, i as MappingKind, M as MappingKindSchema, P as PackLintIssue, k as PackValidationResult, j as RecordProvenance, R as RecordProvenanceSchema, S as StatementCoverageRow, n as evaluateStandardsCoverage, l as lintFrameworkPack, v as validateFrameworkPack } from './standardsCoverageGate-49pJq5t8.js'; import { R as ResolvedGateSettings } from './gateSettings-CKYr5CyX.js'; export { A as ArtifactType, e as AssembledPromptResult, B as BoundaryPeek, b as CurriculumArtifactType, C as CurriculumGateMode, j as CurriculumHorizon, D as DEFAULT_GATE_SETTINGS, i as DetailedLessonBridge, E as ExtractCurriculumHorizonOptions, G as GateSettings, H as HorizonSessionSnapshot, k as HorizonValidationResult, P as PromptSlotBreakdown, c as ScaffoldingLevel, S as SingleArtifactRequest, a as SingleArtifactResult, f as assembleSingleArtifactPrompt, m as extractCurriculumHorizon, g as gateModeFor, h as generateSingleArtifact, d as getArtifactMetadata, l as parseAllSessions, p as parseGateSettings, n as renderHorizonPromptBlock, r as resolveGateSettings, v as validateHorizonCompliance } from './gateSettings-CKYr5CyX.js'; import { z } from 'zod'; export { DeliveryPackResult, JobManifest, LocalWorkspaceManager, ParsedQuizQuestion, buildDeliveryPackages, exportAllProjectQuizzes, formatQuizzesToCsv, parseQuizMarkdown } from './publishers/index.js'; export { G as GitPublishOptions, a as GitPublishResult, S as SupabasePublishOptions, b as SupabasePublishResult, p as publishToGitHub, c as publishToSupabase, u as uploadAssetToBucket } from './supabasePublisher-C627qXFT.js'; import { Root, Node } from 'mdast'; export { BUNDLED_STANDARDS_PACK_IDS, HydratedPack, ImportPackResult, STANDARD_REF_REGEX, SelectedStatement, StandardStackOptions, StandardsRegistryAdapter, StandardsRegistryConfig, StandardsSelectionInput, buildStandardStackMarkdown, buildStandardsContext, buildStandardsContextBlock, extractStandardRefs, findStandardStatement, resolveStandardsPacks, selectStatementsForLesson } from './standards/index.js'; export { AutoFulfillMediaOptions, AutoFulfillMediaResult, CurateOptions, CurationDecision, FulfillOptions, FulfillResult, GenCandidate, GenRanking, GenerateImageOptions, GeneratedImage, MediaError, MediaLedger, MediaLedgerEntry, MediaLedgerMode, MediaLedgerStatus, MediaPolicy, MediaPolicyMode, MediaProvider, SearchImageOptions, SearchVideoOptions, StockImage, StockVideo, autoFulfillArtifactMedia, buildImagePrompt, curateMediaLedger, fulfillMediaLedger, fulfillSlideImageSlots, generateEducationalImage, injectMediaIntoMarkdown, rankGenCandidates, renderMediaPlaceholder, searchEducationalImages, searchEducationalVideos, searchPixabayImages, searchStockImage } from './media/index.js'; import 'ai'; import '@supabase/supabase-js'; /** * Universal Pedagogical Constants & Empirical Classroom Standards * Single Source of Truth for Curriculum Planning, Linters, and LLM-as-Judge Evaluators. */ /** * Student Friction Multiplier (Empirical Classroom Constant): * Senior engineers write code roughly 2.5x to 3.5x faster than students. * A 10-minute expert coding task requires ~25-35 minutes for a student in a classroom setting * due to typing, syntax errors, typos, and debugging. */ declare const STUDENT_FRICTION_MULTIPLIER = 2.5; /** * Vygotsky Zone of Proximal Development (ZPD) Saturation Thresholds: * Maximum number of completely new conceptual primitives allowed in a single session. * @deprecated Prefer SESSION_COGNITIVE_BUDGET_* with LO type weights (ADR-0007). */ declare const MAX_NEW_CONCEPTS_PER_SESSION_K12 = 2; declare const MAX_NEW_CONCEPTS_PER_SESSION_ADULT = 3; /** * Cognitive Load Budget by LO Type Weights (ADR-0007): * Replaces the blunt MAX_NEW_CONCEPTS_PER_SESSION count with a weighted budget * based on the abstraction level (Marr's Tri-Level & Skemp Relational vs Instrumental). * - ULO (Universal / Relational - Why): Highest cognitive abstraction -> 3 pts * - CIO (Algorithmic / Conceptual - How): Intermediate algorithmic design -> 2 pts * - SIO (Implementational / Syntax - Action): Concrete syntax / step -> 1 pt * - Default / Unspecified LO: Safe fallback weight -> 2 pts */ declare const WEIGHT_ULO = 3; declare const WEIGHT_CIO = 2; declare const WEIGHT_SIO = 1; declare const DEFAULT_LO_WEIGHT = 2; /** * Maximum cognitive load budget points allowed in a single session: * - K-12: 10 points (e.g., 1 ULO + 1 CIO + 5 SIOs = 10 pts, or 2 ULOs + 2 CIOs = 10 pts) * - Adult: 15 points (higher cognitive bandwidth and prior schemata) * - Beginner First Session: 3 points (stricter cap for Day 1 setup & toolchain overhead) */ declare const SESSION_COGNITIVE_BUDGET_K12 = 10; declare const SESSION_COGNITIVE_BUDGET_ADULT = 15; declare const FIRST_SESSION_COGNITIVE_BUDGET_BEGINNER = 3; /** * Age-band granularity gate (2026-09-19, regen7/8 semantic audit): * the FIRST teaching session for BEGINNER courses must introduce at most * ONE new concept — session 1 also carries environment setup, and L01 * historically crammed 9 language tokens + toolchain beside its concepts * (regen7 L01: 6 keywords). Adults are exempt (they metabolize setup + * concept in one sitting). */ declare const FIRST_SESSION_MAX_NEW_CONCEPTS_BEGINNER = 1; /** * Language-exposure ceiling (noisy PROXY, evidence for the judge — never a * hard gate): max NEW language tokens per session. var/let/Int/String are * one concept family; counting them as separate concepts breaks cognition * checks, but unbounded vocab dumps still overload beginners (regen7 L01: * 9 tokens on day 1). */ declare const MAX_NEW_KEYWORDS_PER_SESSION_K12 = 6; /** * Standard Classroom Overhead Ratio: * 15% of total session duration is strictly reserved for setup, attendance, * questions, transitions, and hardware teardown. */ declare const DEFAULT_OVERHEAD_RATIO = 0.15; /** * Maximum In-Session Setup Minutes: * The maximum time a student should spend on toolchain/environment configuration * during the first working session before achieving their first running "Hello World". */ declare const MAX_IN_SESSION_SETUP_MINUTES = 15; /** * Session-Cut Tolerance (P52/T2.2): * When the content budget is reached, the packer searches for the nearest * user-visible checkpoint (node with a non-empty user_visible_deliverable) * within ±15% of the session's content budget before falling back to a raw * minute cut. Motivation: a session that ends mid-step without anything to * show kills momentum (P52 plan, Gap 2). */ declare const SESSION_CUT_TOLERANCE = 0.15; /** * 3-Tier Environment Provisioning Models for Complex or Heavy Technology Stacks: * - PRE_INSTALLED_LAB: Environment/IDE/DB is imaged or pre-configured by IT/Lab technician before class. * - CLOUD_MANAGED: Cloud instance (Supabase, Neon, Codespaces, Wokwi) with pre-provisioned connection strings. * - DEDICATED_SETUP: A dedicated full session specifically budgeted for guided local environment setup. */ declare const ENVIRONMENT_PROVISIONING_MODELS: readonly ["PRE_INSTALLED_LAB", "CLOUD_MANAGED", "DEDICATED_SETUP"]; type EnvironmentProvisioningModel = (typeof ENVIRONMENT_PROVISIONING_MODELS)[number]; /** * Autonomous Evaluation Thresholds: */ declare const JUDGE_AUTO_APPROVE_THRESHOLD = 85; declare const JUDGE_ESCALATE_THRESHOLD = 70; declare const MAX_AUTONOMOUS_REPAIR_TURNS = 3; /** * Activity Time Catalog — SEED VALUES for the LO time-estimation model. * * Source of every number: docs/ideas/2026-10-09-lo-time-estimation-models.md * (§2 unit minutes, §3 Bloom floors, §4 bundle example, §5 baseline v0) in the * learning-artifact-gen-ui repo. ALL values are seeds awaiting calibration at * plan gate TC6 (bias < 15%, P75 coverage ≥ 75% against real lesson data). * Every constant carries its idea line as provenance — recalibrate HERE, in * one file, when L2/L3 data arrives; do not scatter coefficients. */ /** Three-point minute range (optimistic / likely / pessimistic). */ interface ThreePoint { readonly o: number; readonly m: number; readonly p: number; } /** * Per-unit minute ranges by measurable quantity (idea §2). * Keys describe the QUANTITY unit, not the ActivityType — one type may be * measurable in several units (read: words; instruction: slides). */ declare const ACTIVITY_UNIT_MINUTES: { /** 120–180 wpm reading-to-learn → minutes per 100 words (100/180, 100/150, 100/120). */ readonly read_per_100_words: { readonly o: 0.56; readonly m: 0.67; readonly p: 0.83; }; /** ~130 wpm lecture; concept slides 1–2 min each (idea §2) → per slide. */ readonly instruction_per_slide: { readonly o: 1; readonly m: 1.5; readonly p: 2; }; /** Expert time for ONE guided/independent practice item; multiply by STUDENT_FRICTION_MULTIPLIER (2.5 guided / 3.0 independent) at use site. */ readonly practice_per_item_expert: { readonly o: 1.5; readonly m: 2; readonly p: 2.5; }; /** Multiple-choice recall question (idea §2). */ readonly quiz_mcq_per_question: { readonly o: 0.75; readonly m: 1; readonly p: 1.5; }; /** Short-answer recall question (idea §2). */ readonly quiz_short_per_question: { readonly o: 2; readonly m: 2.5; readonly p: 3; }; /** Fixed discussion/reflection block (idea §2: 3–5 min). */ readonly discuss_fixed: { readonly o: 3; readonly m: 4; readonly p: 5; }; }; /** * Age pacing factor (idea §5 baseline `Age_Pacing`; bundle model applies it to * instruction/transition activities only — never multiplied across the whole * LO). Band rule uses the band's MAX age: <13 → 1.5, 13–17 → 1.2, ≥18 → 1.0. * SEED — idea §1 keeps the old draft's 1.5/1.2/1.0 as starting values. */ declare function agePacing(ageBand?: readonly [number, number]): number; /** One entry of a bundle template: quantity × unit three-point minutes. */ interface BundleEntrySeed extends ThreePoint { type: ActivityType; quantity: number; /** Practice role — lets authored SIO counts override the independent-practice quantity. */ role?: 'guided' | 'independent'; } /** * Standard activity bundle per depth level (idea §4 table). * adult band (age pacing 1.0) reproduces the idea rows exactly: * ulo {12,15,20} · cio {18,22,30} · sio {28,35,45} → total {58,72,95}. * (Idea §4 states total "55–95" while its own rows sum to 58 — a ±3 seed * rounding inconsistency in the idea doc; rows are the pinned values.) */ declare const BUNDLE_BASE: Record; /** * Bloom-floor overlay entries appended when the base bundle lacks a required * activity group (idea §3 minimum-activity rules). SEED minutes. */ declare const FLOOR_OVERLAY: Record<'practice' | 'project', BundleEntrySeed>; /** * Bloom tier → required activity-type GROUPS (each group = at least one type * from the group must be present). Idea §3. Analyze/Evaluate reuse the * practice floor: their "case/compare-critique" task is authorable as either * 'code' or 'discuss' — ceiling: type alone cannot tell a case task from a * plain drill; upgrade path = carry an activity role on bundle entries. */ declare function bloomFloorGroups(bloom: BloomLevel): ActivityType[][]; /** Map a Bloom level to the bundle floor tier used by the overlay. */ declare function bloomTier(bloom: BloomLevel): 'basic' | 'practice' | 'project'; /** * Baseline v0 — `Base_Time × LO_Type_Weight × Bloom_Weight × Age_Pacing`, * kept ONLY for A/B comparison (idea §5). Weights are reconstructed so the * three published example results are reproduced exactly (pinned by test): * CIO·Understand = 12 · SIO·Apply = 18 · ULO·Create = 54 (adult band). * SEED — not the primary model. */ declare const BASELINE_V0: { base_time: number; lo_weight: { readonly ulo: 1.5; readonly cio: 1; readonly sio: 0.75; }; bloom_weight: { readonly Remember: 0.5; readonly Understand: 1; readonly Apply: 2; readonly Analyze: 2.5; readonly Evaluate: 2.75; readonly Create: 3; }; }; /** * Expected-error band per estimation level (idea "Ước lượng nhiều mức" table): * L0 ±50% · L1 ±30% · L2 ±15% · L3 ±5–10%. Used to build three-point ranges * when only a single point estimate exists (fallback / activity-count paths). */ declare const EXPECTED_ERROR_BANDS: Record<'L0' | 'L1' | 'L2' | 'L3', ThreePoint>; /** * Service to generate high-level status, readiness reports, and resume guidance. */ declare function getProjectStatusReport(storage: ICurriculumStorage, projectId: string): Promise; declare function getSmartResumeContext(storage: ICurriculumStorage, projectId: string): Promise; /** * Dynamically resolves the required artifact scope from SOT (PROJECT_BRIEF.md or CURRICULUM_FRAMEWORK.md) */ declare function getProjectArtifactScope(storage: ICurriculumStorage, projectId: string): Promise; declare function auditQualityReport(storage: ICurriculumStorage, projectId: string): Promise; interface BuildContextOptions { activeArtifactRelPath?: string; maxContentChars?: number; } /** * Builds the complete Ground Truth curriculum context for LLM prompt ingestion. */ declare function buildCurriculumContext(storage: ICurriculumStorage, projectId: string, options?: BuildContextOptions): Promise; /** * SOT Artifact Ownership Taxonomy (kit 1.5.71) * ═════════════════════════════════════════════ * Single source of truth for WHICH artifact owns WHICH information, enforcing * the uni-directional information flow principle from the 2026-09-30 SOT audit * handover: the merged SOT set must paint ONE complete picture with ZERO * overlap — every fact lives in exactly one artifact. * * Three enforcement layers consume this module: * 1. Templates — docs/refs/templates/*_template.md carry the same ownership * headers, so the LLM sees the boundary while filling them. * 2. Prompts — buildSelectiveContext already scopes survey data per role; * prompts now also quote the ownership line from here. * 3. Linter — lintSotBoundaries() scans generated artifacts for content * that belongs to ANOTHER artifact's exclusive fields. */ /** * Actual generation order (measured in sotGeneratorService.ts): * Phase 1 (Foundation, @analyst/@researcher): LEARNER_PROFILE → PROJECT_BRIEF → REFERENCE_PACK * Phase 1.5 (deterministic): STANDARD_STACK * Phase 2 (Architecture, @designer): CURRICULUM_FRAMEWORK → CONTENT_STYLE_GUIDE → ART_DIRECTION * Phase 3: ALIGNMENT_MATRIX * Downstream artifacts READ upstream ones (generatePhase2SotArtifacts reads * the Phase-1 files) — information flows strictly DOWN this list. */ declare const SOT_GENERATION_ORDER: SotArtifactId[]; type SotArtifactId = 'LEARNER_PROFILE' | 'PROJECT_BRIEF' | 'REFERENCE_PACK' | 'CURRICULUM_FRAMEWORK' | 'CONTENT_STYLE_GUIDE' | 'ART_DIRECTION' | 'STANDARD_STACK' | 'ALIGNMENT_MATRIX'; /** Information domains and the ONE artifact that owns each. */ interface OwnershipRule { /** Stable domain key (referenced by linter findings). */ domain: string; /** Human-readable label used in prompts/template headers. */ label: string; /** The single artifact allowed to state facts in this domain. */ owner: SotArtifactId; /** Exclusive field/section names of the owner (its signature content). */ ownerMarkers: string[]; /** * Regexes that detect the domain's content LEAKING into another artifact. * Keep them high-precision: a match is a boundary violation, not a mention. */ leakPatterns: RegExp[]; /** Why this boundary exists (surfaced in linter findings). */ rationale: string; } declare const SOT_OWNERSHIP: OwnershipRule[]; interface SotBoundaryFinding { artifact: SotArtifactId; /** The artifact that legitimately owns the leaked content. */ owner: SotArtifactId; domain: string; line: number; excerpt: string; rationale: string; } /** * Lint ONE generated SOT artifact against the ownership taxonomy. Everything * it owns is exempt; a hit on an exclusive domain of ANOTHER artifact is a * boundary violation with a fix hint. */ declare function lintSotBoundaries(artifact: SotArtifactId, markdown: string): SotBoundaryFinding[]; /** * Order-aware boundary header for prompts + templates. Beyond domain ownership * it states the GENERATION ORDER rule: an artifact may CONSUME upstream facts * (they were its inputs) but must NOT re-state them as its own content — the * merged SOT set must read as one picture where each fact appears exactly once, * in the artifact that owns it. */ declare function ownershipHeader(artifact: SotArtifactId): string; /** AI options (customInference gateway etc.) threaded into every SOT inference call. */ type SotAiOptions = { aiOptions?: StreamRunnerOptions; }; interface ProjectBriefingData { projectName?: string; topic?: string; context?: string; language?: string; targetAge?: string; targetAgeTier?: string; courseDuration?: string; courseDurationTier?: string; hardwarePlatform?: string | string[]; hardwareReadiness?: string; pedagogy?: string; depth?: string; capstoneTheme?: string; exitVision?: string; primaryGoal?: string; valueAndCertification?: string; budgetAndHardwareBOM?: string; cognitiveScaffolding?: string; differentiationStrategy?: string; assessmentStrategy?: string; academicBenchmark?: string; /** Adopted Framework Packs (Standards Registry) — STANDARD_STACK.md is rendered deterministically from these. */ standardsPacks?: FrameworkPack[]; brandingAndTone?: string; recommendedToolchain?: string; artifactScope?: string[]; specialRequirements?: string; [key: string]: any; } /** * Semantic delivery environment — declared by the survey wizard * (HardwareReadinessTier: 'none_budget' | 'lab_ready' | 'sim_only' | 'custom'), * NOT inferred from keywords. Replaces the removed regex heuristic * `isPhysicalHardware` which misclassified any 'tech' course that didn't list * an exclusion keyword (Swift → forced embedded pinouts, 2026-09-30 audit). * 'custom' keeps the user's own hardware string as the source of truth — a * custom Mac Mini is a workstation, not an MCU, so physical pinout guidance * only fires when the custom string itself names embedded-class hardware. */ type DeliveryEnvironment = 'software_only' | 'embedded_hardware' | 'workstation_computer'; declare function resolveDeliveryEnvironment(briefing: ProjectBriefingData): DeliveryEnvironment; /** * Selective survey-context per artifact role (replaces the monolithic briefContext * that injected all 27 survey fields into every Phase-1 prompt). Each artifact gets * only the fields its template owns — the boundary fix from the 2026-09-30 SOT audit: * LEARNER_PROFILE no longer sees logistics fields it used to copy verbatim, and * PROJECT_BRIEF no longer sees psychological-profile fields. */ type SotArtifactType = 'LEARNER_PROFILE' | 'PROJECT_BRIEF' | 'REFERENCE_PACK'; declare function buildSelectiveContext(briefing: ProjectBriefingData, projectId: string, artifactType: SotArtifactType): string; /** * Helper to load Markdown Template from docs/refs/templates * * Path resolution must work in THREE layouts (kit 1.5.70): * 1. Dev — src/services/ → ../../docs/refs/templates * 2. Bundled — dist/index.cjs (esbuild, __dirname = dist/) → ../docs/refs/templates * (../../ would ESCAPE the npm package root — measured live: * every SOT template resolved to '' in the app container) * 3. npm copies — dist/templates/ (copy-templates script) as a final fallback * Previously also hardcoded /Users/tonypham dev-machine paths (removed) and * relied on process.cwd() in a container (=/app, nothing there). */ declare function loadSotTemplate(templateFileName: string): string; /** * Boundary linter hook (kit 1.5.72): runs the ownership taxonomy against a * freshly generated SOT artifact and reports violations via onProgress. * OBSERVATIONAL by design — findings do not block the pipeline yet; they make * the zero-overlap contract VISIBLE (and the /playground Prompt X-Ray will * surface them per-artifact) before we decide on a hard gate. */ declare function reportSotBoundaries(projectId: string, artifact: SotArtifactId, markdown: string, onProgress?: (agent: string, step: string) => void): void; /** * Service to generate Phase 1 Foundation SOT artifacts (@analyst & @researcher) from Brief input. */ declare function generatePhase1SotArtifacts(storage: ICurriculumStorage, projectId: string, briefing: ProjectBriefingData & SotAiOptions, onProgress?: (agent: string, step: string) => void): Promise<{ learnerProfile: string; projectBrief: string; referencePack: string; standardStack?: string; }>; /** * Parses markdown into discrete structured sections (H2 boundaries) as a JSON dictionary. * Does NOT truncate or slice content — preserves 100% of each section's data. */ declare function parseMarkdownToSections(markdown: string): Record; /** * Selectively extracts specified sections by keyword from a markdown document without ANY budget limitation or truncation. * Preserves 100% of the content within the selected sections. */ declare function extractSotSections(markdown: string, targetKeywords: string[]): string; /** * Service to generate Phase 2 Architecture SOT artifacts (@designer) from approved Foundation. */ declare function generatePhase2SotArtifacts(storage: ICurriculumStorage, projectId: string, briefing: ProjectBriefingData & SotAiOptions, onProgress?: (agent: string, step: string) => void): Promise<{ framework: string; styleGuide: string; artDirection: string; projectStatus: string; }>; /** * 🛠️ Framework Linter — hợp đồng "1 buổi = 1 dòng đầy đủ" cho CURRICULUM_FRAMEWORK.md * * Framework là SOT của toàn bộ pipeline production: nếu framework thiếu objective/deliverable/prerequisite * cho từng buổi, MỌI LESSON phía sau sinh sai. Linter này chạy NGAY SAU khi sinh framework * (0 token, deterministic) và trả findings để caller retry có mục tiêu hoặc cảnh báo rõ ràng. */ interface FrameworkLintFinding { code: string; severity: 'CRITICAL' | 'MAJOR' | 'MINOR'; message: string; } interface FrameworkLintReport { passed: boolean; score: number; totalLessons: number; findings: FrameworkLintFinding[]; summary: string; } /** * Trích các dòng dữ liệu từ bảng Scope & Sequence (bỏ header + separator). * Nhận diện bảng theo header chứa cả "Lesson Code" và "Learning Objective". */ declare function extractScopeSequenceRows(framework: string): { headerFound: boolean; rows: string[][]; }; declare function lintCurriculumFramework(framework: string, expectedSessions?: number): FrameworkLintReport; interface ExcerptOptions { /** * Canonical (English) section keys to prioritize, in order. * Each key's body is included before moving to the next priority. */ priorities?: string[]; /** Character budget for the excerpt (default 12_000, ~3k tokens). */ budget?: number; /** File name or artifact type hint (e.g. 'LESSON', 'KNOWLEDGE_EXPOSITION'). */ artifactType?: string; /** * Source file name (e.g. `LESSON_U03_M01_L06.md`) — artifact type derived * from it when `artifactType` is not given. Matches the web app's builder * option so both call-sites share one contract. */ fileName?: string; /** Min chars below which the excerpt is flagged as insufficient (default 400). */ minContentChars?: number; /** * Whole-section selection mode (RC 2026-09-30): when true, ONLY the priority * sections are eligible — canonical/unmatched leftovers are NOT appended * under leftover budget. Used by per-artifact SOT selection (e.g. SLIDE * takes exactly style-guide §2/3/4/7/8) so non-selected sections never * dilute the prompt. Default false keeps the historical append behavior. */ exclusive?: boolean; } interface ExcerptResult { /** Excerpt markdown safe to inject into prompt context blocks. */ excerpt: string; /** True when the source parsed cleanly, passed sufficiency checks, and resolved priorities. */ verified: boolean; /** True when canonical section resolution matched at least one priority section. */ sectionAware: boolean; /** Canonical section keys included in the excerpt, in order. */ includedSections: string[]; /** Warning or error flags explaining why verified === false. */ issues: string[]; /** Approximate token count (chars / 4). */ tokenEstimate: number; } /** * Semantic keys, không phải heading. Trước 2026-10-03 bảng này viết bằng * heading tiếng Anh và chỉ khớp được vì `findCanonicalFuzzy` trả về đúng dạng * đó; bảng đó bị xoá thì bảng này không còn resolve gì — `parse:no-priority- * resolution` và `verified: false`. */ declare const DEFAULT_LESSON_PRIORITIES: string[]; /** * Priorities for the canonical-lesson excerpt injected into SATELLITE artifact * contexts (ACT, QUIZ, SLIDE, ...). Excludes 'Symbol & Identifier Ledger' — * the symbol registry is injected as its own dedicated block * ([MANDATORY CODE SYMBOL REGISTRY]) to avoid duplicated ground truth. * * Derived from the registry default (semantic keys) so excerpt priority has a * SINGLE source of truth. This list used to be a private literal set of English * headings that could silently drift away from the registry specs the AST * projection uses. */ declare const SATELLITE_LESSON_PRIORITIES: string[]; /** * Không một bảng ưu tiên lesson nào trong kit được phép chứa parent key * 'lessonDesignPlan'. Guard ở lesson-slot-priority-overlap.test.ts chỉ bắt * được parent CHUNG VỚI lá của nó trong cùng danh sách; một danh sách chỉ chứa * parent (như bảng cũ ở trên) lọt qua. Đây là hệ quả đo được trên bài thật. */ declare const DEFAULT_KX_PRIORITIES: string[]; declare function buildSectionAwareExcerpt(markdown: string, opts?: ExcerptOptions): ExcerptResult; declare function buildExpositionExcerpt(markdown: string, opts?: ExcerptOptions): ExcerptResult; declare function buildLessonExcerpt(markdown: string, opts?: ExcerptOptions): ExcerptResult; /** * Tìm ưu tiên viết dạng HEADING trong mã nguồn — `['Key Terms', 'A. Lesson Design Plan']`. * * Ưu tiên phải là semantic key (`keyTerms`, `lessonDesignPlan`). Trước 2.0.22 còn * một bảng heading thứ hai nên heading-form vẫn khớp được và lỗi này im lặng; * sau 2.0.22 nó biến thành `verified: false` → caller rơi vào fallback cắt cụt. * Lỗi đã xảy ra ở chính repo này VÀ ở app (lib/sot/graph-tasks.ts) — app gọi * builder qua `@thanh01.pmt/curriculum-kit` nên phải dùng chung một luật kiểm, * không tự viết lần hai. * * Trả về danh sách chuỗi vi phạm; chuỗi rỗng = sạch. */ declare function findHeadingFormPriorities(source: string): string[]; /** * Extracts code symbol & identifier contracts from LESSON markdown. * Provides deterministic symbol names (Primary Struct/Class, Entry File, Key Functions) * so all satellite agents (@activity, @illustrator, @assessor) inherit them verbatim. */ interface SymbolLedgerResult { primarySymbol?: string; entryFileName?: string; keySymbols: string[]; rawBlock: string; } declare function extractSymbolLedger(lessonMarkdown: string): SymbolLedgerResult; type ContextRoutingMode = 'legacy' | 'hybrid'; interface SatContextResult { /** Full context string to pass as the satellite prompt's user context. */ context: string; /** Context blocks with provenance, for execution-history telemetry. */ blocks: Array<{ slot: string; source: string; chars: number; verified: boolean; issues: string[]; }>; /** Aggregate — mirrors ExcerptResult semantics for the composite. */ verified: boolean; sectionAware: boolean; issues: string[]; /** Composite token estimate (chars/4). */ tokenEstimate: number; /** * The lesson-derived canonical excerpt THIS artifact type actually consumed * (scoped lesson excerpt for LESSON-primary types, the activity-contract * mini-slot for KX-only types, the full 12k excerpt in legacy mode). The * satellite judge uses it as the drift-comparison ground truth (P49 G3). */ canonicalExcerpt?: string; } interface SatelliteContextInput { /** Artifact type (ACT, QUIZ, SLIDE, GUIDE, HANDOUT, WKS, CODE, EXT, EXIT_TICKET). */ artifactType: string; /** * Common context assembled by produceSingleLesson (framework, style guide, ref pack, session slice, standards, guardrails). * In hybrid mode pass the KX-FREE composite (assembleCommonContext(sg, false)): * the scoped per-type KX excerpt below becomes the single canonical-knowledge * block, so KX is never injected twice. */ commonContext: string; /** Canonical LESSON markdown. */ lessonContent: string; /** Pre-built full lesson excerpt (SATELLITE_LESSON_PRIORITIES, 12k) — reused for LESSON-primary types when no per-type override needed. */ lessonExcerpt: ExcerptResult; /** KX markdown — the source for the per-type scoped KX excerpt (hybrid mode). */ expositionContent: string; /** Symbol ledger block already rendered by the caller (appended to LESSON-primary and CODE contexts). */ symbolLedgerBlock: string; /** Pedagogy label for the legacy composite heading (byte-compat with pre-P49). */ pedagogyLabel?: string; /** 'legacy' = old one-size-fits-all satelliteContext (default). 'hybrid' = per-type slots. */ mode?: ContextRoutingMode; } /** * Extract ONLY the Activity Sequence rows whose Artifact Contract column * assigns work to this artifact (fuzzy match on the last column), plus the * table header. Bounded to `maxChars`; keeps first rows (sequence order). * Returns '' when no row matches (caller falls back to nothing — the KX * excerpt still carries the concept; the prompt text already demands * alignment with the lesson's hands-on task). */ declare function extractActivityContractRows(lessonContent: string, artifactType: string, maxChars?: number): string; /** * Extract the B-flow tiered scaffolding block (Bronze/Silver/Gold) for * CODE/EXT — the plan's differentiation is often boilerplate (P49 G0), the * LESSON flow tiers are the real per-lesson task ladder. */ declare function extractTieredScaffoldingBlock(lessonContent: string, maxChars?: number): string; /** * Extract the LESSON 'Assessment Map' subsection (H3 inside 'A. Lesson Design * Plan') for QUIZ/WKS — the H2-level excerpt builder cannot select it * directly. Mirrors the heading-capture pattern of extractTieredScaffoldingBlock. */ declare function extractAssessmentMap(lessonContent: string, maxChars?: number): string; /** * Build the satellite context for one artifact type. * Returns the legacy composite when mode === 'legacy' (byte-identical to the * pre-P49 behaviour) so the flag can shadow-compare safely. */ declare function buildSatelliteContext(input: SatelliteContextInput): SatContextResult; declare function isActivityAlignmentLogOnly(now?: Date): boolean; interface ActivityAlignmentResult { checked: boolean; passed: boolean | null; matchedTokens: string[]; missingTokens: string[]; /** 'log_only' until the shadow window closes, then 'enforcing'. */ mode: 'log_only' | 'enforcing'; } declare function evaluateActivityAlignment(canonicalExcerpt: string | undefined, generatedContent: string, now?: Date): ActivityAlignmentResult; /** * P52/P53 — Runtime artifact-template loading (single source of truth). * * Restores the curriculum-mcp architecture that was lost when prompt * skeletons were retyped as hardcoded strings inside * `lessonProductionService.ts` (the "mandated duplication" regression): * - artifact structure lives in template .md files, loaded at RUNTIME; * - methodology directives stay in the prompt-builder; * - project-local `_templates/` may override any template (MCP parity). * * P53 rev3 (echo model): a template file = YAML frontmatter (system-owned * cached echo: `template_language`, `template_required_sections`) + fill-in * body. The BODY headings are the single source of structure — the * frontmatter list is regenerated mechanically (assembleTranslatedTemplate / * editor save), never hand-maintained. * * Heading standard (H1–H3 only; H4+ do not exist): * - every heading is REQUIRED by default → the `[REQUIRED]` marker is * stripped everywhere (bundled + baked + generated artifacts); * - `[OPTIONAL]` → still a heading, but excluded from the echo/contract; * - `[CONDITIONAL]` → required echo + exposed as semantic metadata; * - a heading containing a VARIABLE part (`{{placeholder}}` or bracket * `[guidance]`) is not a section at all — it is an instance/guidance * header (Q1, Challenge 1, Term Name, phase timing) → excluded from the * echo. Static durations belong on a `**Duration:**` line under the * heading, never inside it. */ interface ResolvedTemplate { /** Fill-in body (frontmatter + leading HTML comments stripped). */ content: string; /** * P53 rev3 — mechanical echo of the template BODY headings (H2/H3, static * text only, `[OPTIONAL]` excluded, markers/ordinals stripped). This IS the * contract; the frontmatter list is just its cached copy. */ sections: string[]; /** Headings explicitly marked `[OPTIONAL]` (excluded from `sections`). */ optionalSections: string[]; /** Absolute path the template was loaded from (telemetry / debugging). */ sourcePath: string; /** * P53 — canonical sections carrying a `[CONDITIONAL]` marker in the body. */ conditionals: string[]; /** * P53 — declared authoring language of the template body * (`template_language:` frontmatter, default "en"). "en" = bundled source; * anything else = translated project copy (bake-aware regime downstream). */ declaredLang: string; } /** * Strip YAML frontmatter from a template document. * NOTE: HTML comments are intentionally preserved — some templates embed * semantic markers (e.g. ACT's ``) that downstream * extraction pipelines depend on. Only frontmatter is noise here. */ declare function stripTemplateFrontmatter(raw: string): string; /** * Legacy reader for the `template_required_sections:` YAML list (the cached * echo). Kept for app-side consumers reading artifact frontmatter; the kit * itself now derives structure from the body (extractEchoSections). */ declare function extractRequiredSections(raw: string): string[] | null; /** * P53 — canonical heading key: strips contract markers AND ordinal prefixes * so `### 1. Learning Objectives & Evidence` and `1) Learning Objectives…` * both normalize to the same key. Users may renumber headings without * breaking matching. */ declare function stripHeadingKey(h: string): string; /** * P53 rev3 — the contract echo of a template/artifact document: required * sections (default) and explicitly-optional ones, straight from the body. */ declare function extractEchoSections(raw: string): { required: string[]; optional: string[]; }; /** P53 — canonical sections carrying a `[CONDITIONAL]` marker in the body. */ declare function extractConditionalSections(raw: string): string[]; /** P53 — `template_language:` frontmatter value (default "en"). */ declare function extractDeclaredLanguage(raw: string): string; /** * Resolve a canonical template by file name. First existing candidate wins: * explicit dir → CURRICULUM_TEMPLATES_DIR → /_templates → packaged * dist/templates → repo docs/refs/templates. Returns null when unresolvable * (callers fall back to inline scaffolding, same contract as before). */ declare function resolveArtifactTemplate(templateName: string, opts?: { templatesDir?: string; }): ResolvedTemplate | null; /** AI runner contract for template translation (injected — kit stays provider-agnostic). */ type TemplateTranslateRunner = (prompt: string) => Promise; interface AssembledTemplate { /** Full document: REGENERATED frontmatter echo + translated body. */ raw: string; /** Contract echo of the translated body (= the regenerated FM list). */ sections: string[]; templateLanguage: string; } /** * P53 rev3 — assemble a project template copy from an AI-translated BODY. * The frontmatter is never AI-edited: it is regenerated mechanically — * `template_language` stamp + `template_required_sections` echoed from the * translated headings (the body is the single source; the FM list follows it). * * Structural verification: heading count, order, and levels must survive * translation 1:1 (required AND optional). Any drift → null; the caller * falls back to the bundled English template rather than shipping a broken * contract. `{{placeholder}}` / marker preservation is verified here too. */ declare function assembleTranslatedTemplate(templateName: string, translatedBody: string, targetLanguage: string, opts?: { templatesDir?: string; }): AssembledTemplate | null; /** * P53 — full-body template translation (AI, once per language + content hash; * caching is the caller's job). The kit stays language-neutral: bundled * templates are never translated in-repo. * * Pipeline: split frontmatter (never sent to AI) → prompt the runner with * preservation rules → assembleTranslatedTemplate regenerates the frontmatter * echo and structurally verifies the result. Returns null on any violation; * the caller falls back to the bundled English template. */ declare function translateTemplate(templateName: string, targetLanguage: string, runner: TemplateTranslateRunner, opts?: { templatesDir?: string; }): Promise; /** * Legacy raw-content lookup retained for existing callers * (`singleArtifactService`, SLIDE workflow). Returns the file verbatim — * frontmatter included, byte-compatible with the pre-P52 helper it replaces. * Empty string = not found. */ declare function loadCurriculumTemplate(templateName: string, templatesDir?: string): string; /** * Frontmatter-stripped lookup for JSON-first authoring builders * (`ai/prompts/*`) that embed the template in a prompt as a structural * alignment reference. Prompt-embedded noise (frontmatter) is stripped so * the LLM sees only the fill-in skeleton. Empty string = not found. */ declare function loadAuthoringTemplate(templateName: string, templatesDir?: string): string; declare const NO_VERBATIM_COPYING = "\nVERBATIM SOURCING RULE: When a section in the template says to extract a table\nor list from the canonical knowledge context (KX/LESSON), copy that table\nVERBATIM \u2014 do not re-invent or paraphrase it. Every fact must live in exactly\none canonical artifact; your document references, it does not restate."; type PedagogicalModel = '5e' | 'edp' | 'pbl' | 'general'; interface ArtifactPromptParts { /** Methodology directive — persona, quality bar, anti-duplication rules. */ directive: string; /** Canonical template file name (e.g. `CODE_template.md`). */ templateFile: string; /** Extra scaffold appended after the template body (optional). */ epilogue?: string; /** * Heading keys (P53 stripped form) to DROP from the embedded template body, * with their whole H2/H3 subtree, before the body enters the prompt. * Used to keep the embedded body consistent with a domain-resolved contract * (ticket 2026-09-27 issue #2: hardware-only sections must not leak into * software-only labs as placeholder tables). */ excludeSections?: string[]; } /** * Compose a satellite prompt: methodology directive + runtime-loaded fill-in * template body. Falls back to `inlineScaffold` when the template file cannot * be resolved (same fail-open contract as the pre-P52 hardcoded prompts). * * The delimiting banner is plain text (not an HTML comment) so the artifact * linter's placeholder scanner can never confuse it with template scaffolding * that leaked into generated content. */ declare function buildArtifactPrompt(parts: ArtifactPromptParts, opts?: { templatesDir?: string; }): string; /** * Remove a heading's whole subtree (same level + any deeper) from a template * body. Headings match in the P53 stripped-key form so `[CONDITIONAL]` / * ordinal markers do not need to be repeated by the caller. Fence-aware. */ declare function dropTemplateSections(body: string, headingKeys: string[]): string; /** * Builds the canonical LESSON prompt (P52: template-driven). * Structure = runtime-loaded LESSON_{5E,EDP,GENERAL}_template.md fill-in body; * this builder keeps only the methodology directive + frontmatter contract. */ declare function buildLessonPrompt(pedagogy: PedagogicalModel, lessonCode: string, unitCode: string, lessonTitle: string, concept: string, bloomLevel: string, dateStr: string, targetLanguage?: string): string; /** Everything a directive needs. All dates are passed in so a dry-run is reproducible. */ interface DirectiveInput { lessonCode: string; dateStr: string; /** CODE only — the domain-resolved hardware/software branch. */ isHardwareLab?: boolean; /** EXT only — the curriculum-horizon ZPD block. */ zpdCeilingPrompt?: string; /** EXT only — localized mandatory headings. */ extHeadings?: ExtHeadings; } interface ExtHeadings { main: string; sub: string; c1: string; c2: string; c3: string; meta: string; } declare function codeHeadingsDirective(isHardwareLab: boolean): string; declare const EXT_HEADINGS_VI: ExtHeadings; declare const EXT_HEADINGS_EN: ExtHeadings; /** ZPD block — horizon present ⇒ strict boundary; absent ⇒ generic scope. */ declare function zpdCeilingPrompt(horizon: { targetKeywords: string[]; boundaryPeek: Array<{ lessonIndex: number; title: string; keywords: string[]; }>; } | null | undefined): string; /** EXT is the one satellite that does NOT wrap buildArtifactPrompt — it never * embeds EXT_template.md, so the model gets headings but no fill-in body. */ declare function extPrompt(i: DirectiveInput & { languageDirective: string; }): string; type ProductionArtifactType = 'LESSON' | 'ACT' | 'QUIZ' | 'SLIDE' | 'GUIDE' | 'HANDOUT' | 'WKS' | 'CODE' | 'EXT'; /** Every artifact type `produceSingleLesson` can actually author. */ declare const PRODUCTION_ARTIFACT_TYPES: readonly ProductionArtifactType[]; interface ProductionPromptSpec { artifactType: string; lessonCode: string; dateStr?: string; language?: string; /** LESSON only. */ pedagogy?: PedagogicalModel; unitCode?: string; lessonTitle?: string; concept?: string; bloomLevel?: string; mediaDirective?: string; /** CODE only — omit to take the software-only branch. */ isHardwareLab?: boolean; /** EXT only. */ horizon?: Parameters[0]; /** SLIDE (marp engine) only. */ pedagogyLabel?: string; slidesOutline?: string[]; lessonFlowExcerpt?: string; /** SLIDE only — override the loaded SLIDE_template.md scaffold. */ templateScaffold?: string; } interface ProductionPromptResult { artifactType: string; /** False when produceSingleLesson has no branch for this type. */ exists: boolean; persona: string; templateFile: string | null; templateResolved: boolean; /** Where the SOT context travels: a separate inference arg, not the prompt. */ contextChannel: 'commonContext' | 'satelliteContext' | 'none'; /** Exactly the messages produceSingleLesson hands to the inference runner. */ messages: Array<{ role: 'system' | 'user'; content: string; }>; /** Parsed back out of the prompt's own frontmatter — one source of truth. */ requiredSections: string[]; notes: string[]; } /** Read `template_required_sections` back out of a composed prompt so the * comparison tab never carries a hand-maintained second list. */ declare function parseRequiredSections(prompt: string): string[]; /** * The single composition point for every satellite prompt. `produceSingleLesson` * calls this — it is the reason the playground can show the production prompt * without keeping a second copy that could drift. */ declare function buildSatellitePrompt(type: string, input: DirectiveInput, languageDirective: string): string; /** * Render the production prompt for one artifact type without calling an LLM. * Unknown types return `exists: false` rather than throwing — the playground * needs to show that e.g. BELL_RINGER has no production branch at all. */ declare function assembleProductionArtifactPrompt(spec: ProductionPromptSpec): ProductionPromptResult; /** * KNOWLEDGE_EXPOSITION slot for the plan-driven LESSON flow — AST-primary * with the ExcerptResult telemetry shape. The AST projection only ever ships * the requested keys, so it matches the markdown builder's `exclusive: true` * whole-section selection semantics. `verified: true` means "resolved", not * "complete": the projection drops a section that does not fit the budget WHOLE, * so its `section:dropped:` warnings are forwarded as `issues` — hardcoding * `issues: []` here is what made a truncated canonical KX excerpt look * indistinguishable from a complete one. The markdown excerpt builder (same * priorities + budget, exclusive) remains the fallback when the AST overlay * resolves nothing. */ declare function canonicalExpositionSource(markdown: string | undefined, priorities: string[], budget: number): { excerpt: string; verified: boolean; sectionAware: boolean; issues: string[]; }; interface ProduceLessonOptions { artifactScope?: string[]; force?: boolean; pedagogy?: PedagogicalModel; targetLanguage?: string; slidesEngine?: 'html' | 'marp'; /** * Deck engine for the HTML slide path (RC 2026-09-23): 'bespoke' (model * authors full HTML/CSS per slide — the frontend-slides skill) is the * STANDARD; 'chunked'/'hybrid' keep the slot-template pipeline. Previously * this call-site never passed an engine, so every queue run silently * degraded bespoke → hybrid slot slides. */ slidesDeckEngine?: 'bespoke' | 'hybrid' | 'chunked'; /** Optional REQUIRED slide outline (kit 1.5.60): ordered section titles the * SLIDE deck must cover in order. Supplied → deck blueprint follows it as a * hard structural constraint (same outline across engines ⇒ same deck * structure). Omitted → each engine self-plans its blueprint (standalone * slide-only artifacts without a LESSON still work). */ slidesOutline?: string[]; /** Chiến lược batch (chỉ produceBatchLessons dùng). */ batchStrategy?: 'depth_first_lesson' | 'breadth_first_artifact'; /** * Gate Settings — NGUỒN DUY NHẤT quyết định "ai kiểm artifact nào". * Chấp nhận config thô (vd: gateModes từ project.config.json của Composer): * { LESSON: 'llm_judge', ACT: 'none', gate1: 'hitl', ... } — kit tự chuẩn hoá. * Riêng approvedArtifacts là INPUT của HITL (bản đã được người duyệt), không phải config. */ gateSettings?: unknown; /** * Standards Registry packs (đã validate + activate) để GROUNDING prompt và Judge. * Không truyền → pipeline chạy như cũ, không inject block chuẩn nào. */ standardsPacks?: FrameworkPack[]; /** Id pack đóng gói sẵn trong kit (vd: 'csta-k12-2017') — cách Composer truyền chuẩn gọn nhất. */ standardsPackIds?: string[]; /** Grade band của lesson (để chọn statement theo lớp). Fallback [6,12]. */ gradeBand?: [number, number] | number; /** * Media Ledger policy (nếu có): agent chèn placeholder [IMAGE: slug], Curator duyệt, Fulfiller thực thi. * maxGenImagesPerArtifact = quota ảnh AI/gen — search kho ảnh (Pexels) KHÔNG tốn quota này. */ mediaPolicy?: { maxGenImagesPerArtifact: number; autoFulfill?: boolean; preferredProvider?: 'openai' | 'gemini'; mode?: 'search_only' | 'gen_only' | 'auto'; }; approvedArtifacts?: string[]; /** * 5-Whys RC-canonicality: project briefing feeding the canonical PRODUCT_SPEC * block (platform, hardware, deliverable template). Injected identically into * every artifact's ground truth so no artifact re-decides product shape. */ briefing?: { techStack?: string; coreTechnology?: string; topic?: string; hardwarePlatform?: string; studentEquipment?: string; classDynamic?: string; language?: string; /** P49 G1.2/G2: pedagogical slots consumed by context routing (age-appropriate language, bridge hints). */ targetAge?: string; targetAgeTier?: string; entryBridge?: string; assessmentStrategy?: string; }; /** * P49 G2: Micro-Slot context routing mode. 'legacy' (default) = the * pre-P49 one-size-fits-all satelliteContext. 'hybrid' = per-artifact * whitelisted slots (LESSON-primary scoped excerpts; KX-only types get KX * priorities + activity-contract mini-slot). Shadow-compare before * flipping the app default. */ contextRoutingMode?: ContextRoutingMode; /** * P46 RC2: host-provided inference override (Vercel AI SDK gateway). * When supplied, ALL lesson/satellite LLM calls route through it — the kit's * internal raw-fetch providers never run, so the embedding app gets one * auditable, traceable (Langfuse/OTel) inference engine. */ customInference?: StreamRunnerOptions['customInference']; onProgress?: (agent: string, message: string, meta?: any) => void; } interface ContextInjectionMeta { /** Which canonical source the excerpt came from (e.g. 'KNOWLEDGE_EXPOSITION', 'LESSON'). */ source: string; /** True when the builder excerpt passed verify (priority resolution + sufficiency). */ verified: boolean; /** True when canonical section resolution contributed to the excerpt. */ sectionAware: boolean; /** Structured reasons when verified === false (empty otherwise). */ issues: string[]; } interface ProduceLessonResult { lessonId: string; pedagogy: PedagogicalModel; producedArtifacts: string[]; pausedForReview: boolean; gateStatus?: string; /** P43 Cụm 5: observability for context injection — surfaced by every path * (queue, standalone, batch) so callers can record telemetry / execution * history without re-parsing. */ contextInjection?: ContextInjectionMeta; promptChars?: number; /** Truncation telemetry (1.5.54): every canonical section a satellite prompt * ran WITHOUT (whole-section dropped for budget, or truncated). Empty runs * omit the field — presence itself is the degradation signal. */ contextDrops?: Array<{ artifactType: string; slot: string; section: string; kind: 'dropped' | 'truncated'; }>; standardsCoverage?: CoverageGateReport; } /** * Detects pedagogical model from SOT (Framework, Style Guide, or Brief) */ declare function detectProjectPedagogy(frameworkText: string, styleGuideText: string, explicitPedagogy?: PedagogicalModel): PedagogicalModel; /** * Extracts lesson information (Title, Concept, Bloom, Unit, Module) from CURRICULUM_FRAMEWORK.md. */ declare function getLessonMetadata(storage: ICurriculumStorage, projectId: string, lessonId: string): Promise<{ unitCode: string; moduleCode: string; lessonCode: string; lessonTitle: string; concept: string; prerequisites: string; bloomLevel: string; }>; /** * Produces artifacts for a single lesson with support for dynamic pedagogy, HITL gating, and artifact scope. */ declare function produceSingleLesson(storage: ICurriculumStorage, projectId: string, lessonId: string, options?: ProduceLessonOptions): Promise; /** * Batch production orchestrator supporting Lesson-by-Lesson (Strategy A) or Artifact-by-Artifact (Strategy B) execution. */ declare function produceBatchLessons(storage: ICurriculumStorage, projectId: string, lessonIds: string[], options?: ProduceLessonOptions): Promise<{ totalLessons: number; completedLessons: string[]; pausedLessonId?: string; report: ProjectStatusReport; }>; interface ProjectCreationPayload { projectName: string; projectCode: string; coreObjective: string; topic: string; targetAge: string; pedagogy: '5e' | 'edp' | 'pbli' | string; hardwarePlatform: string[]; artifactScope: string[]; context?: 'school' | 'corporate' | 'community' | 'competition' | string; depth?: 'remember' | 'understand' | 'apply' | 'evaluate' | 'create' | string; tone?: 'friendly' | 'academic' | 'inspiring' | string; language?: 'vi' | 'en' | string; specialRequirements?: string; } interface ProjectClarification { question: string; missingField: keyof ProjectCreationPayload | string; options: string[]; } interface ProjectIntentAnalysisResult { status: 'READY' | 'NEEDS_CLARIFICATION'; message: string; payload?: ProjectCreationPayload; clarification?: ProjectClarification; } /** * Slugifies a project name into standard kebab-case project code. * Ensures uniqueness against any existing project codes. */ declare function slugifyProjectName(name: string, existingCodes?: string[]): string; /** * Analyzes natural language project creation request and extracts structured parameters or clarification questions. */ declare function analyzeProjectCreationIntent(userPrompt: string, currentContext?: Record): Promise; /** * Initializes a new course project and writes initial SOT files into storage. */ declare function initializeProjectInStorage(storage: ICurriculumStorage, payload: ProjectCreationPayload): Promise<{ projectId: string; filesCreated: string[]; }>; /** * Converts a Project Roadmap JSON into a standardized ProjectCreationPayload. */ declare function parseRoadmapJsonToProjectPayload(roadmapJson: any): ProjectCreationPayload; /** * Ingests a Project Graph JSON (Architecture, Features, Implementation symbols) as a Reference Resource in the project SOT. */ declare function ingestProjectGraphIntoProject(storage: ICurriculumStorage, projectId: string, graphJson: any): Promise<{ success: boolean; filesCreated: string[]; summary: string; }>; interface SlashCommandDefinition { id: string; command: string; label: string; description: string; category: 'workflow' | 'audit' | 'knowledge' | 'specs'; } declare const CURRICULUM_SLASH_COMMANDS: SlashCommandDefinition[]; interface ExecuteCommandResult { success: boolean; command: string; actionTaken: string; artifactPath?: string; content?: string; message: string; } /** * Executes a curriculum-kit slash command against the given project storage. */ declare function executeCurriculumCommand(storage: ICurriculumStorage, projectId: string, command: string, payload?: { messages?: Array<{ role: string; content: string; }>; projectName?: string; pedagogy?: string; }): Promise; /** * Deterministic Pipeline Runner (Parity with LangGraph unit_loop_node & ARTIFACT_EXECUTION_ORDER) * * Enforces the strict sequential waterfall for lesson production: * 1. Step 1: LESSON (5E Master Plan — The Artifact Contract) * 2. Step 2: ACT (STEM Lab Operations bound to LESSON contract) * 3. Step 3: QUIZ (Diagnostic & Summative Quizzes bound to LESSON evidence) * 4. Step 4: SLIDE (Marp Visual Slides bound to 5E Phases) * 5. Step 5: SATELLITES (GUIDE, WKS, HANDOUT, EXT) */ interface ArtifactProductionSpec { artifactType: 'LESSON' | 'ACT' | 'QUIZ' | 'SLIDE' | 'GUIDE' | 'WKS' | 'HANDOUT' | 'EXT' | 'MEDIA_SCRIPT'; assignedPersona: string; isContractRoot: boolean; requiresPriorLesson: boolean; } declare const ARTIFACT_EXECUTION_ORDER: ArtifactProductionSpec[]; interface PipelineExecutionProgress { lessonId: string; currentStepIndex: number; totalSteps: number; activeArtifact: string; assignedPersona: string; completedArtifacts: string[]; pendingArtifacts: string[]; status: 'IDLE' | 'IN_PROGRESS' | 'AWAITING_APPROVAL' | 'COMPLETED' | 'ERROR'; error?: string; } declare class DeterministicPipelineRunner { /** * Determine what artifacts need to be produced next for a lesson, honoring the strict dependency order. */ static getNextProductionTarget(lessonId: string, existingArtifacts: string[], scopedArtifactTypes?: string[]): { nextArtifact: ArtifactProductionSpec | null; isLessonComplete: boolean; parallelQueue: string[]; progress: PipelineExecutionProgress; }; } /** Lifecycle event for one cascade candidate — hosts forward it to the UI so a * silent model switch (idle-timeout failover) is never invisible again. */ interface PrefillProviderEvent { type: 'candidate-start' | 'candidate-failed' | 'candidate-success'; provider: string; model: string; attempt: number; total: number; elapsedMs: number; error?: string; } interface LayerPrefillOptions { action?: 'prefill' | 'research'; targetLayer?: number; accumulatedData?: Record; apiKeys?: Record; liveSearchConfig?: Record; /** Target language for pre-filled wizard values: 'vi' | 'en' (default: 'vi'). */ language?: string; stream?: boolean; model?: string; provider?: AIProviderName; /** Total wall-time budget override for this prefill run (ms). */ timeoutMs?: number; /** Idle (no-data) budget override for this prefill run (ms). */ idleTimeoutMs?: number; /** Optional parent abort signal (e.g. from HTTP request) to stop immediately on client disconnect. */ signal?: AbortSignal; /** * Host-provided inference override (Vercel AI SDK tiered gateway, test stubs). * Same contract as StreamRunnerOptions['customInference']. When set it is the * SOLE inference path: the built-in cascade (streamLLMWithFallback) never runs, * so host apps that mandate one auditable gateway (Langfuse tracing, raw-wire * idle kicks, reasoning_content extraction) get exactly that engine here too. * Mirrors the unified-tracing mandate already enforced in lesson/chat/slide paths. */ customInference?: (request: { systemInstruction: string; userPrompt: string; messages: Array<{ role: 'user' | 'assistant' | 'system' | 'model'; content: string; }>; temperature: number; maxTokens: number; onChunk: (token: string, type: ChunkType) => void; }) => Promise; /** Observe cascade candidate transitions (start/fail/success) for UI status. */ onProviderEvent?: (event: PrefillProviderEvent) => void; } interface PreliminaryResearchResult { groundTruthSummary: string; hardwareVersion: string; ideVersion: string; activeLibraries: string[]; technicalGotchas: string[]; } interface LayerPrefillResult { success: boolean; targetLayer?: number; parsedResponse?: any; research?: PreliminaryResearchResult; rawText?: string; } type LayerChunkCallback = (chunk: string, type: 'thought' | 'content') => void; /** Budget knobs for a streamed inference (see createStreamAbortSignal). */ interface StreamBudget { /** Abort when no data arrives for this long (ms). 0 disables. */ idleMs?: number; /** Abort when the whole stream exceeds this total wall time (ms). 0 disables. */ totalMs?: number; } declare const DEFAULT_STREAM_IDLE_MS = 180000; declare const DEFAULT_STREAM_TOTAL_MS = 480000; declare const LAYER_IDLE_BUDGET_MS: Record; /** * Layer-aware total budget: * - Layer 1 & 2: 8 minutes hard cap. * - Layer 3: 10 minutes hard cap (600s) to allow deep reasoning models (e.g. NVIDIA Nemotron Ultra 550B) * to complete the full deliverable and pathways synthesis without mid-JSON truncation. */ declare const LAYER_TOTAL_BUDGET_MS: Record; /** * Resolve the abort budget for a prefill run. Precedence: explicit options > * env (`WIZARD_PREFILL_IDLE_TIMEOUT_MS` / `WIZARD_PREFILL_TOTAL_TIMEOUT_MS`) > * layer-aware & provider-aware defaults. Exposed as a pure function for decision-table tests. */ declare function resolveStreamBudget(layer?: number, opts?: StreamBudget & { model?: string; provider?: string; }): Required; /** * Abort signal combining an IDLE window with an optional TOTAL cap. * RC-W1: `AbortSignal.timeout(60_000)` hard-killed Layer 2 mid-stream even while * tokens were flowing (free-tier models think + stream slowly) — the aborted * `fullContent` then failed `safeParseJson` (empty or truncated JSON). * The idle window only fires when NO data arrives (hung connection), while a * generous layer-aware total cap is the safety net. */ interface StreamAbortHandle { signal: AbortSignal; /** Reset the idle window — call on EVERY received stream part. */ kick: () => void; /** Clear both timers once the stream lifecycle is over. */ dispose: () => void; } /** Chunks extracted from one raw Vercel AI SDK stream part. */ interface ExtractedStreamChunk { /** Reasoning/thinking text to forward via onChunk(chunk, 'thought'). */ thought?: string; /** Content text to forward via onChunk(chunk, 'content') and accumulate. */ content?: string; } /** * Channel Isolation Pattern (5-WHY root-cause architecture, 2026-09-10): * * CONTENT channel — single source of truth: SDK-mapped `text-delta` ONLY. * Raw provider chunks ALWAYS carry `delta.content` too; * reading it duplicates every token (DUP-STREAM). * * THOUGHT channel — SDK-mapped `reasoning-delta` PREFERRED; raw * `delta.reasoning_content` used as FALLBACK only, for * providers whose non-standard reasoning field the SDK * does not map (measured live: NVIDIA NIM emits * reasoning-delta=0, reasoning exists ONLY inside raw). * A per-stream `hasStandardReasoning` latch guarantees * exactly one source ever wins, so an SDK upgrade that * starts mapping reasoning can never re-introduce * DUP-THOUGHT. */ type StreamChunkExtractor = (part: any) => ExtractedStreamChunk; /** Per-stream extractor with the reasoning source latch. Use ONE instance per stream. */ declare function createStreamChunkExtractor(): StreamChunkExtractor; /** * Stateless single-part mapper (kept for compatibility/tests): same channel * rules minus the reasoning latch — real streams must use * createStreamChunkExtractor, whose latch is the authoritative dedupe. */ declare function extractStreamChunk(part: any): ExtractedStreamChunk; declare function createStreamAbortSignal(budget: Required, parentSignal?: AbortSignal): StreamAbortHandle; /** * Close an unterminated JSON object/array: append the delimiters that are * still open, closing any open string first. Handles streams aborted * mid-JSON (budget timeout) where the structure is otherwise valid. * Returns the repaired candidate or null when unrecoverable. */ declare function closeTruncatedJson(candidate: string): string | null; /** * Strip common LLM prose wrappers: code fences, leading "Here is ..." lines, * blocks. Returns the raw inner text (may still be imperfect JSON). */ declare function stripLlmJsonWrappers(rawText: string): string; /** * Robust JSON extraction and repair helper. * * Tolerates every real-world LLM output defect observed with free-tier * reasoning models (nemotron-ultra, OpenRouter :free presets): * 1. code fences / blocks / prose around the JSON, * 2. trailing commas, * 3. TRUNCATED output — the stream abort (idle/total budget) can cut the * payload mid-JSON; open strings/braces are closed deterministically, * 4. mixed defects — each candidate goes through jsonrepair last. * Layered: cheap strict parse first, heavier repair only on failure. */ declare function safeParseJson(rawText: string | null): T | null; /** * Multi-tiered resilient streaming inference helper using 100% Vercel AI SDK. */ declare function streamLLMWithFallback(systemPrompt: string, userPrompt: string, apiKeys?: Record, onChunk?: LayerChunkCallback, preferredModel?: string, preferredProvider?: AIProviderName, budget?: StreamBudget, signal?: AbortSignal, onEvent?: (event: PrefillProviderEvent) => void): Promise; /** * Conducts preliminary ecosystem research for a course project. */ declare function conductPreliminaryResearch(options: LayerPrefillOptions, onChunk?: LayerChunkCallback): Promise; /** * Executes concentric 3-layer drill-down prefill inference with live reasoning stream. */ declare function streamLayerPrefillWithFallback(options: LayerPrefillOptions, onChunk?: LayerChunkCallback): Promise; /** * Curriculum Planner — turns a domain planning graph + constraints into a * validated CurriculumPlan (planner outputs [1]-[7] from the design doc). * * Deterministic-first: LLM is optional and only used for prose objectives via * the `llmFn` hook. Packing, depth and prereq/scaffold decisions are pure * functions — testable, replayable, no silent fallbacks. */ interface PlannerLlmFn { (systemPrompt: string, userPrompt: string): Promise; } interface PlanOptions { constraints: PlanConstraints; translation?: TranslationPolicy; /** Optional LLM for prose objectives; absent => deterministic templates. */ llmFn?: PlannerLlmFn; /** * LO time-estimation mode (plan 2026-10-09-lo-time-estimation-model-implementation-plan, phase B/C): * - 'observe' (default): compute estimates, attach plan.time_estimates and * emit `time_estimate:` divergence warnings — NEVER mutates minutes. * - 'authoritative': single price source (plan C1) — writes model minutes * back and regenerates depth_variants/depth_scaffold_candidates from the * estimator. Opt-in: the default flips only after data gate TC6 (step TC7); * reference data is still missing — see the plan. */ time_estimate_mode?: 'observe' | 'authoritative'; } interface PlanResult { plan: CurriculumPlan; warnings: string[]; } /** * Normalize any accepted input shape into a PlanningGraph. * Accepted: CurriculumFeed v2 (learning_nodes), knowledge_graph (concepts), * AssembledRoadmap (phases/milestones), raw project_graph (features/steps), * hybrid (concepts + features/roadmap + links). Throws on unusable input. */ declare function normalizePlanningGraph(raw: unknown): PlanningGraph; declare function assertAcyclic(nodes: PlanningNode[], edges: DependencyEdge[]): void; declare function topoSort(nodes: PlanningNode[], edges: DependencyEdge[]): string[]; interface UnitGrouping { key: string; name: string; orderedIds: string[]; rationale: string; phaseIds: string[]; productCompletion: string; } interface PackingSpec { contentBudget: number; overheadMinutes: number; sessionDurationMinutes: number; ageBand?: [number, number]; /** 2026-09-18 RC-2: cognitive budget — max DISTINCT new concepts per * session (Vygotsky ZPD constant). 0 disables the check. * @deprecated Retained for backward-compat; prefer sessionCognitiveBudget (ADR-0007). */ maxNewConceptsPerSession?: number; /** 2026-09-19 (age-band granularity gate): max DISTINCT new concepts for * the FIRST teaching session of a BEGINNER course — 1. * @deprecated Retained for backward-compat; prefer firstSessionCognitiveBudget (ADR-0007). */ firstSessionMaxNewConcepts?: number; /** Language-exposure ceiling for K-12: max NEW keywords per session * (noisy proxy — reported in zpd_status, never a hard gate). */ maxNewKeywordsPerSession?: number; /** ADR-0007: Cognitive budget in points (ULO=3, CIO=2, SIO=1, fallback=2). * K-12 default: 10 pts; Adult default: 15 pts. */ sessionCognitiveBudget?: number; /** ADR-0007: Beginner first session cognitive budget (defaults to FIRST_SESSION_COGNITIVE_BUDGET_BEGINNER = 3 pts). */ firstSessionCognitiveBudget?: number; } declare function computePackingSpec(constraints: PlanConstraints): PackingSpec; interface PackedEntry { id: string; minutes: number; nominal_minutes?: number; part: number; totalParts: number; } interface PackedSession { groupId: string; nodeIds: string[]; entries: PackedEntry[]; knowledgeMinutes: number; practiceMinutes: number; oversized: boolean; /** Distinct NEW concepts counted against the ZPD budget at flush time — * product sessions legitimately restate already-taught concepts, so the * load that matters is what is unseen, not the concept_codes union. */ cognitiveNew: number; /** ADR-0007: Cumulative cognitive load points for this session */ cognitiveLoad: number; } /** * Coalesce eligibility (2026-09-18 regen4 audit): a merge must never break * the ZPD cognitive budget the packer enforces. Guard = the MERGED session's * unique new-concept count ≤ maxNew — the same invariant checkSessionZpd * enforces per session. A per-side check is NOT sufficient ({C1,C2} + * {C3,C4} passes per-side but merges to a 4-concept monster — exactly how * L01 got overloaded). When the guard blocks every candidate pair, sessions * stay separate and the shortfall is surfaced via warnings for HITL instead * of silently overloading sessions. */ /** * 2026-09-19 (session-count closed loop): a spiral REVISIT node (C5__ADV03) * re-teaches an already-encountered concept at greater depth — pedagogically * it is known material, not new learning. Comparing raw codes made every * revisit count against the ZPD cap and block coalescing (regen8: 9 * concept-only sessions of 24-40m at unit starts). Stripping the suffix * restores the semantics: revisit ≡ base concept for load accounting. * Coverage/gates elsewhere still see the distinct revisit code. Exported so * downstream evidence builders share the ONE normalization (5-WHY chain 2: * a single semantics for "new concept"). */ declare function zpdConceptKey(code: string): string; /** * THE one place that decides which concepts a session introduces as NEW vs * KNOWN. Semantics (shared by checkSessionZpd, the packer's cognitive flush, * coalesce, and the app's judge-evidence TRUE-counter): * 1. a session's concepts = distinct zpdConceptKey-normalized codes of its * nodes (spiral revisits C5__ADV03 ≡ base C5 — revisiting is knowing); * 2. NEW = not present in the normalized seen set at session start, with * the session-local union deduped in (repeat nodes on one concept don't * double-count); * 3. the returned nextSeen set is the cumulative state to feed the NEXT * session (add concepts, then update, never update-then-add). * * zpdConceptKey alone is the key NORMALIZATION; this function owns the * COUNTING so the packer and the ZPD checker cannot drift again (5-WHY * chain 2: two hand-rolled seen-set implementations disagreed on revisits). */ declare function splitZpdConceptLoad(nodeIds: readonly string[], nodeById: ReadonlyMap, seenBefore: ReadonlySet): { concepts: string[]; newConcepts: string[]; knownConcepts: string[]; nextSeen: Set; }; /** * Resolves the Learning Objective (LO) abstraction level for a node: * - 'ulo': Universal / Conceptual understanding (Why) -> highest cognitive abstraction * - 'cio': Common / Algorithmic implementation (How) -> intermediate procedural design * - 'sio': Specific / Syntax execution (Action) -> concrete implementation */ declare function getNodeLoType(node: PlanningNode | undefined | null): 'ulo' | 'cio' | 'sio' | undefined; /** * Returns the cognitive weight for a node based on its LO type (ADR-0007). * Fallback to DEFAULT_LO_WEIGHT (2.0) if type is unspecified. */ declare function getNodeCognitiveWeight(node: PlanningNode | undefined | null): number; /** * Calculates total cognitive load points for a collection of nodes or node IDs (ADR-0007). */ declare function calculateCognitiveLoad(nodesOrIds: readonly (PlanningNode | string)[], nodeById?: ReadonlyMap): number; declare function canCoalesceWithinZpdBudget(curr: { nodeIds: string[]; }, next: { nodeIds: string[]; }, nodeById: Map, maxNewOrBudget: number): boolean; declare function packUnitSessions(group: UnitGrouping, nodeById: Map, spec: PackingSpec, warnings: string[], sessionOffset?: number): PackedSession[]; /** * 2026-09-23 (swift-101 F5-S1): a node split across sessions (strand-guard / * oversized) must appear in exactly `totalParts` entries with parts in order * 1..totalParts, in the same or consecutive sessions (coalesce may merge the * parts into one session). The old seenNodes invariant only whitelisted * multi-part repeats — it could not catch a broken continuation chain (part 2 * without part 1, non-consecutive parts, wrong part count), which downstream * consumers would read as a duplicate assignment. */ declare function assertSplitPartsConsecutive(packed: PackedSession[]): void; declare function assignDepths(nodeIds: string[], nodeById: Map, conceptEncounterMap?: Map, partInfo?: Map): CurriculumPlan['sessions'][number]['depth_assignments']; /** * Bruner's Spiral Curriculum progression tracker across the entire course. * Tracks encounter count per concept code: * Encounter 1 -> Bloom ceiling: Understand, Depth: CIO * Encounter 2 -> Bloom ceiling: Apply, Depth: SIO * Encounter 3+ -> Bloom ceiling: Analyze, Depth: SIO */ declare function computeConceptSpiralProgression(sessions: Array<{ id: string; node_ids: string[]; }>, nodeById: Map): ConceptSpiralEncounter[]; /** * P50-G2 — ONE depth computation for the whole course. * * Spec: "kết quả được cập nhật trực tiếp vào `s.depth_assignments`". Before * this, assignDepths and computeConceptSpiralProgression ran as two independent * computations — one counting encounters inline per session, one scanning the * finished session list — so the same node could be recorded as SIO in * `depth_assignments` and CIO in `concept_spiral_progression`, and BOTH shipped * in one plan feeding different subsystems (KX reads depth_assignments; the * curriculumHorizon prompt reads the spiral). * * Now the spiral is computed once, and this pass drives every * `depth_assignments` from it. Two invariants: * - one node = one teaching depth: a node split across sessions keeps the * depth of its FIRST occurrence. The spiral counts encounters per session, * so it would otherwise treat a split tail as a second encounter and * promote it to SIO mid-teach; * - product steps are untouched — the spiral tracks concept_codes only, and * step depth stays driven by the feed hint (P52/T3.1 prices scaffolding * candidates off it). * * Returns the number of assignments written, for caller-side evidence. */ declare function assignDepthsForSessions(sessions: Array<{ id: string; node_ids: string[]; depth_assignments: CurriculumPlan['sessions'][number]['depth_assignments']; }>, nodeById: Map, spiral: ConceptSpiralEncounter[], entriesBySession: Map): number; /** * P50-G1: Vygotsky ZPD & Cognitive Overload Guard. * Evaluates session cognitive capacity against the cumulative horizon: * - TOO_MANY_NEW: More than 2 new concepts (or >4 new keywords if conceptless) introduced in 1 session * - NO_ZPD_BRIDGE: Session index > 0 with >1 new concepts and 0 known concepts from prior sessions * Self-healing: If NO_ZPD_BRIDGE, injects a recap anchor into prerequisite decisions. */ declare function checkSessionZpd(sessionIndex: number, nodeIds: string[], nodeById: Map, allSeenConcepts: Set, allSeenKeywords: Set, entryKw: Set, warnings: string[], conceptPrereqMap?: Map, spec?: PackingSpec): { status: SessionZpdStatus; bridgeRepair?: { node_id: string; decision: PrerequisiteDecision; reason: string; }; }; /** * P50-G3: Reigeluth Walking Skeleton Validator. * Formulates Unit 1 as the Epitome (minimal end-to-end working software slice), * and subsequent Units as Elaborations that deepen and expand specific subsystems. */ declare function buildWalkingSkeleton(units: UnitPlan[], sessions: Array<{ id: string; unit_id: string; exit_evidence?: string[]; }>): WalkingSkeleton; /** * P50-G4: Inter-Phase Mastery Gates & Remediation Sprints. * Builds formal competency gates between consecutive units with measurable * acceptance criteria and a targeted 15-minute remediation protocol. */ declare function buildMasteryGates(units: UnitPlan[], sessions: Array<{ id: string; unit_id: string; exit_evidence?: string[]; }>, options?: { includeFinalCapstoneGate?: boolean; }): MasteryGate[]; /** * Drops symmetric edges (A->B and B->A) and performs DFS cycle detection * to guarantee an acyclic concept prerequisite graph (curriculum_graph.py port). */ declare function dropCyclicConceptEdges(edges: ConceptPrerequisiteEdge[]): ConceptPrerequisiteEdge[]; /** * Gagné Cross-Concept Prerequisite DAG (ADR-0005 & curriculum_graph.py port). * Derives cross-concept dependency edges from planning node dependencies, * validates structure support (taught earlier in teaching order), flags hubs (fan-out >= 6), * and eliminates cycles. */ declare function buildConceptPrerequisites(sessions: Array<{ id: string; node_ids: string[]; }>, nodeById: Map, edges: DependencyEdge[]): ConceptPrerequisiteEdge[]; /** * LO time estimation hook (plan 2026-10-09, phases A/B/C): per-node estimate * via bundle template when depth+bloom metadata exists, otherwise an honest * L0 reference-class fallback that KEEPS the incoming minutes. * * mode 'observe' (default): attaches estimates only — no mutation of * estimated_minutes / depth_variants. * mode 'authoritative': SINGLE PRICE SOURCE (plan C1) — regenerates * depth_variants for all three depths from the same estimator, sets * estimated_minutes to the price at the node's own depth, and rebuilds * depth_scaffold_candidates from that same table. Opt-in until TC7 flips the * default (data gate TC6 not yet passed). */ declare function applyLoTimeEstimates(graph: PlanningGraph, constraints: PlanConstraints, mode: 'observe' | 'authoritative'): LoTimeEstimate[]; declare function buildCurriculumPlan(rawGraph: unknown, options: PlanOptions): Promise; /** * P53: Deterministic Quality & Invariant Validator. * Enforces hard pedagogical invariants without heuristic compromises: * 1. Capacity & Real Minutes Conservation * 2. Session node count (<= 4 nodes per session) * 3. ZPD Cognitive Load (<= 2 new concepts per session) * 4. Bruner Spiral Depth (Encounter 1 must be CIO/Understand) * 5. Macro Structure & Session counts * 6. Deliverable Completeness (every session has exit_evidence) * 7. Teach-Before-Use (DAG knowledge prerequisite order) */ declare function validatePlan(plan: CurriculumPlan, graph: PlanningGraph, constraints: PlanConstraints): PlanValidationResult; /** Extract the machine-readable slice the LESSON agent consumes for one session. */ declare function extractSessionSlice(plan: CurriculumPlan, lessonCode: string): CurriculumPlan['sessions'][number]; /** Compact plan-slice context block for LESSON/satellite prompts (activity design inputs). */ declare function buildSessionSliceContext(plan: CurriculumPlan, lessonCode: string): string; /** * P52/T3.2+T3.3 — depth reconcile (plan P52, Gap 3). * * When the bottom-up minute total exceeds the course budget * (total_sessions × contentBudget), the planner historically had only one * way out: stretch time (part-sessions). The reconciler adds the missing * direction: LOWER KNOWLEDGE DEPTH along the Bruner spiral (SIO→CIO→ULO), * never below the ULO floor, never on core concepts (is_core → escalate). * * Pedagogical downgrade priority (least pedagogical loss first): * 1. `advanced` revisits (second pass — review, not first teach) * 2. SIO→CIO on LEAF concepts (no other concept depends on them) * 3. SIO→CIO on non-leaf non-core concepts * 4. CIO→ULO on leaf concepts * 5. CIO→ULO on non-leaf non-core concepts * * After each downgrade round the caller re-runs its fail-closed verifications * (teaching-order audit + ZPD) — the reconciler returns per-node evidence so * that re-audit has the exact change-set, and reports exhausted candidates as * a structured escalation (never a silent phase cut). */ interface ReconcileCandidate { nodeId: string; fromDepth: 'ulo' | 'cio' | 'sio'; toDepth: 'ulo' | 'cio' | 'sio'; minutesSaved: number; reason: string; } interface ReconcileResult { /** true when total fit inside the budget without any downgrade. */ unchanged: boolean; /** Applied downgrades in application order (fixed-point evidence). */ applied: ReconcileCandidate[]; /** Nodes mutated, for targeted re-audit by the caller. */ mutatedNodeIds: string[]; /** True when candidates were exhausted while still over budget. */ escalate: boolean; deficitMinutes: number; } /** * Compute leaf-ness on the CONCEPT level: a concept is a leaf when no other * concept lists it as a prerequisite. Node-level attributes (introduce_aspect * advanced, __ADV ids) map back to their base concept id. */ declare function classifyDepthCandidates(nodes: PlanningNode[], edges: DependencyEdge[]): Map; /** * Apply depth downgrades until total ≤ budget, the candidate pool is empty, * or MAX_ROUNDS is reached (fixed-point with a bounded loop — escalate on * non-convergence). Mutates `nodes` in place (minutes/depth_hint) and returns * the evidence. */ declare function reconcilePlanDepth(nodes: PlanningNode[], edges: DependencyEdge[], spec: PackingSpec, budgetMinutes: number): ReconcileResult; interface ProjectionMeta { courseName: string; shortDescription?: string; targetLanguage?: string; } declare function renderFrameworkFromPlan(plan: CurriculumPlan, meta: ProjectionMeta): string; /** Extract the glossary scope (terms per session) the EXPOSITION service consumes. */ declare function glossaryTermsForSession(plan: CurriculumPlan, lessonCode: string): string[]; /** * KNOWLEDGE_EXPOSITION service — canonical knowledge reference per session, * generated ON DEMAND after framework approval (design doc: option b). * * Guarantees: * - fail-closed: refuses without approval.status === 'approved' * - hash invalidation: regenerates when plan_hash changed after approval * - scope-locked: covers exactly the session's nodes/keywords/depths * - student-facing: no teacher-only content (LESSON owns activities) */ interface ExpositionLlmFn { (systemPrompt: string, userPrompt: string): Promise; } interface ExpositionStorage { readArtifact(projectId: string, relPath: string): Promise; saveArtifact(projectId: string, relPath: string, content: string): Promise; } declare const EXPOSITION_REL: (lessonCode: string) => string; declare class ExpositionApprovalError extends Error { constructor(message: string); } /** Determine whether an existing EXPOSITION can be reused for this lesson. */ declare function isExpositionFresh(existing: string | null, plan: CurriculumPlan, lessonCode: string): boolean; interface DepthViolation { nodeId: string; depth: string; message: string; severity: 'ERROR' | 'WARNING'; } /** * Validates depth compliance for KX Concept Narratives. * - SIO: requires at least 1 fenced code block. * - ULO: warns if fenced code blocks are present (concept should be technology-independent WHAT+WHY). * - CIO: code blocks optional. */ declare function validateDepthCompliance(kxMarkdown: string, depthAssignments: Array<{ node_id: string; depth: string; }>): { ok: boolean; issues: DepthViolation[]; }; declare function buildDomainLexiconGuardrail(techStack?: string, hardwarePlatform?: string): string; declare function buildUserPrompt(session: SessionPlan, plan: CurriculumPlan, glossary: Array<{ term: string; definition?: string; example?: string; }>, targetLanguage?: string, refPack?: string): string; interface GenerateExpositionOptions { projectId: string; lessonCode: string; plan: CurriculumPlan; glossary: Array<{ term: string; definition?: string; example?: string; }>; llmFn: ExpositionLlmFn; storage: ExpositionStorage; gates?: ResolvedGateSettings; targetLanguage?: string; techStack?: string; hardwarePlatform?: string; /** REFERENCE_PACK.md raw content — technical ground truth (versions, APIs). * 5-Whys RC-vacuum: without it the KX model regresses to pretrained facts. */ refPack?: string; /** 5-Whys RC-canonicality: canonical PRODUCT_SPEC fields so KX does not * re-decide the deliverable shape that LESSON/satellites already share. */ productSpec?: { deliverableTemplate?: string; primaryLanguage?: string; }; } interface ExpositionResult { relPath: string; content: string; reused: boolean; gateMode: 'OFF' | 'LLM_JUDGE' | 'HITL'; } /** * Generate (or reuse) the KNOWLEDGE_EXPOSITION for one lesson. * Throws ExpositionApprovalError when the plan is not approved or approval * hash mismatches the current plan — callers must NOT proceed to LESSON. */ declare function ensureKnowledgeExposition(options: GenerateExpositionOptions): Promise; /** Build a compact exposition context block for LESSON / satellite prompts. */ declare function buildExpositionContext(expositionContent: string, maxChars?: number): string; /** Integrity hash helper for cache bookkeeping. */ declare function expositionCacheKey(planHash: string, lessonCode: string): string; /** * End-to-end helper for the produce flow: read plan + glossary from SOT * storage, ensure approval, generate/reuse the EXPOSITION, return a compact * context block. Returns null when no plan exists (legacy flow) — callers * render that state explicitly in telemetry, never silently. */ declare function ensureExpositionForLesson(storage: ICurriculumStorage, projectId: string, lessonCode: string, options?: { gates?: ResolvedGateSettings; force?: boolean; targetLanguage?: string; customInference?: StreamRunnerOptions['customInference']; techStack?: string; hardwarePlatform?: string; }): Promise<{ relPath: string; context: string; reused: boolean; rawContent?: string; } | null>; /** * Translation policy resolver — decides which artifacts need a translated copy * at which point, per the plan's translation policy. Composer executes the * actual translation jobs; the kit owns the policy decision (pure function). * * Policy semantics (approved design D5): * - after_artifact: every artifact gets translated as soon as it passes its gate * - end_of_unit: artifacts of a unit are translated when the unit's last lesson is done * - at_publish: nothing translates until explicit publish — recommended default */ type TranslationTrigger = 'after_artifact' | 'end_of_unit' | 'at_publish'; interface TranslationTarget { /** Artifact-relative path of the SOURCE (always English). */ sourceRelPath: string; /** Where the translated copy belongs (e.g. _i18n/vi/...). */ targetRelPath: string; targetLanguage: string; trigger: TranslationTrigger; /** Unit code for end_of_unit grouping; null for course-wide artifacts. */ unitId: string | null; } declare function resolveTranslationTargets(plan: CurriculumPlan, knownArtifactPaths: string[]): TranslationTarget[]; /** Should this target be translated NOW given the trigger and current state? */ declare function isTranslationDue(target: TranslationTarget, context: { completedLessonsByUnit: Record; totalLessonsByUnit: Record; publishRequested: boolean; }): boolean; /** * Language Directive and section-heading resolution for Curriculum Generation. */ declare function resolveTargetLanguageCode(language?: string | null): string; declare function targetLanguageDisplayName(code: string): string; declare function buildLanguageDirective(targetLanguage?: string | null): string; /** * Identity heading map from the resolved template's echo (canonical = display). */ declare function extractSectionHeadings(artifactType: string, opts?: { templatesDir?: string; }): Record; /** * Builds the heading directive block to instruct the LLM on section headings. * * P53 rev3 — one regime only: the resolved template's ECHO is the source. * - Translated project copy (declaredLang ≠ "en"): headings are already the * display strings. * - Bundled English template: echo = English headings. * The frontmatter list is system-owned (it IS the echo), so the directive * tells the LLM to copy it verbatim — never to translate or invent entries. */ declare function buildHeadingDirective(artifactType: string, opts?: { templatesDir?: string; }): string; /** * Kit 1.5.64: heading directive for the SLIDE artifact that respects a caller- * supplied REQUIRED outline. buildHeadingDirective('SLIDE') injects the * resolved template's "MANDATORY SECTION HEADINGS" + "copy * template_required_sections VERBATIM" — with a required outline that * directive beats the outline (the model clones the template's section list; * measured live on kit 1.5.61–1.5.63 L02 marp runs). When an outline is * supplied, the outline IS the section directive. */ declare function slideHeadingDirective(slidesOutline?: string[]): string; /** * Curriculum OS - Standardized Error Taxonomy & Traceability System * * Provides typed, structured, and traceable error codes for all pipeline failures, * API exceptions, safeguard blocks, and contract violations. */ type CurriculumErrorCode = 'ERR_AI_NO_API_KEY' | 'ERR_AI_RATE_LIMIT' | 'ERR_AI_AUTH_FAILED' | 'ERR_AI_NETWORK_TIMEOUT' | 'ERR_AI_RESPONSE_MALFORMED' | 'ERR_AI_ALL_PROVIDERS_FAILED' | 'ERR_CUSTOM_INFERENCE_REQUIRED' | 'ERR_SOT_MISSING' | 'ERR_SOT_INVALID_SCHEMA' | 'ERR_TASK_GATE_BLOCKED' | 'ERR_METERED_LIMIT_EXCEEDED' | 'ERR_SCHEMA_CONTRACT_VIOLATION' | 'ERR_STORAGE_IO_FAILED' | 'ERR_LESSON_NOT_IN_SOT' | 'ERR_CONTEXT_MISSING'; interface CurriculumErrorDetail { errorCode: CurriculumErrorCode; agent?: string; artifactType?: string; lessonId?: string; provider?: string; statusCode?: number; message: string; suggestedAction: string; retryable: boolean; timestamp: string; rawError?: string; } declare class CurriculumError extends Error { readonly detail: CurriculumErrorDetail; constructor(detail: Omit); get errorCode(): CurriculumErrorCode; get retryable(): boolean; get suggestedAction(): string; toJSON(): CurriculumErrorDetail; } /** * Helper to build standardized AI inference errors */ declare function createAiInferenceError(params: { errorCode: CurriculumErrorCode; message: string; provider?: string; statusCode?: number; agent?: string; artifactType?: string; lessonId?: string; rawError?: any; suggestedAction?: string; retryable?: boolean; }): CurriculumError; declare function createContextMissingError(params: { artifactType: string; missingSource: string; lessonId?: string; agent?: string; }): CurriculumError; type ContextSourceKey = 'KNOWLEDGE_EXPOSITION' | 'CANONICAL_LESSON' | 'SESSION_SLICE' | 'FRAMEWORK_EXCERPT' | 'STYLE_GUIDE' | 'REFERENCE_PACK' | 'LESSON_OBJECTIVES'; interface ArtifactDependencyRule { required: ContextSourceKey[]; optional?: ContextSourceKey[]; rationale: string; } declare const ARTIFACT_DEPENDENCY_ROUTING: Record; interface ValidationOptions { lessonId?: string; agent?: string; failClosed?: boolean; } interface DependencyValidationResult { valid: boolean; missing: ContextSourceKey[]; error?: CurriculumError; } /** * Validates that all required context sources are present and non-empty for an artifact. * When failClosed is true (default), throws CurriculumError(ERR_CONTEXT_MISSING) on first missing source. */ declare function validateArtifactDependencies(artifactType: string, availableSources: Partial>, opts?: ValidationOptions): DependencyValidationResult; interface ParsedActivityRow { seq: number; phase: string; activityType: string; actor: string; purpose: string; studentAction: string; teacherMove: string; /** P49 G4: canonical Output/Evidence column (template col 8). */ outputEvidence: string; /** P49 G4: LO references parsed from the LO column, e.g. ["LO1","LO2"]. */ lo: string[]; time: string; artifactContract: string; } interface ParsedLessonPhase { phaseName: string; title: string; timing?: string; content: string; codeSnippets: string[]; mermaidDiagrams: string[]; } interface ParsedLessonFlow { lessonId: string; lessonTitle: string; pedagogicalModel: string; estimatedDuration: string; slideContract?: string; activities: ParsedActivityRow[]; phases: ParsedLessonPhase[]; rawContent: string; } declare function parseLessonFlow(lessonMarkdown: string): ParsedLessonFlow; interface SlideBlueprintItem { slideIndex: number; clusterId: number; clusterTitle: string; lessonPhase: string; layoutId: string; /** * DEPRECATED (kit 1.5.44, option C unified registry): the bespoke skeletons * ARE layoutIds now. Kept for backward compatibility with persisted * blueprints; normalizeBlueprintItems collapses it into layoutId. */ layoutSkeleton?: string; /** * The slide's headline ASSERTION (high-quality-slides Phase 3 gate): one * declarative sentence ≤12 words — "Commit verification takes one hash", * not "Git Commit". Empty title-style headlines are the #1 slop tell. */ headlineAssertion?: string; /** * The slide's ONE intended visual (high-quality-slides Phase 3): chart / * diagram / photo / icon set / typographic treatment / code walkthrough. * Forces the art-director decision before any markup exists. */ intendedVisual?: string; title: string; pedagogicalGoal: string; contentFocus: string[]; codeSnippetIntent?: string; visualIntent?: string; } interface SlideBatch { /** 1-based position of this batch in the deck request order. */ index: number; items: T[]; estimatedTokens: number; /** Blueprint clusters touched by this batch (a merged batch has several). */ clusterIds: number[]; /** True when the batch is only part of the content cluster it came from. */ splitFromCluster: boolean; /** True when ONE item already exceeds the budget on its own. */ oversized: boolean; } interface FirstPassSlideAudit { id: string; layoutId?: string; html: string; lint: { valid: boolean; hardIssues: string[]; compositionIssues: string[]; }; geometry: { available: boolean; deadBand: number; atY: number; } | null; verdict: 'hard-fail' | 'true-positive' | 'lint-overreach' | 'clean'; } /** * Pure audit builder: join first-pass markup + full-enforcement lint verdicts * + first-pass scanline geometry into the overreach/true-positive split. * Tolerates legacy validators (≤0.3.5) that only return `issues` + `compositionOnly`. */ declare function buildFirstPassAudit(firstPass: Array<{ id: string; html: string; layoutId?: string; }>, validate: (html: string) => { valid: boolean; issues: string[]; hardIssues?: string[]; compositionIssues?: string[]; }, geometry: { available: boolean; issues: Array<{ slideIndex: number; deadBand: number; atY: number; }>; } | null): FirstPassSlideAudit[]; /** Thrown when the hybrid engine exhausts its attempts; triggers chunked fallback. */ declare class HybridPipelineError extends Error { } /** * Thrown when the hybrid engine falls back to the chunked pipeline MID-FLIGHT * (budget guard, truncated full-deck call, guardrail exhaustion) AFTER a valid * blueprint exists. Carries that blueprint so the fallback keeps the deck-wide * layout assignment instead of re-rolling it with a fresh blueprint call. */ declare class HybridFallbackSignal extends Error { readonly blueprint: SlideBlueprintItem[]; constructor(message: string, blueprint: SlideBlueprintItem[]); } /** * Hybrid guardrails: semantic validation with corrective feedback. */ declare function validateHybridDeckSlides(slides: any[], blueprint: SlideBlueprintItem[]): string[]; interface ExtractedJson { value?: unknown; error?: string; head?: string; tail?: string; } /** * Re-escape unescaped double quotes inside JSON string values. * * A quote is a genuine string DELIMITER only when the next significant * character (skipping whitespace) is one of , } ] : — otherwise it is part * of the string content (an HTML attribute quote, a Vietnamese quotation * mark, …) and gets escaped. Assumes `jsonrepair` already failed, i.e. the * span is structurally ambiguous and this heuristic is the last resort. * Idempotent on valid JSON: every close there is already followed by a * structural char, so the walk reproduces the input byte-for-byte. */ declare function requoteUnescapedQuotes(span: string): string; /** * Extract a JSON array from reasoning models that may include markdown fences, * blocks, or unescaped HTML attributes. */ declare function extractJsonArray(raw: string | undefined | null): ExtractedJson; declare const SLOTS_MODE_LAYOUTS: Set; /** * Normalize model shape-drift: id → canonical "slide-N"; missing title backfilled * from blueprint items matched by index, falling back to positional order. * Materializes {skeleton, slots} markup through renderSkeleton deterministically. */ declare function makeSlideNormalizer(items: Array>, renderSkeleton?: (id: string, slots: Record) => string): (s: any, idx: number) => any; /** * Skeleton-mimicry detector (fail-closed): a slots-mode slide whose html is NOT * the deterministic renderer's output is a mimicry attempt. Backstop only — * makeSlideNormalizer re-renders slots-mode markup through the renderer since * kit 1.5.51, so this fires when slots were missing/empty (nothing to render * from) and the model shipped authored markup anyway. */ declare function skeletonMimicryIssue(s: any, item: SlideBlueprintItem | undefined, renderSkeleton?: (id: string, slots: Record) => string): string | undefined; /** * Normalizes blueprint items, assigning cluster IDs, sequential indices, and layout skeletons. */ declare function normalizeBlueprintItems(items: Array>): SlideBlueprintItem[]; declare const SlideBlueprintItemSchema: z.ZodObject<{ slideIndex: z.ZodNumber; clusterId: z.ZodDefault>>; clusterTitle: z.ZodDefault>>; lessonPhase: z.ZodDefault>>; layoutId: z.ZodString; layoutSkeleton: z.ZodOptional>; headlineAssertion: z.ZodOptional>; intendedVisual: z.ZodOptional>; title: z.ZodString; pedagogicalGoal: z.ZodDefault>>; contentFocus: z.ZodDefault>>>; codeSnippetIntent: z.ZodOptional>; visualIntent: z.ZodOptional>; }, "strip", z.ZodTypeAny, { title: string; clusterId: number | null; clusterTitle: string | null; layoutId: string; contentFocus: string[] | null; pedagogicalGoal: string | null; slideIndex: number; lessonPhase: string | null; codeSnippetIntent?: string | null | undefined; visualIntent?: string | null | undefined; headlineAssertion?: string | null | undefined; intendedVisual?: string | null | undefined; layoutSkeleton?: string | null | undefined; }, { title: string; layoutId: string; slideIndex: number; clusterId?: number | null | undefined; clusterTitle?: string | null | undefined; contentFocus?: string[] | null | undefined; codeSnippetIntent?: string | null | undefined; visualIntent?: string | null | undefined; pedagogicalGoal?: string | null | undefined; lessonPhase?: string | null | undefined; headlineAssertion?: string | null | undefined; intendedVisual?: string | null | undefined; layoutSkeleton?: string | null | undefined; }>; declare const SlideBlueprintArraySchema: z.ZodArray>>; clusterTitle: z.ZodDefault>>; lessonPhase: z.ZodDefault>>; layoutId: z.ZodString; layoutSkeleton: z.ZodOptional>; headlineAssertion: z.ZodOptional>; intendedVisual: z.ZodOptional>; title: z.ZodString; pedagogicalGoal: z.ZodDefault>>; contentFocus: z.ZodDefault>>>; codeSnippetIntent: z.ZodOptional>; visualIntent: z.ZodOptional>; }, "strip", z.ZodTypeAny, { title: string; clusterId: number | null; clusterTitle: string | null; layoutId: string; contentFocus: string[] | null; pedagogicalGoal: string | null; slideIndex: number; lessonPhase: string | null; codeSnippetIntent?: string | null | undefined; visualIntent?: string | null | undefined; headlineAssertion?: string | null | undefined; intendedVisual?: string | null | undefined; layoutSkeleton?: string | null | undefined; }, { title: string; layoutId: string; slideIndex: number; clusterId?: number | null | undefined; clusterTitle?: string | null | undefined; contentFocus?: string[] | null | undefined; codeSnippetIntent?: string | null | undefined; visualIntent?: string | null | undefined; pedagogicalGoal?: string | null | undefined; lessonPhase?: string | null | undefined; headlineAssertion?: string | null | undefined; intendedVisual?: string | null | undefined; layoutSkeleton?: string | null | undefined; }>, "many">; declare const GeneratedSlideSchema: z.ZodObject<{ id: z.ZodOptional, string, string | number>>>; layoutId: z.ZodString; title: z.ZodString; slots: z.ZodDefault>>>; notes: z.ZodDefault>>; }, "strip", z.ZodTypeAny, { title: string; slots: Record | null; layoutId: string; notes: string | null; id?: string | null | undefined; }, { title: string; layoutId: string; id?: string | number | null | undefined; slots?: Record | null | undefined; notes?: string | null | undefined; }>; declare const GeneratedSlideArraySchema: z.ZodArray, string, string | number>>>; layoutId: z.ZodString; title: z.ZodString; slots: z.ZodDefault>>>; notes: z.ZodDefault>>; }, "strip", z.ZodTypeAny, { title: string; slots: Record | null; layoutId: string; notes: string | null; id?: string | null | undefined; }, { title: string; layoutId: string; id?: string | number | null | undefined; slots?: Record | null | undefined; notes?: string | null | undefined; }>, "many">; declare const HybridBlueprintItemSchema: z.ZodObject<{ slideIndex: z.ZodNumber; clusterId: z.ZodOptional>; clusterTitle: z.ZodOptional>; lessonPhase: z.ZodOptional>; layoutId: z.ZodString; title: z.ZodString; pedagogicalGoal: z.ZodDefault>>; contentFocus: z.ZodDefault>>>; codeSnippetIntent: z.ZodOptional>; visualIntent: z.ZodOptional>; }, "strip", z.ZodTypeAny, { title: string; layoutId: string; contentFocus: string[] | null; pedagogicalGoal: string | null; slideIndex: number; clusterId?: number | null | undefined; clusterTitle?: string | null | undefined; codeSnippetIntent?: string | null | undefined; visualIntent?: string | null | undefined; lessonPhase?: string | null | undefined; }, { title: string; layoutId: string; slideIndex: number; clusterId?: number | null | undefined; clusterTitle?: string | null | undefined; contentFocus?: string[] | null | undefined; codeSnippetIntent?: string | null | undefined; visualIntent?: string | null | undefined; pedagogicalGoal?: string | null | undefined; lessonPhase?: string | null | undefined; }>; declare const HybridBlueprintArraySchema: z.ZodArray>; clusterTitle: z.ZodOptional>; lessonPhase: z.ZodOptional>; layoutId: z.ZodString; title: z.ZodString; pedagogicalGoal: z.ZodDefault>>; contentFocus: z.ZodDefault>>>; codeSnippetIntent: z.ZodOptional>; visualIntent: z.ZodOptional>; }, "strip", z.ZodTypeAny, { title: string; layoutId: string; contentFocus: string[] | null; pedagogicalGoal: string | null; slideIndex: number; clusterId?: number | null | undefined; clusterTitle?: string | null | undefined; codeSnippetIntent?: string | null | undefined; visualIntent?: string | null | undefined; lessonPhase?: string | null | undefined; }, { title: string; layoutId: string; slideIndex: number; clusterId?: number | null | undefined; clusterTitle?: string | null | undefined; contentFocus?: string[] | null | undefined; codeSnippetIntent?: string | null | undefined; visualIntent?: string | null | undefined; pedagogicalGoal?: string | null | undefined; lessonPhase?: string | null | undefined; }>, "many">; declare const HybridDeckSlideSchema: z.ZodObject<{ id: z.ZodOptional>; layoutId: z.ZodString; title: z.ZodString; slots: z.ZodDefault>>>; notes: z.ZodDefault>>; }, "passthrough", z.ZodTypeAny, z.objectOutputType<{ id: z.ZodOptional>; layoutId: z.ZodString; title: z.ZodString; slots: z.ZodDefault>>>; notes: z.ZodDefault>>; }, z.ZodTypeAny, "passthrough">, z.objectInputType<{ id: z.ZodOptional>; layoutId: z.ZodString; title: z.ZodString; slots: z.ZodDefault>>>; notes: z.ZodDefault>>; }, z.ZodTypeAny, "passthrough">>; declare const HybridDeckSlideArraySchema: z.ZodArray>; layoutId: z.ZodString; title: z.ZodString; slots: z.ZodDefault>>>; notes: z.ZodDefault>>; }, "passthrough", z.ZodTypeAny, z.objectOutputType<{ id: z.ZodOptional>; layoutId: z.ZodString; title: z.ZodString; slots: z.ZodDefault>>>; notes: z.ZodDefault>>; }, z.ZodTypeAny, "passthrough">, z.objectInputType<{ id: z.ZodOptional>; layoutId: z.ZodString; title: z.ZodString; slots: z.ZodDefault>>>; notes: z.ZodDefault>>; }, z.ZodTypeAny, "passthrough">>, "many">; declare const BespokeSlideSchema: z.ZodObject<{ id: z.ZodOptional, string, string | number>>>; title: z.ZodOptional>; skeleton: z.ZodOptional>; slots: z.ZodDefault>>>; html: z.ZodOptional>; notes: z.ZodDefault>>; }, "strip", z.ZodTypeAny, { slots: Record | null; notes: string | null; title?: string | null | undefined; id?: string | null | undefined; html?: string | null | undefined; skeleton?: string | null | undefined; }, { title?: string | null | undefined; id?: string | number | null | undefined; html?: string | null | undefined; slots?: Record | null | undefined; notes?: string | null | undefined; skeleton?: string | null | undefined; }>; declare const BespokeSlideArraySchema: z.ZodArray, string, string | number>>>; title: z.ZodOptional>; skeleton: z.ZodOptional>; slots: z.ZodDefault>>>; html: z.ZodOptional>; notes: z.ZodDefault>>; }, "strip", z.ZodTypeAny, { slots: Record | null; notes: string | null; title?: string | null | undefined; id?: string | null | undefined; html?: string | null | undefined; skeleton?: string | null | undefined; }, { title?: string | null | undefined; id?: string | number | null | undefined; html?: string | null | undefined; slots?: Record | null | undefined; notes?: string | null | undefined; skeleton?: string | null | undefined; }>, "many">; type SlideEngine = 'hybrid' | 'chunked' | 'bespoke'; interface SlideProductionWorkflowOptions { lessonMarkdown: string; lessonCode: string; lessonTitle: string; targetSlideCount?: number; stylePresetId?: string; /** Brand color (hex, e.g. "#00503f"): a full deck theme is generated from it * (Oklch lightness math, deterministic) and takes precedence over the style * preset's colors. Persisted as a theme OBJECT in deck.json.theme so every * recompile stays on-brand. */ brandColor?: string; language?: string; languageDirective?: string; headingDirective?: string; /** * Ground-truth context (framework, style guide, glossary, GROUND TRUTH KX+RefPack, * session slice, horizon, symbol registry) injected into the PRIMARY system prompt * of every authoring call — hybrid full-deck and chunked batches alike. * Without it, only the legacy raw-fetch fallback sees this context. * Deliberately EXCLUDES the canonical lesson excerpt: lesson phase content is * already injected into user prompts via parseLessonFlow (no duplication). */ groundContext?: string; /** Canonical PRODUCT_SPEC block (prompt audit S-1): injected into the * blueprint prompt so deck-wide content decisions see binding platform/ * version facts even though the blueprint call carries no groundContext. */ productSpecBlock?: string; /** Caller-supplied REQUIRED slide outline (kit 1.5.60): ordered section * titles the deck MUST cover, in order. Present → blueprint maps every * item to ≥1 slide in order (structure constraint; titles stay free). * Absent → blueprint self-plans from the lesson flow (standalone slides * without a LESSON keep working). */ slidesOutline?: string[]; satelliteContext?: any; /** Vercel AI SDK model resolution options (provider/model/apiKey). */ modelOptions?: ModelResolutionOptions; /** * Which engine to run. * 'hybrid' — blueprint + the WHOLE deck in one call (only allowed when the * estimate fits the 32k pool floor; otherwise auto-falls back). * 'chunked' — blueprint + budget-packed batches of SLOT slides. * 'bespoke' — blueprint + budget-packed batches of AUTHORED HTML slides * (frontend-slides mode: the model designs each slide). Falls * back to 'chunked' when authoring cannot produce valid slides. */ engine?: SlideEngine; /** Content density (frontend-slides skill): 'speaker' upsizes type for * keynote-style decks; 'reading' (default) keeps the neutral scale. */ density?: 'speaker' | 'reading'; /** Repair rounds for contract-violating bespoke slides before the batch is * treated as failed (default 1). */ bespokeRepairRounds?: number; /** Max attempts per inference unit (blueprint / each cluster / full deck). Default 3. */ maxRetries?: number; /** Unused reserved knob of the legacy hybrid planner — do not extend. */ minTurnsPerCluster?: number; /** Max output tokens for hybrid generateText calls. Default 65536. */ maxOutputTokens?: number; /** * Hard cap on slides per authoring call, ON TOP of the token budget * (default 8 for the bespoke HTML engine, 10 otherwise — see packRemaining). * The token estimator is a heuristic even after calibration, so a * prose-light blueprint can otherwise plan a 12-14-slide single call that * truncates (observed: 14 slides in one call, finish=length, whole retry * ladder burned). Lower it for very dense layouts; a value below 1 is * clamped to 1. */ maxSlidesPerTurn?: number; /** When true, ALSO allows the legacy raw-fetch runner as a structured-output * fallback after generateObject fails. Default FALSE (telemetry mandate, * 2026-09-14): the raw path is invisible to the unified OpenTelemetry → * Langfuse trace, so it must never run unless explicitly opted in. When * enabled, pass runnerOptions.customInference so the fallback stays traced * (and satisfies CURRICULUM_KIT_REQUIRE_CUSTOM_INFERENCE=1). */ allowLegacyFallback?: boolean; runnerOptions?: any; onProgress?: (agent: string, message: string, meta?: any) => void; } interface SlideProductionWorkflowResult { deckJson: any; compiledHtml?: string; markdownWrapper: string; blueprint: SlideBlueprintItem[]; slideCount: number; /** Which engine actually produced the deck (hybrid may fall back to chunked). */ engine: SlideEngine; /** Bespoke only: per-slide audit of the FIRST authoring pass, captured * before any repair replaced the markup (also mirrored into * deckJson.audit.firstPass so persisted artifacts carry it). */ firstPassAudit?: FirstPassSlideAudit[]; } /** * Normalize the AI SDK's usage shape and forward it through onProgress in the * kit's canonical usage contract (`JSON.stringify({ promptTokens, * completionTokens, totalTokens, reasoningTokens })` + `meta.type = 'usage'`). * * 5-Whys RC-telemetry (2026-09-13): the slide workflow never emitted usage, so * the app-side queue recorded inputTokens=0/outputTokens=0 for every SLIDE * execution. AI SDK v5+ renames the fields (inputTokens/outputTokens) — read * both shapes defensively. */ declare function emitUsage(usage: { promptTokens?: number; completionTokens?: number; inputTokens?: number; outputTokens?: number; totalTokens?: number; reasoningTokens?: number; } | undefined, onProgress?: (agent: string, message: string, meta?: any) => void): void; /** * Thrown by inferTextJson the moment a call comes back finish=length * (truncation). Kit 1.5.33: a truncation is deterministic for a given batch * size — retrying verbatim re-burns the full token budget (measured: 3 × 5-8 * min per over-budget batch) before any split. Owners of the call convert * this into an immediate split-in-half (batch loops) or an early pipeline * fallback (hybrid full-deck call). Never leak past the workflow boundary — * every throw site catches it. */ declare class SplitBatchSignal extends Error { constructor(label: string); } /** * DENSITY DIRECTIVE (RC 2026-09-23): 2–4 minutes of lesson time per slide. * Derives the blueprint target from the lesson's stated duration; 15 stays as * the unknown-duration fallback. Exported for tests. */ declare function deriveTargetSlideCountFromLesson(lessonMarkdown: string): number; interface ContractTiers { hard: string[]; composition: string[]; } /** * Split a validator result into tier-1 hard violations (always gate) and * tier-2 composition lints (dead-band heuristics). Tolerates legacy * presentation-kit ≤0.3.5 results that only carry `issues` + * `compositionOnly`. */ declare function classifyContractViolations(v: { valid: boolean; issues: string[]; hardIssues?: string[]; compositionIssues?: string[]; compositionOnly?: boolean; }): ContractTiers; /** * Runs every batch through `authorOne`, and when a batch permanently fails * (truncation, provider error, contract violations) SPLITS IT IN HALF and * retries each half — a single slide is the floor. Shared by the slot and * bespoke pipelines so the resilience contract cannot drift between them. */ /** Exported for tests (truncation-split pin). */ declare function authorBatchesWithSplit(batches: SlideBatch[], authorOne: (batch: SlideBatch, depth: number) => Promise, onProgress?: SlideProductionWorkflowOptions['onProgress'], /** After a batch lands, optionally re-plan the queue (self-calibration). */ afterBatch?: (batch: SlideBatch, slides: any[]) => SlideBatch[] | null): Promise<{ slides: any[]; failed: Array<{ index: number; clusterIds: number[]; }>; }>; declare function executeSlideProductionWorkflow(options: SlideProductionWorkflowOptions): Promise; /** * LO Time Estimator — deterministic, activity-anchored minute estimation. * * Model: minutes belong to ACTIVITIES, not to learning objectives (idea * docs/ideas/2026-10-09-lo-time-estimation-models.md). This module is pure: * no I/O, no LLM. The planner calls it; it never calls the planner. * * Levels: L0 reference class (fallback) · L1 bundle template · L2 activity * count (plan phase D: artifact measurement) · L3 observed (out of scope — * no class-log channel yet). */ /** Incoming-vs-model divergence that earns a `time_estimate:` warning (seed — mirrors domain-kit MIN_CALIBRATION_DIVERGENCE). */ declare const TIME_DIVERGENCE_THRESHOLD = 0.5; interface PertResult { /** PERT expected value: (O + 4M + P) / 6. */ likely: number; /** PERT sigma: (P − O) / 6. */ sigma: number; } declare function pert3(tp: ThreePoint): PertResult; declare function p75FromSigma(likely: number, sigma: number): number; /** * Honest fallback: when a node carries no usable depth/bloom metadata we KEEP * the incoming minutes instead of guessing — labeled L0 / reference_class * with low confidence so downstream can tell the difference. */ declare function referenceFallbackEstimate(loId: string, incomingMinutes: number): LoTimeEstimate; interface BundleEstimateInput { lo_id: string; depth: DepthLevel; bloom: BloomLevel; /** PlanConstraints.age_band — paces instruction activities only (seed). */ ageBand?: readonly [number, number]; /** Authored SIO item count (depth_context.sio.length) — overrides the independent-practice quantity. */ sioCount?: number; } /** * Build the activity list for (depth, bloom): depth base bundle + Bloom-floor * overlay for any required group the base lacks (idea §3). */ declare function bundleEntriesFor(depth: DepthLevel, bloom: BloomLevel, sioCount?: number): BundleEntrySeed[]; /** * L1 estimate from a bundle template. Three-point comes straight from the * template entries; `likely` is the PERT value of the summed range. */ declare function estimateByBundleTemplate(input: BundleEstimateInput): LoTimeEstimate; interface ActivityCountInput { type: ActivityType; quantity: number; unit_minutes: number; modifiers?: Record; /** Default true — pair/parallel work can set false to avoid double-counting. */ counts_toward_total?: boolean; } /** * Counted-activity estimate: Σ quantity × unit × modifier product for entries * that count. Three-point derived from the level's expected-error band (idea * multi-level table) around the summed point estimate. */ declare function estimateByActivityCount(loId: string, activities: ActivityCountInput[], opts?: { level?: 'L1' | 'L2' | 'L3'; confidence?: number; }): LoTimeEstimate; interface ArtifactTimeInput { lo_id: string; /** Word count of HANDOUT/GUIDE material → reading time (120–180 wpm). */ handoutWords?: number; /** Number of concept slides → lecture time (1–2 min/slide). */ slideCount?: number; /** Activity/worksheet procedure items → guided practice (expert × STUDENT_FRICTION_MULTIPLIER). */ activityItems?: number; /** Recall questions (e.g. lesson exit-ticket questions). */ quizQuestions?: number; } /** Word count of markdown-ish text — punctuation/code symbols collapse to spaces. */ declare function countWords(text: string): number; /** * L2 estimate measured from artifacts that actually shipped (idea time-boxing * artifact table): words → reading, slides → lecture, activity items → guided * practice, quiz questions → recall. Three-point per rule from the catalog; * `likely` is the PERT value of the summed range, same as the bundle path. */ declare function measureArtifactMinutes(input: ArtifactTimeInput): LoTimeEstimate; /** L1-vs-L2 divergence warning, or null when within threshold (plan TC8). */ declare function timeDivergenceWarning(loId: string, from: LoTimeEstimate, to: LoTimeEstimate): string | null; /** Groups of activity types; at least one type from each group is required for the Bloom level. */ declare function minActivitiesForBloom(bloom: BloomLevel): ActivityType[][]; declare function baselineV0(input: { depth: DepthLevel; bloom: BloomLevel; ageBand?: readonly [number, number]; }): number; interface BufferSummary { /** Sum of PERT likely minutes. */ p50: number; /** P75 planning point: p50 + 0.675 × pooled sigma. */ p75: number; /** Pooled sigma √Σσ² (one-sigma aggregate buffer). */ buffer: number; } declare function aggregateBuffer(estimates: LoTimeEstimate[]): BufferSummary; /** * Academic Quality & Pedagogical Verification Types */ type AcademicDimension = 'CONSTRUCTIVE_ALIGNMENT' | 'BLOOM_PROGRESSION' | '5E_INSTRUCTIONAL_FIDELITY' | 'MISCONCEPTION_RIGOR' | 'TECHNICAL_AUTHENTICITY' | 'CROSS_ARTIFACT_ZERO_DRIFT'; type FindingSeverity = 'CRITICAL' | 'MAJOR' | 'MINOR'; interface AcademicAuditFinding { id: string; dimension: AcademicDimension; severity: FindingSeverity; title: string; description: string; remediationAdvice: string; affectedElement?: string; } interface DimensionScore { score: number; weight: number; passed: boolean; strengths: string[]; findings: AcademicAuditFinding[]; } interface ComprehensiveAcademicReport { timestamp: string; targetId: string; targetType: 'LESSON' | 'QUIZ' | 'ACT' | 'SLIDE' | 'BUNDLE' | 'SOT_CLUSTER'; overallScore: number; passed: boolean; verdict: 'EXEMPLARY' | 'ACADEMICALLY_SOUND' | 'NEEDS_PEDAGOGICAL_REFINEMENT' | 'REJECTED'; summary: string; dimensionScores: { constructiveAlignment: DimensionScore; bloomProgression: DimensionScore; fiveEFidelity: DimensionScore; misconceptionRigor: DimensionScore; technicalAuthenticity: DimensionScore; crossArtifactZeroDrift: DimensionScore; }; criticalFindingsCount: number; allFindings: AcademicAuditFinding[]; actionablePromptGuidance: string[]; } /** * 🛠️ Deterministic Structural & Contract Linter * Strict rule-based checks: Schema completeness, Zero-drift ID alignment, * format sanity, and structural safety rules. * * ⛔ DOES NOT do regex-based semantic parsing or fake semantic understanding. * All semantic, cognitive, and pedagogical evaluations are delegated to LLM-as-a-Judge. */ declare class DeterministicStructuralLinter { /** * Validates structural invariants across a complete lesson bundle. */ static lintBundle(input: { lesson: LessonPlan; quiz?: DiagnosticQuizInput; activity?: ActivityLab; slides?: SlideDeck; codeLab?: CodeLab; }): { passed: boolean; structuralScore: number; findings: AcademicAuditFinding[]; strengths: string[]; }; /** * P50: Validates macro-pedagogical invariants across a CurriculumPlan. * Checks: * 1. ZPD violations without self-healing recap (NO_ZPD_BRIDGE) * 2. Walking Skeleton existence (Unit 1 delivers working software) * 3. Inter-unit Mastery Gate presence */ static lintPlan(plan: CurriculumPlan): { passed: boolean; score: number; findings: AcademicAuditFinding[]; strengths: string[]; }; /** * Validates structural and environment feasibility invariants for a Project Graph bundle. */ static lintProjectGraph(bundle: { technology_scope?: any; project_graph?: any; }, expectedSessions?: number): { passed: boolean; score: number; findings: AcademicAuditFinding[]; strengths: string[]; }; } interface AuditBundleInput { lesson: LessonPlan; quiz?: DiagnosticQuizInput; activity?: ActivityLab; slides?: SlideDeck; codeLab?: CodeLab; modelOptions?: ModelResolutionOptions; executeLLMJudge?: boolean; } declare class AcademicAuditor { /** * Evaluates a complete lesson bundle. * Step 1 (Deterministic): Fast structural, contract, schema, and safety linting. * Step 2 (Semantic LLM-as-a-Judge): Deep pedagogical, cognitive (Bloom), and misconception analysis with live frontier LLM. */ static auditLessonBundle(input: AuditBundleInput): Promise; } declare const BLOOM_ACTION_VERBS: { remember: string[]; understand: string[]; apply: string[]; analyze: string[]; evaluate: string[]; create: string[]; }; declare class BloomTaxonomyEvaluator { /** * Audits a LessonPlan for Bloom taxonomy fidelity and cognitive scaffolding. */ static evaluateLesson(lesson: LessonPlan): DimensionScore; /** * Audits a Diagnostic Quiz for true cognitive depth matching declared Bloom levels. */ static evaluateQuiz(quiz: DiagnosticQuiz): DimensionScore; } declare class CrossArtifactDriftEvaluator { /** * Audits consistency, metadata synchronization, and zero-drift across all artifacts in a lesson bundle. */ static evaluateBundle(lesson: LessonPlan, quiz?: DiagnosticQuiz, activity?: ActivityLab, slides?: SlideDeck): DimensionScore; } declare class ConstructiveAlignmentEvaluator { /** * Evaluates constructive alignment within a LessonPlan and across its satellite artifacts. */ static evaluateLesson(lesson: LessonPlan, quiz?: DiagnosticQuiz, activity?: ActivityLab): DimensionScore; } declare class FiveEInstructionalEvaluator { /** * Evaluates the pedagogical structure of a Lesson Plan against the 5E Inquiry Model. */ static evaluateLesson(lesson: LessonPlan): DimensionScore; } declare class CodeHardwareFeasibilityEvaluator { /** * Audits technical accuracy, code syntax sanity, and hardware circuit safety. */ static evaluateTechnicalFeasibility(lesson?: LessonPlan, codeLab?: CodeLab, activity?: ActivityLab): DimensionScore; } declare class MisconceptionEvaluator { /** * Audits the psychometric and pedagogical rigor of diagnostic questions and their distractors. */ static evaluateQuiz(quiz: DiagnosticQuiz): DimensionScore; } interface PedagogicalDensityReport { score: number; handsOnRatio: number; activeVerbsCount: number; interactiveElementsCount: number; verdict: 'HIGH' | 'BALANCED' | 'PASSIVE'; recommendations: string[]; } interface CognitiveLoadReport { score: number; avgSentenceLength: number; technicalTermsDensity: number; gradeLevelEstimate: 'PRIMARY' | 'MIDDLE_SCHOOL' | 'HIGH_SCHOOL' | 'ADVANCED'; verdict: 'OPTIMAL' | 'OVERLOAD' | 'UNDERLOAD'; recommendations: string[]; } interface CrossArtifactAlignmentReport { score: number; loCoverageRatio: number; uncoveredObjectives: string[]; timelineContradictions: string[]; verdict: 'STRONG_ALIGNMENT' | 'PARTIAL_ALIGNMENT' | 'MISALIGNED'; } /** * Evaluates the pedagogical density: measures active hands-on vs passive lecture. */ declare function evaluatePedagogicalDensity(artifactType: string, content: string): PedagogicalDensityReport; /** * Evaluates Cognitive Load heuristic based on sentence length and technical density. */ declare function evaluateCognitiveLoad(content: string): CognitiveLoadReport; /** * Evaluates cross-artifact alignment between a Lesson plan and a satellite artifact. */ declare function evaluateCrossArtifactAlignment(lessonObjectives: string[], satelliteContent: string): CrossArtifactAlignmentReport; interface SourceSlotConfig { sections?: string[]; budgetTokens?: number; priority?: number; exclusive?: boolean; } interface InputContract { requiredSources: ContextSourceKey[]; optionalSources: ContextSourceKey[]; sourceSlots?: Partial>; } interface ValidationIssue { severity: 'ERROR' | 'WARNING'; code: string; message: string; field?: string; suggestion?: string; } interface ValidationResult { valid: boolean; issues: ValidationIssue[]; } type ValidatorFunction = (content: string, context?: Record) => ValidationResult | Promise; interface ArtifactTypeContract { type: string; canonicalName: string; filenamePattern: string; persona: string; templateFile: string; outputSchema?: TSchema; inputContract: InputContract; promptInvariants?: string[]; validators?: ValidatorFunction[]; } declare function getContract(type: string): ArtifactTypeContract | undefined; declare function getAllContracts(): ArtifactTypeContract[]; declare function hasContract(type: string): boolean; declare function registerContract(contract: ArtifactTypeContract): void; /** LESSON slot spec; `priorities` are semantic keys (headerDictionary.ts), NOT literal headings. */ declare function getLessonSlotBudget(type: string): { budget: number; priorities?: string[]; } | undefined; /** * Registry default for artifact types that declare no `lessonBudget`. * * SINGLE source of truth for the lesson-excerpt slot: the AST projection, the * markdown fallback, and the shared satellite excerpt all resolve priorities * from here. They used to carry private literal lists that disagreed — the AST * branch fell back to 2 keys while the markdown branch used 5, so the same * lesson yielded different excerpts depending on whether the AST overlay * resolved. 12k is the shared satellite excerpt budget. */ declare const DEFAULT_LESSON_SLOT: { budget: number; priorities: string[]; }; /** * Registry default for artifact types that declare no `kxPriorities`. Same * single-source rule as DEFAULT_LESSON_SLOT — the KX default used to be copy * pasted into every consumer, so they could drift apart. */ declare const DEFAULT_KX_SLOT_PRIORITIES: string[]; /** * KX excerpt budget in characters, used when no per-type spec overrides it. * 4500 is the satellite-path value — the path that actually runs in production * under hybrid routing — so leaving types unset does not silently change what * satellites receive. */ declare const DEFAULT_KX_SLOT_BUDGET = 4500; /** Effective lesson slot spec for a type: per-type entry, else the registry default. */ declare function resolveLessonSlotSpec(type: string): { budget: number; priorities: string[]; }; declare function getKxSlotPriorities(type: string): string[] | undefined; declare function getKxSlotBudget(type: string): number | undefined; /** * Effective KX slot spec for a type: per-type priorities/budget, else the * registry defaults. KX budget used to be a bare literal in each consumer — * 4500 in the satellite path and 6000 in the single-artifact path — so the * same exposition was injected at two different sizes depending on which path * ran. One registry fact now decides. */ declare function resolveKxSlotSpec(type: string): { budget: number; priorities: string[]; }; declare function isKxOnlyType(type: string): boolean; interface ArtifactValidationContext { projectId?: string; lessonId?: string; expectedVersion?: string; allowedScopeTags?: string[]; [key: string]: unknown; } /** * Universal Post-Generation Validation Gate for all 21 Artifact Types. * Runs: * 1. Zod schema validation (if outputSchema configured). When NO typed data was * supplied the step reports ERR_SCHEMA_SKIPPED instead of passing silently — * `valid` only ever means "nothing failed", and the warning says what was * never checked. * 2. Deterministic anti-leak checks (CJK leaks, Version Truth, Scope Drift). * 3. Type-specific custom validators (if defined in contract). */ declare function validateArtifactOutput(artifactType: string, markdownContent: string, entityOrData?: unknown, context?: ArtifactValidationContext): Promise; type AstWarningCode = 'UNRECOGNIZED_HEADING' | 'UNEXPECTED_STRUCTURE' | 'BUDGET_EXCEEDED'; interface AstWarning { code: AstWarningCode; message: string; heading?: string; depth?: number; line?: number; } /** * Ephemeral In-Memory Lossless AST with Semantic Overlay */ interface ArtifactAst { /** Tầng 1: Lossless mdast tree (giữ position nội bộ) */ tree: Root; /** Tầng 2: Semantic overlay (key path -> node references, không copy) */ semanticIndex: Map; /** Nhánh không match từ điển, giữ đúng thứ tự tài liệu */ customBlocks: Node[]; /** Danh sách cảnh báo (ví dụ: heading ngoài từ điển) */ warnings: AstWarning[]; } interface SerializeAstOptions { stripPosition?: boolean; } interface SerializedArtifactAst { tree: Root; semanticIndex: Record; customBlocks: Node[]; warnings: AstWarning[]; } /** * Multilingual Semantic Header Matcher & Dictionary * * Maps headings (English, Vietnamese, with icons/emojis/numbers/system tags) * across 21 artifact types and SOT documents to stable semantic key paths. */ /** * Strips formatting, markers, numbers, emojis, and duration annotations from heading text. */ declare function cleanHeadingText(raw: string): string; /** * Normalizes a heading into a dictionary lookup key: lowercased, diacritics * folded, punctuation dropped. * * Unicode-aware on purpose. Stripping everything outside `[a-z0-9]` erased * every non-Latin script outright — '课程概览', 'Ключевые термины' and * 'キーワード' all normalized to the empty string, and because * `matchHeadingToSemanticKey` falls back to `'unrecognized'` for an empty * result, every distinct heading in those scripts collapsed onto ONE shared * key. Any project taught in Chinese, Russian, Japanese, Korean or Arabic lost * semantic resolution entirely and silently degraded to the regex fallback. * Keeping `\p{L}\p{N}` preserves each script's letters, so those headings stay * distinct. * * Latin input is unaffected: NFD plus diacritic folding maps Vietnamese onto * the same ASCII the dictionary was built from, so every existing key still * resolves. Only non-Latin input changes behaviour. * * NOTE: `norm()` in contextSlots.ts is deliberately NOT this function. It * compares an ASCII artifact-type code against a table cell, so it must fold * hard onto ASCII to match Vietnamese cells like 'Hoạt động' → 'HOATDONG'. */ declare function normHeading(s: string): string; interface SemanticHeaderEntry { /** Stable semantic identifier (e.g. 'learningObjectives') */ key: string; /** Optional preferred parent key path (e.g. 'lessonDesignPlan') */ parentKey?: string; /** Human-readable canonical title */ canonicalTitle: string; } interface MatchHeadingResult { /** The semantic key for this heading (e.g. 'learningObjectives') */ key: string; /** Full semantic key path (e.g. 'lessonDesignPlan.learningObjectives') */ keyPath: string; /** Whether the heading was recognized in the dictionary */ isKnown: boolean; /** Canonical display title if known */ canonicalTitle?: string; } /** * Matches a raw markdown heading line/text to a stable semantic key path. * * @param rawHeading Raw heading string (e.g. "### 2. Activity Sequence" or "## A. Kế hoạch Thiết kế Bài học") * @param activeParentKeyPath Current active parent key path (e.g. "lessonDesignPlan" when parsing under H2) */ declare function matchHeadingToSemanticKey(rawHeading: string, activeParentKeyPath?: string): MatchHeadingResult; /** Chỉ khoá ổn định của một heading, theo chính sách khớp duy nhất. */ declare function resolveSemanticKey(rawHeading: string): string | undefined; /** * Returns the entire dictionary for validation and testing. */ declare function getSemanticHeaderDictionary(): Readonly>; /** * Parses markdown into an Ephemeral In-Memory Lossless AST with a Semantic Overlay. * * - Tier 1 (Lossless Tree): ast.tree contains the full mdast Root with positions. * - Tier 2 (Semantic Overlay): ast.semanticIndex maps canonical key paths to node references. * - customBlocks: captures all nodes not mapped to any known semantic key. * * Guaranteed: Partition of root.children into (semanticIndex + customBlocks) is lossless and non-duplicated. */ declare function parseArtifactAst(md: string): ArtifactAst; /** * Serializes an ArtifactAst into a JSON-friendly format for UI/logging. * Converted Map to Record. Optionally strips position information. */ declare function serializeArtifactAst(ast: ArtifactAst, options?: SerializeAstOptions): SerializedArtifactAst; interface ProjectForPromptOptions { /** * Budget for the projection, in CHARACTERS. The registry slot budgets are * character budgets (the markdown fallback enforces them via * buildSectionAwareExcerpt), so the AST view counts the serialized markdown * directly — one number, one unit, no silent 4× inflation. */ budgetTokens?: number; /** * Reports a slot key that produced nothing. Messages that mean canonical * content was lost carry the `section:dropped:` / `section:truncated:` * prefixes — the same machine vocabulary `contextBuilder` already emits — so * AST drops reach the `contextDrops` telemetry without a second convention * to translate. Those two used to be silent: the whole-section invariant * discards a non-fitting section without a word, so a priority that lost its * canonical table looked identical to one that shipped in full. Measured on * swift-for-dummy LESSON_U01_M01_L01 at budget 6000: learningObjectives was * dropped, zero warnings. * * "Key not in the semantic index" is deliberately NOT a drop — priority keys * that an artifact simply does not carry are routine, and flagging them * would flood contextDrops on every well-formed artifact. */ onWarning?: (msg: string) => void; } /** * Resolves node references for a semantic slot key from the AST's semantic index. * Supports: * - Exact key path (e.g. "lessonDesignPlan.activitySequence") * - Short key / suffix match (e.g. "activitySequence" matches "*.activitySequence") * - Prefix parent match (e.g. "lessonDesignPlan" returns all child sections) */ declare function resolveSlotNodes(ast: ArtifactAst, slotKey: string): Node[]; /** * Projects a subset of the AST into markdown text suitable for LLM prompt injection. * * - Only extracts requested semantic slot keys (unmatched headings in customBlocks are never injected). * - Enforces budget per prompt slot. */ declare function projectAstForPrompt(ast: ArtifactAst, slotKeys: string[], options?: ProjectForPromptOptions): string; /** * Extracts raw table rows from an array of AST nodes as an array of column-value dictionaries. */ declare function extractTableRows(nodes: Node[]): Array>; /** * Extracts structured, validated LearningObjective rows from the AST. */ declare function extractLearningObjectiveRows(ast: ArtifactAst): LearningObjectiveRow[]; /** * Extracts structured, validated ActivitySequence rows from the AST. */ declare function extractActivitySequenceRows(ast: ArtifactAst): ActivitySeqRow[]; /** * Extracts raw AssessmentMap rows from the AST. */ declare function extractAssessmentMapRows(ast: ArtifactAst): Array>; /** Extracts ResourceMap rows from the AST, shaped for `ResourceMapRowSchema`. */ declare function extractResourceMapRows(ast: ArtifactAst): ResourceMapRow[]; /** Extracts ArtifactContract rows from the AST, shaped for `ArtifactContractRowSchema`. */ declare function extractArtifactContractRows(ast: ArtifactAst): ArtifactContractRow[]; /** * Checks whether an activity sequence row is assigned to the given artifact type via its artifactContract. */ declare function rowAssignedTo(row: ActivitySeqRow, artifactType: string): boolean; /** * Extracts and renders markdown table for only the activity sequence rows assigned to an artifact type. */ declare function renderAssignedRowsTableFromAst(ast: ArtifactAst, artifactType: string, maxChars?: number): string; /** * QUIZ → DiagnosticQuizSchema shape. * * Returns null when no question could be read, so the caller reports the schema * step as SKIPPED (see validateArtifactOutput) rather than inventing a valid- * looking-but-empty quiz. */ declare function extractQuizData(ast: ArtifactAst): Record | null; /** * Lesson Flow phases → `LessonFlowPhaseSchema` shape. * * Phase duration comes from the phase body's `> **Duration:** 5 phút` line. * When a phase has no such line we fall back to the Activity Sequence row for * the same phase — and when NEITHER has one the phase is DROPPED rather than * given a fabricated duration, because `durationMinutes` is required by the * schema and a wrong number is worse than a missing phase. */ declare function extractLessonFlowPhases(ast: ArtifactAst): Array>; /** * LESSON → LessonPlan5ESchema shape. * * `artifactType` is deliberately NOT set: the registry declares the 5E schema * for every `lesson`, while real artifacts carry `type: LESSON_EDP` in their * frontmatter and use ASK/IMAGINE/PLAN rather than ENGAGE/EXPLORE. Emitting the * literal would fail; leaving it unset lets the schema default apply, which is * the least-wrong option until the registry stops declaring one pedagogy for * all lessons. */ declare function extractLessonData(ast: ArtifactAst): Record | null; /** * Extracts structured typed data from an AST projection for validation against output schemas. */ declare function extractTypedDataForValidation(artifactType: string, ast: ArtifactAst): Record | null; interface SectionNode { level: number; title: string; normalizedTitle: string; lineStart: number; lineEnd: number; charCount: number; content: string; body: string; } interface SectionBody { /** Tiêu đề nguyên văn trong file — khớp semantic key đã resolve (có thể dài hơn key truyền * vào khi resolve bằng suffix match, vd `activitySequence` → `lessonDesignPlan.activitySequence`). */ title: string; /** Nội dung dưới tiêu đề, KHÔNG gồm heading. Rỗng nếu section không có body. */ body: string; /** `body` kèm heading — tiện cho call-site cần nguyên khối. */ content: string; charCount: number; } /** * Parses markdown headings (H1-H4) and returns a flat list of SectionNodes with exact line boundaries. */ declare function listSections(markdown: string): SectionNode[]; /** * Extracts a specific section matching sectionQuery (fuzzy substring match on normalized title). * If multiple sections match, returns the first match or optionally the one with target level. */ declare function extractSection(markdown: string, sectionQuery: string, options?: { targetLevel?: number; }): SectionNode | null; /** * Replaces a target section's body with newBody, keeping its original heading intact. * Returns the modified markdown string. If section not found, returns original markdown. */ declare function replaceSectionBody(markdown: string, sectionQuery: string, newBody: string): { markdown: string; replaced: boolean; }; /** * Lấy phần thân của một section theo **semantic key**. * * Vì sao cần, khi `extractSection` không đủ: `extractSection` khớp theo *tên heading* đã chuẩn hoá * (`extractSection(md, 'teacherNotes')` → `null` vì tiêu đề thật là * `[OPTIONAL] C. Teacher Facilitation Notes`). Semantic key là địa chỉ mà * `inputContract.sourceSlots` / `resolveLessonSlotSpec` dùng, nên đó phải là địa chỉ đầu vào ở đây. * * `semanticIndex.get(key)` trả về node `heading` — **chỉ có dòng tiêu đề, không có body** * (`children` của node heading chỉ chứa text tiêu đề). Body phải cắt từ `markdown` theo * `position`, mà `listSections()` đã tính sẵn `lineEnd` (heading cùng cấp trở xuống). * * Dùng lại `resolveSlotNodes()` để resolve key, nên hỗ trợ sẵn cả ba dạng gọi: * key phẳng (`lessonFlow`), key lồng (`lessonDesignPlan.activitySequence`), key với tiền tố * cha (`lessonDesignPlan` → parent + toàn bộ con). Không viết lại logic match ở đây. * * @param markdown toàn bộ nội dung file * @param semanticKey semantic key cần lấy * @returns `null` nếu key không có trong semanticIndex — **không throw**, vì thiếu key là chuyện * thường quen (artifact không mang section đó), không phải lỗi. */ declare function getSectionBody(markdown: string, semanticKey: string): SectionBody | null; /** * Which document a field's value is read from. * * This is PROVENANCE, not a permission. Every step may draw on every earlier step — * `SOT_GENERATION_ORDER` in `sotOwnership.ts` already models that ("information flows * strictly DOWN this list"), and which fields a prompt actually uses is the user's * call, not something this taxonomy decides. * * The values exist for one mechanical reason: a saved ref says *where* to read from, * so `phase.4` on a lesson prompt and `keyTerms` on an exposition prompt resolve from * different files. Merge them into a single "previous artifact" pointer and a prompt * saved against a lesson would silently read the wrong document. * * Generation order, for reference (steps 1-8 are SOT, 9 KX, 10 lesson, 11+ satellites): * 1 LEARNER_PROFILE · 2 PROJECT_BRIEF · 3 REFERENCE_PACK · 4 STANDARD_STACK * 5 CURRICULUM_FRAMEWORK · 6 CONTENT_STYLE_GUIDE · 7 ART_DIRECTION · 8 ALIGNMENT_MATRIX */ type FieldScope = 'satellite' | 'sot' | 'lesson' | 'activity'; type FieldTier = 'zod' | 'semantic'; /** * The four states a field can be in, from the plan: * `real` — schema declares it AND the extracted typed data holds it. * `section` — schema does not declare it, but a real markdown section carries it. * `declared` — schema declares it, no value yet (no file generated, or the * extractor does not run for this type). * `missing` — schema declares it and the file exists but the value is absent. * * Measured: 19 of 21 artifact types return null typed data, so `declared` is the * normal state for the Zod column. That is a fact about extraction coverage, not * a bug in the browser, and showing it honestly is the point of having four states. */ type FieldState = 'real' | 'section' | 'declared' | 'missing'; type FieldKind = 'string' | 'number' | 'boolean' | 'list' | 'object'; interface FieldDef { scope: FieldScope; /** Address inside its scope. `$` = Zod output field, `@` = semantic key/section. */ path: string; tier: FieldTier; label: string; kind: FieldKind; state: FieldState; ownerArtifactType: string; /** Character count of the real value — a chip bigger than any budget is undraggable. */ charCount?: number; preview?: string; description?: string; } interface FieldRef { scope: FieldScope; ownerArtifactType: string; tier: FieldTier; path: string; renderAs?: 'markdown' | 'compact'; } /** * Replace `{{$field}}` / `{{@section}}` with the value the resolver returns. * * A ref the resolver cannot resolve is left in place verbatim rather than replaced * with an empty string: a prompt that visibly still contains `{{@lessonFlow}}` is a * bug report, a prompt that silently lost a section is not. */ declare function resolveTemplate(template: string, refs: readonly FieldRef[], resolve: (ref: FieldRef) => string | undefined): { prompt: string; unresolved: string[]; }; /** Every `{{…}}` in the template, whether or not it has a matching ref. */ declare function extractPlaceholders(template: string): string[]; /** * The split strategy for one field's body, independent of where the body came from. * Kept separate from `readFieldValue` so reading a sub-part and listing all sub-parts * can never disagree about what the pieces are. */ declare function splitBody(body: string, path: string): SplitOption[]; /** * Read one field's value out of a markdown document, or `undefined` if the document * does not contain it. * * Two addressing schemes, because the plan needs both: * - `phase.N` / `phase.N.M` — positional, taken from `parseLessonFlow().phases`. * Positional because phases are model-dependent: a lesson may have five (5E, * GENERAL) or six (EDP), and two same-named phases must not collide. * - anything else — a semantic key, via `getSectionBody`. */ declare function readFieldValue(markdown: string, path: string): string | undefined; interface SplitOption { path: string; label: string; charCount: number; preview: string; value: string; } /** * Break one field into draggable parts, or `[]` when it is already small enough. * * Measured reason this exists: `framework.scopeAndSequence` is a single 10,123-char * table of 30 lesson rows — nobody can drag that into a prompt, and no budget covers * it. Two strategies, applied in the order that yields parts: * * 1. child headings — a phase with `#### Bước 1..6` splits into its six steps. * `lessonFlow.phase.4` measured 3,406 chars → 6 parts. * 2. table rows — `scopeAndSequence` has no child heading, only rows. * * Only immediate children, so a part is never larger than its parent. */ declare function listFieldSplits(markdown: string, path: string): SplitOption[]; interface FieldSource { scope: FieldScope; /** Artifact the field belongs to — `lesson`, `act`, or the SOT document kind. */ artifactType: string; /** Raw markdown of the generated document, when there is one. */ markdown?: string; /** Typed data extracted by the artifact's own extractor, when it runs. */ typedData?: Record | null; /** Semantic keys to offer. Defaults to the standard set for the document. */ keys?: readonly string[]; } /** Chips whose real value exceeds this are worth offering a "split" button on. */ declare const SPLIT_THRESHOLD_CHARS = 2000; /** * Build the browser's chip list for one source document. * * Two columns because the two tiers answer different questions and neither wins: * * - `$` (Zod `outputSchema`) knows the TYPE and can validate. 20 of 21 artifact * types declare one; only `bom` lacks it. * - `@` (semantic sections from the actual markdown) knows the REAL VALUE. Only * `lesson` and `quiz` produce typed data — `act`, `guide`, `handout`, `slide` * and `ext` all return null — so a Zod-only browser would show 16 of 17 ACT * fields empty. */ declare function buildFieldDefs(source: FieldSource): FieldDef[]; /** * The Zod column: every field the artifact's `outputSchema` demands, whether or not * a value exists for it. * * This is the "define the fields up front, for every artifact" column — it is * derivable from `outputSchema` for 20 of 21 types, so it needs no new schema. */ /** The Zod column before it is attached to a scope — see `buildFieldDefs`. */ type ZodFieldDef = Omit; declare function zodFieldDefs(artifactType: string, typedData: Record | null): ZodFieldDef[]; interface FieldSourceGroup extends FieldSource { /** Display name in the browser, e.g. "Framework", "Knowledge Exposition". */ label: string; } /** * The browser's input: every document a prompt may draw from, grouped by where it * comes from. * * Groups are kept separate instead of merged because a chip must say where its * value came from — `phase.4` is a lesson (previous step) while `keyTerms` is KX * (generated before the course even started). Merging them would hide the very * distinction that makes a saved prompt reusable on another lesson. */ declare function buildFieldBrowser(groups: readonly FieldSourceGroup[]): FieldDef[]; export { ACTIVITY_UNIT_MINUTES, AIProviderName, ARTIFACT_DEPENDENCY_ROUTING, ARTIFACT_EXECUTION_ORDER, type AcademicAuditFinding, AcademicAuditor, type AcademicDimension, type ActivityAlignmentResult, type ActivityCountInput, ActivityLab, ActivitySeqRow, ActivityType, type ArtifactAst, ArtifactContractRow, type ArtifactDependencyRule, type ArtifactProductionSpec, type ArtifactPromptParts, type ArtifactTimeInput, type ArtifactTypeContract, type ArtifactValidationContext, type AssembledTemplate, type AstWarning, type AstWarningCode, type AuditBundleInput, BASELINE_V0, BLOOM_ACTION_VERBS, BUNDLE_BASE, BespokeSlideArraySchema, BespokeSlideSchema, BloomLevel, BloomTaxonomyEvaluator, type BufferSummary, type BuildContextOptions, type BundleEntrySeed, type BundleEstimateInput, CURRICULUM_SLASH_COMMANDS, ChunkType, CodeHardwareFeasibilityEvaluator, CodeLab, type CognitiveLoadReport, type ComprehensiveAcademicReport, ConceptPrerequisiteEdge, ConceptSpiralEncounter, ConstructiveAlignmentEvaluator, type ContextInjectionMeta, type ContextRoutingMode, type ContextSourceKey, type ContractTiers, CoverageGateReport, type CrossArtifactAlignmentReport, CrossArtifactDriftEvaluator, CurriculumError, type CurriculumErrorCode, type CurriculumErrorDetail, CurriculumPlan, DEFAULT_KX_PRIORITIES, DEFAULT_KX_SLOT_BUDGET, DEFAULT_KX_SLOT_PRIORITIES, DEFAULT_LESSON_PRIORITIES, DEFAULT_LESSON_SLOT, DEFAULT_LO_WEIGHT, DEFAULT_OVERHEAD_RATIO, DEFAULT_STREAM_IDLE_MS, DEFAULT_STREAM_TOTAL_MS, type DeliveryEnvironment, DependencyEdge, type DependencyValidationResult, DepthLevel, type DepthViolation, DeterministicPipelineRunner, DeterministicStructuralLinter, DiagnosticQuiz, DiagnosticQuizInput, type DimensionScore, type DirectiveInput, ENVIRONMENT_PROVISIONING_MODELS, EXPECTED_ERROR_BANDS, EXPOSITION_REL, EXT_HEADINGS_EN, EXT_HEADINGS_VI, type EnvironmentProvisioningModel, type ExcerptOptions, type ExcerptResult, type ExecuteCommandResult, ExpositionApprovalError, type ExpositionLlmFn, type ExpositionResult, type ExpositionStorage, type ExtHeadings, type ExtractedJson, type ExtractedStreamChunk, FIRST_SESSION_COGNITIVE_BUDGET_BEGINNER, FIRST_SESSION_MAX_NEW_CONCEPTS_BEGINNER, FLOOR_OVERLAY, type FieldDef, type FieldKind, type FieldRef, type FieldScope, type FieldSource, type FieldSourceGroup, type FieldState, type FieldTier, type FindingSeverity, type FirstPassSlideAudit, FiveEInstructionalEvaluator, type FrameworkLintFinding, type FrameworkLintReport, FrameworkPack, type GenerateExpositionOptions, GeneratedSlideArraySchema, GeneratedSlideSchema, HybridBlueprintArraySchema, HybridBlueprintItemSchema, HybridDeckSlideArraySchema, HybridDeckSlideSchema, HybridFallbackSignal, HybridPipelineError, ICurriculumStorage, type InputContract, JUDGE_AUTO_APPROVE_THRESHOLD, JUDGE_ESCALATE_THRESHOLD, LAYER_IDLE_BUDGET_MS, LAYER_TOTAL_BUDGET_MS, type LayerChunkCallback, type LayerPrefillOptions, type LayerPrefillResult, LearningObjectiveRow, LessonPlan, LoTimeEstimate, MAX_AUTONOMOUS_REPAIR_TURNS, MAX_IN_SESSION_SETUP_MINUTES, MAX_NEW_CONCEPTS_PER_SESSION_ADULT, MAX_NEW_CONCEPTS_PER_SESSION_K12, MAX_NEW_KEYWORDS_PER_SESSION_K12, MasteryGate, type MatchHeadingResult, MisconceptionEvaluator, ModelResolutionOptions, NO_VERBATIM_COPYING, type OwnershipRule, PRODUCTION_ARTIFACT_TYPES, type PackedSession, type PackingSpec, type ParsedActivityRow, type ParsedLessonFlow, type ParsedLessonPhase, type PedagogicalDensityReport, type PedagogicalModel, type PertResult, type PipelineExecutionProgress, PlanConstraints, type PlanOptions, type PlanResult, PlanValidationResult, type PlannerLlmFn, PlanningGraph, PlanningNode, type PrefillProviderEvent, type PreliminaryResearchResult, PrerequisiteDecision, type ProduceLessonOptions, type ProduceLessonResult, type ProductionArtifactType, type ProductionPromptResult, type ProductionPromptSpec, type ProjectBriefingData, type ProjectClarification, type ProjectCreationPayload, type ProjectForPromptOptions, type ProjectIntentAnalysisResult, ProjectStatusReport, type ProjectionMeta, QualityAuditReport, type ReconcileCandidate, type ReconcileResult, ResolvedGateSettings, type ResolvedTemplate, ResourceMapRow, SATELLITE_LESSON_PRIORITIES, SESSION_COGNITIVE_BUDGET_ADULT, SESSION_COGNITIVE_BUDGET_K12, SESSION_CUT_TOLERANCE, SLOTS_MODE_LAYOUTS, SOT_GENERATION_ORDER, SOT_OWNERSHIP, SPLIT_THRESHOLD_CHARS, STUDENT_FRICTION_MULTIPLIER, type SatContextResult, type SatelliteContextInput, type SectionBody, type SectionNode, type SemanticHeaderEntry, type SerializeAstOptions, type SerializedArtifactAst, SessionPlan, SessionZpdStatus, type SlashCommandDefinition, SlideBlueprintArraySchema, SlideBlueprintItemSchema, SlideDeck, type SlideEngine, type SlideProductionWorkflowOptions, type SlideProductionWorkflowResult, SmartResumeContext, type SotArtifactId, type SotArtifactType, type SotBoundaryFinding, type SourceSlotConfig, SplitBatchSignal, type SplitOption, type StreamAbortHandle, type StreamBudget, type StreamChunkExtractor, StreamRunnerOptions, type SymbolLedgerResult, TIME_DIVERGENCE_THRESHOLD, type TemplateTranslateRunner, type ThreePoint, TranslationPolicy, type TranslationTarget, type TranslationTrigger, UnitPlan, type ValidationIssue, type ValidationOptions, type ValidationResult, type ValidatorFunction, WEIGHT_CIO, WEIGHT_SIO, WEIGHT_ULO, WalkingSkeleton, type ZodFieldDef, agePacing, aggregateBuffer, analyzeProjectCreationIntent, applyLoTimeEstimates, assembleProductionArtifactPrompt, assembleTranslatedTemplate, assertAcyclic, assertSplitPartsConsecutive, assignDepths, assignDepthsForSessions, auditQualityReport, authorBatchesWithSplit, baselineV0, bloomFloorGroups, bloomTier, buildArtifactPrompt, buildConceptPrerequisites, buildCurriculumContext, buildCurriculumPlan, buildDomainLexiconGuardrail, buildExpositionContext, buildExpositionExcerpt, buildFieldBrowser, buildFieldDefs, buildFirstPassAudit, buildHeadingDirective, buildLanguageDirective, buildLessonExcerpt, buildLessonPrompt, buildMasteryGates, buildSatelliteContext, buildSatellitePrompt, buildSectionAwareExcerpt, buildSelectiveContext, buildSessionSliceContext, buildUserPrompt, buildWalkingSkeleton, bundleEntriesFor, calculateCognitiveLoad, canCoalesceWithinZpdBudget, canonicalExpositionSource, checkSessionZpd, classifyContractViolations, classifyDepthCandidates, cleanHeadingText, closeTruncatedJson, codeHeadingsDirective, computeConceptSpiralProgression, computePackingSpec, conductPreliminaryResearch, countWords, createAiInferenceError, createContextMissingError, createStreamAbortSignal, createStreamChunkExtractor, deriveTargetSlideCountFromLesson, detectProjectPedagogy, dropCyclicConceptEdges, dropTemplateSections, emitUsage, ensureExpositionForLesson, ensureKnowledgeExposition, estimateByActivityCount, estimateByBundleTemplate, evaluateActivityAlignment, evaluateCognitiveLoad, evaluateCrossArtifactAlignment, evaluatePedagogicalDensity, executeCurriculumCommand, executeSlideProductionWorkflow, expositionCacheKey, extPrompt, extractActivityContractRows, extractActivitySequenceRows, extractArtifactContractRows, extractAssessmentMap, extractAssessmentMapRows, extractConditionalSections, extractDeclaredLanguage, extractEchoSections, extractJsonArray, extractLearningObjectiveRows, extractLessonData, extractLessonFlowPhases, extractPlaceholders, extractQuizData, extractRequiredSections, extractResourceMapRows, extractScopeSequenceRows, extractSection, extractSectionHeadings, extractSessionSlice, extractSotSections, extractStreamChunk, extractSymbolLedger, extractTableRows, extractTieredScaffoldingBlock, extractTypedDataForValidation, findHeadingFormPriorities, generatePhase1SotArtifacts, generatePhase2SotArtifacts, getAllContracts, getContract, getKxSlotBudget, getKxSlotPriorities, getLessonMetadata, getLessonSlotBudget, getNodeCognitiveWeight, getNodeLoType, getProjectArtifactScope, getProjectStatusReport, getSectionBody, getSemanticHeaderDictionary, getSmartResumeContext, glossaryTermsForSession, hasContract, ingestProjectGraphIntoProject, initializeProjectInStorage, isActivityAlignmentLogOnly, isExpositionFresh, isKxOnlyType, isTranslationDue, lintCurriculumFramework, lintSotBoundaries, listFieldSplits, listSections, loadAuthoringTemplate, loadCurriculumTemplate, loadSotTemplate, makeSlideNormalizer, matchHeadingToSemanticKey, measureArtifactMinutes, minActivitiesForBloom, normHeading, normalizeBlueprintItems, normalizePlanningGraph, ownershipHeader, p75FromSigma, packUnitSessions, parseArtifactAst, parseLessonFlow, parseMarkdownToSections, parseRequiredSections, parseRoadmapJsonToProjectPayload, pert3, produceBatchLessons, produceSingleLesson, projectAstForPrompt, readFieldValue, reconcilePlanDepth, referenceFallbackEstimate, registerContract, renderAssignedRowsTableFromAst, renderFrameworkFromPlan, replaceSectionBody, reportSotBoundaries, requoteUnescapedQuotes, resolveArtifactTemplate, resolveDeliveryEnvironment, resolveKxSlotSpec, resolveLessonSlotSpec, resolveSemanticKey, resolveSlotNodes, resolveStreamBudget, resolveTargetLanguageCode, resolveTemplate, resolveTranslationTargets, rowAssignedTo, safeParseJson, serializeArtifactAst, skeletonMimicryIssue, slideHeadingDirective, slugifyProjectName, splitBody, splitZpdConceptLoad, streamLLMWithFallback, streamLayerPrefillWithFallback, stripHeadingKey, stripLlmJsonWrappers, stripTemplateFrontmatter, targetLanguageDisplayName, timeDivergenceWarning, topoSort, translateTemplate, validateArtifactDependencies, validateArtifactOutput, validateDepthCompliance, validateHybridDeckSlides, validatePlan, zodFieldDefs, zpdCeilingPrompt, zpdConceptKey };