IETF Draft Analyzer v0.1.0 — track, categorize, and rate AI/agent drafts
Python CLI tool that fetches AI/agent-related Internet-Drafts from the IETF Datatracker, rates them using Claude, generates embeddings via Ollama for similarity/clustering, and produces markdown reports. Features: - Fetch drafts by keyword from Datatracker API with full text download - Batch analysis with Claude (token-optimized, responses cached in SQLite) - Embedding-based similarity search and overlap cluster detection - Reports: overview, landscape by category, overlap clusters, weekly digest - SQLite with FTS5 for full-text search across 260 tracked drafts Initial analysis of 260 drafts reveals OAuth agent auth (13 drafts) and agent gateway/collaboration (10 drafts) as the most crowded clusters, while AI safety/alignment is underserved with the highest quality scores. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
72
src/ietf_analyzer/models.py
Normal file
72
src/ietf_analyzer/models.py
Normal file
@@ -0,0 +1,72 @@
|
||||
"""Data models for drafts, ratings, and categories."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
@dataclass
|
||||
class Draft:
|
||||
name: str # e.g. "draft-zheng-dispatch-agent-identity-management"
|
||||
rev: str # e.g. "00"
|
||||
title: str
|
||||
abstract: str
|
||||
time: str # ISO datetime from API
|
||||
dt_id: int | None = None # Datatracker document ID
|
||||
pages: int | None = None
|
||||
words: int | None = None
|
||||
group: str | None = None # Working group name (resolved)
|
||||
group_uri: str | None = None # Raw API URI
|
||||
expires: str | None = None
|
||||
ad: str | None = None # Area director URI
|
||||
shepherd: str | None = None
|
||||
states: list[str] = field(default_factory=list)
|
||||
full_text: str | None = None
|
||||
categories: list[str] = field(default_factory=list)
|
||||
tags: list[str] = field(default_factory=list)
|
||||
fetched_at: str | None = None
|
||||
|
||||
@property
|
||||
def text_url(self) -> str:
|
||||
return f"https://www.ietf.org/archive/id/{self.name}-{self.rev}.txt"
|
||||
|
||||
@property
|
||||
def datatracker_url(self) -> str:
|
||||
return f"https://datatracker.ietf.org/doc/{self.name}/"
|
||||
|
||||
@property
|
||||
def date(self) -> str:
|
||||
"""Return just the date portion of time."""
|
||||
if self.time:
|
||||
return self.time[:10]
|
||||
return ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class Rating:
|
||||
draft_name: str
|
||||
novelty: int # 1-5
|
||||
maturity: int # 1-5
|
||||
overlap: int # 1-5 (5 = highly overlapping with others)
|
||||
momentum: int # 1-5
|
||||
relevance: int # 1-5
|
||||
summary: str # 2-4 sentence AI summary
|
||||
novelty_note: str = ""
|
||||
maturity_note: str = ""
|
||||
overlap_note: str = ""
|
||||
momentum_note: str = ""
|
||||
relevance_note: str = ""
|
||||
categories: list[str] = field(default_factory=list)
|
||||
rated_at: str | None = None
|
||||
|
||||
@property
|
||||
def composite_score(self) -> float:
|
||||
"""Weighted composite: novelty and relevance matter most."""
|
||||
return (
|
||||
self.novelty * 0.30
|
||||
+ self.relevance * 0.25
|
||||
+ self.maturity * 0.20
|
||||
+ self.momentum * 0.15
|
||||
+ (6 - self.overlap) * 0.10 # Invert: less overlap = better
|
||||
)
|
||||
Reference in New Issue
Block a user