Skip to content

#184: drafter row_count_anomaly_by_period scope fix - #194

Merged
wjduenow merged 17 commits into
devfrom
plan/184-anomaly-scope-fix
Jun 3, 2026
Merged

wjduenow merged 17 commits into
devfrom
plan/184-anomaly-scope-fix

Conversation

@wjduenow

@wjduenow wjduenow commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Summary

Super plan for #184 — drafter mis-scopes row_count_anomaly_by_period to date columns on models with audit timestamps (reproduced 3/3 on Phase B of the #179 retest).

Phase: detailing (awaiting approval)
Stories: 8 implementation + Quality Gate + Patterns & Memory = 10 total
Decisions: 11 captured (DEC-001 … DEC-011)

What the plan ships

  • Primary lever: prose-only rewrite of _ROW_COUNT_ANOMALY_SCOPE_INSTRUCTION to explicitly teach model-level scope (closes the LLM-steering gap).
  • Belt-and-braces parser: silent re-attach for column-scoped emissions of all three model-only variants (row_count_anomaly_by_period / row_count_between / unique_combination), with an always-emit _LOGGER.warning AND a durable audit record (parser_reshaped: tuple[ReshapeRecord, ...] on LLMResponseEvent).
  • LLMResponseEvent.audit_schema_version: 1 → 2 — new fixture row + drift-detector strict mirror added; v1 fixture stays valid (extra="ignore").
  • exclude_tests kill-switch beats re-attach — operator opt-out is always honoured.
  • Validation: full 15-candidate Phase B re-aggregation against the intuit_airflow substrate; results land as a "Followup #171 follow-on: Drafter mis-scopes row_count_anomaly_by_period to date columns on models with audit timestamps #184 resolution" section in docs/research/179-test-primitive-expansion-retest.md.

Eight-surface lockstep change (extends #183's six-surface template)

prompts.py + parser.py + audit.py + test_prompts.py + test_prompt_cache_stability.py + test_parser.py + drift detector / fixture + four doc surfaces (draft-ops.md, two .claude/rules/ files, CHANGELOG.md).

Plan document

See plans/super/184-anomaly-scope-fix.md for the full plan — decisions, story breakdown, dependency ordering, and Quality Gate focus areas.

Next steps

  • Review the plan in this PR
  • Reply "approved" / "looks good" to proceed to devolve (beads creation)

Related

Summary by CodeRabbit

  • Bug Fixes

    • Model-only tests (row_count_anomaly_by_period, row_count_between, unique_combination) incorrectly placed under a column are now automatically moved to model scope; a single operator-visible warning is emitted when this happens.
  • Documentation

    • Updated guidance and worked examples to show correct model-level placement and to advise removing prior workarounds.
  • Audit

    • Audit trail now records when the parser performs an automatic re-attachment for forensic visibility.

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b6a16a44-aa7d-4564-8362-031910cbad9e

📥 Commits

Reviewing files that changed from the base of the PR and between aa7623f and 7f8401b.

📒 Files selected for processing (1)
  • docs/research/179-test-primitive-expansion-retest.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/research/179-test-primitive-expansion-retest.md

📝 Walkthrough

Walkthrough

This PR rewrites prompt guidance and adds parser recovery that detects model-only tests emitted under column scope, emits a structured warning, re-attaches them to model scope (with argument revalidation), records ReshapeRecord(s) in a v2 audit event, and updates tests/docs end-to-end.

Changes

Model-only variant scope correction

Layer / File(s) Summary
Audit schema v2 with ReshapeRecord
src/signalforge/draft/audit.py, tests/draft/test_audit.py, tests/fixtures/draft/llm_response_with_reshape_v2.jsonl
New frozen ReshapeRecord model and LLMResponseEvent.parser_reshaped: tuple[ReshapeRecord,...] = (); audit_schema_version default bumped to 2; _build_response_event accepts parser_reshaped and exports updated.
Parser re-attach core logic
src/signalforge/draft/parser.py, src/signalforge/draft/schema.py, tests/draft/test_parser.py
_validate_anchor_contract detects model-only variants in column scope, emits _LOGGER.warning("parser re-attach: %s", json_payload), optionally appends ReshapeRecord, records (col_idx,test_idx) reattach actions, validates test args at model scope via _validate_model_only_test_args, and _apply_reattach_actions rebuilds the frozen CandidateSchema before raising violations; respects exclude_tests and preserves collect-all/no-dedupe semantics.
Prompt scope guidance update
src/signalforge/draft/prompts.py, tests/draft/test_prompts.py, tests/llm/test_prompt_cache_stability.py
Rewrite of _ROW_COUNT_ANOMALY_SCOPE_INSTRUCTION with a worked YAML example teaching model-level placement; prompt-version pin rotated and prompt tests added/updated.
End-to-end wiring through pipeline
src/signalforge/draft/schema.py
draft_from_request initializes reshapes_collected: list[ReshapeRecord], passes it and model.unique_id into parse_draft_response, and attaches parser_reshaped=tuple(reshapes_collected) to the persisted audit event.
Integration tests and drift detector
tests/draft/test_schema.py, tests/draft/test_drift_detector.py, tests/fixtures/draft/llm_response_with_reshape_v2.jsonl
Integration tests validate re-attach and audit JSONL round-trip; drift detector adds StrictReshapeRecord mirror and v2 fixture checks; tests updated for audit_schema_version==2 and parser_reshaped defaults.
User documentation and reference
.claude/rules/business-rule-tests.md, .claude/rules/llm-drafter.md, CHANGELOG.md, docs/draft-ops.md, docs/research/179-test-primitive-expansion-retest.md, plans/super/184-anomaly-scope-fix.md
Business rules, drafter rules, CHANGELOG, ops docs, research notes, and plan updated to describe re-attach conventions (dual prompt+parser defense, exclude_tests precedence, frozen-model rebuild via model_copy(update=...), logger-string formatting constraint, and audit threading).

Sequence Diagram (high-level)

sequenceDiagram
  participant Client as draft_from_request
  participant Parser as parse_draft_response
  participant Anchor as _validate_anchor_contract
  participant Args as _validate_model_only_test_args
  participant Logger as _LOGGER
  participant Rebuilder as _apply_reattach_actions
  participant Audit as _build_response_event

  Client->>Parser: parse candidate (pass reshapes_collected, model_unique_id)
  Parser->>Anchor: validate columns/tests (collect reattach actions)
  Anchor->>Logger: warning("parser re-attach: %s", payload_json)
  Anchor->>Args: re-validate test args at model scope
  Anchor-->>Parser: violations + reattach actions + reshape records
  Parser->>Rebuilder: apply reattach actions (immutable rebuild)
  Rebuilder-->>Parser: rebuilt CandidateSchema
  Parser->>Audit: build event with parser_reshaped
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 I found a test where it didn't belong,

Moved it gently, sang a warning song.
Audit keeps the tale in tidy rows,
Prompt now shows where the model goes.
Hop, reshape, log — the rabbit knows!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: fixing the scoping of row_count_anomaly_by_period in the drafter to resolve issue #184. It is specific, directly related to the core changeset across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 89.74% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

wjduenow added 14 commits June 2, 2026 19:32
Pass 1 (Correctness) fixes:
- New _validate_model_only_test_args helper called from the re-attach
  branch — re-attached tests' date_column / where / unique_combination.columns
  args are now re-validated against model_columns, preserving the
  'fail loud on hallucinations' contract. Without it a re-attached
  row_count_anomaly_by_period(date_column='phantom') silently degraded
  to kept-without-evidence at prune instead of surfacing a typed parser
  violation. (Pass 1 Finding 1, promoted to must-fix per
  qg-pass-3-defer-defensive-tests-fails-codecov.)
- 4 new tests in test_parser.py pinning the new validation path:
  test_reattach_validates_anomaly_date_column_against_model_columns,
  test_reattach_validates_row_count_between_where_against_model_columns,
  test_reattach_validates_unique_combination_columns_against_model_columns,
  test_reattach_preserves_sibling_tests_on_same_column (Pass 1 Finding 2 —
  sibling-test preservation in _apply_reattach_actions was previously
  unpinned).

Pass 4 (Docs+UX) fixes:
- BLOCKER: docs/draft-ops.md audit-fields table updated audit_schema_version
  from 'Currently 1' to 'Currently 2' (was stale post-US-002 bump).
- MAJOR: Added a row to the audit-fields table for the new
  parser_reshaped field, with the back-compat default explanation.
- MINOR: Added operator-workflow cleanup paragraph to docs/draft-ops.md
  parser-re-attach section + CHANGELOG Fixed entry instructing operators
  to remove the pre-fix llm.exclude_tests workaround.
- TRIVIAL: Added sort_keys=True to the parser re-attach WARNING json.dumps
  so the doc sample and the actual emitted bytes share key ordering
  (alphabetical is also diff-friendly across runs).

Pass 2 (Conventions) and Pass 3 (Tests) returned zero findings.

Validation: 3368 passed, 6 skipped, 99 deselected; ruff / format /
pyright all 0 errors.
@wjduenow
wjduenow marked this pull request as ready for review June 3, 2026 13:49
@wjduenow
wjduenow requested a review from Copilot June 3, 2026 13:57
@wjduenow

wjduenow commented Jun 3, 2026

Copy link
Copy Markdown
Owner Author

@CodeRabbit review

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

This PR addresses issue #184 where the LLM drafter incorrectly emits the model-only row_count_anomaly_by_period test at column scope (often on audit timestamp columns), causing the parser’s anchor-contract validation to fail. The change tightens prompt guidance to explicitly teach model-level placement, and adds a parser-side “belt-and-braces” re-attach mechanism with warning + durable audit trail so runs don’t fail when the LLM still mis-scopes.

Changes:

  • Update _ROW_COUNT_ANOMALY_SCOPE_INSTRUCTION to explicitly state model-level placement and include a worked YAML example; rotate prompt version and update cache-stability pin.
  • Add parser support to re-attach column-scoped emissions of model-only variants (row_count_anomaly_by_period, row_count_between, unique_combination) to model scope, emitting a warning and recording reshapes.
  • Bump LLMResponseEvent.audit_schema_version from 1 → 2 and add parser_reshaped audit field, with fixtures + strict drift-detector coverage and end-to-end threading from draft_from_request.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/signalforge/draft/prompts.py Clarifies anomaly test model-level scope and adds worked example; preserves calibration guidance.
tests/draft/test_prompts.py Pins the new scope wording and worked example so prompt regressions fail loudly.
tests/llm/test_prompt_cache_stability.py Updates _EXPECTED_PROMPT_VERSION to match the rotated prompt hash and documents the rotation.
src/signalforge/draft/parser.py Implements column→model re-attach for model-only variants, warning emission, and reshape collection + rebuild.
tests/draft/test_parser.py Adds comprehensive re-attach behavior tests (all 3 variants, warning shape, exclude gate, collect-all, arg validation, sibling preservation).
src/signalforge/draft/audit.py Introduces ReshapeRecord, adds parser_reshaped, and bumps audit_schema_version default to 2.
src/signalforge/draft/schema.py Threads reshapes_collected into parsing and forwards it into the response audit event.
tests/draft/test_schema.py Verifies reshape threading into the audit JSONL and v2 defaults on the no-reshape path.
tests/draft/test_audit.py Updates audit schema default expectations and asserts the new field default.
tests/draft/test_drift_detector.py Adds strict mirrors for ReshapeRecord + v2 fixture validation while keeping v1 fixture valid.
tests/fixtures/draft/llm_response_with_reshape_v2.jsonl New v2 audit fixture exercising the reshape path.
docs/draft-ops.md Documents the new audit field and the parser re-attach behavior (including exclude_tests precedence).
docs/research/179-test-primitive-expansion-retest.md Adds follow-up writeup section describing the #184 resolution and partial validation results.
CHANGELOG.md Adds Fixed + Changed entries for the scope fix and audit schema bump.
.claude/rules/llm-drafter.md Documents the parser re-attach carve-out and invariants (exclude gate, collect-all, warning shape, no dedupe).
.claude/rules/business-rule-tests.md Captures #184 as a durable pattern for dual-defence prompt+parser fixes with audit visibility.
plans/super/184-anomaly-scope-fix.md Adds the detailed plan/DEC log and acceptance criteria for the change set.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@wjduenow wjduenow changed the title #184: drafter row_count_anomaly_by_period scope fix (plan) #184: drafter row_count_anomaly_by_period scope fix Jun 3, 2026
@wjduenow
wjduenow requested a review from Copilot June 3, 2026 14:09

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

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Comment thread docs/research/179-test-primitive-expansion-retest.md Outdated
Copilot flagged that the writeup overclaimed DEC-008's acceptance bar.
The plan's DEC-008 explicitly committed to all 15 Phase B candidates;
the partial 3-of-15 run was an opt-in budget concession, not the bar
DEC-008 set. Adjusted to honestly mark the remaining 12 candidates as
PENDING and to scope the 3-candidate evidence to 'the bug is fixed on
the load-bearing failure shape' (necessary but not sufficient for the
full DEC-008 close). No code changes — research-doc clarification only.
@wjduenow

wjduenow commented Jun 3, 2026

Copy link
Copy Markdown
Owner Author

PR Review Summary

Fixed (1 item)

File Line Issue Commit
docs/research/179-test-primitive-expansion-retest.md 348 Writeup overclaimed that DEC-008's acceptance bar permits a 3/15-candidate run; the plan's DEC-008 actually commits to all 15. 7f8401b

The writeup now honestly marks Status: PARTIAL — 3 of 15 candidates run, names the remaining 12 candidates as PENDING, and scopes the 3-candidate evidence to "the bug is fixed on the load-bearing failure shape" (necessary but not sufficient for the full DEC-008 close). A future maintainer-side pass with a fresh API window (or chunked across sessions to avoid the Anthropic rate-limit pressure that capped this run) will close the gap.

False Positives (0 items)

No false positives in this review pass.

@wjduenow
wjduenow merged commit 857c79f into dev Jun 3, 2026
6 checks passed
@wjduenow
wjduenow deleted the plan/184-anomaly-scope-fix branch June 3, 2026 15:07
@coderabbitai coderabbitai Bot mentioned this pull request Jun 10, 2026
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.

2 participants