Скилл Maintenance

Datarim Doctor

Спецификация тонкой индексной схемы оперативных файлов: канонический regex, контракт YAML frontmatter, семантика 5-проходной миграции, контракт защиты от потери данных. Загружается по требованию /dr-doctor и /dr-init.

Обзор

Datarim Doctor — runtime-модуль знаний, определяющий контракт тонкого индекса. Оперативные файлы (tasks.md, backlog.md, activeContext.md) хранят однострочные указатели на задачи; описания живут в файлах datarim/tasks/{TASK-ID}-task-description.md с замкнутой YAML-схемой. progress.md и rolling-лог activeContext.md § Последние завершённые упразднены — история завершённых задач хранится только в documentation/archive/ и git log.

Зачем тонкие индексы

Оперативные файлы — это индексы, а не содержимое. Каждая строка отвечает на четыре вопроса: какая задача, какой статус, где описание. Никакой прозы, требований, контента плана в tasks.md / backlog.md.

  • Ограниченный контекст — агенты читают 1 KB индекс, а не 100 KB монолит.
  • Единый источник правды на задачу — описание, ACs, ограничения в одном файле.
  • Greppable состояние — формат строки машиночитаем; смена статуса = 1-line diff.
  • Идемпотентные миграции/dr-doctor можно запускать сколько угодно раз без drift.

Канонический Regex

^- ([A-Z]{2,10}-[0-9]{4}) · (STATUS) · P[0-3] · L[1-4] · (.{1,80}) → tasks/\1-task-description\.md$

Наборы статусов:

  • tasks.md: in_progress | blocked | not_started
  • backlog.md: pending | blocked-pending | cancelled

Разделитель: · (U+00B7 MIDDLE DOT). Стрелка: (U+2192). Заголовок: 1–80 символов, single-line, без .

Контракт description-файла

У каждой задачи есть description-файл по пути datarim/tasks/{TASK-ID}-task-description.md с замкнутой 12-ключевой YAML-frontmatter:

---
id: <TASK-ID>
title: <string>               # ≤ 80 символов
status: <enum>
priority: <enum>              # P0|P1|P2|P3
complexity: <enum>            # L1|L2|L3|L4
type: <string>
project: <string>
started: <date>               # YYYY-MM-DD
parent: <TASK-ID|null>
related: <list[TASK-ID]>
prd: <relpath|null>
plan: <relpath|null>
---

Тело: 5 канонических секций (Overview / Acceptance Criteria / Constraints / Out of Scope / Related), не более 250 строк. Опционально ## Implementation Notes и ## Decisions.

Алгоритм миграции (6 проходов)

  1. Pass 1 — Description-файлы (build cache): обход legacy ### TASK-ID: заголовков; извлечение status/priority/complexity/type/started/parent/related/prd/plan; запись per-task файла с frontmatter.
  2. Pass 2 — Оперативные файлы: перезапись tasks.md и backlog.md в виде одностройных индексов, сгруппированных по разделам.
  3. Pass 3 — activeContext.md: конверсия legacy **Current Task:** в список ## Active Tasks (Active-Tasks-only mirror, ≤30 строк).
  4. Pass 4 — миграция backlog-archive: AWK section-state machine + per-ID dispatch разделяет legacy backlog-archive.md на documentation/archive/cancelled/ (синтезированные стабы) и area-specific archive-{TASK-ID}.md для завершённых записей (verify-or-synthesise в general/); флаг --no-prompt для CI.
  5. Pass 5 — post-fix re-scan: композиция existing scan dispatch в dry-run после --fix; проверяет post-fix zero findings + сохранность .pre-v2.bak sidecar + идемпотентность повторного запуска (второй --fix = no-op).
  6. Pass 6 — миграция архивных секций оперативных файлов (TUNE-0085 v1.21.5, hardened TUNE-0088 v1.21.6): убирает ## Archived из tasks.md/backlog.md и ### Archived/### Recently Archived/## Последние завершённые из activeContext.md — секции, нарушающие канонический thin-index контракт («one section only», v1.19.1). Четыре формы bullet'ов auto-detected (S1 arrow-link, S2 status-paren, S4 mid-bold-context, S3 plain-bold). Compound task IDs поддержаны (например DEV-1212-S8, DEV-1196-FOLLOWUP-lock-ownership-doc). Явный pointer → documentation/archive/{path}.md в теле bullet'а имеет приоритет над хардкоженным mapping prefix_to_area. Per bullet: verify canonical archive по resolved path → strip; отсутствует → defensive find по area subdirs (depth ≤ 3) — если найден с literal ID, strip-with-warning; иначе synthesise stub; collision → respect --conflict-policy. Headerless fallback: операционные файлы без archive-заголовка обрабатываются построчно; bullets с явным non-terminal статусом (in_progress, not_started, blocked, …) проходят как active content.

Idempotency guard: если нет ### TASK-ID: заголовков, нет legacy backlog-archive.md, и все bullet-строки совпадают с canonical regex — выход 0 немедленно. Дешёвый probe для /dr-init.

Контракт защиты от потери данных

Defence-in-depth вокруг --fix (TUNE-0077):

  • Pre-write tarball backupumask 077 архив пишется в ${DATARIM_DOCTOR_BACKUP_DIR:-/tmp}/datarim-backup-{TS}.tgz до любой мутации. Путь печатается в success-summary.
  • Sidecar copy — каждый legacy-файл, мутируемый Pass 4, получает .pre-v2.bak рядом в дереве (operator-visible).
  • ИнвариантEMITTED_COUNT >= PARSED_COUNT. Doctor считает task-записи до и после rewrite. Нарушение запускает restore_backup_and_die(): rm-rf мутированного состояния, tar -xzf tarball обратно, exit 2.
  • Symlink-default uniformity — при install.sh default режиме ~/.claude/scripts/datarim-doctor.sh — directory-symlink на canonical Datarim repo. Расхождение невозможно by construction; чужой v2-бинарь нельзя молча подложить.

Точки входа Self-Heal

  • /dr-doctor (всегда)
  • /dr-init — probes datarim-doctor.sh --quiet; предлагает /dr-doctor --fix при non-compliance.
  • /dr-archive pre-archive gate — pre-archive-check.sh проверяет формат строк; обход через --no-schema-check только во время in-flight миграции.

Edge cases

  • Bash 3.2 (macOS по умолчанию) — инструмент использует two-pass grep+awk parser, БЕЗ NUL-delimited reads.
  • Заголовок с символом → — экранирован или отклонён (regex запрещает). Оператор должен переименовать.
  • Параллельный запускflock на $DATARIM_ROOT/.dr-doctor.lock. Второй экземпляр выходит с кодом 3.
  • Path traversal — лексическая канонизация через scripts/lib/canonicalise.sh (без I/O). Инструмент выходит с кодом 4.

Загружается

  • /dr-doctor (всегда)
  • /dr-init self-heal (когда probe возвращает exit 1)
  • /dr-archive line-format gate (при сбое — для объяснения non-compliance)