Corrective Action: HubSpot Beginners Course — Silent System Failures Across Full Education Stack

Corrective Action: HubSpot Beginners Course — Silent System Failures Across Full Education Stack

Date: March 12, 2026 Category: Verification Failure + Data Format Mismatch (compound) Impact: Entire HubSpot education system non-functional at the integration layer. Course progress, quiz completion, certificate issuance, and pipeline tracking all fail silently. Visitor-facing content has enforcement violations and critical dead ends. Zero relationship capture across 90-minute learning journey. Resolution Time: Identified during multi-agent audit. Repair pending.


Incident

What Happened

A multi-agent review of the HubSpot Beginners course (/learn/course/hubspot-beginners) revealed that the entire HubSpot integration layer is broken. Course progress tracking, quiz completion, certificate issuance, and pipeline stage transitions all fail silently because the API layer sends wrong data types (string stage names instead of numeric IDs), references non-existent HubSpot properties (4 certificate properties on Contact), uses a deprecated object (Signal), and sets read-only system properties (hs_object_id). The localStorage fallback for unauthenticated users masks these failures — the course appears to work for anonymous visitors, but no data persists to HubSpot for any user.

Simultaneously, the course content contains a critical dead-end page (lesson 6-2 "Your Next Steps" lists 8+ resources as text with zero clickable links), forbidden language on the live site ("quick wins", "plan phased improvements"), a visible rendering bug (duration shows blank due to course.duration vs totalDuration property mismatch), and zero email capture across the entire 90-minute learning journey.

Timeline

Event Detail
~Jan 2026 Course pages and APIs built. Education Hub launched.
Feb 16, 2026 Signal object deprecated (migrated to Interest). quiz/complete.ts still calls createSignal.
Mar 12, 2026 Multi-agent audit discovers 8 critical, 10 major, 12 minor issues.
Mar 12, 2026 LMS Manager agent created to own education system integrity. CAR drafted.

Root Cause

Primary: Speculative Integration — Code Written Against Assumed HubSpot Schema, Never Verified

The education system APIs were built with assumptions about the HubSpot portal that were never validated:

  1. Pipeline stages as stringscourse-progress.ts passes 'Enrolled', 'In Progress', 'Passed' to hs_pipeline_stage. HubSpot requires numeric stage IDs (e.g., '1251442051'). This is the same pattern that was correctly handled in other parts of the codebase (e.g., theater-seed-deployer.ts uses proper stage IDs). The education APIs simply never adopted the correct pattern.

  2. Non-existent contact properties — The certificate system writes to vf_certificates_earned, vf_certificate_count, vf_last_certificate_earned, and vf_last_certificate_date on Contact objects. None of these properties exist in HubSpot (verified against contact.json exported 2026-03-02). They were defined in TypeScript types but never created in the portal.

  3. Enum value mismatchcourse-progress.ts filters courses by course_content_type === 'Learning Course'. The HubSpot property index shows the valid enum values are snake_case (trap_assessment, framework_education, bootcamp, capability_building). 'Learning Course' may not be a valid value, which would cause every course lookup to return empty — triggering duplicate Course creation on every visit.

  4. Unverified association typehubspotClient.associateCourseToContact uses hardcoded associationTypeId: 182 with only a comment as documentation. This ID does not appear in associations.json. If wrong, courses are created but never linked to contacts.

Secondary: Silent Error Handling Masks Failures

Every HubSpot API call in the education system is wrapped in try/catch blocks that return fallback responses instead of surfacing errors:

  • course-progress.ts returns { lessonProgress: [] } when HubSpot calls fail
  • certificate.ts returns null on failure, and the calling code silently continues
  • useCourseProgress.ts falls back to localStorage on any API error

This means: the system appears functional even when every HubSpot operation fails. Anonymous users get localStorage progress. Authenticated users get the same localStorage fallback after silent API failures. No one sees an error. No data reaches HubSpot.

Tertiary: Content Published Without Enforcement Scanning

Lesson 6-2 contains forbidden language ("quick wins" at line 167, "Plan phased improvements" at line 174) that should have been caught by enforcement scanning before the content shipped. Additionally, the page lists 8 resources (Education Hub pages, Record Builder, Theater, etc.) as text-only cards with zero <a> tags — creating a dead end at the course's most critical engagement moment.

Category Breakdown

Category Pattern Specific Instance
Data Format Mismatch Wrong value type sent to API Pipeline stage strings instead of IDs
Missing Configuration Properties defined in TypeScript but never created in HubSpot 4 certificate properties, potentially 8 course properties
Verification Failure Code assumed to work, never tested against live portal All 4 API routes (course-progress, quiz/complete, quiz/history, certificate/issue)
API Behavior Assumption Using deprecated object without migration quiz/complete.ts calls createSignal (deprecated Feb 16)
API Behavior Assumption Setting read-only system property quiz/complete.ts sets hs_object_id
Content Integrity Published content with enforcement violations Forbidden language + dead-end links in lesson 6-2

Fix Applied

Immediate Resolution

LMS Manager agent created (.claude/agents/lms-manager.md) with:

  • Full Known Issues Registry documenting all 30 findings
  • 6 validation check categories for pre-deployment and ongoing monitoring
  • Coordination model with concierge-learner, audit, lookout, q, and squire

Concierge-learner agent updated:

  • Lesson count corrected from 18 to 20
  • Status changed from "COMPLETE" to "NEEDS REPAIR"

Code/Configuration Changes Required (Not Yet Applied)

Priority File Required Change
CRITICAL src/pages/learn/course/hubspot-beginners.astro:57 Change course.duration to course.totalDuration
CRITICAL src/pages/api/course-progress.ts:163,197-201 Replace string stage names with numeric pipeline stage IDs from HubSpot
CRITICAL src/pages/api/course-progress.ts:21 Verify 'Learning Course' is valid enum for course_content_type or fix to match schema
CRITICAL HubSpot portal Create 4 certificate properties on Contact: vf_certificates_earned, vf_certificate_count, vf_last_certificate_earned, vf_last_certificate_date
CRITICAL src/pages/api/quiz/complete.ts:66 Remove hs_object_id from Course creation payload
CRITICAL src/pages/api/quiz/complete.ts:108 Replace createSignal with createInterest (Signal deprecated Feb 16) or wrap in try/catch
CRITICAL src/pages/learn/course/hubspot-beginners/6-2-next-steps.astro Add links to all 8 resource mentions; remove "quick wins" and "plan phased improvements"
CRITICAL Course journey Add email capture mechanism (newsletter, registration prompt, or similar)
MAJOR src/pages/api/quiz/complete.ts:188 Change 'all_unified_views' to 'multi_quiz' for Unified Views Specialist cert lookup
MAJOR skills/hubspot/property-index/course.json Add pipeline stages with numeric IDs; verify course_content_type enum includes Learning Course
MAJOR skills/hubspot/property-index/associations.json Verify and document Course ↔ Contact association type ID

Verification Plan

Each fix must be verified, not assumed:

  1. Pipeline stages: Query HubSpot for Course pipelines, get actual stage IDs, update code and property index
  2. Certificate properties: Create properties in HubSpot, update property index, verify updateContact succeeds
  3. Enum values: Query HubSpot for course_content_type enum, verify or update the value used in code
  4. Association type: Query HubSpot for Course ↔ Contact association types, verify or update the hardcoded ID
  5. Signal → Interest: Verify Interest object accepts the same data shape, update the method call
  6. Duration bug: After fix, fetch live page and confirm duration displays
  7. Lesson 6-2: After adding links, verify every href resolves to a live page

Prevention Measures

Rules to Add

Layer File Rule
Critical Lessons memory/MEMORY.md "Every HubSpot API integration MUST be verified against the live portal before shipping. Silent try/catch fallbacks mask failures for months. Verify: (1) properties exist, (2) enum values match, (3) pipeline stage IDs are numeric, (4) association type IDs are correct. The education system shipped with ALL four wrong."
Self-Correction skills/enforcement/vf-self-correction.md New Architecture Trigger: "Writing HubSpot pipeline stage values as human-readable strings" → "HubSpot requires numeric stage IDs. Check property-index for the pipeline, use the ID."
Self-Correction skills/enforcement/vf-self-correction.md New Verification Trigger: "Building an API that catches HubSpot errors and returns fallback data without logging" → "Silent fallbacks mask failures. Log errors server-side. Return specific error codes so the frontend can distinguish 'no progress yet' from 'system failure'."
Content Enforcement Enforcement scanning process Every lesson page must pass forbidden language grep before deployment. LMS Manager Check 5 codifies this.

Detection Triggers

  1. Pipeline stage strings in any new API code — If code writes hs_pipeline_stage: 'SomeName' instead of hs_pipeline_stage: '12345678', the LMS Manager's Check 2 catches it.

  2. HubSpot property references without property-index verification — Any new code that writes to HubSpot properties should cross-reference the property index first.

  3. Silent error fallbacks — APIs that catch HubSpot errors and return success-shaped responses should at minimum log the error server-side.

  4. Deprecated object usagecreateSignal should be grep-scanned during any code audit. Signal (2-53177182) was deprecated Feb 16, 2026.


Lessons

The education system shipped with a visually complete frontend and a fundamentally broken backend. The localStorage fallback — designed as a graceful degradation for unauthenticated users — accidentally became the ONLY functional path, masking total HubSpot integration failure for every user. This is the compound failure: silent error handling + speculative schema assumptions + no integration verification = a system that looks right but stores nothing.

The generalized principle: any system with a fallback path will silently fail for months if the primary path is never verified. The fallback becomes the de facto behavior, and no one notices the primary path is broken until someone audits the data layer.

This reinforces the existing verification rules in vf-self-correction.md ("VERIFY. Run the command, read the output, confirm. Then claim.") but extends them to a new category: integration verification. Reading TypeScript types is not verifying HubSpot properties exist. Writing try/catch is not verifying the API call succeeds. The verification must reach the actual destination system.


Related Incidents

Date Incident Pattern
Feb 16, 2026 Signal object deprecated, migrated to Interest Object lifecycle — quiz code never updated
Mar 2, 2026 Paragon document invisible (wrong listing_content_type) Enum value mismatch — exact same class of bug
Mar 10, 2026 Paragon portal showing 40% of data Silent data drift — exact same masking pattern
Mar 11, 2026 Sponsor API creating Deals without Contact associations Missing association — exact same pattern as Course ↔ Contact

This is the fourth instance of "HubSpot writes that silently fail due to wrong values or missing associations." The pattern is systemic, not isolated.