website-htmx-rustelo/.ontoref/ontology/purpose.ncl
Jesús Pérez 3ccd15a14b init repo
2026-07-10 03:33:46 +01:00

146 lines
9 KiB
Text

let p = import "purpose-defaults.ncl" in
p.make_purpose {
declaration = {
id = "website-htmx-rustelo-purpose",
name = "Website (HTMX/Rustelo) Purpose",
pole = 'Yin,
statement = "This site exists to publish bilingual EN/ES technical content through a Rustelo HTMX implementation, giving both language audiences the same depth of material with crawlable, server-rendered pages.",
elaboration = "The bilingual constraint is not cosmetic — it commits the site to closing the quality-technical-content gap for Spanish-speaking developers. The HTMX rendering profile is chosen for simplicity and crawlability; Leptos hydration remains available per-route. The purpose is fulfilled when both audiences (EN and ES) reach parity in content and in rendered quality, and the implementation never forks the Rustelo framework to get there.",
primary_audience = ['Developer, 'EndUser],
anti_purpose = "This site is not a marketing funnel, not a general-opinion blog, and not a lead-capture portfolio. It is not intended to maximize traffic at the cost of content depth, and it must never ship a route in one language only.",
horizon = 'Ongoing,
},
publication_intent = {
id = "website-htmx-rustelo-publication-intent",
name = "Publication Intent",
description = "Publishing means deploying to production where both EN and ES audiences can reach every launched content section. Publication requires bilingual completeness on launched sections, hydration parity for any hydration-opted route, and verified purpose-aligned SEO criteria.",
channels = ['PublishedSite, 'RSSFeed],
readiness_gate = "purpose-gate",
trigger_condition = "content-coverage is at full-parity, rendering-mode hydration-opted routes pass validate-hydration, and publication-readiness has reached production-ready. validate-purpose-alignment passes all Hard criteria.",
anti_patterns = [
"Launching a content section with only one language populated",
"Publishing while publication-readiness is still pre-production",
"Publishing with known hydration mismatches on hydration-opted routes",
"Publishing content that serves no declared audience (Developer or EndUser)",
],
},
content_objectives = [
{
id = "bilingual-content",
name = "Bilingual Technical Content",
description = "Technical articles and pages published in both English and Spanish covering Rust, web architecture, and infrastructure. Bilingual parity is non-negotiable — every EN item has its ES equivalent and vice versa.",
target_audience = ['Developer, 'EndUser],
content_kinds = ["blog", "pages"],
purpose_alignment_note = "Primary vehicle of the purpose: closes the quality-technical-content gap for Spanish-speaking developers on the same stack.",
seo_intent = 'Organic,
horizon = 'Ongoing,
active = true,
},
{
id = "project-showcase",
name = "Project Showcase",
description = "Bilingual presentation of technical projects with architecture, real status, and goals. Published status must reflect reality, not the desired state.",
target_audience = ['Developer, 'EndUser],
content_kinds = ["projects"],
purpose_alignment_note = "Demonstrates technical work with depth and honesty — reinforces the site as a knowledge platform, not marketing.",
seo_intent = 'Reference,
horizon = 'Months,
active = true,
},
],
validation_criteria = [
{
id = "bilingual-completeness",
name = "Bilingual Content Completeness Before Publication",
description = "No menu-visible section may publish if EN and ES counts diverge. Every menu-enabled route must have corresponding content in both language directories.",
check_hint = "Run the validate-content mode. The diff-routes and count-content steps must report zero asymmetries for menu-enabled routes.",
severity = 'Hard,
applies_to = ["bilingual-content", "project-showcase"],
},
{
id = "purpose-audience-relevance",
name = "Content Serves Declared Audience",
description = "Every published content item must classify as serving the 'Developer or 'EndUser audience. Content serving no declared audience is a purpose-alignment violation.",
check_hint = "Review each content item's front-matter for audience markers; flag items with no audience classification. Run validate-purpose-alignment.",
severity = 'Hard,
applies_to = ["bilingual-content", "project-showcase"],
},
{
id = "no-publish-during-hydration-instability",
name = "No Publication During Hydration Instability",
description = "The site must not deploy to production while any hydration-opted route fails hydration parity — rendering-mode must not regress below its current htmx-ssr baseline for served routes.",
check_hint = "Run validate-hydration: no empty HashMap in *Client components, SsrTranslator used, FTL registry populated for hydration-opted routes.",
severity = 'Hard,
applies_to = ["bilingual-content", "project-showcase"],
},
],
seo_criteria = [
{
id = "bilingual-canonical-urls",
name = "Bilingual Canonical URLs with hreflang",
description = "Every EN URL must carry <link rel=\"alternate\" hreflang=\"es\"> to its ES equivalent and vice versa. The XML sitemap must include both variants for each page.",
rationale = "Serves the purpose directly: EN and ES audiences must find the same content in their language via organic search. Without hreflang, search engines may index only one variant.",
check_hint = "Audit a rendered blog route's HTML: confirm <link rel=\"alternate\" hreflang=\"es|en\"> in <head>, and that sitemap.xml includes both URLs.",
severity = 'Hard,
applies_to = ["bilingual-content", "project-showcase"],
},
{
id = "structured-data-articles",
name = "Article Structured Data (JSON-LD)",
description = "Technical blog articles must include JSON-LD typed Article or TechArticle: author, datePublished, headline, inLanguage.",
rationale = "Improves prominence for developers searching technical guides — serves the purpose by connecting content to technical audiences through rich results.",
check_hint = "Inspect a rendered article's HTML for <script type=\"application/ld+json\"> with @type Article or TechArticle.",
severity = 'Hard,
applies_to = ["bilingual-content"],
},
{
id = "meta-description-purpose-aligned",
name = "Meta Descriptions Are Accurate and Purpose-Aligned",
description = "Every published page must have a <meta name=\"description\"> describing the real content. No clickbait, no keyword stuffing.",
rationale = "The purpose demands editorial honesty. A misleading meta description contradicts the anti_purpose ('not a marketing funnel').",
check_hint = "Audit meta descriptions of the most-visited pages; verify each matches the real article content, not artificial keywords.",
severity = 'Hard,
applies_to = ["bilingual-content", "project-showcase"],
},
{
id = "core-web-vitals-threshold",
name = "Core Web Vitals Meet Threshold",
description = "Lighthouse performance score >= 90 on mobile for main content pages. LCP < 2.5s, CLS < 0.1.",
rationale = "A technical audience judges quality by performance; the HTMX SSR profile should make this readily achievable. Core Web Vitals are also a ranking factor.",
check_hint = "Run Lighthouse (mobile) for /, and main content routes; verify score >= 90 and LCP/CLS within thresholds.",
severity = 'Soft,
applies_to = ["bilingual-content", "project-showcase"],
},
],
propagation_channels = [
{
id = "published-site",
name = "Production Site",
channel = 'PublishedSite,
description = "Primary distribution channel: HTMX server-rendered pages serving all content kinds in EN and ES, with optional per-route Leptos hydration.",
status = 'Active,
target_audience = ['EndUser, 'Developer],
content_kinds = ["blog", "pages", "projects"],
seo_role = 'Organic,
gate_id = "purpose-gate",
},
{
id = "rss-feed",
name = "RSS Feed",
channel = 'RSSFeed,
description = "RSS feed for blog articles, enabling syndication and subscription-based consumption.",
status = 'Planned,
target_audience = ['Developer, 'EndUser],
content_kinds = ["blog"],
seo_role = 'None,
frequency = "on every new blog post",
},
],
}