Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions .specify/memory/constitution.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
<!--
SYNC IMPACT REPORT
==================
Version change: 1.2.0 → 1.3.0 (2026-03-10)
Amendment: Principle I — added mandatory documentation impact review requirement
Templates updated:
✅ .specify/memory/constitution.md — this file
✅ .specify/templates/plan-template.md — Constitution Check row added for Principle I docs gate
✅ CLAUDE.md — Documentation Discipline section added with concrete checklist

Version change: 1.1.0 → 1.2.0 (2026-02-27)
Amendment: Principle II — added story-scoped TDD decomposition requirement

Expand Down Expand Up @@ -51,10 +58,15 @@ clean, comprehensible, and internally consistent.
- Code reviews MUST be completed by at least one peer before merging to any protected branch.
- Dead code, commented-out blocks, and orphaned files MUST be removed rather than retained.
- All dependencies MUST be explicitly declared; implicit transitive reliance is prohibited.
- Every feature MUST include a documentation impact review before completion. Changes that affect
user-facing behaviour, architecture, public APIs, or operational procedures MUST update the
relevant documentation (README, design docs, architecture diagrams, contributor guides) in the
same PR. Documentation debt is treated with the same urgency as code debt.

**Rationale**: Technical debt compounds. Defects caught at review time cost an order of magnitude
less to fix than those discovered post-deployment. Consistent quality lowers onboarding time and
reduces cognitive overhead for the entire team.
reduces cognitive overhead for the entire team. Stale documentation is worse than no documentation —
it actively misleads.

### II. Testing Standards (NON-NEGOTIABLE)

Expand Down Expand Up @@ -161,6 +173,7 @@ Every pull request MUST pass all of the following gates before merge:
- [ ] Performance budget checks pass in CI (Principle IV)
- [ ] At least one peer code review approved (Principle I)
- [ ] Constitution Check section in `plan.md` completed with pass/fail per principle (all)
- [ ] Documentation impact reviewed — README, design docs, architecture diagrams updated if affected (Principle I)
- [ ] Any principle violations documented in the Complexity Tracking table with justification

Compliance reviews MUST be conducted at the start of each feature (Constitution Check in
Expand Down Expand Up @@ -200,4 +213,4 @@ For runtime development guidance and active technology context, see agent files

---

**Version**: 1.2.0 | **Ratified**: 2026-02-20 | **Last Amended**: 2026-02-27
**Version**: 1.3.0 | **Ratified**: 2026-02-20 | **Last Amended**: 2026-03-10
2 changes: 1 addition & 1 deletion .specify/templates/plan-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ For each principle, record **PASS**, **FAIL + justification**, or **N/A + reason

| Principle | Status | Notes / Justification |
|-----------|--------|----------------------|
| I. Code Quality — linting enforced, single-responsibility, complexity ≤ 10, peer review | | |
| I. Code Quality — linting enforced, single-responsibility, complexity ≤ 10, peer review, documentation impact reviewed | | |
| II. Testing Standards — TDD cycle, ≥ 80% unit coverage, contract tests on interface changes | | |
| III. UX Consistency — design system adherence, WCAG 2.1 AA, actionable error messages | | |
| IV. Performance — latency SLA defined, performance budget in CI, profiling before optimization | | |
Expand Down
22 changes: 22 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,27 @@ def investigate_subsystem(subsystem: str, ...) -> list[dict]:
- Registration: side-effect import `import pmmcp.prompts` in `server.py` (bottom, like tools)
- Contract tests use `srv.mcp._prompt_manager.list_prompts()` and `asyncio.run(srv.mcp.get_prompt(...))`

## Documentation Discipline

**Mandatory before any feature is considered complete** (required by Constitution v1.3.0, Principle I).

Every feature MUST include a documentation impact review. Before closing a PR, check whether changes affect any of the following — and update them in the same PR:

| Document | Update when... |
|----------|---------------|
| `README.md` | New/changed tools, prompts, CLI flags, setup steps, or user-facing behaviour |
| `docs/investigation-flow.md` | Workflow steps, specialist domains, coordinator behaviour, or diagram topology change |
| `CONTRIBUTING.md` | Dev workflow, testing approach, or project conventions change |
| `CLAUDE.md` | New conventions, gotchas, or patterns discovered during implementation |
| Architecture diagrams (mermaid) | Component relationships, data flow, or dispatch patterns change |
| Prompt table in README | Prompt signatures, descriptions, or argument lists change |
| `docker-compose.yml` comments | Container topology, env vars, or service dependencies change |

Rules:
- Documentation updates land in the **same PR** as the code change — not "we'll do it later"
- If no docs are affected, note it explicitly in the PR description: "Docs impact: none"
- Stale documentation is worse than no documentation — it actively misleads

## Pre-Push Sanity Check

**Mandatory before any `git push`** (required by Constitution v1.2.0, Principle II).
Expand All @@ -210,6 +231,7 @@ The check runs in order: lint → format → unit+integration tests (≥80% cove
- N/A — stateless tool; no persistence (006-quick-investigate)
- Python 3.11+ + `mcp[cli]` ≥1.2.0 (FastMCP), `pydantic` v2.x — no new dependencies (010-specialist-agents)
- N/A — prompts are stateless text generators (010-specialist-agents)
- Python 3.11+ + `mcp[cli]` ≥1.2.0 (FastMCP), `pydantic` v2.x — no new dependencies (011-specialist-baselining)

## Recent Changes
- 002-add-integration-e2e-tests: Added Python 3.11+ + `mcp[cli]` ≥1.26.0 (FastMCP + ClientSession), `anyio` (memory streams), `respx` (already present — mocks httpx for integration tier), `pytest-asyncio` (already present)
Expand Down
48 changes: 32 additions & 16 deletions docs/investigation-flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ flowchart TD
PROC --> SYN
CROSS --> SYN

SYN --> OUT["Unified Report\n• Root cause narrative\n• Timeline correlation\n• Findings ranked by severity\n• Concrete recommendations"]
SYN --> OUT["Unified Report\n• Root cause narrative\n• Timeline correlation\n• Findings ranked by classification & severity\n (ANOMALY > RECURRING > BASELINE)\n• Concrete recommendations"]

style CI fill:#2d6a4f,color:#fff
style PAR fill:#40916c,color:#fff
Expand All @@ -107,10 +107,13 @@ relationships, and interpretation rules from experienced performance engineers.

## Specialist Workflow

Every specialist follows the same 4-step discipline: discover what metrics exist,
fetch the data, analyse against domain heuristics, then report structured findings.
This prevents the common failure mode of querying metrics that don't exist on the
target host.
Domain specialists (CPU, Memory, Disk, Network, Process) follow a 5-step
discipline: discover what metrics exist, establish a 7-day baseline for anomaly
detection, fetch current data, analyse against domain heuristics with baseline
context, then report structured and classified findings.

The **cross-cutting** specialist does NOT include a Baseline step — it consumes
classifications from the domain specialists rather than baselining independently.

```mermaid
sequenceDiagram
Expand All @@ -126,22 +129,29 @@ sequenceDiagram
T-->>S: Available metric names
end

rect rgb(225, 235, 225)
Note over S,T: 2. Baseline (domain specialists only)
S->>T: pcp_fetch_timeseries(names=[...], interval="1hour", start="-7days")
T-->>S: 7-day historical data
S->>T: pcp_detect_anomalies(recent vs 7-day baseline)
T-->>S: Anomaly results (z-scores, directions)
Note over S: Note results for step 4<br/>If insufficient data → threshold-only fallback
end

rect rgb(230, 235, 245)
Note over S,T: 2. Fetch
Note over S,T: 3. Fetch
S->>T: pcp_fetch_timeseries(names=[...])
T-->>S: Time-series data
S->>T: pcp_compare_windows(...) [optional]
T-->>S: Statistical comparison
T-->>S: Current investigation window data
end

rect rgb(245, 235, 225)
Note over S,T: 3. Analyse
Note over S: Apply domain heuristics<br/>Check thresholds & correlations<br/>Identify anomalies
Note over S,T: 4. Analyse
Note over S: Apply domain heuristics<br/>Check thresholds & correlations<br/>Classify: ANOMALY / RECURRING / BASELINE<br/>Assign severity_despite_baseline
end

rect rgb(240, 230, 230)
Note over S,T: 4. Report
S-->>C: Structured findings<br/>(metric, value, severity,<br/>affected window, recommendation)
Note over S,T: 5. Report
S-->>C: Classified findings<br/>(metric, value, classification,<br/>baseline_context, severity,<br/>severity_despite_baseline)
end
```

Expand All @@ -155,8 +165,14 @@ coordinator synthesises findings:
2. **Timeline correlation** — the subsystem that changed first is the likely root
cause
3. **Unified narrative** — tell the story of what happened, not just list findings
4. **Rank by impact** — order by severity and blast radius
5. **Recommend actions** — concrete next steps, not "investigate further"
4. **Rank by classification, then severity** — ANOMALY findings rank above
RECURRING, which rank above BASELINE (severity is secondary sort within each
tier). What changed is more actionable than what has always been wrong.
5. **Call out normal behaviour** — explicitly identify chronic baseline conditions
6. **Highlight recurring patterns** — flag when an apparent anomaly matches a known
recurring pattern (e.g., daily backup window)
7. **Recommend actions** — concrete next steps, not "investigate further"

The output follows a structured format: executive summary → root cause analysis →
findings by severity → recommendations → specialist status.
findings by classification & severity (New Anomalies → Recurring Patterns →
Baseline Behaviour → Normal Operation) → recommendations → specialist status.
37 changes: 37 additions & 0 deletions specs/011-specialist-baselining/checklists/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Specification Quality Checklist: Specialist Historical Baselining

**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2026-03-10
**Feature**: [spec.md](../spec.md)

## Content Quality

- [x] No implementation details (languages, frameworks, APIs)
- [x] Focused on user value and business needs
- [x] Written for non-technical stakeholders
- [x] All mandatory sections completed

## Requirement Completeness

- [x] No [NEEDS CLARIFICATION] markers remain
- [x] Requirements are testable and unambiguous
- [x] Success criteria are measurable
- [x] Success criteria are technology-agnostic (no implementation details)
- [x] All acceptance scenarios are defined
- [x] Edge cases are identified
- [x] Scope is clearly bounded
- [x] Dependencies and assumptions identified

## Feature Readiness

- [x] All functional requirements have clear acceptance criteria
- [x] User scenarios cover primary flows
- [x] Feature meets measurable outcomes defined in Success Criteria
- [x] No implementation details leak into specification

## Notes

- Spec references specific tool names (`pcp_detect_anomalies`, `pcp_fetch_timeseries`) which are domain-specific terminology in this project context, not implementation details — these are the user-facing MCP tool names that the LLM agent invokes.
- The spec references specific file paths in the Scope section, which is acceptable for a purely prompt-engineering feature where the scope is narrow and well-defined.
- All items pass. Spec is ready for `/speckit.plan`.
- Clarification session 2026-03-10: 4 questions asked and resolved (severity_despite_baseline, ranking order, RECURRING detection, cross-cutting scope).
56 changes: 56 additions & 0 deletions specs/011-specialist-baselining/contracts/prompt-contracts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Prompt Contracts: Specialist Historical Baselining

**Feature**: 011-specialist-baselining | **Date**: 2026-03-10

## Contract: No Interface Changes

This feature makes **zero changes** to function signatures or MCP protocol surface.

### specialist_investigate (UNCHANGED)

```python
def specialist_investigate(
subsystem: str,
request: str | None = None,
host: str | None = None,
time_of_interest: str | None = None,
lookback: str | None = None,
) -> list[dict]:
```

- Parameters: unchanged
- Return type: `list[dict]` — unchanged
- MCP registration: unchanged

### coordinate_investigation (UNCHANGED)

```python
def coordinate_investigation(
request: str,
host: str | None = None,
time_of_interest: str | None = None,
lookback: str | None = None,
) -> list[dict]:
```

- Parameters: unchanged
- Return type: `list[dict]` — unchanged
- MCP registration: unchanged

## Content Contracts (Unit Test Assertions)

Since no interfaces change, the "contracts" for this feature are content assertions verified in unit tests:

| Contract | Verified By |
|----------|------------|
| Domain specialists (5) include Baseline step | String assertion: "Baseline" in workflow for cpu, memory, disk, network, process |
| Cross-cutting does NOT include Baseline step | String assertion: "Baseline" NOT in cross-cutting workflow |
| Classification fields in report guidance | String assertion: "classification", "ANOMALY", "RECURRING", "BASELINE" |
| `baseline_context` in report guidance | String assertion: "baseline_context" |
| `severity_despite_baseline` in report guidance | String assertion: "severity_despite_baseline" |
| Coordinator ranks by classification | String assertion: "ANOMALY" ranking guidance in synthesis |
| Graceful degradation | String assertion: "insufficient baseline" or fallback in prompt |

## Existing Contract Tests (UNCHANGED)

The existing contract tests in `tests/contract/test_prompts.py` continue to pass unchanged — they verify prompt registration and argument schemas, which are not modified.
42 changes: 42 additions & 0 deletions specs/011-specialist-baselining/data-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Data Model: Specialist Historical Baselining

**Feature**: 011-specialist-baselining | **Date**: 2026-03-10

## Overview

This feature adds no new Pydantic models or database entities. All changes are to prompt text templates that guide LLM behaviour. The "data model" here describes the report structure fields added to prompt output guidance.

## Report Structure Fields (Prompt-Guided)

These fields are instructed in the specialist report guidance — the LLM produces them as structured text. They are NOT enforced by code; they are advisory prompt instructions.

### Finding Classification

| Field | Type (advisory) | Values | Description |
|-------|-----------------|--------|-------------|
| `classification` | enum string | ANOMALY, RECURRING, BASELINE | Whether the finding is new (anomaly), a known periodic pattern, or normal baseline behaviour |
| `baseline_context` | free text | — | Human-readable comparison to the 7-day baseline (e.g., "CPU idle has been below 15% for the past 7 days") |
| `severity_despite_baseline` | enum string | critical, warning, info, none | Threshold-based severity independent of classification. A BASELINE finding with severity=warning means "your normal is degraded" |

### Classification Decision Rules (LLM Heuristics)

| Classification | Condition |
|---------------|-----------|
| ANOMALY | `pcp_detect_anomalies` reports significant z-score AND pattern does not recur at consistent times in the 7-day timeseries |
| RECURRING | 7-day timeseries shows repeated spikes at consistent times of day (batch jobs, log rotation, backups, cron jobs) |
| BASELINE | Current values are within normal range based on 7-day history (low z-score or no anomaly detected) |

### Coordinator Ranking Order

| Priority | Classification | Severity Sort |
|----------|---------------|---------------|
| 1 (highest) | ANOMALY | critical → warning → info |
| 2 | RECURRING | critical → warning → info |
| 3 (lowest) | BASELINE | critical → warning → info |

## Existing Entities (Unchanged)

- `_SPECIALIST_KNOWLEDGE` dict in `specialist.py` — keys: `prefix`, `display_name`, `domain_knowledge`, `report_guidance`. Structure unchanged; content updated.
- `_specialist_investigate_impl()` signature — unchanged (subsystem, request, host, time_of_interest, lookback)
- `_coordinate_investigation_impl()` signature — unchanged (request, host, time_of_interest, lookback)
- `pcp_detect_anomalies` tool — unchanged (metrics, recent_start, recent_end, baseline_start, baseline_end, z_score_threshold, host, interval)
Loading