feat(rules): migrate /rules/ to Astro page with RulesInteractive island

Add the migrated chapter page (task 14). One island owns the five
interactions (language toggle, stage tabs, skill tabs, copy prompt,
scroll progress) because they share the active-language state. Bilingual
copy, stages, skills, and prompts live in src/content/rules/ JSON files
imported by the page. Script is plain JS with is:inline so Vite compiles
no TS chunk for it (avoids the inline-script + Astro/Vite 6 tsconfig
null-byte bug). Legacy colour/breakpoint/font-size values are kept and
tagged token-gap so the gate stays green without a silent redesign of
rules/styles.css.

Done-when:
- dist/rules/index.html server-renders the same DOM and classes as
  rules/index.html
- snapshot-route.mjs diff vs .agents/snapshots/rules.txt is empty
- pnpm run verify returns 0; audit-ui passes
- bilingual EN/PT toggle on topbar (data-lang=) renders all strings
  from src/content/rules/copy.json; <html lang> follows
- responsive behaviour identical at 600/900/2200px
- no external runtime dependency

Handoff:
- src/content/config.ts unchanged; the rules data is not in a typed
  Zod collection because config.ts is owned by content-i18n-migrator.
  Add a rules collection there when the collection layer is extended.
- verify.mjs reads rulesHtml/rulesJs/rulesCss from the OLD source files
  in rules/, which are still on disk and untouched. New rulesHtml-style
  assertions should target dist/rules/index.html once the build is the
  published source of truth; the verification-engineer owns that move.
- 30 token-gap markers in RulesInteractive.astro; design-system-keeper
  may migrate them to named tokens in a follow-up.
This commit is contained in:
Marcos Paulo
2026-09-05 17:02:17 +00:00
parent 107e429fb9
commit 134bd37ec4
6 changed files with 1522 additions and 0 deletions
+128
View File
@@ -0,0 +1,128 @@
{
"en": {
"back": "field guide",
"navPipeline": "Pipeline",
"navSkills": "Skills",
"navExamples": "Examples",
"stageContext": "CONTEXT",
"stageReview": "REVIEW",
"heroEyebrow": "A real repository case study",
"heroTitle": "Rules that<br />survive the <em>prompt.</em>",
"heroText": "Prompts ask for behavior. Repositories preserve it. The interview project combines written context, reusable skills, executable checks, commit hooks, and independent review so the rule is still present when the conversation is gone.",
"heroAside": "8 skills · 3 agents · 4 enforcement layers",
"thesisLabel": "THE SHORT VERSION",
"thesis": "A prompt is advice for one run. A repository rule is reusable context plus an executable boundary.",
"pipelineLabel": "Enforcement pipeline",
"pipelineMeta": "select a checkpoint",
"pipelineEyebrow": "From intent to evidence",
"pipelineTitle": "Five places<br />a rule can <em>hold.</em>",
"pipelineText": "Not every rule belongs in a hook. Put guidance where an agent can discover it, deterministic policy in a command, cheap checks at commit time, and independent judgment at review.",
"skillsLabel": "Project-local skills",
"skillsMeta": "procedures born from repeated friction",
"skillsEyebrow": "Small instruction packages",
"skillsTitle": "Teach the trap.<br />Name the <em>trigger.</em>",
"skillsText": "These skills are not downloaded magic. They are repository-specific procedures under <code>.agents/skills/</code>, distilled from mistakes, commands, and architectural decisions that kept recurring.",
"skillGate": "prove green is real",
"skillParallel": "worktree per task",
"skillRepo": "query before crawling",
"skillDebt": "separate line of work",
"skillWriter": "repeat twice, encode once",
"skillArea": "stack-specific traps",
"examplesLabel": "Concrete examples",
"examplesMeta": "open the source, then adapt",
"ratchetLabel": "CLI RATCHET",
"ratchetTitle": "Debt may go down.<br />Never silently up.",
"hookTitle": "Fast checks before history.",
"commitLabel": "COMMIT MESSAGE",
"commitTitle": "Intent has a grammar.",
"reviewLabel": "INDEPENDENT REVIEW",
"reviewTitle": "A second reader checks intent.",
"readChecker": "Read the checker →",
"readHook": "Read the hook →",
"readCommit": "Read commitlint config →",
"readReview": "Read review policy →",
"copyLabel": "COPY / ADAPT",
"copyTitle": "Ask your agent to map the enforcement stack.",
"copyText": "Use this in the interview repository or adapt the path names to another project.",
"copyButton": "COPY PROMPT",
"deeperLabel": "GO DEEPER",
"deeperTitle": "Read the implementation, not just this summary.",
"deepContext": "Repository context",
"deepSkills": "Skill catalog",
"deepAgents": "Specialist agents",
"deepPolicy": "Staged-file policy",
"stageOpenSource": "OPEN SOURCE ↗",
"stageOpenSourcePt": "ABRIR FONTE ↗",
"skillReadSkill": "READ SKILL ↗",
"skillReadSkillPt": "LER SKILL ↗",
"skillTriggerLabel": "TRIGGER",
"skillTriggerLabelPt": "GATILHO",
"copyStatus": "Prompt copied.",
"copyStatusPt": "Prompt copiado.",
"copyFallback": "Select the text manually.",
"copyFallbackPt": "Selecione o texto manualmente."
},
"pt": {
"back": "guia de campo",
"navPipeline": "Pipeline",
"navSkills": "Skills",
"navExamples": "Exemplos",
"stageContext": "CONTEXTO",
"stageReview": "REVISÃO",
"heroEyebrow": "Um estudo de caso de repositório real",
"heroTitle": "Regras que<br />sobrevivem ao <em>prompt.</em>",
"heroText": "Prompts pedem comportamento. Repositórios o preservam. O projeto interview combina contexto escrito, skills reutilizáveis, verificações executáveis, hooks de commit e revisão independente para que a regra continue existindo quando a conversa terminar.",
"heroAside": "8 skills · 3 agentes · 4 camadas de enforcement",
"thesisLabel": "A VERSÃO CURTA",
"thesis": "Um prompt orienta uma execução. Uma regra de repositório é contexto reutilizável mais uma fronteira executável.",
"pipelineLabel": "Pipeline de enforcement",
"pipelineMeta": "selecione um checkpoint",
"pipelineEyebrow": "Da intenção à evidência",
"pipelineTitle": "Cinco lugares<br />onde a regra <em>segura.</em>",
"pipelineText": "Nem toda regra pertence a um hook. Coloque orientação onde o agente descobre, política determinística em um comando, checks baratos no commit e julgamento independente na revisão.",
"skillsLabel": "Skills locais do projeto",
"skillsMeta": "procedimentos nascidos de atrito repetido",
"skillsEyebrow": "Pequenos pacotes de instrução",
"skillsTitle": "Ensine a armadilha.<br />Nomeie o <em>gatilho.</em>",
"skillsText": "Estas skills não são mágica baixada. São procedimentos específicos do repositório em <code>.agents/skills/</code>, extraídos de erros, comandos e decisões arquiteturais recorrentes.",
"skillGate": "prove que o verde é real",
"skillParallel": "um worktree por tarefa",
"skillRepo": "consulte antes de explorar",
"skillDebt": "linha de trabalho separada",
"skillWriter": "repita duas vezes, codifique uma",
"skillArea": "armadilhas da stack",
"examplesLabel": "Exemplos concretos",
"examplesMeta": "abra a fonte, depois adapte",
"ratchetLabel": "CATRACA CLI",
"ratchetTitle": "A dívida pode cair.<br />Nunca subir em silêncio.",
"hookTitle": "Checks rápidos antes do histórico.",
"commitLabel": "MENSAGEM DE COMMIT",
"commitTitle": "A intenção tem gramática.",
"reviewLabel": "REVISÃO INDEPENDENTE",
"reviewTitle": "Um segundo leitor verifica a intenção.",
"readChecker": "Ler o checker →",
"readHook": "Ler o hook →",
"readCommit": "Ler config do commitlint →",
"readReview": "Ler política de revisão →",
"copyLabel": "COPIAR / ADAPTAR",
"copyTitle": "Peça ao agente para mapear o enforcement.",
"copyText": "Use isto no repositório interview ou adapte os caminhos para outro projeto.",
"copyButton": "COPIAR PROMPT",
"deeperLabel": "APROFUNDE",
"deeperTitle": "Leia a implementação, não apenas este resumo.",
"deepContext": "Contexto do repositório",
"deepSkills": "Catálogo de skills",
"deepAgents": "Agentes especialistas",
"deepPolicy": "Política dos arquivos staged",
"stageOpenSource": "ABRIR FONTE ↗",
"stageOpenSourcePt": "ABRIR FONTE ↗",
"skillReadSkill": "LER SKILL ↗",
"skillReadSkillPt": "LER SKILL ↗",
"skillTriggerLabel": "TRIGGER",
"skillTriggerLabelPt": "GATILHO",
"copyStatus": "Prompt copied.",
"copyStatusPt": "Prompt copiado.",
"copyFallback": "Select the text manually.",
"copyFallbackPt": "Selecione o texto manualmente."
}
}
+4
View File
@@ -0,0 +1,4 @@
{
"en": "Inspect this repository's enforcement stack before changing code.\n\n1. Read AGENTS.md.\n2. List .agents/skills and select only skills whose descriptions match the task.\n3. Query .agents/db/commands.json and .agents/db/known-issues.json.\n4. Explain what is guidance versus mechanically enforced by scripts, Husky, commitlint, CI, and PR review.\n5. For each relevant rule, cite the source path and the command that proves it.\n6. Identify gaps where documentation claims enforcement but no executable check exists.\n\nDo not modify files. Return a compact map: rule → source → enforcement point → verification command → remaining gap.",
"pt": "Inspecione a stack de enforcement deste repositório antes de alterar código.\n\n1. Leia AGENTS.md.\n2. Liste .agents/skills e selecione apenas skills cuja descrição corresponda à tarefa.\n3. Consulte .agents/db/commands.json e .agents/db/known-issues.json.\n4. Explique o que é orientação e o que é imposto mecanicamente por scripts, Husky, commitlint, CI e revisão de PR.\n5. Para cada regra relevante, cite o caminho fonte e o comando que a comprova.\n6. Identifique lacunas onde a documentação promete enforcement sem check executável.\n\nNão modifique arquivos. Retorne um mapa compacto: regra → fonte → ponto de enforcement → comando de verificação → lacuna restante."
}
+80
View File
@@ -0,0 +1,80 @@
{
"gate": {
"name": "gate-discipline",
"trigger": {
"en": "Before commit, PR, or merge.",
"pt": "Antes de commit, PR ou merge."
},
"lesson": {
"en": "Run canonical gates separately, inspect exit codes, distrust convenient cache hits, and prove generated code is current.",
"pt": "Rode gates separadamente, leia exit codes, desconfie de cache conveniente e prove que código gerado está atual."
},
"example": "pnpm lint; echo \"lint=$?\"",
"path": ".agents/skills/gate-discipline/SKILL.md"
},
"parallel": {
"name": "parallel-agents",
"trigger": {
"en": "When independent tasks can run concurrently.",
"pt": "Quando tarefas independentes podem rodar juntas."
},
"lesson": {
"en": "One worktree and file ownership per task; prior-art scout first, verifier last, merge sequentially.",
"pt": "Um worktree e ownership por tarefa; prior-art scout primeiro, verifier por último, merges sequenciais."
},
"example": "git worktree add .claude/worktrees/task -b feat/task",
"path": ".agents/skills/parallel-agents/SKILL.md"
},
"repo": {
"name": "repo-db",
"trigger": {
"en": "At task start and before debugging.",
"pt": "No início da tarefa e antes de diagnosticar."
},
"lesson": {
"en": "Query the repo map, canonical commands, and known-issues ledger before crawling thousands of files.",
"pt": "Consulte mapa, comandos canônicos e known-issues antes de vasculhar milhares de arquivos."
},
"example": "jq -r '.verify[]' .agents/db/commands.json",
"path": ".agents/skills/repo-db/SKILL.md"
},
"debt": {
"name": "tech-debt",
"trigger": {
"en": "When unrelated debt appears mid-task.",
"pt": "Quando dívida não relacionada aparece no meio."
},
"lesson": {
"en": "Do not smuggle cleanup into a feature. Record it, give it its own branch, and finish the underlying condition.",
"pt": "Não esconda limpeza em uma feature. Registre, dê uma branch própria e finalize a condição original."
},
"example": "feature diff ≠ debt cleanup",
"path": ".agents/skills/tech-debt/SKILL.md"
},
"writer": {
"name": "skill-writer",
"trigger": {
"en": "When a workflow is explained twice.",
"pt": "Quando um fluxo é explicado duas vezes."
},
"lesson": {
"en": "Procedures become skills; isolated facts become known-issues entries. Keep the body short and the trigger discriminating.",
"pt": "Procedimentos viram skills; fatos isolados viram known-issues. Corpo curto e gatilho discriminante."
},
"example": ".agents/skills/<name>/SKILL.md",
"path": ".agents/skills/skill-writer/SKILL.md"
},
"area": {
"name": "frontend / go-api",
"trigger": {
"en": "When changing the matching subsystem.",
"pt": "Ao alterar o subsistema correspondente."
},
"lesson": {
"en": "Encode version-specific traps close to the work: Next/React/AntD boundaries, Connect APIs, sqlc types, migrations, and code generation.",
"pt": "Codifique armadilhas de versão perto do trabalho: Next/React/AntD, APIs Connect, tipos sqlc, migrations e codegen."
},
"example": "area → local skill → canonical checks",
"path": ".agents/skills/"
}
}
+72
View File
@@ -0,0 +1,72 @@
{
"context": {
"number": "01",
"file": "AGENTS.md",
"title": {
"en": "Give every agent the same map",
"pt": "Dê o mesmo mapa a cada agente"
},
"text": {
"en": "Stack, commands, product boundaries, and known traps load before implementation. This is discoverable guidance—not an executable guarantee.",
"pt": "Stack, comandos, limites do produto e armadilhas conhecidas carregam antes da implementação. É orientação descobrível — não garantia executável."
},
"code": "Read AGENTS.md\n→ query .agents/db\n→ load area skill",
"link": "https://git.marcospaulo.dev.br/netcracker/interview/src/branch/main/AGENTS.md"
},
"skills": {
"number": "02",
"file": ".agents/skills/",
"title": {
"en": "Load only the relevant procedure",
"pt": "Carregue apenas o procedimento relevante"
},
"text": {
"en": "Frontend, Go API, gate discipline, parallel agents, repo databases, issues, skill writing, and tech debt each have a narrow trigger.",
"pt": "Frontend, API Go, disciplina de gates, agentes paralelos, bancos do repo, issues, escrita de skills e dívida técnica têm gatilhos estreitos."
},
"code": "request + description\n→ matching SKILL.md\n→ focused workflow",
"link": "https://git.marcospaulo.dev.br/netcracker/interview/src/branch/main/.agents/skills"
},
"cli": {
"number": "03",
"file": "scripts/check-ui-contract.mjs",
"title": {
"en": "Turn measurable policy into a ratchet",
"pt": "Transforme política mensurável em catraca"
},
"text": {
"en": "The UI checker counts known violations and fails only when a count rises. Existing debt can be reduced, but a new change cannot quietly increase it.",
"pt": "O checker de UI conta violações conhecidas e falha quando o total sobe. Dívida existente pode cair, mas uma mudança não pode aumentá-la em silêncio."
},
"code": "pnpm check:ui\ncurrent ≤ baseline → pass\ncurrent > baseline → fail",
"link": "https://git.marcospaulo.dev.br/netcracker/interview/src/branch/main/scripts/check-ui-contract.mjs"
},
"commit": {
"number": "04",
"file": ".husky/pre-commit",
"title": {
"en": "Block cheap mistakes at the boundary",
"pt": "Bloqueie erros baratos na fronteira"
},
"text": {
"en": "Husky runs lint-staged plus the whole-tree UI ratchet. Commitlint separately enforces Conventional Commit messages.",
"pt": "Husky executa lint-staged mais a catraca de UI da árvore inteira. Commitlint aplica Conventional Commits separadamente."
},
"code": "git commit\n├─ lint-staged\n├─ check:ui\n└─ commitlint",
"link": "https://git.marcospaulo.dev.br/netcracker/interview/src/branch/main/.husky/pre-commit"
},
"review": {
"number": "05",
"file": ".pr-review.json",
"title": {
"en": "Reserve judgment for the PR",
"pt": "Reserve julgamento para o PR"
},
"text": {
"en": "An AI reviewer checks security, generated-code discipline, test quality, scope, and repository-specific traps. A verifier independently reruns gates before merge.",
"pt": "Um revisor de IA verifica segurança, código gerado, qualidade dos testes, escopo e armadilhas do repositório. Um verifier roda os gates novamente antes do merge."
},
"code": "diff + house rules + prior review\n→ findings + risks\n→ human merge decision",
"link": "https://git.marcospaulo.dev.br/netcracker/interview/src/branch/main/.pr-review.json"
}
}