cc-os/plugins/os-adr/invariants.md

54 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# os-adr invariants
Behavioral invariants of the plugin. Changing any of these requires explicit human approval and
a matching update to the tests named beside it. Suite entry points: `ruby tests/all.rb` and
`python3 tests/hook_test.py` (both model-free).
1. **Non-destructiveness (migration).** Migration writes only new files under `docs/adr/`;
existing source content is never deleted, moved, or edited by any tooling path. Old-system
removal is a separate, explicit, user-approved step (skill-mediated, never automatic).
`migrator_test.rb#test_sources_stay_byte_identical`, pilot sha256 checks.
2. **Index regeneration, never accretion.** `docs/adr/README.md`'s table is regenerated in full
from directory contents on every ADR write; it is never appended to or hand-edited, and
self-heals after manual edits. Content outside the markers is preserved.
`index_test.rb` (golden fixture, self-heal, prose preservation, generated-header cases).
3. **IDs come from the directory, never the index.** Next ID = max existing filename ID + 1,
derived by scanning `docs/adr/`; a stale or missing index never influences numbering.
`repository_test.rb#test_next_id_ignores_{missing,stale}_index`.
4. **No LLM in the hook.** The SessionStart hook is a pure function of filesystem state (ADR
dir, index, suppression state, snooze stamp) — no model call, no network, no Ruby spin-up;
always exits 0; emits nothing (and creates no state) outside a git project. Its existence
rule is identical to `Adr::Repository#exists?`.
`hook_test.py` (all cases; `PythonRubyAgreementTest` pins the shared rule).
5. **Single uncertainty-flagging mechanism.** Migration uncertainty surfaces only via
`migration_confidence: low|medium|high` frontmatter plus `docs/adr/migration-report.md`.
No scattered inline uncertainty comments.
`migrator_test.rb#test_report_lists_files_confidence_sources_and_flag_rate`.
6. **Core fields are never invented.** A Decision or Context absent from a migration source is
written as `_not stated in source_` and flags the file low-confidence; LLM fills apply only
to pending-marker fields (enforced structurally by `apply_fills!` — a stray fill key is a
no-op), and an LLM-filled file stays flagged (≤ medium).
`migrator_test.rb#test_missing_core_fields_*`, `#test_apply_fills_only_touches_pending_fields`.
7. **Unrecognized content is reported, never auto-converted.** Content matching no known shape
— including multi-decision files without mechanically splittable unit headings — is listed
in the report for manual handling only.
`detector_test.rb#test_multi_decision_file_without_unit_headings_is_unrecognized`,
`migrator_test.rb#test_unrecognized_content_is_reported_never_converted`.
8. **Deterministic-first retrieval.** `adr-find` narrows by frontmatter path/component match,
then Accepted-only status filter (explicit override), then optional one-hop graph expansion
that degrades gracefully (absent or corrupt graph → layers 12). AI judgment happens only in
the `find` skill, only over the CLI's returned candidates.
`finder_test.rb` (all cases, including both degradation paths).
9. **Skills delegate mechanics to `bin/` CLIs.** Numbering, templating, indexing, supersession
bookkeeping, detection, conversion, and retrieval filtering are never re-implemented in
prompt instructions.
— by construction of `skills/*/SKILL.md`; `cli_test.rb` pins the CLI contracts.