Fix remaining critical, high, and medium issues from 4-perspective review
Critical fixes:
- Fix rating clamp range 1-10 → 1-5 (actual scale)
- Add `ietf ideas convergence` command (SequenceMatcher at 0.75 threshold)
- Fix "628 cross-org ideas" → 130 (verified from current DB) across 8 files
Security fixes:
- Sanitize FTS5 query input (strip special chars + boolean operators)
- Add rate limiting (10 req/min/IP) on Claude-calling endpoints
- Change <path:name> → <string:name> on draft routes
Codebase fixes:
- Add Database context manager (__enter__/__exit__)
- Wire false_positive filtering into queries (exclude by default in web UI)
- Fix Post 3 arithmetic ("~300" → "~409" distinct proposals)
Content & licensing:
- Add MIT LICENSE file
- Add IPR/FRAND notes (BCP 79, RFC 8179) to Posts 03 and 07
- Qualify "4:1 safety ratio" with monthly variation in 6 remaining files
- Add "Data as of March 2026" freeze-date headers to all 10 blog posts
- Hedge causal language in Post 04
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -286,6 +286,12 @@ class Database:
|
||||
self._conn.close()
|
||||
self._conn = None
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, *exc):
|
||||
self.close()
|
||||
|
||||
# --- Drafts ---
|
||||
|
||||
def upsert_draft(self, draft: Draft) -> None:
|
||||
@@ -343,8 +349,16 @@ class Database:
|
||||
).fetchall()
|
||||
return [self._row_to_draft(r) for r in rows]
|
||||
|
||||
def count_drafts(self) -> int:
|
||||
return self.conn.execute("SELECT COUNT(*) FROM drafts").fetchone()[0]
|
||||
def count_drafts(self, include_false_positives: bool = True) -> int:
|
||||
if include_false_positives:
|
||||
return self.conn.execute("SELECT COUNT(*) FROM drafts").fetchone()[0]
|
||||
return self.conn.execute(
|
||||
"""SELECT COUNT(*) FROM drafts d
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM ratings r
|
||||
WHERE r.draft_name = d.name AND r.false_positive = 1
|
||||
)"""
|
||||
).fetchone()[0]
|
||||
|
||||
def search_drafts(self, query: str, limit: int = 50) -> list[Draft]:
|
||||
rows = self.conn.execute(
|
||||
@@ -408,13 +422,17 @@ class Database:
|
||||
).fetchall()
|
||||
return [self._row_to_draft(r) for r in rows]
|
||||
|
||||
def drafts_with_ratings(self, limit: int = 200) -> list[tuple[Draft, Rating]]:
|
||||
def drafts_with_ratings(
|
||||
self, limit: int = 200, include_false_positives: bool = False,
|
||||
) -> list[tuple[Draft, Rating]]:
|
||||
fp_clause = "" if include_false_positives else "WHERE COALESCE(r.false_positive, 0) = 0"
|
||||
rows = self.conn.execute(
|
||||
"""SELECT d.*, r.novelty, r.maturity, r.overlap, r.momentum, r.relevance,
|
||||
f"""SELECT d.*, r.novelty, r.maturity, r.overlap, r.momentum, r.relevance,
|
||||
r.summary, r.novelty_note, r.maturity_note, r.overlap_note,
|
||||
r.momentum_note, r.relevance_note, r.categories as r_categories, r.rated_at
|
||||
FROM drafts d
|
||||
JOIN ratings r ON d.name = r.draft_name
|
||||
{fp_clause}
|
||||
ORDER BY (r.novelty * 0.30 + r.relevance * 0.25 + r.maturity * 0.20
|
||||
+ r.momentum * 0.15 + (6 - r.overlap) * 0.10) DESC
|
||||
LIMIT ?""",
|
||||
|
||||
Reference in New Issue
Block a user