Living document tracking bugs, improvements, and new features. Work proceeds in phases: fix bugs first, then improve existing code, then add new capabilities.
Critical issues that affect correctness or maintainability.
Status: DONE
Evidence: The CHANGELOG documents extensive experimentation proving LLMs cannot reliably check multiple rules simultaneously. Yet the primary code path still does exactly that.
Fix:
- Refactor
review_lecture_smart()to usereview_lecture_single_rule()for each category - Remove
_review_category()andreview_lecture()(dead/superseded methods) - Remove
check_style()fromAnthropicProvider(no longer needed) - Ensure single-rule evaluation is the ONLY path for all modes
Files: style_checker/reviewer.py
Status: DONE
- Remove the first (older) implementation
- Verify the second implementation is the one used by
main.py - Confirm tests still pass
Files: style_checker/github_handler.py
Status: DONE
-
parser_md.py— removed (was not imported by any production code) -
review_lecture()method inreviewer.py— removed - Removed associated tests:
test_parser_md.py,test_semantic_grouping.py,test_migration.py - Removed
verify_setup.py(referenced dead parser) - Removed unused
--github-refargument frommain.py - Removed unused
load_promptimport fromreviewer.py
Files: style_checker/parser_md.py, style_checker/reviewer.py, style_checker/main.py, tests/
Status: DONE
- Removed
PyYAML(not imported by action code) - Removed
python-dateutil(not imported by action code) - Verified action imports still work
Files: requirements.txt
All docs should be accurate before adding new features.
Status: DONE
- Update README badge from
0.5.0to match__init__.pyversion - Fix "50+ rules" claim to "49 rules" in README
- Ensure CHANGELOG, README, and
__init__.pyall reference the same version at release
Status: DONE
Complete rebuild from rule files (source of truth). The old version had 15+ type/description mismatches.
- Update rule count (49 actual, doc said 48)
- Update rule type count (32 actual, doc said 31)
- Fix all rule type assignments to match rule files
- Fix all rule titles/descriptions to match rule files
- Add missing
qe-writing-008entry - Fix
qe-writing-006andqe-writing-007descriptions (were swapped)
Status: DONE
-
CONTRIBUTING.md— removedLLMProvider/check_style()references, fixed priority taxonomy -
testing-quick-reference.md— replacedtest_basic.pyrefs with current test files, updated coverage stats -
tests/README.md— rewritten to list current test files, removedverify_setup.pyreference -
production-testing.md— updated@v0.4to@v0.5 -
ci-cd-setup.md— added historical note, marked CI pipeline as not yet created
Status: DONE
- Add version comments to all 8 prompt files:
<!-- Prompt Version: 0.5.1 | Last Updated: 2026-02-12 | Single rule per LLM call --> - Updated
writing-prompt.mdversion from0.3.23to0.5.1
Status: DONE
- Define evaluation order for all 8 categories in
reviewer.py - Follow the principle: mechanical → structural → stylistic → migrate
The test suite has gaps and some tests don't test the right things.
Status: DONE
- Rewrite to import and test the real
GitHubHandler.extract_lecture_from_comment()method - Remove duplicated parsing logic (TestHandler class with copied regex)
- Use pytest class structure with 11 focused test cases
- Fix
PytestReturnNotNoneWarning(was returning True/False instead of using assertions)
Status: DONE — No hardcoded paths found in test_llm_integration.py (may have been cleaned up previously).
Status: DONE
-
fix_applier.py— Addedtest_fix_applier.py(13 tests):apply_fixes()andvalidate_fix_quality() -
prompt_loader.py— Addedtest_prompt_loader.py(9 tests): single/multi category, all categories, invalid category, version tracking -
extract_individual_rules()— Addedtest_reviewer.py(15 tests): rule counts, types, order, field validation -
main.py— No unit tests yet (requires significant mocking of CLI/GitHub/LLM — deferred)
Status: DONE
-
test_parsing.pyrewritten to use assertions (warning fixed) -
test_migration.pywas deleted in Phase 1 (tested removed parser)
Status: DONE
- Updated
.github/workflows/ci.yml— runs unit tests on push/PR to main - Ruff for linting (replaced flake8/black/isort)
- Python 3.11, 3.12, 3.13 matrix
- Removed stale
verify_setup.pyreference and integration job
Reduce LLM hallucinations, improve fix accuracy, and move mechanical rules to deterministic checking. Full analysis and rule-by-rule review in IMPROVEMENTS.md.
Add validation to fix_applier.py to prevent destructive fixes:
- Reject fixes that replace headings (
#) with non-heading content - Reject fixes that replace/remove directives (
```) - Reject fixes where
current_textandsuggested_fixhave very low similarity (edit distance check) - Reject fixes that change more than 10 lines
- Validate resulting markdown structure after all fixes applied
Replace free-text quoting with line-number targeting:
- Add
add_line_numbers(content)utility to prependL001:to each line - Update all 8 prompt templates to instruct LLM to reference line ranges
- Update
parse_markdown_response()to extract line ranges - Update
fix_applier.pyto use line-based targeting instead ofstr.replace()
Move ~13 rules to regex/programmatic checking (zero hallucination risk):
- Create
deterministic_checker.pywith pattern-matching checks - Move qe-writing-008 (whitespace), qe-math-002 (transpose), qe-math-003 (pmatrix), qe-math-004 (mathbf), qe-math-006 (aligned), qe-math-007 (\tag detection)
- Move qe-fig-003 (set_title detection), qe-fig-007 (spine removal), qe-admon-004 (prf prefix)
- Move qe-code-004 (time.time detection), qe-code-005 (%timeit detection)
- Run deterministic checks before LLM calls to reduce API usage
- Integrate results into existing violation/fix pipeline
Improve rule descriptions to reduce LLM misinterpretation (12 rules):
- qe-writing-001: Add exclusion list (code blocks, math, lists, frontmatter, edge cases)
- qe-writing-002: Raise word threshold, add "show which words to remove" guidance
- qe-writing-004: Add proper noun exception list for economics/math terms
- qe-writing-005: Add exclusions (links, admonitions, slang); narrow "definition"
- qe-math-001: Restrict to Greek letters only, don't convert
$x$→x - qe-math-008: Clarify scope (first use, define before use)
- qe-math-009: Narrow to avoid flagging standard mathematical notation
- qe-code-003: Add explicit Anaconda package list, structural fix guardrail
- qe-fig-004: Relax word count limit, focus on formatting rules
- qe-admon-001: Add examples showing gated syntax pattern
- qe-admon-003: Add examples showing tick count nesting
- qe-admon-005: Add examples showing solution-exercise linking
Reconsider rules that produce noise:
- qe-writing-003 (logical flow) — make advisory-only or remove
- qe-writing-007 (visual elements) — make advisory-only or remove
- qe-fig-002 (prefer code-generated) — make advisory-only or remove
Status: PLANNED
Currently 8 identical {category}-prompt.md files exist in style_checker/prompts/. They were made identical in v0.7.0 after experiments showed category-specific prompt instructions hurt accuracy (signal dilution, scope conflicts). The rule definitions already carry all category context.
What we learned (v0.7.0 experiments):
- Category-specific prompts were ~90% identical boilerplate with minor category wording
- The boilerplate diluted the task signal (~60% format template, ~15% actual task)
- "Decision process" instructions (e.g., "for each paragraph...") triggered exhaustive classify-everything behavior, generating false positives
- Scope instructions (e.g., "skip code blocks") are rule-specific — writing rules check narrative, code rules check code blocks — so they can't be in a shared prompt
- The RULE definition already specifies its own unit of analysis, scope, and violation criteria
- A minimal rule-agnostic prompt (identity + task + format template) performs best
Plan:
- Consolidate 8 identical files into a single
style_checker/prompts/prompt.md - Update
create_single_rule_prompt()inreviewer.pyto load the single file - Remove per-category file loading (
{category}-prompt.mdpattern) - Keep per-category files as a fallback option: if
{category}-prompt.mdexists, use it; otherwise fall back toprompt.md - Update
test_prompt_loader.pytests - Update copilot-instructions.md to reflect single prompt architecture
Deferred until: Extended thinking + minimal prompt approach is validated across all 8 categories in production use.
Status: DONE (v0.7.0)
Extended thinking lets Claude reason internally before outputting, which eliminates the report-then-retract pattern that caused false positives.
Experiment results (qe-writing-001 on test lecture):
| Approach | Violations | False Positives | FP Rate |
|---|---|---|---|
| Baseline (verbose prompt, no thinking) | 21 | 9 | 43% |
| Minimal prompt, no thinking | 27 | 13 | 48% |
| Minimal prompt + "verify first" | 16 | 10 | 63% |
| Minimal prompt + "analyze then report" | 20 | 8 | 40% |
| Minimal prompt + extended thinking | 6 | 0 | 0% |
Root cause: Without extended thinking, the model commits tokens before finishing analysis (autoregressive generation). It reports a violation, then realizes the text is already compliant, and either retracts inline or emits identical current/suggested text. No amount of prompt instruction can fix this because the model can't "undo" tokens once written.
Implementation:
-
AnthropicProviderusesthinking={"type": "enabled", "budget_tokens": 10000} - Temperature set to 1.0 (Anthropic requirement for extended thinking)
- Streaming fallback handles thinking + text content blocks
- Previous prompts archived in
style_checker/prompts/v0.6.1/
The core goal: make it easy for authors to review and accept/reject style suggestions.
Improve format_style_suggestions_report() output:
- Add line number references for each suggestion
- Use side-by-side table format for current vs. suggested text
- Cap displayed suggestions (e.g., top 10) to prevent suggestion fatigue
- Improve language: "suggestion" not "violation" throughout
The big UX win. Post style suggestions as PR review comments with suggestion blocks. Authors get a one-click "Commit suggestion" button.
How it works:
- PR is created with rule fixes applied (as today)
- For each style suggestion, post a PR review comment on the relevant line:
**qe-writing-002** — Simplify for clarity ```suggestion This algorithm was first developed by Bellman in 1957. ``` - Author clicks "Commit suggestion" to accept, or ignores it
Constraint: Suggestion blocks only work on lines in the PR diff. For lines not in the diff, fall back to the formatted comment approach from 5.1.
Implementation:
- Add line-number tracking to violation data (LLM already provides
location) - Parse line numbers from violation location field
- Build
find_line_in_diff()utility to check if a line is in the PR diff - Use PyGithub
pull.create_review(comments=[...])to post suggestion blocks - Fall back to comment-based format for suggestions not in diff
- Test with real lectures
- Parse
usagefield from Anthropic API responses - Aggregate tokens by rule, category, and lecture
- Add usage summary to PR comment
- Expose as action output for workflow access
Longer-term features, after the foundation is solid.
Trigger style checking automatically when a PR is opened against the lecture repo.
- New
--mode proption - Parse PR diff to identify changed
.mdfiles - Review only changed files
- Post results as PR review comments (integrates with 5.2)
- Tag rules with
scope: linevsscope: documentmetadata
For style suggestions not in the diff (can't use suggestion blocks):
- Post structured checkbox list in PR comment
- Author checks desired items, comments
/apply-style - Action triggers, parses checked items, applies as new commit
- Resume capability for bulk reviews (track progress in state file)
- Progress reporting:
[15/47] Reviewing: intro_to_python.md - Estimated time remaining
- Partial failure handling with retry
- Track suggestion acceptance rates (manual initially)
- Use data to promote reliable style → rule
- Use data to identify rules needing prompt improvements
Improve tool-style-checker/ for pre-submission author workflow:
- Structured terminal output with file:line references
- Machine-readable output format (JSON) for editor integration
- Share prompts/rules with main action (already partially done)
- Interactive mode: review suggestions one at a time
Phase 1 (Bugs) ──→ Phase 2 (Docs) ──→ Phase 3 (Tests) ──→ Phase 4 (Reliability) ──→ Phase 5 (UX) ──→ Phase 6 (Features)
│ │ │ │
│ │ │ └── 4.3 (deterministic) enables 4.2 (line numbers)
│ │ └── 3.5 CI should land before Phase 4+
│ └── Can run parallel with Phase 1
│
└── 1.1 (architecture fix) is prerequisite for everything else
- 1.1 must be done first — it fixes the core evaluation path
- 1.2, 1.3, 1.4 are independent and quick
- Phase 2 can start in parallel with Phase 1 (different files)
- Phase 3 depends on Phase 1 (dead code removal changes what tests exist)
- Phase 4 depends on Phases 1-3 being stable — focuses on reducing hallucinations
- Phase 4.1 (guardrails) is the quickest safety win
- Phase 4.3 (deterministic) reduces the LLM surface area before 4.2 (line numbers) changes the prompt format
- Phase 4.4 (rule clarity) can run in parallel with 4.1-4.3
- Phase 5 depends on Phase 4 reliability improvements being proven
- Phase 6 depends on Phase 5 patterns being proven
| Version | Includes | Status |
|---|---|---|
| 0.6.0 | Phase 1 + Phase 2 (bugs, docs, rule clarity) | Done |
| 0.6.1 | Anti-false-positive prompt instruction (all 8 prompts) | Done |
| 0.7.0 | Extended thinking, minimal unified prompt, qestyle CLI, test improvements | Done |
| 0.8.0 | Phase 4.1 + 4.4 (guardrails, rule clarity) | Not started |
| 0.9.0 | Phase 4.2 + 4.3 + 4.6 (line numbers, deterministic checkers, prompt consolidation) | Not started |
| 0.10.0 | Phase 5.1-5.2 (suggestion UX, suggestion blocks) | Not started |
| 0.11.0 | Phase 5.3 + Phase 6.1 (tracking, PR mode) | Not started |
| 1.0.0 | Stable release after production validation | Not started |