# redmine handoff ## Where to find things - Project rules: `/home/jason/projects/redmine/PROJECT.md` - Active checklist: `/home/jason/projects/redmine/PLAN.md` - Main script touched: `/home/jason/projects/redmine/redmine_contacts.py` - Ticket sync script: `/home/jason/projects/redmine/redmine_tickets.py` - Tests added: `/home/jason/projects/redmine/tests/test_redmine_contacts.py` - Ticket sync tests: `/home/jason/projects/redmine/tests/test_redmine_tickets.py` - Ticket spam cleanup handoff: `/home/jason/projects/redmine/docs/ticket_spam_cleanup_handoff_2026-07-09.md` - Known-spam fast close plan: `/home/jason/projects/redmine/docs/known_spam_fast_close_plan.md` - Rebot legacy spam rules: `/home/jason/projects/redmine/docs/rebot_legacy_spam_rules.md` - Known-spam profile seed: `/home/jason/projects/redmine/profiles/known-spam/customer-service.json` - Ticket decomposition plan: `/home/jason/projects/redmine/docs/ticket_decomposition_knowledge_ingestion_plan.md` - Obsidian process note: `/home/jason/lilaBuild/vaults/obsidian-ldr/Processes/Redmine/ticket-decomposition-and-knowledge-ingestion.md` - Decomposition pilot contact proposals: `/home/jason/projects/redmine/docs/decomposition_pilot_contact_update_proposals_2026-07-09.json` - KarpathyWiki plugin inspection: `/home/jason/projects/redmine/docs/karpathywiki_plugin_inspection.md` ## Last completed milestones 1. Applied the shared PROJECT template into this repo with redmine-specific requirements and continuity-doc expectations. 2. Implemented and tested `redmine_contacts.py` upgrades: - date/tag filtering helpers used by `fetch` + `search` - `show` command (cache/api source) - `issue-full` command (issue + helpdesk context) - `update` tag and custom-field ergonomic options (`--add-tag`, `--remove-tag`, `--set-custom-field`) 3. Added unit tests for new filter/tag/custom-field behavior and verified: - `python3 -m unittest discover -s tests -p 'test_redmine_contacts.py' -v` - `python3 -m py_compile redmine_contacts.py` 4. Completed LAN integration validation on `192.168.50.170`: - validated `show --source api` and `issue-full` - executed safe `update --apply` on contact `14` with temporary tag/custom-field, then rolled it back to original state - locked fetch behavior: default `fetch` caches full results; filtered cache requires `--cache-mode filtered` 5. Implemented and verified a dry-run-first `batch-update` command: - supports date/tag filters + `--max-contacts` - supports shared update payload options (`--set`, `--add-tag`, `--remove-tag`, `--set-custom-field`) - defaults to dry-run output and only writes when `--apply` is passed 6. Implemented deterministic batch ordering + UX upgrades: - added `batch-update --order` with choices: - `as-is` - `oldest-updated-first` / `newest-updated-first` - `oldest-created-first` / `newest-created-first` - `id-asc` / `id-desc` - added tests for oldest-updated-first ordering and missing-timestamp behavior - expanded argparse `--help` descriptions/options across commands - added Bash completion script at `/home/jason/projects/redmine/redmine_contacts_completion.sh` and verified with `bash -n` 7. Captured Jason's broader contact triage loop vision in: - `/home/jason/projects/redmine/docs/contact_triage_loop_workflow.md` - includes workflow explanation, scoring rubric examples, queue-tag architecture, and a mermaid loop diagram - linked the document from `/home/jason/projects/redmine/README.md` for discoverability 8. Adjusted `fetch` filter behavior to match expected UX: - `fetch --cache-mode auto` (default) now caches filtered results when any filter flag is supplied - `--cache-mode full` remains available for canonical full-snapshot caching - added tests for `resolve_fetch_cache_mode` and verified against LAN command example 9. Implemented and verified ticket-centric sync/search foundation: - new `/home/jason/projects/redmine/redmine_tickets.py` - new `/home/jason/projects/redmine/tests/test_redmine_tickets.py` - `sync` command caches enriched issue payloads using standard `/issues` API with `include=journals,helpdesk` - per-project cache under `.cache/redmine_tickets_lan/customer-service/*.json` - `manifest.json` tracks `updated_on`, local cache paths, and per-ticket action idempotency markers - `search` command filters cached issues without API calls - `spam-check` action scores cached tickets for promotional/spam signals and can record local idempotency with `--apply` 10. LAN validation completed on `192.168.50.170` / `customer-service`: - dry-run: `seen=10 fetched=10 skipped_cached=0 written=0` - cache write: `seen=10 fetched=10 skipped_cached=0 written=10` - immediate second sync: `seen=10 fetched=0 skipped_cached=10 written=0` - cached search showed newest open tickets matching UI, including `#41788` / `#41789` “Up to 20% Off Select Fans & Blowers” - `spam-check` flagged `#41788` and `#41789` as `SPAM` (`score=2`) and left the other 8 as not-spam/low-score - `spam-check --apply` recorded local manifest action markers; a second `spam-check` checked 0 tickets - `close-if-spam` dry-run planned closures for `#41788` and `#41789` with payload `{status_id: 5, notes: ...}` - `close-if-spam` fetched/reviewed sender `contact_id=621` history and found `4/10` recent tickets scoring as spam, so `likely_spammer=True` - no Redmine ticket close mutation has been applied yet; `close-if-spam --apply` is pending explicit approval - `close-if-spam --apply` defaults write impersonation to `--impersonate-user rebot`; reads/dry-runs do not impersonate - tests verified: `python3 -m unittest discover -s tests -p 'test_redmine_tickets.py' -v` (`23` tests) - compile verified: `python3 -m py_compile redmine_tickets.py tests/test_redmine_tickets.py redmine_contacts.py` ## Next step and why Jason identified the Obsidian KarpathyWiki plugin as close to the desired decomposition behavior. Inspection found it has no standalone CLI and depends on Obsidian `App/Vault/TFile` APIs, but its prompts/schema are strong references for a headless mirror. Compatibility rule: the plugin owns `obsidian-ldr/wiki/` (`wiki/entities`, `wiki/concepts`, `wiki/sources`, `wiki/index.md`, `wiki/log.md`), so the Python decomposer must not write there by default; use LDR-owned paths like `Timeline/`, `entities/organizations/`, and `Processes/Redmine/`, with explicit wikilinks to plugin pages when useful. Current implementation: `redmine_tickets.py decompose --issue-id/--input-json --format json|markdown` produces dry-run plans and includes a KarpathyWiki-style structured extraction layer (`summary`, `entities`, `concepts`, `key_points`, `contradictions`, `clean_text`) for the three pilot tickets. Tests pass (`23` tests). Dry-run outputs live under `.cache/decomposition-pilot-20260709/dry-run-output/`. Next: add prompt-driven/LLM JSON extraction for broader ticket types, then compare output quality against hand-written pilot notes before adding vault-write mode.