Skip to content

feat(agent): add recommendation outcome feedback - #229

Merged
JSONbored merged 14 commits into
JSONbored:mainfrom
mkdev5:feat/recommendation-outcome-feedback
Jun 2, 2026
Merged

feat(agent): add recommendation outcome feedback#229
JSONbored merged 14 commits into
JSONbored:mainfrom
mkdev5:feat/recommendation-outcome-feedback

Conversation

@mkdev5

@mkdev5 mkdev5 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add deterministic recommendation outcome persistence for agent actions, including merged, closed, improved, accepted, ignored, and stale states.
  • Feed private aggregate recommendation outcome feedback into contributor decision packs and repo decision confidence/risk signals.
  • Keep maintainer-lane outcomes separate and preserve sanitized public output boundaries.

Closes #96

Scope

  • This PR is focused and does not mix unrelated backend, UI, MCP, docs, dependency, and deploy changes.
  • This follows CONTRIBUTING.md and does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked an issue, or this is small enough that the summary explains why an issue is not needed.

Validation

  • npm run test:ci / CI validate on head de717a2
  • git diff --check
  • npm run actionlint
  • npm run typecheck
  • npm run test:coverage locally; global coverage stays at or above 97% for lines, statements, functions, and branches (aim for 98%+ branch coverage locally so CI variance does not fail near the threshold)
  • npm run test:workers
  • npm run build:mcp
  • npm run test:mcp-pack
  • npm run ui:openapi:check
  • npm run ui:lint
  • npm run ui:typecheck
  • npm run ui:build
  • npm audit --audit-level=moderate
  • New or changed behavior has unit/integration tests for new branches, fallback paths, and sanitizer boundaries

If any required check was skipped, explain why:

  • None. CI validate passed on the current PR head.

Safety

  • No secrets, wallet details, hotkeys, coldkeys, user PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics.
  • Auth, cookie, CORS, GitHub App, Cloudflare, or session changes include negative-path tests.
  • API/OpenAPI/MCP behavior is updated and tested where needed.
  • UI changes use live API data or real empty/error/loading states, not production mock/demo fallbacks.
  • Visible UI changes include screenshots or a short recording. (N/A: no visible UI changes; the UI-path diff is generated OpenAPI JSON only.)
  • Public docs/changelogs are updated where needed; changelogs are only edited for release-prep PRs.

Notes

  • Adds migration 0017_agent_recommendation_outcomes.sql for deterministic recommendation outcome storage.
  • OpenAPI is regenerated for the new private decision-pack feedback field.
  • No screenshot or recording is attached because there are no visible UI changes; the frontend-touched artifact is generated OpenAPI JSON.
  • No visible UI changes or public GitHub output changes are intended by default.

@mkdev5
mkdev5 requested a review from JSONbored as a code owner June 2, 2026 03:07
@dosubot dosubot Bot added the size:XL label Jun 2, 2026
@dosubot

dosubot Bot commented Jun 2, 2026

Copy link
Copy Markdown

Related Knowledge

2 documents with suggested updates are ready for review.

gittensory

Architecture
View Suggested Changes
@@ -301,6 +301,7 @@
 - **agentRuns** — Agent orchestration runs with objective and status ([src/db/schema.ts](https://github.com/JSONbored/gittensory/blob/f63f125e2126dc58ac5a63e88f4f33d1e13b2979/src/db/schema.ts#L408-L428))
 - **agentActions** — Agent action recommendations with risk impact ([src/db/schema.ts](https://github.com/JSONbored/gittensory/blob/f63f125e2126dc58ac5a63e88f4f33d1e13b2979/src/db/schema.ts#L430-L457))
 - **agentContextSnapshots** — Agent context with decision pack and signal snapshot IDs ([src/db/schema.ts](https://github.com/JSONbored/gittensory/blob/f63f125e2126dc58ac5a63e88f4f33d1e13b2979/src/db/schema.ts#L459-L474))
+- **agentRecommendationOutcomes** — Tracks deterministic recommendation outcome classifications (merged, closed, improved, accepted, ignored, stale) for agent actions, including target details (repo/PR/issue), confidence levels, and maintainer-lane flag. Indexed by action ID, actor/state, target, and maintainer-lane.
 - **githubAgentCommandAnswers** — Stores command invocations and responses from the GitHub agent (@gittensory), including repo, issue number, command name, request/response comment IDs, actor kind, and metadata. Indexed by (repo_full_name, issue_number) and (command, updated_at).
 - **githubAgentCommandFeedback** — Records usefulness votes (thumbs-up/thumbs-down reactions) on command answers, with unique constraint on (answer_id, actor_hash) to deduplicate feedback per actor. Tracks vote, source (reaction or app feedback), actor kind, and links to github_agent_command_answers via foreign key. Indexed by (answer_id, actor_hash), (command, updated_at), and (repo_full_name, issue_number).
 - **syncRuns** — Sync job execution tracking ([src/db/schema.ts](https://github.com/JSONbored/gittensory/blob/f63f125e2126dc58ac5a63e88f4f33d1e13b2979/src/db/schema.ts#L523-L533))
@@ -355,7 +356,7 @@
 
 ## Key Backend Modules
 
-The backend intelligence of Gittensory is organized into nine major modules, each handling a distinct domain of the system's functionality. These modules operate as the core orchestration layer between GitHub data, Gittensor registry state, and Gittensory's signals intelligence.
+The backend intelligence of Gittensory is organized into major modules, each handling a distinct domain of the system's functionality. These modules operate as the core orchestration layer between GitHub data, Gittensor registry state, and Gittensory's signals intelligence.
 
 ### Scoring Module (`src/scoring/`)
 
@@ -480,6 +481,29 @@
 - **Extension-scoped tokens** for the browser extension, issued via `POST /v1/auth/extension/session`.
 
 Rate limiting is enforced via a Durable Object named `RateLimiter` ([wrangler.jsonc](https://github.com/JSONbored/gittensory/blob/f63f125e2126dc58ac5a63e88f4f33d1e13b2979/wrangler.jsonc#L58-L65)), which tracks request counts per actor and applies sliding window rate limits.
+
+### Services Layer (`src/services/`)
+
+The services layer provides cross-cutting functionality that spans multiple backend domains. Key service modules include:
+
+#### Decision Packs (`src/services/decision-pack.ts`)
+
+The decision pack service builds comprehensive contributor action plans by integrating data from the registry, signals engine, scoring model, GitHub activity, and recommendation outcome feedback. The `buildAndPersistContributorDecisionPack()` function orchestrates the full pipeline: evaluating recommendation outcomes, fetching repository context, building role analysis, and ranking opportunities. Decision packs include a `recommendationOutcomeFeedback` field containing aggregate statistics (positive/negative counts by state: merged, closed, improved, accepted, ignored, stale), per-repository summaries with signal classification (positive, negative, mixed, neutral), and priority score adjustments based on feedback (+8 for positive signal, -12 for negative, -4 for mixed). Maintainer-lane outcomes are separated and tracked independently to preserve privacy boundaries.
+
+#### Recommendation Outcomes (`src/services/recommendation-outcomes.ts`)
+
+The recommendation outcome service evaluates the fate of agent action recommendations by matching them against later PR and issue activity. The `evaluateRecommendationOutcomes()` function fetches recent agent runs and contributor PR/issue history, then deterministically classifies each action into one of six outcome states:
+
+- **merged** — The recommended PR was merged after the recommendation.
+- **closed** — The recommended PR was closed without merging, or the recommended issue was closed.
+- **improved** — The recommended PR remains open but now has approval or clean mergeability evidence.
+- **accepted** — Later cached activity matches the recommendation target (PR/issue created or updated).
+- **stale** — No activity past the stale-outcome window (default 14 days).
+- **ignored** — No matching activity after the ignored-outcome window (default 7 days), but not yet stale.
+
+The classification logic in `classifyRecommendationOutcome()` uses deterministic matching rules: exact target PR/issue match, linked issue match, or later repo activity. The `isMaintainerLane()` function identifies maintainer-lane outcomes by checking if the actor is the repo owner, or if the PR/issue has a maintainer-associated author association (OWNER, MEMBER, COLLABORATOR). Maintainer-lane outcomes are tracked but kept separate from public contributor feedback.
+
+The service persists outcome records to the `agentRecommendationOutcomes` table with confidence levels (high for exact matches, medium for partial matches, low for no-match). Aggregate feedback is consumed by the decision pack system to adjust priority scores and provide private feedback signals for contributor decisions and repo decision confidence/risk indicators.
 
 ## Testing
 

✅ Accepted

Gittensory Architecture
View Suggested Changes
@@ -64,6 +64,8 @@
 The decision pack service aggregates multi-source data into per-contributor decision artifacts [[18]](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/src/services/decision-pack.ts#L1-L34). It enforces a 6-hour freshness threshold (`DECISION_PACK_MAX_AGE_MS`) and a 15-second debounce window (`DECISION_PACK_REBUILD_DEBOUNCE_MS`) to prevent excessive rebuild storms [[19]](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/src/services/decision-pack.ts#L54-L55).
 
 Decision packs classify recommendations into five states: pursue, cleanup_first, maintainer_lane, avoid_for_now, and watch. Action kinds include PR cleanup/landing, new PR filing, issue discovery, and maintainer-specific work. Freshness states track whether a pack is fresh, stale, rebuilding, or missing.
+
+`buildAndPersistContributorDecisionPack()` now calls `evaluateRecommendationOutcomes()` before building the pack to refresh outcome data, then fetches `AgentRecommendationOutcomeSummary` via `getAgentRecommendationOutcomeSummary()`. The resulting `ContributorDecisionPack` includes `recommendationOutcomeFeedback` with aggregate stats (positive/negative counts, states breakdown). Each `RepoDecision` receives per-repo feedback with priority score adjustments: +8 for positive signal, -12 for negative, -4 for mixed. Feedback is incorporated into risk reasons and "why this helps" explanations. Maintainer-lane outcomes are kept separate to preserve privacy boundaries.
 
 ### **E. Agent Orchestrator (`src/services/agent-orchestrator.ts`)**
 
@@ -103,7 +105,9 @@
 
 ### **I. Database Layer (`src/db/`)**
 
-The database uses Drizzle ORM with Cloudflare D1 (SQLite) [[30]](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/src/db/client.ts). The schema spans 50+ tables across 16 migrations [[31]](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/migrations), grouped into six categories: GitHub integration (installations, repositories, repositorySettings), sync state (repoSyncState, repoSyncSegments), scoring (scoringModelSnapshots, scorePreviews, contributorEvidence), agent orchestration (agentRuns, agentActions, agentContextSnapshots), auth/compliance (authSessions, auditEvents), and analytics (productUsageEvents, productUsageDailyRollups) [[32]](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/src/db/schema.ts).
+The database uses Drizzle ORM with Cloudflare D1 (SQLite) [[30]](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/src/db/client.ts). The schema spans 50+ tables across 17 migrations [[31]](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/migrations), grouped into six categories: GitHub integration (installations, repositories, repositorySettings), sync state (repoSyncState, repoSyncSegments), scoring (scoringModelSnapshots, scorePreviews, contributorEvidence), agent orchestration (agentRuns, agentActions, agentContextSnapshots, agentRecommendationOutcomes), auth/compliance (authSessions, auditEvents), and analytics (productUsageEvents, productUsageDailyRollups) [[32]](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/src/db/schema.ts).
+
+The `agentRecommendationOutcomes` table (migration 0017) stores deterministic outcome classifications for agent actions. Fields include action and run identifiers (with foreign keys to `agentActions` and `agentRuns`), target identifiers (repo, PR number, issue number), outcome state (merged, closed, improved, accepted, ignored, stale), outcome target details (type, repo, PR/issue number), maintainer lane flag to separate maintainer vs contributor activity, confidence level (high, medium, low) with reason text, detection timestamp and source update timestamp for time-based analysis, and metadata JSON for additional context. Indexes optimize queries by actor+state, target lookups, and maintainer-lane filtering.
 
 ### **J. Queue Processor (`src/queue/`)**
 
@@ -174,7 +178,7 @@
 packages/gittensory-mcp/  # npm MCP package (@jsonbored/gittensory-mcp)
 apps/gittensory-ui/       # web frontend (TypeScript/Vite)
 apps/gittensory-extension/# browser extension (Manifest V3)
-migrations/               # 16 Drizzle/D1 SQL migrations
+migrations/               # 17 Drizzle/D1 SQL migrations
 scripts/                  # utility and build scripts
 test/                     # test files
 ```
@@ -211,6 +215,8 @@
 - `auth/` — github-oauth, rate-limit, security
 - `utils/` — crypto helpers, JSON utilities
 
+`services/` includes `recommendation-outcomes.ts`, which implements `evaluateRecommendationOutcomes()` to process agent runs and classify recommendation outcomes. It matches agent actions against cached PR/issue activity to determine what happened after a recommendation, using heuristics: exact PR/issue match, linked issue to PR, later repo activity from the same contributor. Time windows (default 14 days for stale, 7 days for ignored) classify unmatched recommendations. The module generates summaries aggregated by actor and by repository.
+
 ### MCP Package Structure
 
 The `@jsonbored/gittensory-mcp` package (v0.3.0) ships as a standalone npm module with Node >= 22 requirement [[55]](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/packages/gittensory-mcp/package.json#L1-L48):
@@ -336,7 +342,7 @@
 
 ### Data Layer
 
-**Database:** Cloudflare D1 (SQLite at the edge) with a binding named [`DB`](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/wrangler.jsonc#L50-L57) pointing to the `gittensory` database. The schema comprises [50+ tables across 16 migrations](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/migrations), spanning GitHub integration, sync state, scoring, agent orchestration, auth/compliance, and analytics.
+**Database:** Cloudflare D1 (SQLite at the edge) with a binding named [`DB`](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/wrangler.jsonc#L50-L57) pointing to the `gittensory` database. The schema comprises [50+ tables across 17 migrations](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/migrations), spanning GitHub integration, sync state, scoring, agent orchestration, auth/compliance, and analytics.
 
 **ORM:** [Drizzle ORM ^0.45.0](https://github.com/JSONbored/gittensory/blob/40c019c82d87568c232fbe7fabf50212e983075a/package.json#L62) provides type-safe query construction and schema management.
 

✅ Accepted

How did I do? Any feedback?  Join Discord

@JSONbored JSONbored left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MkDev11 the recommendation outcome feedback model is useful, especially keeping maintainer-lane outcomes separate from contributor feedback.

A few notes:

  • CI is green on the branch.
  • Current main now conflicts with this PR in apps/gittensory-ui/public/openapi.json, src/openapi/schemas.ts, and src/services/decision-pack.ts.
  • The PR checks the screenshot box but does not provide actual screenshot or recording evidence.

Required changes:

  • Resolve the merge conflicts against current main.
  • Regenerate OpenAPI artifacts after resolving backend schema changes.
  • Attach screenshot/recording evidence for the frontend-touched artifact path, or remove the frontend touch if it is not part of the change.

Validation expected:

  • Re-run npm run test:ci.
  • Confirm the migration, OpenAPI schema, and decision-pack tests still pass together.

mkdev11 and others added 4 commits June 2, 2026 08:55
@mkdev5
mkdev5 requested a review from JSONbored June 2, 2026 07:23
@mkdev5

mkdev5 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

@JSONbored please review the change

@JSONbored JSONbored left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MkDev11 please fix merge conflicts.

@mkdev5

mkdev5 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

@MkDev11 please fix merge conflicts.

fixed

@JSONbored
JSONbored self-requested a review June 2, 2026 16:42

@JSONbored JSONbored left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MkDev11 the branch is clean against current main and CI is green, but it conflicts with #219 since it just landed.

Required change:

  • Rebase after the #219 merge-order decision.
  • Regenerate OpenAPI artifacts and rerun the decision-pack/outcome tests.

Validation expected:

  • npm run test:ci
  • npm run ui:openapi:check

@mkdev5

mkdev5 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

@MkDev11 the branch is clean against current main and CI is green, but it conflicts with #219 since it just landed.

Required change:

Validation expected:

  • npm run test:ci
  • npm run ui:openapi:check

fixed

@JSONbored
JSONbored self-requested a review June 2, 2026 22:34

@JSONbored JSONbored left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MkDev11

A few notes:

  • This is the right closed-loop direction for #96: Gittensory should learn from deterministic outcomes, not opaque scoring claims.
  • The implementation separates merged/closed/improved/stale/ignored outcomes and keeps maintainer-lane outcomes out of normal contributor feedback.
  • The tests cover idempotent outcome updates, stale/ignored classification, maintainer associations, OpenAPI shape, and decision-pack feedback impact.

No code changes requested.

@dosubot dosubot Bot added the lgtm label Jun 2, 2026
@JSONbored
JSONbored merged commit 3eff615 into JSONbored:main Jun 2, 2026
4 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in gittensory - v1 roadmap Jun 2, 2026
@github-actions github-actions Bot mentioned this pull request Jun 3, 2026
12 tasks
@JSONbored JSONbored added gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. and removed feature gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. labels Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

feat(agent): add closed-loop feedback from accepted recommendations

2 participants