Skip to content

feat(code): adopt ponytail's ponytail: marker convention as // sin-debt: <ceiling>, upgrade: <trigger> #177

Description

@Delqhi

Summary

Übernimm ponytail's wichtigste Innovation: die ponytail:-Marker-Konvention (DietrichGebert/ponytail v4.7.0, 20.7k stars, https://github.com/DietrichGebert/ponytail/blob/main/skills/ponytail/SKILL.md:50-53) als sin-debt:-Konvention für SIN-Code. Jeder Shortcut im Code wird mit // sin-debt: <ceiling>, upgrade: <trigger> markiert. Die Marker sind first-class Information und werden von einem neuen cmd/sin-code/debt_cmd.go (analog zu ponytail-debt) gescannt, geledgert, auditiert.

Format:

// sin-debt: <ceiling>, upgrade: <trigger>
// sin-debt: this exists

Beispiele:

// sin-debt: global mutex, upgrade: per-account locks when throughput > 1k req/s
// sin-debt: O(n²) scan, upgrade: switch to map lookup when n > 100
// sin-debt: hand-rolled retry, upgrade: use cenkalti/backoff when context cancellation matters

Motivation

ponytail's ponytail:-Marker-Konvention ist die Innovation des Projekts. Sie löst ein Problem, das jeder kennt, aber niemand systematisch löst: technische Schulden sichtbar und nachverfolgbar machen.

Aus https://github.com/DietrichGebert/ponytail/blob/main/skills/ponytail/SKILL.md:50-53:

Mark intentional simplifications with a ponytail: comment — a shortcut with a known ceiling names the ceiling and the upgrade path in the comment.

Aus https://github.com/DietrichGebert/ponytail/blob/main/skills/ponytail-debt/SKILL.md:1-40:

Every deliberate ponytail shortcut is marked with a ponytail: comment naming its ceiling and upgrade path. This collects them into one ledger so a deferral can't quietly become permanent.

SIN-Code hat aktuell:

  • cmd/sin-code/internal/lessons/ (Closed Learning Loop) – für Tool-Error-Patterns
  • cmd/sin-code/internal/ledger/ (Session Ledger) – für Session-Events
  • Keinen Code-Level-Debt-Tracker

Das // sin-debt:-Format schließt diese Lücke. Die Schulden sind im Code selbst sichtbar und über sin-code debt abfragbar.

Current State in SIN-Code

Bereich Datei Zeilen Was da ist
Lessons cmd/sin-code/internal/lessons/store.go SQLite-Store für gelernte Patterns. Kein Code-Scan.
Ledger cmd/sin-code/internal/ledger/store.go 87-100 SQLite-Store für Session-Events. Kein Code-Scan.
Codebase-Konventionen AGENTS.md:359+ ### Bundled skill naming rules, aber keine Debt-Marker-Konvention.
Bestehende Shortcuts cmd/sin-code/internal/orchestrator/dispatcher.go // ponytail: this exists (zufällig vorhanden) – wir adoptieren diese Konvention.
Coverage-Tests cmd/sin-code/internal/.../stcov_test.go 4591 Hinter //go:build coverage (von uns gegated). Keine ponytail:-Marker.

Was fehlt: Ein systematischer Mechanismus, um bewusste technische Schulden zu markieren, zu zählen, und in den Code-Review-Loop zu integrieren.

Was ponytail genau macht

Aus https://github.com/DietrichGebert/ponytail/blob/main/skills/ponytail-debt/SKILL.md:1-40:

Scan: Grep the repo for comment markers, skipping node_modules, .git, and build output:
grep -rnE '(#|//) ?ponytail:' . (add other comment prefixes if your stack uses them)

Output: One row per marker, grouped by file:
<file>:<line> — <what was simplified>. ceiling: <the limit named>. upgrade: <the trigger to revisit.

The convention is ponytail: <ceiling>, <upgrade path>, so pull the ceiling and the trigger straight from the comment.

Flag the rot risk: any ponytail: comment that names no upgrade path or trigger gets a no-trigger tag, those are the ones that silently rot.

End with <N> markers, <M> with no trigger.

Die ponytail-debt-Skill ist read-only – er scannt, harvested, und reportet. Kein Schreiben. Optional: ask and it writes the ledger to a file (e.g. PONYTAIL-DEBT.md).

Detailed Implementation Plan

Phase 1 — Scanner & Format-Spec

  1. Erstelle docs/sin-debt-convention.md mit:

    • Format: // sin-debt: <ceiling>, upgrade: <trigger>
    • Erlaubte Kommentar-Syntaxe: //, #, /*, --, <!-- (HTML in Markdown)
    • Pflichtfelder: ceiling (Was ist limitiert), upgrade (Wann nachrüsten)
    • Beispiele (mindestens 5 reale aus dem Code)
  2. Erstelle cmd/sin-code/internal/sindept/scanner.go (Go-Single-Pass-Scanner):

    type Marker struct {
        Path      string
        Line      int
        Comment   string  // roh, z.B. "// sin-debt: ..."
        Ceiling   string
        Upgrade   string  // leer = no-trigger
        HasUpgrade bool
    }
    func Scan(root string, opts ScanOptions) ([]Marker, error)
    • ScanOptions.Skip = []string{"node_modules", ".git", "dist", "vendor", ".venv", "build"}
    • Regex: (?m)(?:#|//|/\*|--|<!--) ?sin-debt:\s*(?P<ceiling>[^,]+?)(?:,\s*upgrade:\s*(?P<upgrade>.+?))?$
  3. Validierung: cmd/sin-code/internal/sindept/scanner_test.go:

    • 5 reale Beispiele parsen korrekt
    • no-trigger-Erkennung
    • Multi-Line-Kommentare werden ignoriert
    • Markdown-Comments (<!--) werden erkannt

Phase 2 — Ledger & Persistence

  1. Erstelle cmd/sin-code/internal/sindept/ledger.go (Integration mit bestehendem Ledger):

    • Neue EntryType: TypeDebtMarker = "debt_marker"
    • Felder: {path, line, ceiling, upgrade, has_upgrade}
    • Persistiert pro Session: sin-code debt list zeigt aktuelle + historische Marker
  2. Aggregation pro Repo: cmd/sin-code/internal/sindept/aggregate.go:

    • AggregateStats mit total, no_trigger_count, by_tag, by_path
    • by_tag mappt auf delete | stdlib | native | yagni | shrink (von ponytail-review)
    • by_path mappt auf cmd/sin-code/internal/<pkg>/*.go

Phase 3 — CLI

  1. Erstelle cmd/sin-code/debt_cmd.go mit:

    • sin-code debt list [--path <path>] [--no-trigger] – listet alle Marker
    • sin-code debt audit – zeigt no-trigger Marker, ranked by age
    • sin-code debt stats – Total/Trigger-Verteilung/By-Tag/By-Path
    • sin-code debt export <file.md> – exportiert als SIN-DEBT.md (analog zu PONYTAIL-DEBT.md)
    • sin-code debt fix <path:line> – öffnet Editor an der Stelle, um den Trigger zu ergänzen
  2. Integration mit sin-code review --complexity (siehe Issue feat(skill): add skill-code-lazy bundled skill (SIN-Code variant of ponytail, respects M3 verify-first) #178):

    • Wenn ein Review-Finding einen delete:-Tag hat und der Code einen sin-debt:-Marker hat → als "approved shortcut" markieren, nicht als zu löschendes Issue.
    • Wenn ein Review-Finding keinen Marker hat → als "neues Issue" markieren.

Phase 4 — Auto-Marker (optional, Phase 2)

  1. Automatische Marker-Erkennung im Learning-Subsystem:

    • Wenn der Critic (internal/orchestrator/critic.go:1-101) feststellt, dass v.Diagnosis() auf einen bewussten Shortcut hinweist, schlägt das System vor: "Add // sin-debt: <x>, upgrade: <y> here? [y/n]"
    • Bei y wird der Marker in cmd/sin-code/internal/instinct/extract.go extrahiert und in die Lessons-DB geschrieben
  2. CI-Integration (Phase 5):

    • scripts/ci-precheck.sh ruft sin-code debt audit auf
    • CI fail, wenn no_trigger_count > N (Schwelle konfigurierbar via debt.max_no_trigger)

Phase 5 — Tests

  1. Unit-Tests (Coverage-Ziel ≥ 80%):

    • scanner_test.go: 5 reale Beispiele
    • ledger_test.go: Round-trip, Aggregation
    • debt_cmd_test.go: alle 5 Subcommands
  2. Integration-Tests:

    • Erstelle ein Test-Repo mit 10 bekannten Markern (5 mit Trigger, 5 ohne)
    • sin-code debt audit listet exakt die 5 ohne Trigger
    • sin-code debt export erzeugt eine korrekte Markdown-Tabelle
  3. Race-Test: go test -race -count=1 ./cmd/sin-code/internal/sindept/...

Phase 6 — Docs

  1. Erstelle docs/sin-debt.md: Format-Spec, Beispiele, Best Practices.
  2. Update AGENTS.md §10 (Naming and stability rules): füge sin-debt:-Konvention hinzu.
  3. Update BACKLOG.md: markiere als done.
  4. Update CHANGELOG.md Unreleased-Section.

Acceptance Criteria

  • cmd/sin-code/internal/sindept/ Paket existiert mit Scanner, Ledger, Aggregator
  • cmd/sin-code/debt_cmd.go existiert mit 5 Subcommands (list, audit, stats, export, fix)
  • // sin-debt: <ceiling>, upgrade: <trigger> Format wird in mind. 95 % der Fälle korrekt geparst
  • no-trigger Erkennung funktioniert
  • Marker werden im internal/ledger/ mit TypeDebtMarker persistiert
  • sin-code debt export erzeugt eine Markdown-Datei
  • docs/sin-debt-convention.md existiert
  • Mindestens 5 reale Beispiele in cmd/sin-code/internal/ mit // sin-debt:-Marker ergänzt (vom PR-Author)
  • Alle Tests passen mit -race
  • golangci-lint, govulncheck, gosec (SARIF) grün
  • BACKLOG.md und CHANGELOG.md aktualisiert

Risk and Rollback

  • Risk: Scanner zu aggressiv – erkennt ponytail: als sin-debt: (false positive). Mitigation: präziser Regex mit explizitem sin-debt: Token.
  • Risk: Marker ohne Trigger – das System sammelt sie, aber niemand fixt sie. Mitigation: CI-Threshold + Slack-Notification (geplant für separater Issue).
  • Risk: Marker-Drift – der Code ändert sich, aber der Marker bleibt. Mitigation: periodischer Re-Scan mit sin-code debt audit (cron-ähnlich).
  • Rollback: Revert PR. Die Marker im Code bleiben inert (Comments).

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions