On this page
- Operational Workflows (Agentic)
- The Toolchain Trinity (Core Scripts)
- Architectural Patterns
- The Animation Sequence Protocol (Folder-to-WebP)
- Asset Pipeline
- Standard Operating Procedure: Lightroom Export (The Honda Standard)
- DXF Rendering Issues
- MDX Errors (Astro Content Layer)
- The Timeline Trap (Infinite Bubble)
- Broken Site Logos / Favorites
- Cloudflare Image Service Warning
- Cloudflare KV Binding Error (Static Build)
- IDE Tooling Errors (“Stream Error”)
- Asset & Schema Errors
- Hyperspace Migration (Batch Upgrade)
- The Orphan Trap (Data Stripping)
- The “Ghost Folder” 404 (Static Assets)
- Gallery Crashes (Relative URLs)
- Auditory/Visual Engine Maintenance
- Starfield Visibility (The “Black Curtain” Trap)
- Audio Protocol Leakage (Iron Dome Failure)
- Resume Infrastructure (PDF Pipeline)
Maintenance & Troubleshooting
System Maintenance & Troubleshooting
Status: Historical reference. The operational commands and source paths below describe the retired sidecar pipeline and are not current instructions. Use the repository’s
CLAUDE.mdfor current commands and ownership,README.md#deployment-and-rollbackfor release work, andD:\GitHub\portfolio-canon\DEEP_DIVE_SOP.mdplusD:\GitHub\portfolio-canon\NOTEBOOKLM_MIGRATION_SOP.mdfor research and custody. Retained prompt/compiler material does not authorize a publication path.
Operational Workflows (Agentic)
These tasks are now automated via Slash Commands in the IDE.
- Runtime Rule: Agent-critical scripts must use explicit interpreters. Use
D:\GitHub\global_agent\venv\Scripts\python.exefor session-open/global-agent checks, and use the Codex bundled Python/Node underC:\Users\erik\.cache\codex-runtimes\codex-primary-runtime\dependencies\for sandboxed portfolio validation. - New Project:
/scaffold-project(Generates strict C24 Schema). - Deploy:
/deploy-production(Verify Build + Push to Main). - New Project:
/scaffold-project(Generates strict C24 Schema). - Deploy:
/deploy-production(Verify Build + Push to Main). - Hack Pack:
scripts/compile_hack_pack.py(GeneratesBOLUS+REPORT+PODCAST). - Master Resume:
assets.eriknorris.com/resume/Erik_Norris_Resume_Current.pdf(served from R2, not from the site — see Resume Infrastructure below).
The Toolchain Trinity (Core Scripts)
These scripts are the engine of the “Forensic Data Factory.”
Architectural Patterns
-
The Hybrid Scroll (Performance):
- Context: Heavy 3D scenes (R3F) cause main-thread lag if coupled with React State-driven scroll hooks (like
useScroll). - Pattern: Use Vanilla JS
scrolllisteners attached to specific containers (e.g.,#hyperspace-container) to calculate progress (0-1) and pass it into the Canvas via a single State update or Ref. - Benefit: Decouples the 60fps render loop from the scroll event loop.
- Context: Heavy 3D scenes (R3F) cause main-thread lag if coupled with React State-driven scroll hooks (like
-
Hydration Engine:
npm run content:hydrate- Source:
scripts/hydrate_content.py - Purpose: Injects NotebookLM “Bolus” data (JSON) into MDX Frontmatter (Metrics, Toolchains, Summaries).
- Behavior:
- Mines Stickies: Scans
R2_MASTERfor bubble assets. - Injects Intelligence: Auto-detects
{slug}.mdinnotebook_dumps/and copies it to_intelligence.mdfor Assembly metrics. - Updates Metadata: Syncs
forensic_metrics,toolchain,tier, andtheme.
- Mines Stickies: Scans
- Source:
-
Schema Modernizer:
npm run content:modernize- Source:
scripts/modernize_content.py - Purpose: Mass-updates legacy content to the latest C24 Schema.
- Behavior: Injects default values for new fields (
cyberspace,metrics,statusLabel). Use for bulk refactors.
- Source:
-
Asset Refinery:
npm run assets:process- Source:
scripts/process_assets.py(formerlyprocess_images.py) - Purpose: The “Heavy Lifter” for media.
- Capabilities:
- Images: Resizes to standard breakpoints (xl, lg, md, sm) and generates WebP.
- Audio:
- Source:
R2_MASTER/[slug]/[filename].wav - Naming:
[slug]-briefing.wav(Standard) or[slug]-deep_dive.wav - Output:
R2_MIRROR/[slug]/[filename].mp3(192kbps) - Global Audio: Use
identityslug (e.g.,R2_MASTER/identity/identity-overview.wav).
- Source:
- Usage:
npm run assets:process(Process specific slugs in R2_MASTER).npm run assets:process -- --all(Re-process EVERYTHING).npm run assets:process -- [slug](Target specific project).
- Source:
The Animation Sequence Protocol (Folder-to-WebP)
Context: Used for “Stop Motion” style clips or frame-by-frame UI animations (like boot sequences).
- Trigger: Create a Folder inside a project or bubble (instead of a single image file).
- Folder Metrics:
- Syntax:
[sequence_name]-[duration]ms - Example:
boot_sequence-50ms(Each frame plays for 50ms). - Default: 2000ms if no suffix is provided.
- Syntax:
- Content:
- Place sequential images inside:
001.jpg,002.jpg, etc. - Sorting: Alphanumeric. Use leading zeros (
001, not1) to ensure correct order.
- Place sequential images inside:
- Output:
- Animated WebP:
[sequence_name]-[breakpoint].webp(The playable clip). - Frame Folder: Copies source frames to
[output]/[sequence_name]/for individual frame access (React components).
- Animated WebP:
Asset Pipeline
Standard Operating Procedure: Lightroom Export (The Honda Standard)
Rationale: The process_assets.py script is a “Lossy Downscaler.” It requires high-quality, high-resolution inputs (JPEGs) to generate optimized WebP outputs.
Export Settings (R2_MASTER):
- File Settings:
- Format:
JPEG(Quality 90-100). Do NOT use TIFF (Overkill) or JXL (Unsupported). - Color Space:
sRGB.
- Format:
- Image Sizing:
- Resize to Fit: Width & Height.
- W / H:
2500px. (Provides buffer for the1920pxXL breakpoint). - Resolution:
72ppi (Metadata only). - Legacy Assets: If original < 800px, use Super Resolution or Upscayl to target ~2500px BEFORE export.
- Output Sharpening:
- Sharpen For: Screen (Standard).
- Metadata:
- Copyright Only: Strip GPS/Camera info.
DXF Rendering Issues
-
Symptom:
ModuleNotFoundError: No module named 'ezdxf'ormatplotlib. -
Context: The DXF pipeline (“The Sidecar”) introduces heavy Python dependencies that are not part of the standard
requirements.txtcore set to keep the main build light. -
Fix:
Terminal window pip install -r scripts/requirements.txtNote: We recently added
ezdxfandmatplotlibtorequirements.txt(Jan 2026), so ensure your local environment is synced. -
Symptom:
[ERROR] Rendering failed: ... -
Fix:
- Verify the input file is a valid DXF (Try opening in a viewer like Autodesk TrueView or ODA Viewer).
- Check for “Text Style” missing fonts (matplotlib backend may fallback to default font, which is non-fatal but looks different).
- Run the sidecar in standalone mode to isolate the error:
Terminal window python scripts/lib/dxf_renderer.py "path/to/dxf/file.dxf"
MDX Errors (Astro Content Layer)
- Symptom:
MDXError: Unexpected character 0(or 1-9) preventing dev server startup. - Cause: The MDX parser interprets unquoted keys starting with numbers (e.g.,
01_intro:) as octal or invalid identifiers. It also flags<symbols followed by numbers in body text (e.g.,<0.5mm) as invalid JSX tags. - Fix:
- Frontmatter: Quote ALL keys/values starting with a number:
01_intro->"01_intro". - Body Text: Escape
<if followed by a number or currency:<0.5mm-><0.5mm.- Trap:
<$15k(interpreted as tag). FIX:<$15korless than $15k. - Trap:
<40%(interpreted as tag). FIX:less than 40%.
- Trap:
- Frontmatter: Quote ALL keys/values starting with a number:
The Timeline Trap (Infinite Bubble)
- Symptom: A project’s bubble in the Visualization is massively oversized (e.g., covering the whole screen).
- Cause: Missing End Date. If a project has
date(Start) but noendDateorduration, the visualization engine assumes it is still active (Duration = Start Date to Now -> 20+ Years). - Fix: Ensure every project has an
endDatein frontmatter.date: 2003-01-01endDate: 2004-05-01 # Cap the duration
Broken Site Logos / Favorites
- Symptom: “EN” Logo appears as a broken image icon or text alt-tag in Header/Footer.
- Cause: Missing or corrupt
EN_logo_1200.svginpublic/assets/branding/. - Fix: Restore the canonical “Fake SVGs” from the backup vault:
copy "d:\portfolio\portfolio_working\EN_logo\EN_15-based_good-reference-but _fake-SVGS____\*.svg" "public/assets/branding\" - Note: Do not use
Asset 2.svg(Wireframe); it is incorrect.
Cloudflare Image Service Warning
- Symptom:
[WARN] Cloudflare does not support sharp at runtime. However, you can configure imageService: "compile"... - Cause: The Cloudflare adapter detects Sharp is installed but unavailable in the Edge runtime.
- Fix: Explicitly configure the adapter to use Sharp during the build/compile phase only:
astro.config.mjs adapter: isProduction ? undefined : cloudflare({ imageService: "compile" }),
Cloudflare KV Binding Error (Static Build)
- Symptom: Build fails with
Invalid binding 'SESSION': binding not found in wrangler.toml. - Cause:
adapter: undefined(Static Mode) inastro.config.mjsdisables server-side sessions, butwrangler.tomlstill has a[[kv_namespaces]]binding forSESSION. - Fix: Remove the
[[kv_namespaces]]block fromwrangler.tomlwhen deploying a Static site.
IDE Tooling Errors (“Stream Error”)
- Symptom: “Error generating commit message: … stream error” or “404 models/gemini-1.5-flash not found”.
- Cause:
- Global IDE Outage: The Antigravity IDE has a known bug with the native “Generate” button failing to stream responses (Jan 2026).
- Billing Mismatch: “Google One Ultra” (Consumer) does NOT cover API usage. You must have a credit card on the specific Google Cloud Project for the API Key.
- Fix:
- Run Diagnostic:
python scripts/test_gemini_key.py. - If Script Works: The API Key is fine. The IDE is broken. Use Manual Commits.
- If Script Fails (429): Add billing to Google Cloud Console for the project.
- Run Diagnostic:
Asset & Schema Errors
-
Symptom:
ImageNotFound: Could not find requested image... -
Cause: A component is referencing a relative asset path that was deleted (e.g.,
web-reaper/avatar.jpg). -
Fix: Grep the
srcdirectory for the missing filename. It’s often in a “Tiny Image” component or legacy content. -
Symptom:
YAMLException: can not read an implicit mapping pair; a colon is missed -
Cause: A markdown line in frontmatter starts with
*. YAML interprets this as an alias anchor or list item. -
Fix: The Asterisk Law: You MUST quote any string starting with
*or special characters.narrative: "* The system failed..."->narrative: "* The system failed..."(Wait, quotes are required).narrative: "* The system"(Fails).narrative: "* The system"(Fixed:narrative: '* The system').
Hyperspace Migration (Batch Upgrade)
-
Script:
node scripts/migrate_to_hyperspace.js -
Usage:
--dry-run: Preview changes.--write: Apply changes (Back up first!).
-
Logic:
- Standardizes
theme: "hyperspace". - Promotes
metrics->deep_dive. - Renames
deck->legacy_deck.
- Standardizes
-
Symptom:
Error: Field validation failed: teamSize: Must be a string -
Cause: The Zod schema expects a String, but a Number was provided in the markdown frontmatter.
-
Fix: Quote the value in the
.mdxfile:teamSize: 6->teamSize: "6".
The Orphan Trap (Data Stripping)
- Symptom: Python Hydration script runs successfully (
✅ Updated: 1), but the data (toolchain,forensic_summary) does not appear in the Build. - Cause: Schema Collision. The field exists in the MDX file, but Astro’s Zod Schema (
content.config.ts) is in strict mode and silently strips fields it does not define. - Fix: The Schema Law:
- Define field in
src/content.config.ts(Build Safety). - Inject field via
hydrate_content.py(Automation).
- Define field in
The “Ghost Folder” 404 (Static Assets)
- Symptom: You add a folder to
public/(e.g.,public/digiME), butlocalhost:4321/digiME/returns a 404. - Cause:
- Astro Caching: The Dev Server does not always hot-reload structure changes in
public/. - Zombie Processes (Windows):
npm run devmight fail to close the port, leaving a stalenode.exerunning on 4321 while your new server runs on 4322. You are browsing the OLD server.
- Astro Caching: The Dev Server does not always hot-reload structure changes in
- Fix: Terminate with extreme prejudice.
Terminal window taskkill /F /IM node.exenpm run dev
Gallery Crashes (Relative URLs)
-
Symptom:
TypeError: Invalid URLcrashing the entire Gallery component. -
Cause: Using
new URL(image.href)on a relative internal link (e.g.,/legacy). The browserURLconstructor mandates an absolute URI schema. -
Fix:
// BADnew URL(image.href).hostname;// GOODtry {return new URL(image.href).hostname;} catch {return "INTERNAL"; // or handle relative path manually
Auditory/Visual Engine Maintenance
-
Symptom: Morphing animation (ECG -> Pulse) looks broken, “teleporting” or snapping lines.
-
Cause: Topology Mismatch. Framer Motion cannot smoothly interpolate between paths with different point counts or command types (e.g., converting a Curve
Cto a LineL). -
Fix: Normalize both paths to use the same number of Segment commands (
L).- ECG Path: 11 points (10 Line segments).
- Pulse Path: 11 points (10 Line segments).
- Do not use Bezier curves for the target shape if the source is polygonal.
-
Symptom: Active EQ Visualization looks like a “Techno Strobe” or glitchy.
-
Cause: Animation cadence is too fast (<0.4s) or uses
lineareasing. -
Fix: Tune to Iambic Pentameter.
- Duration: 0.6s - 1.0s.
- Ease:
easeInOut. - Noise: Inject randomized height variance (
Math.random()) so bars don’t move in unison.
Starfield Visibility (The “Black Curtain” Trap)
- Symptom: The Starfield is visible on Homepage but “Black” on Project Pages, or flashes black then appears.
- Cause:
- Hydration Latency:
client:idle(default) delays the R3F Canvas initialization until the main thread is free. On heavy project pages, this gap is visible as a black void. - Opaque Layers: Tailwind defaults like
bg-black/90on HUDs orbg-neutral-900on containers create overlapping “Curtains” that block the collimated background.
- Hydration Latency:
- Fix:
- Boost Hydration: Use
client:loadfor<CollimatedBackground />on[...slug].astro. - Enforce Stealth: Locate opaque containers (Review Assembly/Timeline divs) and set
bg-transparent.
- Boost Hydration: Use
Audio Protocol Leakage (Iron Dome Failure)
- Symptom: The Audio Host reads your prompts aloud (e.g., “System Instruction: You are a Forensic Architect…”).
- Cause: Contamination. You included “Instructional Headers” in a file visible to the Audio Model. The Audio Model treats ALL source text as “Script.”
- Fix:
- Purge: Remove
REFINE_READY.txtfrom the source list. - Decouple: Use
PODCAST_READY.txt(which has NO instruction headers) + The “Densified Report” (converted to Source). - Reset: You MUST start a new chat context. Once the model has “read” the bad prompt, it is poisoned.
- Purge: Remove
Resume Infrastructure (PDF Pipeline)
- Source of Truth:
src/config/resume_master.ts(Structured Content). - Generation (Headless):
node scripts/generate_resume_pdf.cjs(from the repo root). Spawns a headless Astro dev server on port 4321 and prints/resumevia Puppeteer with print-media emulation. Replaces the old interactive Browser Print -> Save-to-PDF flow.- Trap: The script exits 0 even when printing fails inside its try/catch. Verify the output PDF’s mtime on the filesystem; stdout success lines prove nothing.
- Output (R2_MIRROR, not
public/):- Current:
D:\GitHub\portfolio-assets\R2_MIRROR\resume\Erik_Norris_Resume_Current.pdf - Archive:
D:\GitHub\portfolio-assets\R2_MIRROR\resume\archive\Erik_Norris_Resume_[YYYY-MM-DD].pdf
- Current:
- Deploy:
venv/Scripts/python.exe scripts/sync_r2.py --target portfolio(fromD:\GitHub\global_agent). Additive sync ofR2_MIRROR-> R2 bucketassets-eriknorris-com. Size-matched files are skipped; nothing is pruned. RequireErrors: 0in the printed summary (the exit code lies); if the fresh PDF shows as Skipped, re-run with--force.- Retired:
scripts/fix_resume_r2.py(now inscripts/_archive/). Do not use it.
- Retired:
- Live URL:
https://assets.eriknorris.com/resume/Erik_Norris_Resume_Current.pdf. Verify withcurl -sI: require HTTP 200 and aContent-Lengthequal to the staging file’s byte size. - Legacy Vanity URL (
resume.eriknorris.com): 302s to the HTML pagehttps://eriknorris.com/resume(verified 2026-06-12), NOT to a PDF. Never use it to verify a deploy — checking the redirect instead of the asset is how a stale live PDF went unnoticed for ~3 months. - Orchestration: The
/update-resumeskill (global_agent/.agent/skills/update-resume/SKILL.md) runs the full sequence: synthesis -> LGTM gate -> generate -> deploy -> live byte-parity check.