refactor(review): unify six advisory-feature activation checks behind one shared resolver - #4692
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
gittensory-ui | 4c5556e | Commit Preview URL Branch Preview URL |
Jul 10 2026, 11:56 PM |
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4692 +/- ##
=======================================
Coverage 94.22% 94.22%
=======================================
Files 441 441
Lines 38740 38742 +2
Branches 14108 14106 -2
=======================================
+ Hits 36503 36505 +2
Misses 1577 1577
Partials 660 660
🚀 New features to boost your workflow:
|
|
Warning 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏸️ Gittensory review result - manual review recommendedReview updated: 2026-07-10 23:43:11 UTC
⏸️ Suggested Action - Manual Review
Review summary Nits — 5 non-blocking
Concerns raised — review before merging
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
… one shared resolver (#4616) Consolidates the config-sprawl the review-stack audit flagged as its flagship finding: ~16 src/review/*-wire.ts modules each hand-rolled their own env-flag/per-repo-override/allowlist boolean arithmetic, with at least four subtly different precedence shapes and no single place documenting which feature used which -- already the root cause of one production incident (GITTENSORY_REVIEW_REPOS/GITTENSORY_PUBLIC_STATS_REPOS once sharing a value). Adds resolveFeatureActivation, a single pure core in src/review/feature-activation.ts that every precedence shape now reduces to (standard / forceOnOnly / allowlistRequired / manifestOnly), with resolveConvergedFeature (the features: block) and the new resolveManifestOnlyFeature (the review: block features with no allowlist role) as thin adapters over it. Migrates six features onto the shared resolver with no behavior change for any repo's current effective feature set: screenshots joins the six existing ConvergedFeatureKeys (features.screenshots is now a real override, closing the exact gap the audit called out -- it previously had env+allowlist only, unlike its documented siblings); impactMap, reviewMemory, cultureProfile, inlineComments, and fixHandoff move onto the new manifestOnly mode, preserving their existing no-allowlist, explicit-opt-in semantics exactly.
b0b8dcd to
4c5556e
Compare
Summary
Closes #4616 (the review-stack architecture audit's flagship config-sprawl finding).
src/review/*-wire.tsbehind one shared, pure precedence resolver.
resolveFeatureActivation(src/review/feature-activation.ts) — a single pure core that everyper-feature activation precedence shape in this codebase now reduces to, expressed as one of four named
modes:
standard,forceOnOnly(safety, fix(review): features.safety is per-repo disableable via .gittensory.yml even when the operator enabled it globally #2269),allowlistRequired(grounding), and the newmanifestOnly.resolveConvergedFeature(thefeatures:-block keys) and the newresolveManifestOnlyFeature(thereview:-block keys with no allowlist role) are thin adapters over it.the identical activation decision before/after across every yml-set / yml-unset / allowlist-set /
allowlist-unset / env-flag-on / env-flag-off combination (see "No-behavior-change verification" below):
screenshotsjoins the six existingConvergedFeatureKeys (features.screenshotsis now a real,bidirectional per-repo override) — this closes the exact gap the audit called out: it previously had
env-flag-AND-allowlist only, with no
features:override at all, unlike its six documented siblings.A self-hoster who guessed
features.screenshots: true(a natural guess given the sibling keys right nextto it in
.gittensory.yml.example) previously found it silently did nothing.impactMap,reviewMemory,cultureProfile,inlineComments,fixHandoffnowdelegate to the new
manifestOnlymode instead of each independently re-implementing the identicalisXEnabled(env) && <manifest toggle> === trueboolean pair.cultureProfileadditionally gained aproper
shouldApplyRepoCultureProfilefunction (mirroring its four siblings) — it previously had nodedicated resolver at all and was inlined twice at its call sites in
processors.ts..gittensory.yml.example(and its mirror,config/examples/gittensory.full.yml) document the newfeatures.screenshotskey alongside its six siblings, with an updated precedence comment.Scope cut (disclosed)
Given the size (~16 call sites across distinct features, per the issue), this PR lands the shared resolver
plus the clearest, individually-lowest-risk inconsistent cases, and explicitly leaves the rest for a
fast-follow rather than trying to migrate all ~16 in one PR:
content-lane(src/review/content-lane/spec-resolver.ts'sresolveRegistryLaneSpec): alreadyimplements the same env-kill-switch → override → allowlist-default precedence one-for-one (verified by
reading the function in full), it just isn't literally routed through
resolveConvergedFeatureyet — itresolves a whole
RegistryLaneSpecobject, not a boolean, so migrating it is a larger, more speculativerefactor for zero behavior-consistency gain (it wasn't inconsistent to begin with).
selftune: already self-documented in the codebase (CONVERGED_FEATURE_KEYS's own comment, andselftune-wire.ts) as a deliberate non-fit — its base eligibility isisAgentConfigured(theacting-autonomy consent boundary), not the
GITTENSORY_REVIEW_REPOSallowlist, so it has no "allowlist"input to plug into either
resolveConvergedFeatureor the newresolveManifestOnlyFeaturewithout alarger redesign (a pluggable base-eligibility predicate, not just a pinned boolean).
enrichment(REES): gated byGITTENSORY_REVIEW_ENRICHMENTandREES_URLbeing configured — adeployment-integration toggle, not a per-repo
features:/review:boolean; per-reporeview.enrichmentonly narrows which analyzers run, not whether the capability exists at all.
ops,outcomes/parity-audit,maintainer-recap: deployment-level (ops/telemetryrecording, cross-repo digest cadence) rather than per-PR, per-repo advisory capabilities — none has ever had
a
features:/review:per-repo toggle to begin with, so there's no inconsistency to fix here.issue-rag-wire.ts: not an activation-gate file at all — a query-composition re-export shim.No-behavior-change verification
For every migrated feature,
resolveFeatureActivation's mode was derived to be mathematically identicalto the feature's prior hand-rolled expression, not just "similar":
screenshots: new capability (a features: override that didn't exist before) — for every repo that has notset
features.screenshots, the override resolves tonulland falls back to the allowlist exactly asscreenshotsAllowed's oldisScreenshotsEnabled(env) && isConvergenceRepoAllowed(env, repo)already did.Existing
review.visual.enabled/review.visual.production_urlconfig (a separate, richer layer) isuntouched.
impactMap/reviewMemory/inlineComments/fixHandoff:resolveManifestOnlyFeature(flag, override)with
allowlistedpinned tofalsecollapses to exactlyflag && override === truefor every input —algebraically identical to each feature's prior
isXEnabled(env) && manifestToggle === true(or&& manifestXEnabledfor the two that took an already-collapsed boolean).cultureProfile: the twoprocessors.tscall sites' inlineisRepoCultureProfileEnabled(env) && reviewCultureProfile === truenow readshouldApplyRepoCultureProfile(env, reviewCultureProfile === true)— same expression, centralized into one named function.
This is backed by:
resolveFeatureActivation/resolveManifestOnlyFeatureunit-test suite infeature-activation.test.tsexercising every (globalFlag × override × allowlist × mode) combinationexplicitly.
public functions (
shouldComputeImpactMap,shouldApplyReviewMemory,shouldRequestInlineFindings,shouldEmitFixHandoff, plus the newshouldApplyRepoCultureProfile, plus a rewrittenvisual-wire.test.tscoveringscreenshots' new override) — all pass unchanged against the refactoredinternals, since the public signatures and behavior are unchanged.
lcov.infooutput (not just the terminal summary):feature-activation.ts,visual-wire.ts,impact-map-wire.ts,inline-comments.ts,fix-handoff.ts,and
repo-culture-profile-wire.tsall show zero uncovered lines and zero uncovered branches; thethree touched call sites in
processors.tsdo not appear in that file's uncovered-line list either.Validation
git diff --checknpm run actionlintnpm run typechecknpm run test:coveragelocally;codecov/patchrequires ≥99% coverage of the lines AND branches you changed (aim for 100% on your diff so CI variance does not fail near the threshold). Global coverage is a non-blocking trend with a loose 90% backstop, not the gate.npm run test:workersnpm run build:mcpnpm run test:mcp-packnpm run ui:openapi:checknpm run ui:lintnpm run ui:typechecknpm run ui:buildnpm audit --audit-level=moderateIf any required check was skipped, explain why:
src/review/**,src/queue/processors.ts,packages/gittensory-engine/src/focus-manifest.ts) plus two mirrored yml docs — noapps/gittensory-ui,packages/gittensory-mcp,packages/gittensory-miner,wrangler.jsonc, or Cloudflare Workers-runtime codeis touched, so the UI/MCP/miner/workers checks are not applicable and were not run.
npm run test:coverage, I ran (a)npm run typecheck(clean), (b) everytest file that imports or exercises a file I changed —
feature-activation.test.ts,visual-wire.test.ts,impact-map-wire.test.ts,review-memory-wire.test.ts,repo-culture-profile-wiring.test.ts,repo-culture-profile.test.ts,inline-comments.test.ts,inline-comments-select.test.ts,review-fix-handoff.test.ts,fix-handoff-collapsible.test.ts,fix-handoff-render.test.ts,focus-manifest.test.ts,content-lane-wire.test.ts,cutover-gate.test.ts,config-templates.test.ts,and the full
queue.test.ts(807 tests, the integration suite forprocessors.ts) — all green, with--coveragescoped to the changed files and cross-checked against the rawlcov.infoper-line/per-branchdata (see "No-behavior-change verification" above); and (c)
npm run test:changed(Vitest's diff-awaretest selection against
origin/main) as a broader safety net — 9084 tests across 368 files, all green.That sweep caught a real gap my initial file list missed (
config/examples/gittensory.full.yml, a mirroredcopy of
.gittensory.yml.examplechecked byconfig-templates.test.ts), now fixed and included. I also rannpm run docs:drift-check,npm run manifest:drift-check, andnpm run engine-parity:drift-check(all relevant given the
packages/gittensory-engineand.gittensory.yml.exampleedits) — all pass. CIruns the full
test:cigate as the authoritative signal.Safety
UI Evidencesection — not applicable, no visible UI change..gittensory.yml.exampleand itsconfig/examples/mirror updated;CHANGELOG.mduntouched.)Notes
origin/main(c3b10f296) immediately before pushing; the only upstream change sincebranching (
perf(review): downscale before/after screenshots before the local VLM, perf(review): downscale before/after screenshots before sending to the local VLM #4370/perf(review): downscale before/after screenshots before the local VLM #4687) touchedsrc/review/visual/capture.tsandsrc/review/visual/image-downscale.ts— no file overlap with this PR, sothe rebase applied cleanly with no conflicts. Re-ran
npm ci,npm run typecheck, and the full touched-testlist (1683 tests) after the rebase — all green.
src/queue/processors.tsbeyond the three call sites this migration actuallyrequires (two
cultureProfilesites, onescreenshotssite) plus the corresponding import updates.resolveFeatureActivationtakes already-resolved primitives (globalFlagOn: boolean,override: boolean | null,allowlisted: boolean), notEnvor a raw manifest — so a future per-tenant resolution path (atenant DB row standing in for the global env var, or a tenant's own allowlist) can supply the same three
inputs without this function, or its two callers' precedence logic, changing at all — the reuse target the
issue's acceptance criteria calls for.
Update (rebase + independent re-verification)
Rebased onto the latest
origin/mainto resolve a conflict withimprovementSignal(#4738), which landedon
CONVERGED_FEATURE_KEYSafter this branch forked — merged bothscreenshotsandimprovementSignalinto the array/doc-comments/yml examples/tests, full suite re-verified green (687 files / 13,706 tests).
Independently re-researched the "Scope cut" list above from scratch tonight (fresh read of all 9 excluded
*-wire.tsfiles, not just a recap) before deciding whether more of #4616 could land in a follow-up. Itreached the identical conclusion: every one of
content-lane,selftune,enrichment,ops,outcomes,parity,maintainer-recap, andissue-rag-wireis either already self-documented in-repo as a deliberatenon-fit, structurally incompatible with the resolver's boolean/per-repo shape (cross-repo cron jobs, an
object-valued resolver, telemetry-only recorders), or not an activation gate at all. There is no clean,
low-risk second increment left — this PR is the full realistic scope of #4616, hence
Closes.