Polaris/.agents/skills/polaris-lint/SKILL.md

134 lines
8.1 KiB
Markdown

---
name: polaris-lint
description: "Health-check an Polaris vault: dead links, orphans, frontmatter and workstream-contract gaps, people-tier defects, unsourced reference material, vocabulary violations, misplaced files, stale holds, and an overdue log fold. Flags only — never auto-fixes. Writes exactly one wiki/meta/lint-report-YYYY-MM-DD.md stamped with the git commit it describes; the previous report is archived. Triggers on: lint, health check, audit the vault, check the vault, find orphans, find dead links."
---
# polaris-lint — vault health check
**Flags only.** Lint reports; the owner or the next session decides. (Repairs lint surfaces may then be made under the *Repair* rule in `AGENTS.md`.)
⛔ Fenced paths (`AGENTS.md`, *Fences*) are excluded from every check. Links *into* them are checked for existence only.
---
## Scope — two kinds of check
**The test:** *would this finding stop being true if nobody ever worked on this file again?*
| | Answer | Scope |
|---|---|---|
| **Attention** | Yes — it's "this needs someone's attention" | **Skip** `paused`/`closed`/`archived` hubs and everything under `5. Archive/` |
| **Integrity** | No — it's "this is broken" | **Run vault-wide, `5. Archive/` included** |
A blanket archive skip on an integrity check hides broken links behind a clean report. Every new check classifies itself before it's written.
**Run every check mechanically** — glob and grep actual file contents, resolve every candidate. A finding produced by reading a sample and generalising is a hypothesis, not a finding. **Spot-check anything surprising** (a large round number, a well-known file reported broken) before it goes in the report.
**Stamp the tree:** record `git rev-parse --short HEAD` if the vault is a git repo, and say at the top if the working tree is dirty.
---
## Integrity checks — vault-wide
**1. Dead links.** Every `[[target]]` / `[[target|alias]]` that resolves to no file. Strip fenced code blocks and inline code first — documentation examples aren't links. Resolve against full path, then bare filename anywhere in the vault. Report archive findings under their own heading.
**2. Link style.** Links containing `.md` (`[[file.md]]`).
**3. Frontmatter contract.** Against `6. Templates/_contracts.md`:
- Every file below `0. Inbox/` root in the numbered folders: `type`, `updated` (`4. Decisions/` uses `date`).
- Hubs: `type` is `project` or `area` (**`hub` is a defect**) · `status` in the vocabulary.
- Projects: `id`, `area` (value or literal `none`), `done_when` non-empty · `paused_because` when paused · hub filename is `<id>_hub.md`.
- Areas: `id_prefix`, `workstream_counter` · `parent` never equals the Area's own name.
- Decisions: `date`, `topic`, `status`. Threads: `status`, `opened`.
- **Exempt:** `AGENTS.md`, `CLAUDE.md`, `README.md` and other vault-root files · `6. Templates/` · `0. Inbox/` notes (they use `date` + `tags`, no `type`).
- **Before reporting a missing field, check whether any file in that folder has ever carried it.** A field absent from every file is a convention, not a set of defects.
**4. ID integrity.** For each Area, every issued ID `<PREFIX>-N` (in `1. Projects/` and `5. Archive/`) has `N ≤ workstream_counter`. Any duplicate ID anywhere is a defect.
**5. Provenance.** Every `type: reference` file has a non-empty `source:` (or "source unrecorded" in the body). Report path and line count. **Never auto-fixable** — the owner confirms or strikes the source.
**6. Vocabulary.** For each row of `AGENTS.md`'s vocabulary table, grep the *Never use* forms in vault-voice prose. Exempt: the table itself, lint reports, `open-questions.md`, `0. Inbox/processed/`, and verbatim quotes of a source. **If both the banned and canonical forms have zero hits, report the row itself as suspect** — the table is data to be tested, not the test. **An ordinary English word can only be enforced inside a scope the row names**; if a row's scope can't be determined mechanically, report the row as unenforceable instead of its hits.
**7. Stale index entries.** Links in `wiki/index.md` or `wiki/hot.md` pointing at files that moved or don't exist.
## Attention checks — live material only
**8. Orphans.** A file in the numbered folders with no inbound `[[link]]` from any other page. Collect every link target vault-wide (including archived hubs as *sources*), then test each candidate by full path and bare name. Also count backtick-quoted paths as references — report those separately as *"referenced by path, not linked"*. **Exempt:** hubs · `4. Decisions/` · `3. Resources/Research/` root · `6. Templates/` · `0. Inbox/` · `5. Archive/` · vault-root files.
**9. People tiers.**
- `tier: relationship` without `cadence` or `follow_up_by` → **defect** (it can never flag).
- `tier: contact` carrying `cadence` or `follow_up_by` → defect.
- A spent `follow_up_by` (on or before `last_contact`) is **not** a defect.
- An `organic` page whose `follow_up_by` has been pushed repeatedly with no contact (check git history if available) → finding: that's a cadence that never fires.
**10. `next:` validity.** Each entry uses `send`/`wait`/`build`/`decide`; `send`/`wait` name a person. **Report every `send`/`wait` older than 14 days at the very top of the report**, above every structural finding — an unsent message is worth more than all of them.
**11. Misplaced files.** Hubs outside `1. Projects/`/`2. Areas/` · person pages outside `People/` · decisions outside `4. Decisions/` · content files in `wiki/` other than `hot.md`, `index.md`, `log.md`, `folds/*`, `meta/*` · binaries (pdf, images, office files) anywhere in the vault · a file in `3. Resources/Research/` root carrying an Area tag · reference material inside a Project folder with no Area tag.
**12. Standalone Areas.** A standing Area with no live Project and `updated:` older than 30 days. Report as context — it may be quiet on purpose.
**13. Holds.** An open hold older than 30 days with no end date · an open hold with no start date older than 7 days. **A hold never discharges an obligation** — report open sends alongside it.
**14. Log fold.** Unfolded entries (headings minus `[folded]` pointers) against the threshold of 16 — **print the count every run**. Also: any unfolded entry sitting *below* a `[folded]` pointer is a hole from a middle-window fold.
---
## Report — `wiki/meta/lint-report-YYYY-MM-DD.md`
**Retention 1.** Before writing, move any previous lint report to `5. Archive/wiki-meta/`.
```markdown
---
type: meta
title: "Lint report YYYY-MM-DD"
created: YYYY-MM-DD
commit: abc1234
tree_clean: true
supersedes: lint-report-YYYY-MM-DD
tags: [meta, lint]
---
## Outstanding sends — before anything structural
## Summary ← one line per check: count, or "clean"
## Dead links
### Inside 5. Archive/
## Frontmatter & contracts
## IDs
## Provenance
## Vocabulary
## Orphans
## People
## Misplaced files
## Areas & holds
## Log ← "unfolded: N / 16" — always printed
## Carried findings — second cycle
```
Omit empty sections except Summary and Log.
## The two-cycle rule
**A finding that survives two consecutive lints without action is a decision nobody has made.** Second appearance: list it under *Carried findings*. Third: **remove it from the report** and add it to `wiki/meta/open-questions.md` as a forced binary — `**<Question>** — Option A / Option B. Raised YYYY-MM-DD.` Then stop reporting it.
**Corollary — the more important half: when a check keeps producing the same backlog, suspect the check.** A rule nobody ever acts on is usually wrong, not ignored.
## Output (to chat)
```
## Lint — YYYY-MM-DD @ <commit>
Sends > 14 days: N
Integrity: N dead links (N in archive) · N contract gaps · N provenance · N vocabulary
Attention: N orphans · N people defects · N misplaced
Log: N / 16
Report: wiki/meta/lint-report-YYYY-MM-DD.md
```
## Rules
- **Flags only. No auto-fix.**
- **Attention checks skip retired material; integrity checks run everywhere.**
- **Mechanical, exhaustive, spot-checked.** Never estimate.
- **Sends outrank structure.**
- **One report at a time, stamped with its commit.**
- **Two-cycle rule — and question the check before the files.**