Skip to content

refactor(triage): agent-supplied category + exclusion + canonical context + owner-input rule - #8

Merged
br4vesirrobin merged 4 commits into
mainfrom
refactor/triage-agent-supplied-category
Jul 14, 2026
Merged

refactor(triage): agent-supplied category + exclusion + canonical context + owner-input rule#8
br4vesirrobin merged 4 commits into
mainfrom
refactor/triage-agent-supplied-category

Conversation

@br4vesirrobin

Copy link
Copy Markdown
Contributor

Summary

Pivots the triage feature (from #7) to an agent-in-the-loop model and adds precision controls so that being from an important sender is not enough — a task is created only when the email genuinely requires the owner's input.

Built by deep-interview intent → implement → code-review (APPROVE) → live-verified against a real mailbox + Asana.

What changed

  • Agent is the classifier. Removed the in-process LLM categorizer (judge_category/httpx/llm.*) from triage. The agent reads candidates and supplies the CategoryDecision. classifier.py + llm.* are untouched (they still power folder classification).
  • Two-command interface (the pipeline auto-hook is removed — headless process can't classify):
    • kontor-cli triage — lists qualifying candidates (with bodies + canonical folder), read-only.
    • kontor-cli triage-create --email-id --category [--deadline] [--no-dry-run] — creates one idempotent Asana task (dedup marker kontor-id:<message-id|uid> scoped to the target project). Defaults to dry-run.
  • Exclusion ruleis_automated() heuristic + config triage.exclude_senders (no-reply/notifications/digests/*.mail.microsoft/Office365Reports/Google/Miro/Azure/…). Notification & platform mail never becomes a task.
  • Customer rule tightened — a bare external sender no longer auto-qualifies; it needs content signal. The deterministic gate is explicitly a recall net.
  • Owner-input precision ruletriage.owner_email + SKILL rubric: create a task only when the content requires the owner's personal input/action (decision/review/approval/answer). Sender importance alone is never sufficient — this is the agent's judgment.
  • Canonical-structure context — each candidate carries its taxonomy folder (e.g. 2_Projects/PRJ_Willemen) from the deterministic rules engine (lazy, best-effort) to inform categorization.
  • Cleanuptriage_enabled now gates the CLI; removed the vestigial triage.scan_rebuild.

Live verification (real mailbox → Asana)

  • Gate after exclusion tuning: 140 → 79 candidates (automated noise dropped; real customers like Willemen/Eiffage kept).
  • Precision rule proven: 5 "important sender but no action" emails (a "thanks" reply, four "approved" confirmations) → 0 tasks; 5 genuine asks (PR review on a customer blocker, budget approval, AI investment input, license approvals) → 5 correctly-categorized tasks. Re-run → skipped_dedup.

Tests

228 tests pass, coverage 94% (≥90 gate), ruff check + ruff format --check + mypy --strict clean. Code-reviewer: APPROVE (2 LOW findings fixed in the follow-up commit).

🤖 Generated with Claude Code

@br4vesirrobin
br4vesirrobin force-pushed the refactor/triage-agent-supplied-category branch from ed8093e to 1e5f9b8 Compare July 14, 2026 10:37
@br4vesirrobin

Copy link
Copy Markdown
Contributor Author

Autobahn forward-port completed against current main at 68c47bc.

Key repairs in the refreshed head 1e5f9b8:

  • replaced the deleted legacy rules-engine integration with the current canonical Pipeline.classify_with_rules() path;
  • preserved agent-supplied categorization and dry-run-by-default behavior;
  • made real Asana writes validate configured projects before mailbox access;
  • made Asana dedup/create API failures fail nonzero instead of being reported as skipped;
  • enforced exact dashed YYYY-MM-DD deadlines before mailbox access;
  • added current AI-SDLC intake, specification, handoff, traceability, and workflow evidence;
  • expanded regression coverage, including the --no-dry-run write path.

Local verification on the published head:

  • 249 tests passed
  • Ruff check and format check passed
  • mypy passed
  • AI-SDLC validation, rules validation, and archgate passed
  • independent architecture and code-review passes approved the exact head

Fresh hosted checks are now running; this PR will be merged only if they are all green.

br4vesirrobin and others added 4 commits July 14, 2026 12:42
…l context

Pivot triage from a configured-LLM call to an agent-in-the-loop model and add
precision controls so important senders alone don't generate Asana tasks.

- Remove the in-process LLM categorizer (judge_category/httpx/llm.*) from
  triage; the agent now reads candidates and supplies the CategoryDecision.
  classifier.py + llm.* are untouched (they still drive folder classification).
- Replace the pipeline auto-hook (can't classify headlessly) with a two-command
  agent interface: `triage` lists qualifying candidates (with bodies), and
  `triage-create --email-id --category [--deadline] [--no-dry-run]` creates one
  idempotent task. Pipeline returns to its pre-triage behavior.
- Exclusion rule: is_automated() heuristic (no-reply/notifications/digests/
  *.mail.microsoft/Office365Reports/…) + config-driven triage.exclude_senders,
  so notification/newsletter/platform mail never becomes an action item.
- Customer rule now requires content signal (a bare external sender no longer
  auto-qualifies). The deterministic gate is explicitly a recall net.
- Owner-input precision rule: triage.owner_email + SKILL rubric — create a task
  only when the email genuinely requires the owner's personal input/action;
  sender importance alone is never sufficient. The agent makes this call.
- Canonical-structure context: each candidate carries its taxonomy folder from
  the deterministic rules engine (lazy, best-effort) to inform categorization.

226 tests pass, coverage 94% (>=90 gate), ruff + mypy strict clean.
…p scan_rebuild

Address code-review LOW findings on the agent-supplied-category refactor:
- Add CliRunner tests for `triage-create --no-dry-run` (the only Asana write
  path, asserting dry_run=False flows through) and the disabled-triage guard.
- Give triage_enabled a runtime role: `triage` and `triage-create` now refuse
  with a clear message when triage.enabled is false (previously orphaned).
- Remove the vestigial triage.scan_rebuild config (its only consumer, the
  pipeline rebuild gate, was removed in the refactor) + its tests/examples.

228 tests pass, coverage 94% (>=90 gate), ruff + mypy strict clean.
@br4vesirrobin
br4vesirrobin force-pushed the refactor/triage-agent-supplied-category branch from 1e5f9b8 to 27aa51e Compare July 14, 2026 10:42
@br4vesirrobin
br4vesirrobin merged commit 055aa07 into main Jul 14, 2026
5 checks passed
@br4vesirrobin
br4vesirrobin deleted the refactor/triage-agent-supplied-category branch July 14, 2026 10:43
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.

1 participant