Open Multi-Agent Interactive Classroom — Get an immersive, multi-agent learning experience in just one click
This report presents the forensic synthetic code analysis of THU-MAIC/OpenMAIC, a TypeScript project with 19,670 GitHub stars. SynthScan v2.0 examined 347,700 lines of code across 1483 source files, recording 574 pattern matches distributed across 11 syntactic categories. The overall adjusted score of 2.7 places this repository in the Likely human-written band.
The scanner applied 160+ deterministic lexical heuristics, multi-line block detectors, abstract syntax tree depth profilers, and a cross-file Jaccard similarity matrix to construct a statistically normalised synthetic code estimate. All matches are individually weighted by severity coefficient and contextual multiplier before summation, and the resulting headline score is temporally discounted to account for the repository's development history relative to the commercial emergence of large language model coding tooling (November 2022 onward).
This chart maps the temporal evolution of the adjusted synthetic code score across successive scan runs. An upward trajectory indicates ongoing incorporation of AI-generated code or expanding LLM-assisted scaffolding; a stable or declining trajectory may reflect active human refactoring, code removal, or the adoption of stricter authorship policies. The dashed secondary line (right axis) independently tracks total raw pattern hit count, which can diverge from the normalised score when codebase size changes significantly between scans.
Classifies detected patterns by their diagnostic confidence and structural impact. CRITICAL patterns (coefficient 10) represent definitive synthetic signatures — hallucinated imports, explicit LLM attribution metadata — virtually never produced by human authors. HIGH (5) indicates strong structural tells such as cross-file repetition or cross-linguistic idioms. MEDIUM (2) covers recognisable conversational padding and AI-specific vocabulary. LOW (1) captures subtle indicators like tautological comments and generic boilerplate that require density to carry independent signal.
This horizontal bar chart decomposes the repository's raw synthetic code score by top-level directory, allowing you to pinpoint precisely which modules or components carry the highest AI authorship density. Directories with disproportionately high scores relative to their size warrant targeted manual review: concentrated AI signatures often trace back to mass-generated configuration layers, auto-ported test suites, LLM-scaffolded boilerplate classes, or entire subsystems authored under heavy copilot assistance. Use this view to prioritise your human code-review effort.
The scanner identified 574 distinct pattern matches across 11 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a statistically significant AI authorship indicator. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the diagnostic confidence level (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — comment-context matches receive a ×1.5 weight because LLMs systematically over-annotate. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier as dense clusters constitute far stronger evidence of synthetic authorship than isolated hits.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | app/generation-preview/vocational-mode.ts | 1 | export function resolveTaskEngineModeFromOutlineDoneEvent(event: { | CODE |
| LOW | app/generation-preview/components/visualizers.tsx | 246 | function StreamingOutlineVisualizer({ | CODE |
| LOW | app/generation-preview/components/visualizers.tsx | 386 | function AgentGenerationVisualizer() { | CODE |
| LOW | app/api/extract-document/route.ts | 34 | function isSelfHostedMinerUProvider( | CODE |
| LOW | app/api/generate/scene-outlines-stream/route.ts | 100 | function extractCourseTitleFromComplete(buffer: string): string | null { | CODE |
| LOW | app/api/generate/scene-outlines-stream/route.ts | 178 | function normalizeTaskEngineProceduralOutline( | CODE |
| LOW | app/api/generate/scene-outlines-stream/route.ts | 212 | function normalizeTaskEngineSlideOutline(outline: SceneOutline): SceneOutline { | CODE |
| LOW | app/api/generate/scene-outlines-stream/route.ts | 225 | function normalizeTaskEngineOutline(outline: SceneOutline, requirement: string): SceneOutline { | CODE |
| LOW | app/api/generate/scene-outlines-stream/route.ts | 245 | function sanitizeNonTaskEngineOutline(outline: SceneOutline): SceneOutline { | CODE |
| LOW | tests/pbl/v2/drain.test.ts | 50 | function deterministicPBLSessionId(stageId = STAGE_ID, learnerKey = LEARNER_KEY): string { | CODE |
| LOW | tests/ai/openai-provider.test.ts | 26 | async function captureInjectedRequestBody( | CODE |
| LOW | …mpts/procedural-skill-content-quality-contract.test.ts | 13 | function buildProceduralSkillPrompt() { | CODE |
| LOW | tests/generation/procedural-skill-content-gates.test.ts | 28 | function createProceduralSkillOutline(): SceneOutline { | CODE |
| LOW | tests/generation/procedural-skill-routing.test.ts | 80 | function createProceduralSkillOutline(): SceneOutline { | CODE |
| LOW | …generation/scene-content-route-vocational-gate.test.ts | 110 | function createProceduralSkillOutline(): SceneOutline { | CODE |
| LOW | tests/store/stage-generation-complete.test.ts | 89 | function applyFallbackToStageStore(stageId: string, token: StageSceneLoadToken, scenes: Scene[]) { | CODE |
| LOW | components/settings/utils.ts | 71 | export function createCustomProviderSettings( | CODE |
| LOW | components/scene-renderers/classroom-complete.tsx | 499 | export function ClassroomCompletePageConnected() { | CODE |
| LOW | components/scene-renderers/pbl/v2/protocol-markers.ts | 6 | export function stripEmbeddedDividerMarkers(text: string): string { | CODE |
| LOW | components/scene-renderers/pbl/v2/protocol-markers.ts | 10 | export function isStandaloneDividerMessage(content: string): boolean { | CODE |
| LOW | …onents/scene-renderers/pbl/v2/use-instructor-stream.ts | 377 | export function isToleratedReactionStreamError( | CODE |
| LOW | …onents/scene-renderers/pbl/v2/use-instructor-stream.ts | 386 | export function findMilestoneIdForMicrotask( | CODE |
| LOW | components/scene-renderers/pbl/v2/workspace.tsx | 70 | function streamStatusForEvaluationKind(kind: unknown): StreamStatus { | CODE |
| LOW | components/scene-renderers/pbl/v2/workspace.tsx | 540 | function milestoneProgressFraction(milestone: PBLMilestone): number { | CODE |
| LOW | components/scene-renderers/pbl/v2/workspace.tsx | 553 | export function workspaceActiveMilestoneIndex(project: PBLProjectV2): number { | CODE |
| LOW | components/scene-renderers/pbl/v2/submission.tsx | 111 | export function isSubmitLockedDuringStream(args: { | CODE |
| LOW | components/scene-renderers/pbl/v2/submission.tsx | 183 | function appendSubmissionReceiptMessage( | CODE |
| LOW | components/scene-renderers/pbl/v2/submission.tsx | 247 | export function buildRevisionGuidanceMessage(args: { | CODE |
| LOW | …nents/scene-renderers/pbl/v2/scenario-briefing-gate.ts | 20 | export function shouldShowScenarioBriefing(project: PBLProjectV2): boolean { | CODE |
| LOW | components/scene-renderers/pbl/v2/sidebar.tsx | 411 | export function sidebarDefaultExpandedMilestoneIds(project: PBLProjectV2): string[] { | CODE |
| LOW | components/scene-renderers/pbl/v2/chat.tsx | 747 | function SubmissionEvaluationBubble({ | CODE |
| LOW⚡ | components/scene-renderers/pbl/v2/chat.tsx | 1399 | export function handoverForMilestoneEvaluation( | CODE |
| LOW⚡ | components/scene-renderers/pbl/v2/chat.tsx | 1409 | export function streamingEvaluationPreview(text: string): string { | CODE |
| LOW⚡ | components/scene-renderers/pbl/v2/chat.tsx | 1419 | export function stripLeakedToolJsonPreview(text: string): string { | CODE |
| LOW | components/scene-renderers/pbl/v2/completion.tsx | 79 | export function buildCompletionReportViewModel(project: PBLProjectV2): CompletionReportViewModel { | CODE |
| LOW | …s/scene-renderers/pbl/v2/eval-cards/milestone-card.tsx | 177 | export function milestoneHandoverCtaState(handover?: PBLHandover): 'hidden' | 'ready' | 'consumed' { | CODE |
| LOW | …s/scene-renderers/pbl/v2/eval-cards/milestone-card.tsx | 182 | export function stripFinalMilestoneContinueGuidance(text: string): string { | CODE |
| LOW | components/chat/use-chat-sessions.ts | 40 | function buildQuizResultsForStoreState( | CODE |
| LOW | components/whiteboard/whiteboard-canvas.tsx | 107 | >(function InteractiveWhiteboardCanvas( | CODE |
| LOW | components/edit/MultiTabEditConflictPrompt.tsx | 31 | export function MultiTabEditConflictPrompt({ | CODE |
| LOW | components/edit/scene-timeline.ts | 12 | export function supportsNarrationTimeline( | CODE |
| LOW | components/edit/surfaces/slide/use-slide-surface.ts | 318 | export function useSelectedNonTextElement(): PPTElement | null { | CODE |
| LOW | components/edit/ActionsBar/actions-edit.ts | 115 | export function setSpeechTextClearAudioById(actions: Action[], id: string, text: string): Action[] { | CODE |
| LOW | components/edit/ActionsBar/actions-edit.ts | 194 | function setDiscussionOptionalById( | CODE |
| LOW | components/edit/ActionsBar/ActionsBar.tsx | 97 | function useClearCuePreviewOnUnmount() { | CODE |
| LOW | components/audio/speech-button.tsx | 21 | export function shouldCancelRecordingOnDisable(args: { | CODE |
| LOW | components/roundtable/presentation-speech-overlay.tsx | 41 | export function buildPresentationBubbleModel({ | CODE |
| LOW | components/roundtable/presentation-speech-overlay.tsx | 388 | export function PresentationSpeechOverlay({ | CODE |
| LOW | …r/components/element/VideoElement/BaseVideoElement.tsx | 22 | function isLegacySequentialVideoRef(value: string | undefined): boolean { | CODE |
| LOW | …er/Editor/Canvas/hooks/useInsertFromCreateSelection.ts | 16 | export function useInsertFromCreateSelection(viewportRef: RefObject<HTMLElement | null>) { | CODE |
| LOW | components/generation/outlines-editor.tsx | 1144 | function InteractiveConfigDisclosure({ | CODE |
| LOW | components/generation/generation-toolbar.tsx | 517 | function formatCompactThinkingValue(value?: string, t?: (key: string) => string) { | CODE |
| LOW | packages/pptxgenjs/src/gen-objects.ts | 1147 | export function addPlaceholdersToSlideLayouts(slide: PresSlide): void { | CODE |
| LOW | packages/pptxgenjs/src/gen-xml.ts | 819 | function slideObjectRelationsToXml (slide: PresSlide | SlideLayout, defaultRels: Array<{ target: string, type: string }> | CODE |
| LOW | packages/pptxgenjs/src/gen-xml.ts | 884 | function genXmlParagraphProperties (textObj: ISlideObject | TextProps, isDefault: boolean): string { | CODE |
| LOW | packages/@openmaic/renderer/src/utils/geometry.ts | 16 | export function getElementPercentageGeometry( | CODE |
| LOW | …ckages/@openmaic/renderer/src/editing/core/geometry.ts | 207 | export function getEditingElementListRange(els: PPTElement[]): ElementRange { | CODE |
| LOW | packages/@openmaic/importer/src1/pptxtojson.js | 673 | function processNestedGroupElements(elements, ws, hs, depth = 0) { | CODE |
| LOW | …s/@openmaic/importer/src/serializer/shapeSerializer.ts | 723 | function resolveInheritedPlaceholderFill( | CODE |
| LOW | …es/@openmaic/importer/src/serializer/textSerializer.ts | 252 | function buildMergedParagraphStyle( | CODE |
| 245 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | app/page.tsx | 1234 | // ─── Classroom Card — clean, minimal style ────────────────────── | COMMENT |
| MEDIUM | tests/lib/agent/tools/regenerate-scene-actions.test.ts | 77 | // ── Bug 1 regression: SlideContent shape conversion ────────────────────────── | COMMENT |
| MEDIUM | tests/lib/agent/tools/regenerate-scene-actions.test.ts | 130 | // ── Bug 1 & Bug 2: empty generation is surfaced as an error ────────────────── | COMMENT |
| MEDIUM | tests/export/classroom-zip.test.ts | 9 | // ─── rewriteAudioRefsToIds ──────────────────────────────────── | COMMENT |
| MEDIUM | tests/export/classroom-zip.test.ts | 82 | // ─── actionsToManifest ──────────────────────────────────────── | COMMENT |
| MEDIUM | tests/export/classroom-zip.test.ts | 168 | // ─── Manifest round-trip ────────────────────────────────────── | COMMENT |
| MEDIUM | components/scene-renderers/quiz-view.tsx | 36 | // ─── Types ────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/scene-renderers/quiz-view.tsx | 137 | // ─── Sub-components ───────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/scene-renderers/quiz-view.tsx | 687 | // ─── Main Component ───────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/chat/inline-action-tag.tsx | 32 | // ── Style tokens ────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/chat/inline-action-tag.tsx | 47 | // ── Action config ───────────────────────────────────────────── | COMMENT |
| MEDIUM | components/chat/inline-action-tag.tsx | 83 | // ── Component ───────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/edit/AgentsView/AgentRosterPanel.tsx | 12 | // ─── Avatar with camera overlay ────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/edit/AgentsView/AgentRosterPanel.tsx | 53 | // ─── Inline editable name ──────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/edit/AgentsView/AgentRosterPanel.tsx | 90 | // ─── Persona textarea ───────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/edit/AgentsView/AgentRosterPanel.tsx | 154 | // ─── Teacher card ───────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/edit/AgentsView/AgentRosterPanel.tsx | 265 | // ─── Classmate card ──────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/edit/AgentsView/AgentRosterPanel.tsx | 421 | // ─── Main panel ─────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/generation/outlines-editor.tsx | 429 | // ──────────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/generation/outlines-editor.tsx | 431 | // ──────────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/generation/outlines-editor.tsx | 713 | // ──────────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/generation/outlines-editor.tsx | 715 | // ──────────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/generation/outlines-editor.tsx | 1502 | // ──────────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/generation/outlines-editor.tsx | 1504 | // ──────────────────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/generation/generation-toolbar.tsx | 52 | // ─── Constants ─────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/generation/generation-toolbar.tsx | 56 | // ─── Types ─────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/generation/generation-toolbar.tsx | 68 | // ─── Component ─────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/generation/generation-toolbar.tsx | 212 | // ─── Pill button helper ───────────────────────────── | COMMENT |
| MEDIUM | components/generation/generation-toolbar.tsx | 742 | // ─── ModelSettingsPopover (provider + model picker) ───── | COMMENT |
| MEDIUM | packages/pptxgenjs/src/gen-media.ts | 56 | // ──────────── NODE LOCAL FILE ──────────── | COMMENT |
| MEDIUM | packages/pptxgenjs/src/gen-media.ts | 74 | // ──────────── NODE HTTP(S) ──────────── | COMMENT |
| MEDIUM | packages/pptxgenjs/src/gen-media.ts | 99 | // ──────────── BROWSER ──────────── | COMMENT |
| MEDIUM | …es/@openmaic/importer/src/serializer/textSerializer.ts | 1053 | // ── 行首 tab/空格缩进折叠 ────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/config/token-plan-presets.ts | 78 | // ── Full-set token plan (template) ──────────────────────────────────────── | COMMENT |
| MEDIUM | lib/config/token-plan-presets.ts | 129 | // ── Vendor token plans (LLM; one key, often spans many models) ──────────── | COMMENT |
| MEDIUM | lib/pdf/mineru-cloud.ts | 79 | // ── API envelope ────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/pdf/mineru-cloud.ts | 108 | // ── Filename sanitization ───────────────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/pdf/mineru-cloud.ts | 122 | // ── ZIP parsing ─────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/pdf/mineru-cloud.ts | 232 | // ── Main entry point ────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/read-scene-content.ts | 19 | // ── Deps ───────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/read-scene-content.ts | 28 | // ── Content projection (model-visible text) ────────────────────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/read-scene-content.ts | 155 | // ── Params ─────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/read-scene-content.ts | 169 | // ── Details returned to the client ─────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/read-scene-content.ts | 182 | // ── Factory ────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/regenerate-scene-actions.ts | 39 | // ── Scene context shape (client-sourced, injected via deps) ────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/regenerate-scene-actions.ts | 63 | // ── Deps injection interface ───────────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/regenerate-scene-actions.ts | 94 | // ── Content shape conversion ───────────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/regenerate-scene-actions.ts | 132 | // ── Typebox parameter schema ───────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | lib/agent/tools/regenerate-scene-actions.ts | 154 | // ── Details shape returned to the client ──────────────────────────────────── | COMMENT |
| MEDIUM⚡ | lib/agent/tools/regenerate-scene-actions.ts | 161 | // ── Factory ────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/regenerate-scene-actions.ts | 200 | // ── Build cross-scene context (mirrors route.ts logic) ───────────── | COMMENT |
| MEDIUM | lib/agent/tools/regenerate-scene-actions.ts | 219 | // ── Generate actions ─────────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/regenerate-scene.ts | 41 | // ── Existing media → generator RESOURCES (assignedImages + imageMapping) ────── | COMMENT |
| MEDIUM | lib/agent/tools/regenerate-scene.ts | 132 | // ── Details returned to the client ─────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/regenerate-scene.ts | 140 | // ── Factory ────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/regenerate-scene.ts | 230 | // ── Step 1: regenerate slide content in EDIT MODE ────────────────────── | COMMENT |
| MEDIUM | lib/agent/tools/regenerate-scene.ts | 268 | // ── Step 2: regenerate actions to match the new content ──────────────── | COMMENT |
| MEDIUM | lib/agent/tools/edit-interactive-html.ts | 27 | // ── Params (trust boundary: only id + edits; html comes from deps) ─────────── | COMMENT |
| MEDIUM⚡ | lib/agent/tools/edit-interactive-html.ts | 61 | // ── Details returned to the client ─────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | lib/agent/tools/edit-interactive-html.ts | 71 | // ── Factory ────────────────────────────────────────────────────────────────── | COMMENT |
| 19 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| CRITICAL | …lide-renderer/components/element/ProsemirrorEditor.tsx | 182 | const mark = editorView.current.state.schema.marks.fontname.create({ | CODE |
| CRITICAL | …lide-renderer/components/element/ProsemirrorEditor.tsx | 188 | const mark = editorView.current.state.schema.marks.fontsize.create({ | CODE |
| CRITICAL | …lide-renderer/components/element/ProsemirrorEditor.tsx | 201 | const mark = editorView.current.state.schema.marks.fontsize.create({ | CODE |
| CRITICAL⚡ | …lide-renderer/components/element/ProsemirrorEditor.tsx | 214 | const mark = editorView.current.state.schema.marks.fontsize.create({ | CODE |
| CRITICAL⚡ | …lide-renderer/components/element/ProsemirrorEditor.tsx | 223 | const mark = editorView.current.state.schema.marks.forecolor.create({ | CODE |
| CRITICAL⚡ | …lide-renderer/components/element/ProsemirrorEditor.tsx | 233 | const mark = editorView.current.state.schema.marks.backcolor.create({ | CODE |
| CRITICAL | …lide-renderer/components/element/ProsemirrorEditor.tsx | 333 | const mark = editorView.current.state.schema.marks.link.create({ | CODE |
| CRITICAL | …lide-renderer/components/element/ProsemirrorEditor.tsx | 351 | const mark = editorView.current.state.schema.marks.link.create({ | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | app/generation-preview/page.tsx | 346 | // Step 0: Extract uploaded course material if needed | COMMENT |
| LOW | app/generation-preview/page.tsx | 954 | // Step 2: Generate content (currentStepIndex is already 2) | COMMENT |
| LOW | tests/config/token-plan-apply-persist.test.ts | 34 | // Step 1: apply fills key + baseUrl + type (what applyTokenPlan does). | COMMENT |
| LOW | tests/config/token-plan-apply-persist.test.ts | 49 | // Step 2: probe success writes ONLY models (what handleApply does next). | COMMENT |
| LOW | lib/pdf/mineru-cloud.ts | 256 | // Step 1: Create batch — request presigned upload URL | COMMENT |
| LOW | lib/pdf/mineru-cloud.ts | 286 | // Step 2: Upload document to presigned URL | COMMENT |
| LOW | lib/pdf/mineru-cloud.ts | 311 | // Step 3: Poll for completion | COMMENT |
| LOW | lib/audio/asr-providers.ts | 44 | * // Step 1: Upload audio file | COMMENT |
| LOW | lib/audio/asr-providers.ts | 69 | * // Step 2: Request transcription | COMMENT |
| LOW | lib/audio/asr-providers.ts | 84 | * // Step 3: Poll for completion | COMMENT |
| LOW | lib/hooks/use-scene-generator.ts | 564 | // Step 1: content — await this outline's pre-warmed fetch (parallel), | COMMENT |
| LOW | lib/hooks/use-scene-generator.ts | 604 | // Step 2: Generate actions + assemble scene | COMMENT |
| LOW | lib/hooks/use-scene-generator.ts | 756 | // Step 1: Content | COMMENT |
| LOW | lib/hooks/use-scene-generator.ts | 776 | // Step 2: Actions | COMMENT |
| LOW | lib/hooks/use-scene-generator.ts | 804 | // Step 3: TTS | COMMENT |
| LOW | lib/orchestration/stateless-generate.ts | 150 | // Step 1: Find the opening `[` if not yet found | COMMENT |
| LOW⚡ | lib/orchestration/stateless-generate.ts | 161 | // Step 2: Check if the array is complete (closing `]` found) | COMMENT |
| LOW⚡ | lib/orchestration/stateless-generate.ts | 165 | // Step 3: Try incremental parse — jsonrepair first (fixes unescaped quotes), fallback to partial-json | COMMENT |
| LOW | lib/orchestration/stateless-generate.ts | 186 | // Step 4: Determine how many items are fully complete | COMMENT |
| LOW | lib/orchestration/stateless-generate.ts | 200 | // Step 5: Emit newly completed items | COMMENT |
| LOW | lib/orchestration/stateless-generate.ts | 234 | // Step 6: Stream partial text delta for the trailing item | COMMENT |
| LOW | lib/orchestration/stateless-generate.ts | 246 | // Step 7: Mark done if array is closed | COMMENT |
| LOW | lib/prompts/templates/slide-content/system.md | 550 | #### Step 1: Design the background shape first | COMMENT |
| LOW | lib/prompts/templates/slide-content/system.md | 561 | #### Step 2: Calculate text dimensions | COMMENT |
| LOW | lib/prompts/templates/slide-content/system.md | 570 | #### Step 3: Center the text inside the shape | COMMENT |
| LOW | lib/generation/scene-builder.ts | 87 | // Step 1: Generate content (with images if available) | COMMENT |
| LOW | lib/generation/scene-builder.ts | 111 | // Step 2: Generate Actions | COMMENT |
| LOW⚡ | lib/generation/action-parser.ts | 47 | // Step 1: Strip markdown code fences if present | COMMENT |
| LOW⚡ | lib/generation/action-parser.ts | 50 | // Step 2: Find the JSON array range | COMMENT |
| LOW | lib/generation/action-parser.ts | 61 | // Step 3: Parse — try JSON.parse first, then jsonrepair, fallback to partial-json | COMMENT |
| LOW | lib/generation/action-parser.ts | 88 | // Step 4: Convert items to Action[] | COMMENT |
| LOW⚡ | lib/generation/action-parser.ts | 131 | // Step 5: Post-processing — discussion must be the last action, and at most one | COMMENT |
| LOW⚡ | lib/generation/action-parser.ts | 137 | // Step 6: Filter out slide-only actions for non-slide scenes (defense in depth) | COMMENT |
| LOW⚡ | lib/generation/action-parser.ts | 147 | // Step 7: Filter by allowedActions whitelist (defense in depth for role-based isolation) | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/video-export/compile.test.ts | 66 | expect(q0.base.kind).toBe('placeholder'); | CODE |
| LOW | components/whiteboard/whiteboard-canvas.tsx | 349 | key="placeholder" | CODE |
| LOW | packages/pptxgenjs/types/index.d.ts | 817 | 'placeholder' = 'placeholder', | CODE |
| LOW | packages/pptxgenjs/src/gen-objects.ts | 77 | else if (MASTER_OBJECTS[key] && key === 'placeholder') { | CODE |
| LOW | packages/pptxgenjs/src/gen-objects.ts | 1050 | item => item._type === 'placeholder' && item.options && item.options.placeholder && item.options.placeholder === it | CODE |
| LOW | packages/pptxgenjs/src/gen-xml.ts | 423 | strSlideXml += `<p:nvPr>${slideItemObj._type === 'placeholder' ? genXmlPlaceholder(slideItemObj) : genXmlPlaceholder | CODE |
| LOW | packages/pptxgenjs/src/gen-xml.ts | 1226 | else if (slideObj._type === 'placeholder') strSlideXml += `<a:lstStyle>${genXmlParagraphProperties(slideObj, true)}</a | CODE |
| LOW | packages/pptxgenjs/src/core-enums.ts | 729 | 'placeholder' = 'placeholder', | CODE |
| LOW | packages/pptxgenjs/src/core-enums.ts | 738 | 'placeholder' = 'placeholder', | CODE |
| LOW | lib/video-export/compile.ts | 84 | base: { ...scene.base, kind: 'placeholder', reason }, | CODE |
| LOW | lib/video-export/ir.ts | 101 | kind: z.enum(['slide-snapshot', 'placeholder']), | CODE |
| LOW | lib/video-export/passes/timeline.ts | 133 | base: { kind: supported ? 'slide-snapshot' : 'placeholder' }, | CODE |
| LOW | lib/i18n/locales/ko-KR.json | 263 | "placeholder": "이 슬라이드에 대한 변경 사항을 설명하세요…", | CODE |
| LOW | lib/i18n/locales/ko-KR.json | 295 | "placeholder": "이 인터랙티브 페이지의 버그를 설명하세요…" | CODE |
| LOW | lib/i18n/locales/ko-KR.json | 542 | "placeholder": "메시지를 입력하세요...", | CODE |
| LOW | lib/i18n/locales/ko-KR.json | 627 | "placeholder": "Chat with {{name}} about your progress...", | CODE |
| LOW | lib/i18n/locales/ko-KR.json | 1667 | "placeholder": "접근 코드", | CODE |
| LOW | lib/i18n/locales/ja-JP.json | 312 | "placeholder": "このスライドの変更内容を入力…", | CODE |
| LOW | lib/i18n/locales/ja-JP.json | 344 | "placeholder": "このインタラクティブページの不具合を入力…" | CODE |
| LOW | lib/i18n/locales/ja-JP.json | 542 | "placeholder": "メッセージを入力...", | CODE |
| LOW | lib/i18n/locales/ja-JP.json | 627 | "placeholder": "{{name}}と進捗について話す...", | CODE |
| LOW | lib/i18n/locales/ja-JP.json | 1667 | "placeholder": "アクセスコード", | CODE |
| LOW | lib/i18n/locales/zh-CN.json | 312 | "placeholder": "描述对这一页的修改…", | CODE |
| LOW | lib/i18n/locales/zh-CN.json | 322 | "placeholder": "描述这个互动页的问题…", | CODE |
| LOW | lib/i18n/locales/zh-CN.json | 542 | "placeholder": "输入消息...", | CODE |
| LOW | lib/i18n/locales/zh-CN.json | 627 | "placeholder": "和 {{name}} 聊聊你的进度...", | CODE |
| LOW | lib/i18n/locales/zh-CN.json | 1667 | "placeholder": "访问码", | CODE |
| LOW | lib/i18n/locales/ar-SA.json | 312 | "placeholder": "صف تغييراتك على هذه الشريحة…", | CODE |
| LOW | lib/i18n/locales/ar-SA.json | 344 | "placeholder": "صِف الخطأ في هذه الصفحة التفاعلية…" | CODE |
| LOW | lib/i18n/locales/ar-SA.json | 542 | "placeholder": "اكتب رسالة...", | CODE |
| LOW | lib/i18n/locales/ar-SA.json | 627 | "placeholder": "تحدث مع {{name}} عن تقدمك...", | CODE |
| LOW | lib/i18n/locales/ar-SA.json | 1667 | "placeholder": "رمز الوصول", | CODE |
| LOW | lib/i18n/locales/pt-BR.json | 297 | "placeholder": "Descreva suas alterações neste slide…", | CODE |
| LOW | lib/i18n/locales/pt-BR.json | 329 | "placeholder": "Descreva o bug desta página interativa…" | CODE |
| LOW | lib/i18n/locales/pt-BR.json | 542 | "placeholder": "Digite uma mensagem...", | CODE |
| LOW | lib/i18n/locales/pt-BR.json | 627 | "placeholder": "Chat with {{name}} about your progress...", | CODE |
| LOW | lib/i18n/locales/pt-BR.json | 1667 | "placeholder": "Código de acesso", | CODE |
| LOW | lib/i18n/locales/zh-TW.json | 312 | "placeholder": "描述對這一頁的修改…", | CODE |
| LOW | lib/i18n/locales/zh-TW.json | 322 | "placeholder": "描述這個互動頁的問題…", | CODE |
| LOW | lib/i18n/locales/zh-TW.json | 527 | "placeholder": "輸入訊息...", | CODE |
| LOW | lib/i18n/locales/zh-TW.json | 612 | "placeholder": "和 {{name}} 聊聊你的進度...", | CODE |
| LOW | lib/i18n/locales/zh-TW.json | 1652 | "placeholder": "課堂碼", | CODE |
| LOW | lib/i18n/locales/ru-RU.json | 312 | "placeholder": "Опишите изменения для этого слайда…", | CODE |
| LOW | lib/i18n/locales/ru-RU.json | 344 | "placeholder": "Опишите ошибку на этой интерактивной странице…" | CODE |
| LOW | lib/i18n/locales/ru-RU.json | 542 | "placeholder": "Введите сообщение...", | CODE |
| LOW | lib/i18n/locales/ru-RU.json | 627 | "placeholder": "Обсудите прогресс с {{name}}...", | CODE |
| LOW | lib/i18n/locales/ru-RU.json | 1667 | "placeholder": "Код доступа", | CODE |
| LOW | lib/i18n/locales/en-US.json | 312 | "placeholder": "Describe your changes to this slide…", | CODE |
| LOW | lib/i18n/locales/en-US.json | 322 | "placeholder": "Describe the bug on this interactive page…", | CODE |
| LOW | lib/i18n/locales/en-US.json | 542 | "placeholder": "Type a message...", | CODE |
| LOW | lib/i18n/locales/en-US.json | 627 | "placeholder": "Chat with {{name}} about your progress...", | CODE |
| LOW | lib/i18n/locales/en-US.json | 1667 | "placeholder": "Access code", | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | app/generation-preview/page.tsx | 346 | // Step 0: Extract uploaded course material if needed | COMMENT |
| LOW | app/generation-preview/page.tsx | 954 | // Step 2: Generate content (currentStepIndex is already 2) | COMMENT |
| LOW | tests/config/token-plan-apply-persist.test.ts | 34 | // Step 1: apply fills key + baseUrl + type (what applyTokenPlan does). | COMMENT |
| LOW | tests/config/token-plan-apply-persist.test.ts | 49 | // Step 2: probe success writes ONLY models (what handleApply does next). | COMMENT |
| LOW | lib/pdf/mineru-cloud.ts | 256 | // Step 1: Create batch — request presigned upload URL | COMMENT |
| LOW | lib/pdf/mineru-cloud.ts | 286 | // Step 2: Upload document to presigned URL | COMMENT |
| LOW | lib/pdf/mineru-cloud.ts | 311 | // Step 3: Poll for completion | COMMENT |
| LOW | lib/audio/asr-providers.ts | 44 | * // Step 1: Upload audio file | COMMENT |
| LOW | lib/audio/asr-providers.ts | 69 | * // Step 2: Request transcription | COMMENT |
| LOW | lib/audio/asr-providers.ts | 84 | * // Step 3: Poll for completion | COMMENT |
| LOW | lib/hooks/use-scene-generator.ts | 564 | // Step 1: content — await this outline's pre-warmed fetch (parallel), | COMMENT |
| LOW | lib/hooks/use-scene-generator.ts | 604 | // Step 2: Generate actions + assemble scene | COMMENT |
| LOW | lib/hooks/use-scene-generator.ts | 756 | // Step 1: Content | COMMENT |
| LOW | lib/hooks/use-scene-generator.ts | 776 | // Step 2: Actions | COMMENT |
| LOW | lib/hooks/use-scene-generator.ts | 804 | // Step 3: TTS | COMMENT |
| LOW | lib/orchestration/stateless-generate.ts | 150 | // Step 1: Find the opening `[` if not yet found | COMMENT |
| LOW⚡ | lib/orchestration/stateless-generate.ts | 161 | // Step 2: Check if the array is complete (closing `]` found) | COMMENT |
| LOW⚡ | lib/orchestration/stateless-generate.ts | 165 | // Step 3: Try incremental parse — jsonrepair first (fixes unescaped quotes), fallback to partial-json | COMMENT |
| LOW | lib/orchestration/stateless-generate.ts | 186 | // Step 4: Determine how many items are fully complete | COMMENT |
| LOW | lib/orchestration/stateless-generate.ts | 200 | // Step 5: Emit newly completed items | COMMENT |
| LOW | lib/orchestration/stateless-generate.ts | 234 | // Step 6: Stream partial text delta for the trailing item | COMMENT |
| LOW | lib/orchestration/stateless-generate.ts | 246 | // Step 7: Mark done if array is closed | COMMENT |
| LOW | lib/generation/scene-builder.ts | 87 | // Step 1: Generate content (with images if available) | COMMENT |
| LOW | lib/generation/scene-builder.ts | 111 | // Step 2: Generate Actions | COMMENT |
| LOW⚡ | lib/generation/action-parser.ts | 47 | // Step 1: Strip markdown code fences if present | COMMENT |
| LOW⚡ | lib/generation/action-parser.ts | 50 | // Step 2: Find the JSON array range | COMMENT |
| LOW | lib/generation/action-parser.ts | 61 | // Step 3: Parse — try JSON.parse first, then jsonrepair, fallback to partial-json | COMMENT |
| LOW | lib/generation/action-parser.ts | 88 | // Step 4: Convert items to Action[] | COMMENT |
| LOW⚡ | lib/generation/action-parser.ts | 131 | // Step 5: Post-processing — discussion must be the last action, and at most one | COMMENT |
| LOW⚡ | lib/generation/action-parser.ts | 137 | // Step 6: Filter out slide-only actions for non-slide scenes (defense in depth) | COMMENT |
| LOW⚡ | lib/generation/action-parser.ts | 147 | // Step 7: Filter by allowedActions whitelist (defense in depth for role-based isolation) | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | README.md | 633 | │ ├── orchestration/ # LangGraph multi-agent orchestration (director graph) | CODE |
| MEDIUM | README.md | 633 | │ ├── orchestration/ # LangGraph multi-agent orchestration (director graph) | CODE |
| MEDIUM | tests/pbl/v2/completion-stats.test.ts | 178 | // When the scored coverage is present, the read-only scaffold fallback | COMMENT |
| MEDIUM | tests/pbl/v2/completion-stats.test.ts | 218 | // The structured review survives as an unscored scaffold. | COMMENT |
| MEDIUM | tests/pbl/v2/completion-stats.test.ts | 845 | const p = rpProjectWithGoals(); // scaffold has 2 goals for ms-rp | CODE |
| MEDIUM | tests/pbl/v2/planner.test.ts | 459 | // We can't run the full agentic loop without an LLM, but the | COMMENT |
| MEDIUM | tests/pbl/v2/instructor.test.ts | 728 | // resolves '' → intermediate, so the scaffold label + release threshold | COMMENT |
| MEDIUM | lib/pbl/generate-pbl.ts | 285 | // Run the agentic loop | COMMENT |
| MEDIUM | lib/pbl/v2/agents/evaluator.ts | 290 | // scaffold. The guard keeps normal projects completely out of this path | COMMENT |
| MEDIUM | lib/pbl/v2/agents/instructor.ts | 477 | // During a stage-synthesis checkpoint the scaffold verdict is noise: | COMMENT |
| MEDIUM | lib/pbl/v2/agents/planner.ts | 167 | // The agentic loop. The Planner emits tool calls until | COMMENT |
| MEDIUM | lib/pbl/v2/operations/completion-stats.ts | 235 | // act, with a goals array of exactly the scaffold's length. A mismatch | COMMENT |
| MEDIUM | lib/pbl/v2/operations/completion-stats.ts | 317 | // alignment gate), still surface the authored act→goal scaffold read-only so | COMMENT |
| MEDIUM | lib/pbl/v2/operations/completion-stats.ts | 319 | // Mutually exclusive with goalCoverage; omitted when the scaffold is empty. | COMMENT |
| MEDIUM | lib/pbl/v2/operations/eval-prompts.ts | 461 | // the very same scaffold. This drives the "what you accomplished" credit and | COMMENT |
| MEDIUM | lib/pbl/v2/prompts/planner-single-call-system.md | 66 | 9. **Hints and descriptions GUIDE, never SOLVE — the #1 failure.** A hint or `description` must NEVER contain the litera | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | components/stage.tsx | 101 | // releases on unmount / tab close. | COMMENT |
| LOW | components/scene-renderers/pbl-renderer.tsx | 181 | readonly sceneId: string; | COMMENT |
| LOW | components/scene-renderers/pbl-renderer.tsx | 201 | // blank during native fullscreen. Default to <body> (classroom is an | COMMENT |
| LOW | components/scene-renderers/pbl-renderer.tsx | 221 | // chat. Transient by design: a full page reload ends the streams and resets | COMMENT |
| LOW | components/scene-renderers/pbl/v2/hero.tsx | 141 | // "What you'll gain" — the Planner's structured `gains` (3-5 readable, | COMMENT |
| LOW | components/scene-renderers/pbl/v2/workspace.tsx | 121 | const [taskBusy, setTaskBusy] = useState(false); | COMMENT |
| LOW | components/edit/EditChromeRoot.tsx | 61 | // promise-cached no-op in that path; it only does real work if edit mode | COMMENT |
| LOW | components/edit/SlideNavRail/SlideNavRail.tsx | 61 | // latency between move events and the visible width change. | COMMENT |
| LOW | …er/Editor/Canvas/hooks/useInsertFromCreateSelection.ts | 81 | const insertElementFromCreateSelection = useCallback( | COMMENT |
| LOW | packages/@openmaic/renderer/src/snapshot/index.ts | 121 | flushSync(() => { | COMMENT |
| LOW | …@openmaic/renderer/src/editing/EditableSlideCanvas.tsx | 221 | // is drawn. Instead render an INERT SVG-path blocker that mirrors | COMMENT |
| LOW | …@openmaic/renderer/src/editing/EditableSlideCanvas.tsx | 241 | // Known gap: endpoint markers (arrow/dot) can paint beyond the | COMMENT |
| LOW | …@openmaic/renderer/src/editing/EditableSlideCanvas.tsx | 321 | strokeWidth={grabCanvas} | COMMENT |
| LOW | …@openmaic/renderer/src/editing/EditableSlideCanvas.tsx | 341 | // selection callback is provided, resolve the click | COMMENT |
| LOW | …s/@openmaic/importer/src/serializer/shapeSerializer.ts | 341 | strokeWidthPx: number, | COMMENT |
| LOW | …es/@openmaic/importer/src/serializer/textSerializer.ts | 1161 | // Empty paragraph (no visible runs → renders as a bare <br/>): PowerPoint | COMMENT |
| LOW | …es/@openmaic/importer/src/serializer/textSerializer.ts | 1181 | } | COMMENT |
| LOW | …es/@openmaic/importer/src/serializer/textSerializer.ts | 1361 | // 已把首行起点定在 marL+indent;槽位只需补满到 marL,所以宽度是 |indent|。 | COMMENT |
| LOW | …es/@openmaic/importer/src/serializer/textSerializer.ts | 1381 | // 落到 element 左外(slide 3 的 ■ 飞到左侧编号圆上)。在槽位上显式归零切断继承,bullet | COMMENT |
| LOW | …es/@openmaic/importer/src/serializer/textSerializer.ts | 1421 | // paragraphs need no <br/> — the wrapper <div> already has a fixed line | COMMENT |
| LOW | …es/@openmaic/importer/src/serializer/mathSerializer.ts | 21 | import mathmlToLatex from 'mathml-to-latex'; | COMMENT |
| LOW | …es/@openmaic/importer/src/serializer/mathSerializer.ts | 281 | COMMENT | |
| LOW | packages/@openmaic/importer/src/shapes/presets.ts | 4641 | // endpoint = (hc, g20+g17) = (hc, g10)? g20+g17 = (g9+g16)+g17 = g9+g13*5/8+g13*3/8 = g9+g13 = g9+ss*3/4 | COMMENT |
| LOW | …mporter/src/import-pipeline/transformParsedToSlides.ts | 961 | // formula+defaultValue 更准确——后者会丢掉非默认 adj(典型例子: | COMMENT |
| LOW | packages/@openmaic/storage/src/runtime/browser.ts | 381 | // The compound primary key ['sessionId', 'seq'] makes a ranged read come | COMMENT |
| LOW | packages/@openmaic/storage/src/document/browser.ts | 221 | // Normalize stale input forward to the current version — the same migration | COMMENT |
| LOW | packages/@openmaic/dsl/test/version.test.ts | 41 | it('is empty today — the runtime line has no unversioned epoch to lift from', () => { | COMMENT |
| LOW | packages/@openmaic/dsl/src/validate.ts | 281 | } | COMMENT |
| LOW | .github/workflows/publish-packages.yml | 1 | name: Publish @openmaic packages | COMMENT |
| LOW | lib/types/stage.ts | 1 | // Stage and Scene data types. | COMMENT |
| LOW | lib/types/action.ts | 1 | // Unified Action System. | COMMENT |
| LOW | lib/types/action.ts | 41 | // The action-category lists are runtime values (plain arrays), so they must be | COMMENT |
| LOW | lib/agent/tools/regenerate-scene-actions.ts | 101 | // GeneratedPBLContent { projectConfig } | COMMENT |
| LOW | lib/pbl/v2/agents/simulator.ts | 141 | // Established facts of the current beat — the system narrator delivers | COMMENT |
| LOW | lib/pbl/v2/agents/simulator.ts | 461 | microtaskId: ev.microtaskId, | COMMENT |
| LOW | lib/pbl/v2/agents/planner-single-call.ts | 241 | } | COMMENT |
| LOW | lib/pbl/v2/agents/instructor.ts | 821 | stageSynthesisOwed(args.project, args.milestone, args.microtask), | COMMENT |
| LOW | lib/pbl/v2/agents/instructor.ts | 1481 | }, | COMMENT |
| LOW | lib/pbl/v2/agents/instructor.ts | 1581 | // cleaned. Task-completion ready prompts are injected by the submission flow, | COMMENT |
| LOW | lib/pbl/v2/agents/instructor.ts | 1661 | // | COMMENT |
| LOW | lib/pbl/v2/operations/proficiency.ts | 621 | // Static batch aggregation is NOT the same maths as the dynamic | COMMENT |
| LOW | lib/hooks/use-canvas-operations.ts | 181 | // Copy selected element data to clipboard | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | lib/types/generation.ts | 137 | // AI-generated media requests (when PDF images are insufficient) | COMMENT |
| HIGH | lib/utils/database.ts | 350 | // Version 8: Add generatedAgents table for AI-generated agent profiles | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | lib/pbl/v2/agents/planner.ts | 318 | // a BCP-47 locale or a nuanced directive like "中文为主,英文技术术语保留原文". | COMMENT |
| MEDIUM | lib/web-search/brave.ts | 77 | // robust to that (and a future) swap; the title text is stripped of tags | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | components/slide-renderer/Editor/Canvas/index.tsx | 167 | // TODO: implement createTextElement (use _viewportRect + e.pageX/Y + canvasScale) | COMMENT |
| LOW | components/slide-renderer/Editor/Canvas/index.tsx | 244 | // TODO: implement insertCustomShape | COMMENT |
| LOW | …mponents/slide-renderer/Editor/Canvas/hooks/useDrop.ts | 18 | // TODO: implement createTextElement | COMMENT |