feat(review): add cached repo quality-culture profile as AI-review grounding - #3802
Merged
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
gittensory-ui | 94cbd15 | Commit Preview URL Branch Preview URL |
Jul 06 2026, 12:36 PM |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3802 +/- ##
==========================================
+ Coverage 93.38% 93.40% +0.01%
==========================================
Files 323 325 +2
Lines 32727 32823 +96
Branches 11982 12022 +40
==========================================
+ Hits 30563 30659 +96
Misses 1530 1530
Partials 634 634
🚀 New features to boost your workflow:
|
JSONbored
force-pushed
the
feat/repo-culture-profile-2995
branch
from
July 6, 2026 11:39
257001e to
2c1f68e
Compare
Contributor
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
JSONbored
force-pushed
the
feat/repo-culture-profile-2995
branch
from
July 6, 2026 11:42
2c1f68e to
c704a1c
Compare
Owner
Author
|
Fixed both real issues found by CI:
1207 tests pass across all touched/related files, typecheck/actionlint/audit clean. |
24 tasks
JSONbored
force-pushed
the
feat/repo-culture-profile-2995
branch
from
July 6, 2026 12:05
c704a1c to
22a896c
Compare
Contributor
|
Important 🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪🟪 🔍 Gittensory is reviewing…AI analysis is in progress. This comment will update when the review is complete. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed · 🟪 Reviewing |
JSONbored
force-pushed
the
feat/repo-culture-profile-2995
branch
from
July 6, 2026 12:26
22a896c to
cae4b9c
Compare
…ounding (#2995) Derives a deterministic per-repo signal (typical merged-PR size, common accepted labels, description-length norms) from recent_merged_pull_requests and caches it via signal_snapshots with TTL + merged-PR-count invalidation, mirroring the focus-manifest cache pattern. Wired additively into the AI reviewer's user prompt alongside RAG/grounding (review/repo-culture-profile* .ts), gated by the GITTENSORY_REVIEW_CULTURE_PROFILE env flag and the new review.culture_profile .gittensory.yml opt-in -- both default off, so the change is byte-identical until deliberately enabled. Never a gate/scoring input; degrades silently to no context on sparse history or any error. Validated: npm run typecheck, npx vitest run on the new + touched test files, and the affected regression suites (queue, ai-review-cache, focus-manifest, signals-coverage) all green with 100% branch coverage on the two new modules. # Conflicts: # .gittensory.yml.example # apps/gittensory-ui/src/routes/docs.privacy-security.tsx # apps/gittensory-ui/src/routes/docs.tuning.tsx # config/examples/gittensory.full.yml # src/env.d.ts # src/queue/processors.ts # src/services/ai-review.ts # src/signals/focus-manifest.ts # test/unit/focus-manifest.test.ts # test/unit/signals-coverage.test.ts # worker-configuration.d.ts # wrangler.jsonc
…lose 2 coverage gaps Superagent (P3): entry.label in formatRepoCultureProfileSection came straight from user-controlled GitHub label text on merged PRs, with no sanitization before it reached the AI reviewer prompt. Neutralize it through the existing prompt-injection defense (neutralizePromptInjection), the same way safeReviewTitle already protects an untrusted PR title. Also closes 2 partial-branch codecov/patch gaps: focus-manifest.ts's reviewConfigToJson had no round-trip test for review.culture_profile (mirrors every sibling boolean flag's existing test), and processors.ts's dynamicReviewFeatures.cultureProfile — unlike its env-only siblings (grounding/rag/enrichment/reputation) — is dual-gated by both the global env flag AND the per-repo manifest opt-in, so no existing test drove both true through a real webhook.
JSONbored
force-pushed
the
feat/repo-culture-profile-2995
branch
from
July 6, 2026 12:35
cae4b9c to
94cbd15
Compare
This was referenced Jul 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
src/review/repo-culture-profile.ts(extractRepoCultureProfile,deriveRepoCultureProfile) derives a deterministic profile — typical merged-PR size (median changed-file count, banded tiny/small/medium/large), typical PR description length, and common accepted labels — purely fromrecent_merged_pull_requestsrows already stored by this engine. Below 5 sampled merged PRs it returns an explicitpresent: falseinsufficient-data branch, never a partial guess.signal_snapshotstable (same mechanismsignals/focus-manifest-loader.tsalready uses for the manifest cache), invalidated on either a 6-hour TTL or a merged-PR-count drift check (a cheapCOUNT(*), not a row re-scan) — matching the issue's "TTL or new commits" invalidation ask with the simplest signal already available.src/review/repo-culture-profile-wire.ts(mirrorsreview/rag-wire.ts's structure exactly) formats the profile into a self-labelled, reference-only prompt block and is gated by a newGITTENSORY_REVIEW_CULTURE_PROFILEenv flag plus a new per-repo.gittensory.ymlreview.culture_profile: trueopt-in (parsed/resolved insignals/focus-manifest.tsthe same wayreview.effort_score/review.changed_files_summaryare). Both default off — the reviewer prompt is byte-identical until a repo deliberately opts in on top of the global flag being enabled.services/ai-review.ts(GittensoryAiReviewInput.cultureProfileContext, appended inbuildUserPromptright after the existing RAG section) and intoqueue/processors.ts'srunAiReviewForAdvisory, following the exact same fetch/gate/pass-through pattern as the RAG feature. Explicitly ADVISORY GROUNDING ONLY — it never becomes a gate/scoring input and never changes the structured AI-review output contract.AI_REVIEW_CACHE_INPUT_VERSION(ai-review-input:v1→v2) since the AI-review result cache's fingerprintfeaturesobject gained acultureProfilemember; every field is now explicitly enumerated (not passed through raw) so a future new feature key can't silently invalidate every existing cache entry again.src/review/repo-profile.ts(extractRepoProfile) is for a different epic (Roadmap: repo-specific CLAUDE.md/AGENT.md + skills generation & maintenance #2993/feat(review): extract a codebase-grounded repo profile from RAG + signals #2999, repo-doc/CLAUDE.md generation from the RAG code index) and does not carry PR-size/label/history signals — this PR does not repurpose it, it adds a new, narrowly-scoped module for the commit/PR-history signal this issue actually asks for.changedFiles.length(already reliably populated by the existing merged-PR backfill), not fromadditions/deletionsin the untyped raw GitHub payload, since the latter isn't part of the typedGitHubPullRequestPayloadshape and would be a less certain source of truth.Scope
type(scope): short summaryConventional Commit format.CONTRIBUTING.mdand does not reintroduce GitHub Pages, VitePress,site/, orCNAME.Validation
git diff --checknpm run actionlintnpm run typechecknpm run test:coverage(targeted, on the touched/new files — see coverage numbers below); 100% statements/branches/functions/lines on the two new modules (repo-culture-profile.ts,repo-culture-profile-wire.ts).npm run test:workersnpm run build:mcpnpm run test:mcp-packnpm run ui:openapi:checknpm run ui:lint(0 errors; only the pre-existing repo-widereact-refresh/only-export-componentswarnings, unrelated to this change)npm run ui:typecheck/npm run ui:build— skipped: both fail in this sandbox withCannot find package '@lovable.dev/vite-tanstack-config', reproduced identically on a cleanorigin/maincheckout with no changes applied (a private-registry package unavailable in this environment), so it is a pre-existing local-environment limitation, not something introduced by this PR.npm audit --audit-level=moderate(0 vulnerabilities)Also ran, beyond the template list, since this touches generated config surfaces:
npm run cf-typegen(newGITTENSORY_REVIEW_CULTURE_PROFILEwrangler var),npm run docs:drift-check,npm run db:schema-drift:check,npm run db:migrations:check,npm run ui:openapi:settings-parity— all clean, no drift.Safety
.gittensory.yml-only + env-flag-only knob, same pattern asreview.effort_score).docs.tuning.tsx,docs.privacy-security.tsx) documenting the new env flag in prose, matching the existing flag-list format exactly — no visual/interactive change..gittensory.yml.example/config/examples/gittensory.full.yml(newreview.culture_profilefield documented), plus the two UI docs routes above.Notes
origin/main(including a real merge conflict against the concurrently-merged Boundary-safe test generation #1972 boundary-safe test-generation advisory PR, which added sibling fields to the sameFocusManifestReviewConfigliterals — resolved by combining both PRs' fields, verified with a full re-run of the affected test suites post-rebase).