Add SCAN injection defense, embedded fonts, shape SVG guard, and refine narrative - #5
Open
lizTheDeveloper wants to merge 1 commit into
Open
Add SCAN injection defense, embedded fonts, shape SVG guard, and refine narrative#5lizTheDeveloper wants to merge 1 commit into
lizTheDeveloper wants to merge 1 commit into
Conversation
Completes the remaining work that does not depend on the Hermes/Playwright drivability spike, leaving only the genuinely engine-dependent stages. #2 research: - §7.1 Prompt Guard 2 injection scan (src/research/scan.mjs): a SCAN stage between RANK and SYNTHESIZE classifies every ingested free-text field in ≤512-token windows; fields tripping a conservative threshold are blanked so they never reach a prompt or #3, while structured metadata survives. Records quarantined_sources. Scorer is dependency-injected/mockable; makeLocalScorer() wires the self-hosted service via PROMPT_GUARD_URL and is null-when-unconfigured so layer-1 defenses still hold. #3 generator: - llm into Compose (refineNarrative): optional, fail-open wording refinement that re-validates and leaves structure/layout/citations untouched. - shape.svg trust boundary (shape-guard.mjs): fail-closed SVG allowlist enforced in the IR validator and again at SVG-emit time (defense in depth). - embedded typeface plumbing (fonts.mjs): makeFontDeps/loadFontDeps build the deps.fonts shape; embedded family names now flow into the SVG, @font-face into styles.css, files under assets/fonts/ (font-src 'self', woff/ttf MIME). - #2→#3→#1 worker seam: selectGenerator() picks the prezi pipeline when an LLM is configured, else the #1 stub; tests stay hermetic via an injected stub. 35 new tests; full suite 215 green.
lizTheDeveloper
added a commit
that referenced
this pull request
Jun 10, 2026
Realizes the capture/assessment half of C9 (the #5 §11 forward-doc): run a #5 interactive deck as a class exercise and capture how students respond, without ever exposing student data publicly. Key decisions: - Roster + join-code students, cohort-scoped (low-friction, minimal PII); student sessions separate from instructor magic-link, same origin. - Class context = authenticated app-origin route (connect-src 'self'); public slug origin stays connect-src 'none' (reconciles #5 §11 as realization, not reversal). - One non-additive seam: #6 adds a CSP-clean prezi:interaction dispatch to the #5 runtime; capture adapter loads only on the class route. - Free-text: always recorded; optional instructor-triggered batch agent grading (LLM-gated, same gate as the #3-generator wiring). - Privacy-first (assume minors): minimal collection, join-time consent, retention auto-purge, cohort data delete, no public exposure. - Three shippable layers: core capture loop (no LLM) -> optional grading -> retention/purge. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements four critical security and presentation-quality features across the research pipeline (#2), presentation generator (#3), and worker seam:
@font-facedeclarations to guarantee sandbox↔viewer rendering fidelity<foreignObject>Key Changes
Research Pipeline (#2)
src/research/scan.mjs(125 lines): SCAN stage implementationchunkText()— splits long text into ≤512-token windows on whitespace boundariesscanField()— scores a field; flags if ANY window exceeds thresholdscanCandidates()— scans all candidates; quarantines malicious free-text fields while retaining structured metadata (copy-on-write)makeLocalScorer()— builds localhost scorer for self-hosted Prompt Guard 2 (dependency-injected; returns null when unconfigured)src/research/scan.test.mjs) covering injection payloads, label-only scorers, and metadata retentionsrc/research/pipeline.mjs(modified): Wires SCAN into the pipelineopts.scan = { scorer, threshold?, maxChars? }scanCandidates()after ranking, before synthesisquarantined_sourcesfieldsrc/research/schema.mjs(modified): Addsquarantined_sourcesto findings doc contractsrc/research/cli.mjs(modified): CLI wiresmakeLocalScorer()whenPROMPT_GUARD_URLis setPresentation Generator (#3)
src/prezi/fonts.mjs(100 lines): Font embedding plumbingbuildFontFaceCss()— emits CSP-clean@font-facerules withassets/fonts/same-origin pathsmakeFontDeps()— assembles{ embedded, faceCss, files, families }shape with fallback stacksloadFontDeps()— reads font files from a directory using a manifest; pure stdlib (no network)src/prezi/fonts.test.mjs) validates CSS generation, file loading, and end-to-end SVG/styles.css emissionsrc/prezi/shape-guard.mjs(90 lines): Shape SVG validatorcheckShapeSvg()— fail-closed allowlist: only inert vector elements (path,rect,circle,g,defs, gradients,clipPath,title,desc)<script>,<foreignObject>,<image>,<use>,<a>, event handlers,href/xlink:href,style, and unsafe URLs (external schemes,javascript:,data:, non-fragmenturl())isSafeShapeSvg()— boolean wrappersrc/prezi/shape-guard.test.mjs) covers geometry, handlers, external content, and IR validation integrationsrc/prezi/ir-schema.mjs(modified): Integrates shape validationvalidateBlock()now calls `https://claude.ai/code/session_01YNZCWtNSiZ5bWkc56eYGeE