Skip to content

feat(watchkeeper): product knowledge review surface and GitHub Action [roadmap:v0.12.x] - #79

Merged
tcballard merged 20 commits into
mainfrom
claude/watchkeeper-v0.9-action-tdjbz6
Jun 13, 2026
Merged

feat(watchkeeper): product knowledge review surface and GitHub Action [roadmap:v0.12.x]#79
tcballard merged 20 commits into
mainfrom
claude/watchkeeper-v0.9-action-tdjbz6

Conversation

@tcballard

@tcballard tcballard commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

Implements the watchkeeper series — rac/roadmaps/v0.12.x-watchkeeper/ (v0.12.0–v0.12.3) — RAC's product knowledge review surface and its delivery as a GitHub Action.

Adds:

  • rac watchkeeper [directory] --base REF [--head REF]: compare two repository states (git revision or directory) and report changed artifacts, validation/relationship/statistics deltas, deterministic intent findings, and a review verdict.
  • --format human|json|github, --json (alias), --fail-on error|warning|none, --no-annotate.
  • A composite action.yml and reusable .github/workflows/watchkeeper.yml that run the command on pull requests, plus a dogfood job that runs the action against this repository on every PR.
  • New service modules (compare, revisions, intent, watchkeeper), four CI test batteries, golden coverage, and docs (docs/watchkeeper.md, CLI reference, README, CHANGELOG).

Roadmap / ADR Trace

Roadmap:

  • rac/roadmaps/v0.12.x-watchkeeper/v0.12.0-repository-review.md
  • rac/roadmaps/v0.12.x-watchkeeper/v0.12.1-intent-analysis.md
  • rac/roadmaps/v0.12.x-watchkeeper/v0.12.2-watchkeeper.md
  • rac/roadmaps/v0.12.x-watchkeeper/v0.12.3-watchkeeper-action.md

Requirement: rac/requirements/rac-product-intent-ci-watchkeeper.md (un-deferred — Guide shipped through v0.10.6).

Relevant ADRs:

  • rac/decisions/adr-043-watchkeeper-revision-materialization.md (new — git materialization, CLI surface, directory-or-revision inputs; numbered 043 because feat(docs-site): Lore documentation site on GitHub Pages [roadmap:v0.10.7] #78 took 042)
  • rac/decisions/adr-015-explorer-as-consumer.md (watchkeeper is a consumer; all intelligence stays in services)
  • rac/decisions/adr-007-json-contract-stability.md (additive schema_version: "1" JSON across the series)
  • rac/decisions/adr-027-ci-test-topology.md (one service = one battery)
  • rac/decisions/adr-013-leverage-existing-source-control-systems.md (git, not a bespoke store)

Renumbering

This series was drafted as v0.9.x. It is renumbered to v0.12.x because the v0.9.x identities were released as the Explorer series (rac/roadmaps/archive/v0.9.0v0.9.3), main already carries the v0.10.x Guide series through v0.10.7, and v0.11.x is the portal/export series (merged in #77). PyPI versions cannot regress. Each artifact records the renumbering in its Assumptions section; a calendar-versioning discussion was raised and explicitly deferred (out of scope here).

Scope

Included

  • Comparison (v0.12.0): added/modified/removed artifacts matched by corpus-relative path with requirement-level diffs; validation delta (per-side counts, newly_invalid/newly_valid); relationship delta (per-side summaries, new_issues/resolved_issues — including references broken purely by a removal elsewhere); statistics delta (per-type and total counts). All derived from the existing Repository model.
  • Revision materialization (v0.12.0): git archive into a temp directory, read-only, corpus-subpath only; a missing subpath yields an empty base corpus.
  • Intent findings (v0.12.1): specificity_regression, ambiguity_introduced, constraint_weakened, constraint_removed, acceptance_criteria_removed, success_measures_removed, unlinked_scope, relationship_impact — token-boundary text matching and parsed-section comparison only.
  • Review verdict, formats, policy (v0.12.2): deterministic recommendation mapping; --format github (Markdown to stdout, workflow-command annotations to stderr); --fail-on exit policy.
  • Action + workflow + dogfood (v0.12.3): composite action.yml, reusable workflow, PR dogfood job, YAML contract tests, docs.

Excluded

  • SARIF / code-scanning output. Not implemented. The GitHub surface is workflow-command annotations plus a step-summary report.
  • No Node.js runtime or second toolchain. The action is a composite shell wrapper around the existing Python CLI.
  • No GitHub App, hosted service, webhook receiver, or dashboard.
  • No GitHub API calls for comments or checks — annotations come from workflow commands only.
  • Configurable watchkeeper: policy block in .rac/config.yaml (named in the requirement). Deferred; --fail-on covers CI policy. Recorded in the requirement's Future Considerations and the v0.12.3 roadmap.
  • Rename detection. A renamed artifact reports as removed plus added (stated non-goal in v0.12.0).
  • No moving major (@v1) tag. setuptools-scm derives package versions from git tags; a floating tag would corrupt derivation. Consumers pin exact release tags.

Product / Architecture Decisions

  • rac watchkeeper, not rac review --intent. rac review keeps its current-state semantics; comparison is a new command that grows additively across the series, matching the requirement's interface section.
  • Comparison services are git-free. --base/--head accept a git revision or a directory; revision materialization is isolated in one module (revisions.py). This keeps golden tests git-independent (directory-to-directory) and lets users compare arbitrary snapshots. Recorded as ADR-043.
  • git archive, not git worktree. No .git mutation, no worktree registration or locking, safe under concurrent CI runs, and only the corpus subpath is extracted.
  • Finding codes reuse the requirement's policy vocabulary so a future policy block needs no translation layer.
  • github format splits streams: Markdown to stdout (redirected to $GITHUB_STEP_SUMMARY), workflow commands to stderr (parsed live from the step log). One invocation feeds both the summary and inline annotations without interleaving.
  • The action is logic-free. All analysis, rendering, and failure policy live in the package; the action installs RAC, resolves the base ref, runs one invocation, and propagates the exit code. install-from: source exists for this repo's dogfood (external action checkouts lack git metadata for setuptools-scm).

User-Facing Contract

CLI

rac watchkeeper rac --base main
rac watchkeeper rac --base "origin/$GITHUB_BASE_REF" --format github > "$GITHUB_STEP_SUMMARY"
rac watchkeeper rac --base main --fail-on warning

Human Output

Sections: Changed Artifacts, Validation, Relationships, Repository Changes, Findings, Review (verdict with reasons or "Nothing requiring attention").

JSON Output

Stable contract (schema_version: "1"), additive across the series:

{
  "schema_version": "1",
  "base": "main",
  "head": "rac",
  "directory": "rac",
  "changes": [{"change": "modified", "type": "requirement", "id": "", "title": "", "path": "", "base_status": "valid", "head_status": "valid", "diff": {}}],
  "validation": {"base": {}, "head": {}, "newly_invalid": [], "newly_valid": []},
  "relationships": {"base": {}, "head": {}, "new_issues": [], "resolved_issues": []},
  "stats": {"total": {}, "by_type": {}},
  "findings": [{"code": "specificity_regression", "severity": "warning", "path": "", "identifier": "", "detail": "", "evidence": []}],
  "review": {"recommended": true, "reasons": [{"code": "", "reason": ""}]}
}

Exit Codes

  • 0: nothing requiring attention under the chosen policy (always with --fail-on none).
  • 1: review recommended (--fail-on error), or additionally any warning finding (--fail-on warning).
  • 2: usage error, unknown revision, or not inside a git repository when a revision is requested.

Verification

Ran (re-run after rebasing onto the current main)

python -m ruff check src/ tests/
python -m ruff format --check src/ tests/
python -m mypy src/
python -m pytest -q                      # 1120 passed (incl. main's export + docs batteries)
mkdocs build --strict                    # exit 0 — docs/watchkeeper.md registered in nav
rac validate rac/                        # 134 valid, 0 invalid
rac relationships rac/ --validate        # 409 checked, 0 issues
rac review rac/                          # ok
rac watchkeeper rac --base origin/main   # green self-test on this branch

Covered

  • Comparison: added/modified/removed by corpus-relative path; modified carries a requirement diff; a relationship broken purely by a removal elsewhere; identical-states-empty; empty base reports everything added.
  • Revisions: byte-for-byte corpus round-trip from a throwaway git repo; revision reflects the commit not the working tree; unknown revision → exit 2; missing subpath → empty corpus; no .git mutation; temp dir removed on exit.
  • Intent: each check fires on its planted case and stays silent on the adjacent negative — kept numbers, pre-existing terms, token-vs-substring (breakfastfast), mandatory→mandatory rewording, linked new scope.
  • Watchkeeper: recommendation mapping and ordering; --fail-on matrix through the CLI (including warning-only findings); github stdout/stderr separation; --no-annotate; JSON alias.
  • Action/workflow: YAML contract tests for inputs, defaults, the single forwarded invocation, both install modes, reusable-workflow pass-through, dogfood source install.
  • End-to-end: fresh-adoption repo (config + one new artifact) gets a green check with an unlinked_scope annotation; this branch passes its own dogfood gate.

Review Path

  1. rac/roadmaps/v0.12.x-watchkeeper/ and rac/decisions/adr-043-watchkeeper-revision-materialization.md — the contract and the materialization decision.
  2. src/rac/services/compare.py, src/rac/services/revisions.py — comparison model and the single git seam.
  3. src/rac/services/intent.py — the deterministic checks.
  4. src/rac/services/watchkeeper.py — report assembly and recommendation mapping.
  5. src/rac/cli.py, src/rac/output/github.py, src/rac/output/human.py, src/rac/output/json.py — CLI surface and rendering.
  6. action.yml, .github/workflows/watchkeeper.yml, .github/workflows/pr-checks.yml — delivery and dogfood.
  7. tests/test_compare.py, tests/test_revisions.py, tests/test_intent.py, tests/test_watchkeeper.py, fixtures, goldens.
  8. docs/watchkeeper.md, docs/cli.md, mkdocs.yml, CHANGELOG.md.

Notes For Reviewer

  • repository_from_corpus seam in src/rac/services/repository.py is an additive extraction from load_repository; the existing behavior is unchanged, but it is the shared join everything reuses.
  • Two follow-ups before external consumers can use the action from PyPI: tag a v0.12.x release (the action's default install mode needs a published version carrying the command — the dogfood job sidesteps this via install-from: source), and bump the @main ref in .github/workflows/watchkeeper.yml to that tag.
  • Deferred policy config leaves one requirement functional area unimplemented; this is recorded in the corpus rather than stubbed.
  • Rebased onto current main (linear history, no merge commit) so it lands cleanly via Rebase and merge. This reconciled both feat(export): portal export and web surface [roadmap:v0.11.0] #77 (v0.11.0 portal/export) and feat(docs-site): Lore documentation site on GitHub Pages [roadmap:v0.10.7] #78 (v0.10.7 docs site): additive overlaps resolved in CHANGELOG.md, CLAUDE.md, src/rac/cli.py, and the README doorway; docs/watchkeeper.md registered in the mkdocs nav so mkdocs build --strict stays green; and this PR's decision renumbered ADR-042 → ADR-043 because feat(docs-site): Lore documentation site on GitHub Pages [roadmap:v0.10.7] #78 landed its own ADR-042 (docs-site hosting).

Implementation Process

Implemented with AI assistance under the roadmap contract. Final scope, review, and acceptance decisions were made by the maintainer.

tcballard added 20 commits June 13, 2026 08:57
…quirement [roadmap:v0.12.0]

Rewrites the unshipped v0.9.x watchkeeper drafts as a canonical
v0.12.x series (v0.12.0 repository review, v0.12.1 intent analysis,
v0.12.2 watchkeeper, new v0.12.3 GitHub Action): v0.9.x identities
were released as the Explorer series, main carries v0.10.x through
v0.10.6, and v0.11.x is allocated to in-flight work.

Un-defers rac-product-intent-ci-watchkeeper now that Guide has
shipped, links it to the new series, and points the working corpus
at v0.12.x.

Implements rac/roadmaps/v0.12.x-watchkeeper/.
…[roadmap:v0.12.0]

Pins git archive into a temporary directory as the only git-aware
seam for watchkeeper comparisons, with directory-to-directory
comparison keeping services and golden tests git-free.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.0-repository-review.md.
Adds compare.py — RepoState loading and compare_states deriving changed
artifacts (matched by corpus-relative path, with requirement-level
diffs), validation deltas, relationship deltas, and statistics deltas,
all read from the existing Repository model. Extracts the
repository_from_corpus seam so a comparison side reuses one corpus walk.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.0-repository-review.md.
The only git-aware module in the package: materialized_revision extracts
the corpus subpath at a revision via git archive into a temporary
directory — read-only, offline, no worktree registration (ADR-042).
Unknown revisions and non-git directories raise typed errors the CLI
maps to exit 2; a revision without the subpath yields an empty corpus.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.0-repository-review.md.
…12.0]

rac watchkeeper [directory] --base REF [--head REF] [--json]: base and
head each accept a git revision or a plain directory, the working tree
is the default head, and the report renders as a human summary or
stable JSON (schema_version 1, additive across the series, ADR-007).
Exit 0 — comparison is informational until v0.12.2 recommendations.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.0-repository-review.md.
…oadmap:v0.12.0]

Fixture corpora plant one case per delta — added, modified, removed,
newly invalid, and a relationship broken purely by a removal elsewhere.
compare and revisions batteries join the CI matrix (ADR-027); golden
cases pin human and JSON output via directory-to-directory comparison,
so goldens never depend on git state.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.0-repository-review.md.
Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.0-repository-review.md.
…:v0.12.1]

analyze_intent screens a repository comparison for clarity regressions:
specificity loss, ambiguity, constraint weakening and removal, section
removal, unlinked scope, and relationship impact. Token-boundary
matching and parsed-section comparison only — no semantic scoring; the
finding codes reuse the requirement's policy vocabulary.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.1-intent-analysis.md.
…dmap:v0.12.1]

The report gains a Findings block (human) and an additive findings
array (JSON, ADR-007), each finding carrying its code, severity, path,
identifier, detail sentence, and diff-style evidence.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.1-intent-analysis.md.
…map:v0.12.1]

Positive cases ride the shared watchkeeper fixtures (now planting an
acceptance-criteria removal); negative boundary cases — kept numbers,
pre-existing terms, token-vs-substring, mandatory rewording, linked new
scope — build minimal corpora under tmp_path. The intent battery joins
the CI matrix and the goldens pin the findings block.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.1-intent-analysis.md.
Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.1-intent-analysis.md.
…v0.12.2]

Newly invalid artifacts, new relationship issues, and the
clarity-regression findings map to Core-owned reasons, deduplicated by
code; ambiguity, unlinked scope, and relationship impact inform but
never recommend alone. JSON gains an additive review block (ADR-007).

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.2-watchkeeper.md.
…:v0.12.2]

--format github writes a Markdown step-summary report to stdout and
workflow-command annotations (repository-relative paths, errors for
recommendation triggers) to stderr; --no-annotate silences the stream.
--fail-on error|warning|none turns the review verdict into CI policy;
human output gains the verdict block.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.2-watchkeeper.md.
… [roadmap:v0.12.2]

The watchkeeper battery covers the recommendation mapping and ordering,
the fail-on matrix through the CLI, stdout/stderr separation of the
github format, and the json alias; a github golden joins the human and
JSON goldens (stdout only — annotations are pinned by the battery).

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.2-watchkeeper.md.
…2.2]

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.2-watchkeeper.md.
A logic-free wrapper: pin Python, install RAC (PyPI by default, the
action checkout in source mode for dogfooding), resolve the pull
request base ref, run one rac watchkeeper --format github invocation
with stdout to the step summary, and propagate the exit code unchanged.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.3-watchkeeper-action.md.
…v0.12.3]

Consumers call .github/workflows/watchkeeper.yml with uses: to get the
checkout and base-ref wiring for free; this repository's own PR checks
now run the local action in source mode — every pull request here is
both reviewed by Watchkeeper and an end-to-end test of action.yml.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.3-watchkeeper-action.md.
YAML contract tests assert the action's input surface and defaults,
the single forwarded CLI invocation, both install modes, the reusable
workflow's pass-through inputs, and the dogfood job's source install —
so the wrappers cannot drift from the command contract silently.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.3-watchkeeper-action.md.
…:v0.12.3]

docs/watchkeeper.md covers the command, the action inputs, the
reusable workflow, the exact-tag pinning policy (no moving major tag —
setuptools-scm derives versions from git tags), and a worked example.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.3-watchkeeper-action.md.
ADR-042 was taken by docs-site hosting (#78, merged to main). Renames
the watchkeeper revision-materialization decision to ADR-043 and updates
its references in the v0.12.0/v0.12.3 roadmaps and the watchkeeper docs,
so 'ADR-043' resolves to this decision and 'ADR-042' stays the docs-site
decision.

Implements rac/roadmaps/v0.12.x-watchkeeper/v0.12.0-repository-review.md.
@tcballard
tcballard force-pushed the claude/watchkeeper-v0.9-action-tdjbz6 branch from 1f4c796 to 4dcc8d1 Compare June 13, 2026 09:05
@tcballard
tcballard merged commit cf6cce0 into main Jun 13, 2026
3 checks passed
@tcballard
tcballard deleted the claude/watchkeeper-v0.9-action-tdjbz6 branch June 15, 2026 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant