Skip to content

feat(hooks/atomic): cross-repo EF pillar-classification enforcement (Cure 4b — companion to dojo-os PR #2381) #31

Description

@lapc506

Resumen (ES)

Hoy (2026-05-28) en dojo-os aterrizamos PR #2381 con un patrón de 4 curas de defensa-en-profundidad contra una deriva real: agentes (y humanos) clasifican Edge Functions por la dependencia externa que tocan (Stripe → ¿Launchpad?) en vez de por su propósito (per-Path SKU → Pathways). El caso fundador fue stripe-create-path-checkout-session: una EF de Pathways (origen DOJ-4002) que un agente etiquetó como "Launchpad/Stripe EF" porque vio Stripe en el código.

Las 4 curas en dojo-os:

  1. Cura 1 — Ownership explícito: docs/repo-health/edge-function-classification.md lista cada EF con su pillar canónico y ticket de origen.
  2. Cura 2 — Clasificación activa: .claude/scripts/classify-ef-pillar.sh clasifica por header ((DOJ-NNNN)), no por dependencia.
  3. Cura 3 — Regla de agente: sección "Pillar Classification" en CLAUDE.md + memoria por-sesión feedback_pillar_by_purpose_not_dependency.md.
  4. Cura 4a — Hook a nivel repo: .claude/hooks/pre-write-ef-pillar-header.sh (PreToolUse) bloquea EFs nuevas sin (DOJ-NNNN) en las primeras líneas.

Lo que falta — Cura 4b: defensa cross-repo. Otros repos que ya alojan o eventualmente alojarán Edge Functions o código atribuido por pillar (dojo-academy, internal-team-trainings, civic-tech, etc.) no tienen el guardrail. Si cualquier repo futuro crea código pillar-attributed sin la convención, la misma deriva recurre.

English summary

The drift: classify-by-dependency vs classify-by-purpose. dojo-os PR #2381 (today) shipped Cures 1–4a as a repo-local defense. Cure 4b lifts the hook into make-no-mistakes-toolkit so any repo using the toolkit can opt in via config, generalizing the rule beyond DojoCodingLabs (org-agnostic ticket-prefix knob).


Agent Layer

Scope

Add a toolkit-level PreToolUse hook (natural home: hooks/atomic/, parallel to the existing pre-atomic.sh / post-atomic-drift.sh pattern from the DOJ-4064 atomic-drift-thesis work).

Detection

  • Trigger: Write tool calls to a path matching the configured EF folder pattern (default: supabase/functions/*/index.ts).
  • Rule: first 25 lines of the file content must contain a Linear ticket reference matching the configured prefix regex (default: [A-Z]{2,4}-[0-9]+).
  • Generalization: do not hardcode DOJ-. The toolkit is org-agnostic; encode the prefix as a config knob so other Linear workspaces (and other ticket systems with similar shapes) can adopt.

Enforcement output

  • Exit 1 with structured stderr guidance:
    • Why this matters (drift thesis link)
    • How to fix (add (TICKET-NNNN) to the EF header, pointing to the origin ticket — not the dependency)
    • Pointer to the repo's local edge-function-classification.md (if present)
  • The hook MUST be a no-op when the rule is disabled in config (default: disabled to avoid breaking existing toolkit consumers).

Configurability

Per-repo opt-in via a new config file hooks/atomic/edge-function-pillar-rules.json (shape parallel to the existing .atomic-design-rules.json consumed by atomic-design-toolkit):

{
  "enabled": false,
  "edge_function_paths": ["supabase/functions/*/index.ts"],
  "ticket_prefix_regex": "[A-Z]{2,4}-[0-9]+",
  "header_scan_lines": 25,
  "classification_doc_path": "docs/repo-health/edge-function-classification.md"
}

Repos adopt by:

  1. Copying the config file into their repo root (or .claude/).
  2. Setting enabled: true.
  3. Tuning edge_function_paths (some repos use AWS Lambda / Cloudflare Workers layouts).
  4. Tuning ticket_prefix_regex for their workspace.

Optional companion: bootstrap slash command

/make-no-mistakes:ef-pillar-init — parallel to the existing v1.14 atomic-rules-init pattern. Scaffolds:

  • hooks/atomic/edge-function-pillar-rules.json
  • A starter docs/repo-health/edge-function-classification.md template
  • Settings entry to register the hook

Acceptance Criteria

  • Hook implemented at hooks/atomic/pre-write-ef-pillar-header.sh (matches dojo-os semantics + adds ticket-prefix config knob)
  • Config schema at hooks/atomic/edge-function-pillar-rules.json (shape parallel to .atomic-design-rules.json)
  • Optional slash command /make-no-mistakes:ef-pillar-init to bootstrap adoption in a new repo
  • Documentation at references/edge-function-pillar-classification.md (parallel to references/atomic-design-hooks-setup.md from the v1.2.0 atomic-design-toolkit precedent)
  • Unit tests in hooks/atomic/__tests__/ covering: (a) EF with valid ticket header → pass, (b) EF missing ticket → block + exit 1, (c) non-EF path → no-op, (d) rule disabled in config → no-op
  • CHANGELOG entry + README mention
  • Backward-compatible: default enabled: false. Existing toolkit consumers (dojo-os, atomic-design-toolkit, etc.) opt in explicitly. No silent breakage.

Tradeoffs (honest)

  • Cost: ~150–250 LOC hook + config + docs, plus ~50–80 LOC tests.
  • Benefit: prevents dependency-vs-purpose drift across all repos using the toolkit. Same defense, one source of truth.
  • Risk — generalization: Edge Function is not a universal concept. AWS Lambda layouts, Cloudflare Workers, Vercel functions, etc. differ. Mitigation: the edge_function_paths config knob lets each repo declare its own EF layout. The rule's essence (a ticket-of-origin in the header of pillar-attributed code) is layout-agnostic.
  • Risk — false positives: a legitimate refactor that moves code between EFs without changing ownership might be blocked. Mitigation: the rule only fires on Write to NEW files (existing files are not re-scanned). Edits to pre-existing EFs without ticket headers are out of scope (handled by a separate audit, not this hook).
  • Maintenance: regex pattern + ticket-prefix knob need clear docs. The reference doc must explain how to configure for non-DojoCodingLabs adopters.

Context Files


Created by Claude Code on behalf of @lapc506

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions