Skip to content

Feat/context tags delta first#587

Open
mick-gsk wants to merge 2 commits into
mainfrom
feat/context-tags-delta-first
Open

Feat/context tags delta first#587
mick-gsk wants to merge 2 commits into
mainfrom
feat/context-tags-delta-first

Conversation

@mick-gsk

@mick-gsk mick-gsk commented May 2, 2026

Copy link
Copy Markdown
Owner

Summary

Related issue

Policy criterion served

  • Credibility (reproducibility, determinism)
  • Signal precision (fewer false positives/negatives)
  • Finding clarity (better explanations, actionable next steps)
  • Adoptability (easier setup, onboarding, docs)
  • Trend capability (temporal analysis, delta tracking)
  • None of the above — explain why this is still valuable:

First contribution?

  • This is my first contribution to drift

Type of change

  • Bug fix
  • New feature
  • Refactor
  • Documentation
  • Test-only change
  • CI/Build change

Release notes label (required)

  • release:feature
  • release:fix
  • release:maintenance
  • release:docs
  • release:skip (internal-only, should not appear in release notes)

Validation

  • pytest passes locally
  • ruff check src/ tests/ passes locally
  • mypy src/drift passes locally
  • drift self delta checked (target: <= +0.010)
  • Added/updated tests for behavioral changes

Empirical evidence (required for new features)

  • This PR introduces no new feature (skip section)
  • OR: empirical artifact added/updated in benchmark_results/ or audit_results/
  • OR: feature has benchmark/validation output attached in PR description

Evidence summary (required when feature is introduced):

  • Scope / dataset:
  • Baseline result:
  • New result:
  • Reproduction command:
  • Interpretation (precision/noise/runtime impact):

Checklist

  • PR is focused on one concern
  • Public docs updated (README/docs-site) if needed
  • Changelog entry added if user-visible
  • If version/changelog changed: top release entry still fits one short summary plus at most 5 curated bullets
  • No unrelated files included

Risk Audit (POLICY §18 — required for signal/architecture changes)

  • This PR does not touch src/drift/signals/, src/drift/ingestion/, or src/drift/output/ (skip section)
  • OR: audit_results/fmea_matrix.md updated (FP + FN entry for affected signal)
  • OR: audit_results/stride_threat_model.md updated (new/changed trust boundary)
  • OR: audit_results/fault_trees.md reviewed (FT-1/FT-2/FT-3 paths checked)
  • OR: audit_results/risk_register.md updated (new risk entry or metric update)
  • All four audit artifacts still exist and are not deleted

Notes for reviewers

Copilot AI review requested due to automatic review settings May 2, 2026 21:23
@github-actions github-actions Bot added documentation Improvements or additions to documentation output Changes to CLI output or formatters tests Test coverage or fixture improvements config Changes to configuration schema or defaults labels May 2, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds delta-first trend context (ADR-005) and inline context tagging with dampening (ADR-006) to make drift scores interpretable over time and reduce false positives during intentional variance.

Changes:

  • Persist and load score history, compute TrendContext, and surface it in Rich/JSON/SARIF outputs.
  • Implement drift:context pragmas to tag findings, dampen their scores, and emit per-finding metadata plus aggregate counts.
  • Add extensive tests and ADR/docs updates for the new behaviors.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/drift/analyzer.py Applies context-tag dampening, computes trend context from persisted history, and appends new snapshots.
src/drift/context_tags.py New scanner + applicator for drift:context tags and score dampening.
src/drift/models.py Adds TrendContext and new RepoAnalysis fields (trend, context_tagged_count).
src/drift/output/json_output.py Emits trend and context_tagged_count in JSON; adds SARIF properties for context + trend.
src/drift/output/rich_output.py Renders trend delta/sparkline and context tag annotations in terminal output.
src/drift/config.py Adds config knobs for context dampening and delta gating.
tests/test_delta_first.py New tests for trend computation, history persistence, and JSON/SARIF trend output.
tests/test_context_tags.py New tests for scanning/applying context tags, config integration, and output metadata.
tests/test_output_golden.py Updates golden key expectations for new JSON output fields.
drift.example.yaml Documents new config options for context dampening and delta gating.
docs/adr/005-delta-first-score-interpretation.md Adds ADR-005 documenting delta-first interpretation and output contracts.
docs/adr/006-context-tagging.md Adds ADR-006 documenting context-tagging semantics and output.
benchmark_results/drift_self.json Updates benchmark artifact values/shape.
EPISTEMICS.md Adds background rationale for intentional variance + delta interpretation.

Comment on lines +49 to +56
"trend": {
"previous_score": analysis.trend.previous_score,
"delta": analysis.trend.delta,
"direction": analysis.trend.direction,
"recent_scores": analysis.trend.recent_scores,
"history_depth": analysis.trend.history_depth,
"transition_ratio": analysis.trend.transition_ratio,
} if analysis.trend else None,
Comment thread src/drift/analyzer.py
Comment on lines +302 to +303
prev = snapshots[-1]["drift_score"]
delta = round(current_score - prev, 4)
Comment thread src/drift/analyzer.py
else:
direction = "degrading"

recent = [s["drift_score"] for s in snapshots[-5:]]
Comment thread src/drift/analyzer.py
Comment on lines +288 to +290
def _build_trend_context(
current_score: float, snapshots: list[dict],
) -> TrendContext:
Comment thread src/drift/analyzer.py
Comment on lines +312 to 321
recent = [s["drift_score"] for s in snapshots[-5:]]

return TrendContext(
previous_score=prev,
delta=delta,
direction=direction,
recent_scores=recent,
history_depth=len(snapshots),
transition_ratio=0.0,
)
Comment thread src/drift/analyzer.py
Comment on lines +223 to +228
ctx_tags = scan_context_tags(files, repo_path)
all_findings, context_tagged_count = apply_context_tags(
all_findings, ctx_tags, dampening=config.context_dampening,
)
# Re-compute impact after dampening so downstream scoring uses adjusted values
assign_impact_scores(all_findings, config.weights)
Comment thread src/drift/context_tags.py
Comment on lines +97 to +102
merged_tags: set[str] = set()
for line_no in range(start_line, end_line + 1):
key = (f.file_path.as_posix(), line_no)
entry = context_tags.get(key)
if entry is not None:
merged_tags |= entry
Comment thread src/drift/config.py
Comment on lines +110 to +112
context_dampening: float = 0.5
fail_on_delta: float | None = None
fail_on_delta_window: int = 5
Comment on lines +93 to +96
trend_parts: tuple = (
(" ", ""),
(f"Δ {trend.delta:+.3f} {arrow} {trend.direction}", delta_color),
)
Comment on lines +135 to +137
# Trend sparkline (ADR-005)
if trend and trend.recent_scores and trend.direction != "baseline":
scores_str = " → ".join(f"{s:.3f}" for s in trend.recent_scores)
@mick-gsk mick-gsk added the size/XL Diff ≥ 500 lines — consider splitting label May 4, 2026
@github-actions github-actions Bot added the has-conflicts PR has merge conflicts with the base branch label May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

config Changes to configuration schema or defaults documentation Improvements or additions to documentation has-conflicts PR has merge conflicts with the base branch output Changes to CLI output or formatters size/XL Diff ≥ 500 lines — consider splitting tests Test coverage or fixture improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants