Skip to main content

ADR-189: Activity Association Fallback Strategies

Status

ACCEPTED (2026-01-28)

Context

Problem Statement

The J.14 Activity-Project Association Pipeline extracts activities from LLM sessions and associates them with projects and TRACK task IDs. However, not all activities can be confidently associated:

ScenarioFrequencyChallenge
No task ID in tool_description~22%Governance hooks not enforced pre-ADR-074
Path doesn't match known project~15%Generic paths like /tmp, ~/.config
Multiple possible tracks~8%Activity spans multiple domains
Completely unassociated~22%No signals available

Current State (Before)

Activities without clear associations were stored with:

  • task_id = NULL
  • track = NULL
  • project_name = NULL
  • confidence = 0.0
  • association_method = 'unassociated'

Problems:

  1. Query Ambiguity: WHERE track IS NULL conflates "unknown" with "genuinely no track"
  2. No Resolution Path: No way to flag for review or track resolution attempts
  3. Lost Context: No record of why association failed

Decision

Four-Tier Confidence Model

Establish clear tiers with distinct behaviors:

TierMethodConfidenceTriggerAction
1explicit0.99Task ID in tool_descriptionDirect association
2path0.85File path matches projectProject association, track inferred
3temporal0.70Nearby activity has task IDInherit from context
4ambiguous0.50Multiple candidatesFlag for resolution
5unassociated0.00No signalsDefault sentinel values

Sentinel Values

Use explicit sentinel values instead of NULL for queryability:

-- Sentinel value conventions
'_NONE' -- Definitively no track/project (e.g., system activity)
'_UNKNOWN' -- Could not determine (needs investigation)
'_AMBIGUOUS' -- Multiple candidates (needs resolution)
NULL -- Genuinely not applicable (rare)

Database Field Defaults

Scenariotask_idtrackproject_nameconfidencemethod
Explicit match'H.8.1.6''H''coditect-core'0.99'explicit'
Path onlyNULL'H''coditect-core'0.85'path'
Temporal'H.8.1.6''H''coditect-core'0.70'temporal'
Ambiguous'_AMBIGUOUS''_AMBIGUOUS''_AMBIGUOUS'0.50'ambiguous'
UnassociatedNULL'_NONE''_UNKNOWN'0.00'unassociated'

Resolution Support Schema

Add columns to support resolution workflow:

-- New columns in activity_associations table (sessions.db)
candidate_tasks TEXT, -- JSON: ["H.8.1", "J.14.1"]
candidate_projects TEXT, -- JSON: ["coditect-core", "rollout"]
needs_review INTEGER, -- 1 if flagged for human/LLM review
resolution_notes TEXT, -- Notes from resolution attempts
resolved_at TEXT -- Timestamp when resolved

Resolution Strategies

When activity is ambiguous or unassociated, apply these strategies in order:

┌─────────────────────────────────────────────────────────────────┐
│ Resolution Strategy Cascade │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. SESSION CONTEXT (±5 messages) │
│ │ Look for explicit task IDs in surrounding messages │
│ │ If found → inherit task_id, confidence = 0.70 │
│ ▼ │
│ 2. TEMPORAL PROXIMITY │
│ │ Find most recent explicit task in same session │
│ │ If < 10 messages ago → inherit, confidence = 0.65 │
│ ▼ │
│ 3. PATH HIERARCHY │
│ │ Derive track from project structure │
│ │ /coditect-core/agents/ → Track H (Framework) │
│ │ If match → confidence = 0.60 │
│ ▼ │
│ 4. LLM SEMANTIC (Future) │
│ │ Use LLM to classify content against track descriptions │
│ │ If high similarity → confidence = 0.55 │
│ ▼ │
│ 5. FLAG FOR REVIEW │
│ Set needs_review = 1, store in candidate_* columns │
│ │
└─────────────────────────────────────────────────────────────────┘

Query Patterns

-- Find all unassociated activities
SELECT * FROM activity_associations
WHERE association_method = 'unassociated';

-- Find activities needing review
SELECT * FROM activity_associations
WHERE needs_review = 1;

-- Find ambiguous activities with candidates
SELECT *,
json_extract(candidate_tasks, '$') as candidates
FROM activity_associations
WHERE association_method = 'ambiguous';

-- Confidence distribution
SELECT
association_method,
COUNT(*) as count,
ROUND(AVG(confidence), 2) as avg_conf
FROM activity_associations
GROUP BY association_method;

Consequences

Positive

  1. Clear Querying: Sentinel values enable unambiguous filtering
  2. Resolution Path: needs_review flag enables workflow
  3. Audit Trail: resolution_notes captures why decisions were made
  4. Candidate Tracking: JSON arrays preserve alternatives

Negative

  1. Schema Change: Existing data needs migration
  2. Complexity: More columns to manage
  3. Resolution Overhead: Manual review for ambiguous cases

Metrics

Track resolution effectiveness:

MetricTarget
Explicit associations> 25%
Path-based associations> 50%
Unassociated activities< 20%
Needs review queue< 100 items

Implementation

Phase 1: Schema Update (Complete)

Updated activity_project_associator.py schema with:

  • Sentinel value documentation
  • candidate_tasks, candidate_projects columns
  • needs_review, resolution_notes, resolved_at columns

Phase 2: Resolution Strategies (Planned)

class ResolutionStrategy:
"""Base class for resolution strategies."""

def resolve(self, activity: ActivityAssociation) -> Optional[Resolution]:
raise NotImplementedError

class SessionContextStrategy(ResolutionStrategy):
"""Look at surrounding messages for task IDs."""

def resolve(self, activity):
nearby = get_nearby_messages(activity.session_id, ±5)
for msg in nearby:
if task_id := extract_task_id(msg):
return Resolution(
task_id=task_id,
confidence=0.70,
method='temporal',
notes='Inherited from nearby message'
)
return None

Phase 3: Review Dashboard (Planned)

Create /cxq --needs-review command to surface activities needing attention.

  • ADR-118: Four-Tier Database Architecture (sessions.db)
  • ADR-054: Track Nomenclature Standard
  • ADR-074: Governance Hooks (task_id_validator)

Changelog

DateChange
2026-01-28Initial version

Track: J.14 (Memory - Activity-Project Association) Task: J.14.1.3