Skip to content

Phase 1: collaboration board substrate (Issue sync, debate cycle, consensus) - #7

Merged
essentialbit merged 5 commits into
mainfrom
feature/phase1-collab-board-substrate
Jul 1, 2026
Merged

Phase 1: collaboration board substrate (Issue sync, debate cycle, consensus)#7
essentialbit merged 5 commits into
mainfrom
feature/phase1-collab-board-substrate

Conversation

@essentialbit

Copy link
Copy Markdown
Owner

Summary

Phase 1 of the Claude/Gemini collaboration board (Phase 0 — PR-gated pushes, branch protection, safe on-device sync — already merged). GitHub Issues are now the system of record for proposals; Claude and Gemini debate them and produce a weighted consensus score.

  • Dedup (memory_store.py): proposal insertion now catches near-duplicates via Jaccard word-overlap on top of exact-title matching — verified Gemini's differently-worded restatement of a Claude proposal collapses into one entry.
  • agent_track_record table + github_issue_number column, bumped automatically in mark_proposal_done.
  • risk_rules.py: keyword/file-path classifier (auth/payment/secret/schema-touching proposals are always high risk — never eligible for future auto-merge regardless of consensus).
  • github_sync.py: mirrors every proposal to a GitHub Issue (labels: FSI level, category, risk, proposed-by) — reuses community.py's existing GitHub client, no new one.
  • Both fred_rnd.py and gemini_rnd.py now set proposed_by explicitly at insertion time — Gemini's old "[Gemini] " title-prefix hack for self-identification is gone, replaced by the real column.
  • debate.py: the actual debate — each agent reviews the other agent's open proposal Issues, posts a stance (agree/disagree/escalate) + confidence + rationale, gated against re-reviewing via a hidden HTML marker. compute_consensus() weighs stance confidence against each agent's historical accuracy (agent_track_record, 0.7 cold-start default); disagree heavily discounts, escalate forces the score to zero.
  • Wired into main.py's scheduler as job_agent_debate (6h, jittered like the other cross-agent jobs).

Test plan (all done against the live repo, artifacts cleaned up after)

  • Dedup: near-duplicate proposals from "different" wording collapse correctly; unrelated ones stay distinct
  • sync_proposal_to_issue: created a real Issue, confirmed labels/body/hidden proposal-id marker, confirmed round-trip lookup
  • run_debate_cycle: created a Claude-authored test proposal, got a genuine Gemini review posted with correct consensus score; ran again and confirmed it skipped re-reviewing
  • Import smoke test passes

Saifodius added 5 commits July 1, 2026 13:24
…sue-number linking

Extends feature_backlog dedup beyond exact-title match so Claude's and
Gemini's independently-worded proposals for the same idea collapse into
one entry (verified: '[Gemini] FinBERT integration for sentiment' vs
'FinBERT sentiment upgrade' now dedupe correctly, unrelated proposals
stay distinct). New agent_track_record table (bumped in mark_proposal_done)
backs the Phase 1 consensus formula. New github_issue_number column +
lookup, for the upcoming Issue-sync work.
New github_sync.py (reuses community.py's existing GitHub REST client)
mirrors every feature_backlog proposal to a GitHub Issue — labels: FSI
level (parsed from the description), category, risk tier, and which
agent proposed it. New risk_rules.py classifies high/medium/low via
keyword + file-path matching (auth/payment/secret/schema-touching
proposals are always high, never auto-mergeable later regardless of
consensus).

Both fred_rnd.py and gemini_rnd.py now pass proposed_by explicitly
("claude"/"gemini") at insertion time — previously neither agent set
this, and Gemini's cycle identified its own proposals via a "[Gemini] "
title-string-prefix hack instead. That hack is gone; proposal selection
now filters on the real proposed_by column.

Verified end-to-end against the live repo: created a real Issue, confirmed
labels/body/hidden proposal-id marker, confirmed the issue-number lookup
round-trips correctly, then cleaned up the test artifacts.
New debate.py::run_debate_cycle() — each agent reviews the OTHER agent's
open proposal Issues (never its own) and posts a stance (agree/disagree/
escalate) + confidence + rationale as a comment, gated by a hidden
<!--fredai:stance:{agent}--> marker so an issue is never reviewed twice.

compute_consensus() combines the reviewer's self-reported confidence with
both agents' historical accuracy (memory_store.get_track_record — 0.7
cold-start default until 5+ samples exist): "disagree" heavily discounts
the score, "escalate" forces it to zero (future auto-merge gate treats
that as always requiring a human, regardless of risk tier).

Wired into main.py's scheduler as job_agent_debate (6h interval, jittered
like the other cross-agent jobs).

Verified against the live repo: created a real Claude-authored test
proposal, ran the cycle, got a genuine Gemini review (agree, 0.90
confidence, real rationale) posted as an issue comment with the correct
consensus score and label; ran again and confirmed it correctly skipped
re-reviewing. Cleaned up test artifacts after.
…-board-substrate

# Conflicts:
#	memory_store.py
@essentialbit
essentialbit merged commit eaf24c2 into main Jul 1, 2026
7 checks passed
@essentialbit
essentialbit deleted the feature/phase1-collab-board-substrate branch July 1, 2026 18:05
essentialbit added a commit that referenced this pull request Jul 1, 2026
…oposal (#20)

Found live, right after PR #7 merged: Gemini's interactive session hit
this within its first hour. insert_feature_proposal()'s dedup correctly
resolved a near-duplicate proposal to an *existing* row's id, but
sync_proposal_to_issue() had no idea — it always created a brand new
GitHub Issue regardless, so the same feature_backlog row ended up mirrored
to two separate Issues (confirmed: #9 and #14 both carried the same
<!--fredai:proposal_id=5--> marker; #11 and #16 the same for proposal_id=7).

New memory_store.get_proposal(id) lets sync_proposal_to_issue check for
an already-linked github_issue_number before creating anything, returning
the existing issue number instead. Verified: simulated the exact scenario
(insert, sync, insert a near-duplicate that dedupes to the same id, sync
again) and confirmed the second sync returns the same issue number instead
of creating a new one.

Co-authored-by: Saifodius <penny-suing-henna@duck.com>
essentialbit added a commit that referenced this pull request Jul 2, 2026
Replaces the dashboard globe's 4 hardcoded decorative "geopolitical
flight path" arcs (always the same 4 hubs -> NY, no real data behind
them at all) with real per-story HQ-to-exchange arcs from Phase 1's
story_arcs data (PR #52, already merged), colored by each story's
actual sentiment score instead of a fixed rainbow palette.

Capped to the 40 most recent stories to keep the globe high-signal per
the new MISSION.md guiding principle #7 (minimalist, high-signal UI) --
uncapped would mean 100+ overlapping arcs on a 24h+ window, which reads
as cluttered, not sophisticated.

Conservative interpretation note: #48's Phase 2 spec bundles both arcs
AND hotspot clustering. Splitting these — this PR is arcs only (the
higher-value, more contained piece); hotspot clustering is a natural
Phase 2b follow-up rather than risking a larger, harder-to-review PR.

Verified with a real functional test: launched the live app, confirmed
/api/news/globe-data still returns real story_arcs (165 for a 24h
window), confirmed the dashboard page serves with the new code intact,
and checked the extracted inline JS with `node --check` (exit 0, no
syntax errors) since a headless browser wasn't available to click
through it directly.

Co-authored-by: Saifodius <penny-suing-henna@duck.com>
essentialbit added a commit that referenced this pull request Jul 7, 2026
…108) (#118)

Fred's L3 backtest loop was real (111 signal_outcomes rows, 4h/24h/72h
checkpoints genuinely filling) but measured one thing: aggregate
direction hit-rate, with no way to tell which signal source actually
earns its keep, and no baseline -- a 55% hit rate means nothing without
knowing what a naive momentum guess would have scored on the same data.

- signal_outcomes gains two additive columns (source default 'aggregate',
  baseline_direction) -- legacy rows untouched, verified byte-for-byte
  parity against pre-migration accuracy math (73 rows / 29 correct,
  unchanged)
- log_scan_outcomes now also logs one row per independent source that
  actually has data for an asset this cycle: news_sentiment (direct
  news_items query, not the blended fallback), insider (SEC Form 4,
  most recent filing), short_interest (ratio TREND not a static
  threshold -- rising=bearish/falling=bullish, needs 2 stored readings),
  technical (SMA20/50 cross). Sources without live data are skipped, not
  fabricated as neutral (Principle #7). Baseline = naive prior-move
  momentum from the already-fetched quotes dict, no new fetches.
- get_backtest_accuracy v2: per-source accuracy + baseline delta +
  proving_value flag (delta<=0 at n>=20). get_underperforming_sources()
  surfaces flags for human review -- no auto-removal.
- New GET /api/backtest/source-health route; Track Record panel shows
  baseline delta per checkpoint and a compact underperforming-sources
  note when any exist.

Real bug caught by the functional test (not a hypothetical): insider
signal_type is sec_client.py's raw code name
(open_market_purchase/open_market_sale), not a bullish/bearish label --
was flowing through unmapped until the test asserted valid directions
against live Form 4 data and failed. Fixed with an explicit mapping.

Verified: 24/24 assertions against a copy of the live DB -- exact
regression match on legacy accuracy math, deterministic scorer math
on synthetic rows (75% signal vs 25% baseline = +50pt; a 25-sample
losing source correctly flagged), and a real end-to-end scan cycle
against live trending/quotes/news/insider/short-interest data.

Co-authored-by: Saifodius <penny-suing-henna@duck.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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