Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gittensory.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ gate:
# note: "Run the test suite before requesting review." # short intro line shown above the panel
# fields: # show/hide rows (default: all shown). Stable keys:
# relatedWork: false # linkedIssue | relatedWork | reviewLoad (Change scope) |
# openPrQueue: false # validationEvidence (Validation posture) | openPrQueue (Contributor workload) | contributorContext | gateResult
# openPrQueue: false # validationEvidence (Validation posture) | openPrQueue (Contributor workload) | contributorContext | gateResult | improvementSignal

# AI-review eligibility filters (#3999): a draft PR previously re-triggered a full AI review on every
# push, letting a contributor iterate for free while tokens kept burning — skip_drafts stops that.
Expand Down
5 changes: 4 additions & 1 deletion .gittensory.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -1075,7 +1075,10 @@ settings:
# text: "Reviewed by the Acme maintainer bot." # Custom lead line. String or null. Default: null.
# note: "Run the test suite before requesting review." # Short intro line shown above the panel. String or null.
# # Per-row show/hide toggles for the panel. Keys: linkedIssue | relatedWork | reviewLoad |
# # validationEvidence | openPrQueue | contributorContext | gateResult. Default: all shown (true).
# # validationEvidence | openPrQueue | contributorContext | gateResult | improvementSignal. Default: all
# # shown (true). improvementSignal (#4744) only ever renders content when the `improvementSignal` converged
# # feature (see `features:` below) is ALSO active for this repo -- this toggle just hides that row/section
# # like any other; it never turns the feature itself on.
# fields:
# relatedWork: false
# openPrQueue: false
Expand Down
5 changes: 4 additions & 1 deletion config/examples/gittensory.full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1088,7 +1088,10 @@ settings:
# text: "Reviewed by the Acme maintainer bot." # Custom lead line. String or null. Default: null.
# note: "Run the test suite before requesting review." # Short intro line shown above the panel. String or null.
# # Per-row show/hide toggles for the panel. Keys: linkedIssue | relatedWork | reviewLoad |
# # validationEvidence | openPrQueue | contributorContext | gateResult. Default: all shown (true).
# # validationEvidence | openPrQueue | contributorContext | gateResult | improvementSignal. Default: all
# # shown (true). improvementSignal (#4744) only ever renders content when the `improvementSignal` converged
# # feature (see `features:` below) is ALSO active for this repo -- this toggle just hides that row/section
# # like any other; it never turns the feature itself on.
# fields:
# relatedWork: false
# openPrQueue: false
Expand Down
7 changes: 5 additions & 2 deletions packages/gittensory-engine/src/focus-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,8 +434,11 @@ export type FocusManifestSettings = Partial<
advisoryAiRouting?: Partial<AdvisoryAiRoutingConfig> | undefined;
};

/** Field keys for the public review-panel rows a maintainer can show/hide via `review.fields`. */
export const REVIEW_FIELD_KEYS = ["linkedIssue", "relatedWork", "reviewLoad", "validationEvidence", "openPrQueue", "contributorContext", "gateResult"] as const;
/** Field keys for the public review-panel rows a maintainer can show/hide via `review.fields`. `improvementSignal`
* (#4744) is the newest: the optional row combining the deterministic structural-improvement tier (#4742) and,
* where also active, the LLM tier's composed value judgment (#4743) -- default-shown, like every sibling here,
* when the `improvementSignal` converged feature itself is active for the repo. */
export const REVIEW_FIELD_KEYS = ["linkedIssue", "relatedWork", "reviewLoad", "validationEvidence", "openPrQueue", "contributorContext", "gateResult", "improvementSignal"] as const;
export type ReviewFieldKey = (typeof REVIEW_FIELD_KEYS)[number];

// `review.profile` (#review-profile): how nitpicky the AI maintainer review is. `chill` = surface only blocking
Expand Down
2 changes: 1 addition & 1 deletion src/config/gittensory-repo-focus-manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ gate:
# note: "Run the test suite before requesting review." # short intro line shown above the panel
# fields: # show/hide rows (default: all shown). Stable keys:
# relatedWork: false # linkedIssue | relatedWork | reviewLoad (Change scope) |
# openPrQueue: false # validationEvidence (Validation posture) | openPrQueue (Contributor workload) | contributorContext | gateResult
# openPrQueue: false # validationEvidence (Validation posture) | openPrQueue (Contributor workload) | contributorContext | gateResult | improvementSignal

# AI-review eligibility filters (#3999): a draft PR previously re-triggered a full AI review on every
# push, letting a contributor iterate for free while tokens kept burning — skip_drafts stops that.
Expand Down
65 changes: 65 additions & 0 deletions src/queue/processors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ import {
buildSlopAssessment,
type SlopBand,
} from "../signals/slop";
import { buildStructuralImprovementAssessment } from "../signals/improvement";
import { runGittensoryLinkedIssueSatisfaction } from "../services/linked-issue-satisfaction-run";
import { decidePublicSurface } from "../signals/settings-preview";
import {
Expand Down Expand Up @@ -468,6 +469,7 @@ import {
runGittensoryAiReview,
utcDayStartIso,
type AiReviewActualUsage,
type ImprovementMagnitude,
type InlineFinding,
} from "../services/ai-review";
import {
Expand Down Expand Up @@ -7395,6 +7397,16 @@ export async function runAiReviewForAdvisory(
// quality-culture reference block (typical merged-PR size + common labels) to the reviewer prompt. Absent/
// false ⇒ byte-identical (no section, no extra D1 read).
reviewCultureProfile?: boolean | undefined;
// `.gittensory.yml` `features.improvementSignal` (#4744, first real caller of #4738's activation wiring),
// resolved by the caller via `convergedFeatureActive`/`resolveConvergedFeature` -- NOT resolved internally
// here (unlike reputation/rag/grounding above), mirroring reviewProfile/reviewImpactMap/reviewCultureProfile
// above, which are ALL caller-resolved rather than looked up internally (see `ModelReview.valueAssessment`'s
// own doc comment in services/ai-review.ts for why `improvementSignal` -- a read-only advisory signal, not a
// security control -- follows that majority pattern rather than `safety`'s internal-resolution exception).
// Threaded straight into runGittensoryAiReview's own `improvementSignal` gate (#4743) for the LLM tier's
// value-assessment prompt addition. Absent/false ⇒ the prompt is byte-identical (no valueAssessment
// requested) -- the only reachable value until this PR started resolving the feature.
improvementSignal?: boolean | undefined;
// The inbound webhook delivery id that triggered this review (#codex-timeout-fields) — forwarded to a
// self-host provider's failure log purely for operator correlation; never read by any review logic. Absent
// (e.g. a sweep/repair fan-out with no single originating delivery, or a unit test) ⇒ the log line omits it.
Expand Down Expand Up @@ -7437,6 +7449,13 @@ export async function runAiReviewForAdvisory(
// within the bounded cooldown could replay "another pass is running" long after that pass finished.
// Defaults to true (persistable) for every other outcome, cacheable or not.
persistable?: boolean | undefined;
// The LLM tier's composed improvement/value judgment (#4743/#4744) -- present ONLY on a FRESH review
// (cache miss) with `improvementSignal` requested and at least one reviewer emitting a usable, public-safe
// judgment. Absent on a cache hit: exactly like `inlineFindings`/`impactMap` above, `ai_review_cache`
// never persists this field (getCachedAiReview/putCachedAiReview, db/repositories.ts, have no column for
// it), so a re-served cached review has no LLM-tier judgment to show on that particular render. The
// deterministic tier is unaffected -- it is computed fresh every pass, never cached.
valueAssessment?: { magnitude: ImprovementMagnitude; rationale: string } | undefined;
}
| undefined
> {
Expand Down Expand Up @@ -7726,6 +7745,9 @@ export async function runAiReviewForAdvisory(
),
repoInstructions: args.reviewInstructions ?? null,
changedFiles: files,
// improvementSignal (#4744): ask the model for the ordinal value/improvement judgment (#4743) only when
// the caller resolved the feature on for this repo. Absent/false ⇒ byte-identical prompt.
improvementSignal: args.improvementSignal === true,
});
if (result.status !== "ok") return undefined;
const findings: AdvisoryFinding[] = [];
Expand Down Expand Up @@ -7818,6 +7840,7 @@ export async function runAiReviewForAdvisory(
findings,
metadata: metadataFor(result.advisoryNotes, []),
cacheable: false,
valueAssessment: result.valueAssessment ?? undefined,
};
}
if (hasPublicReviewAssessment(result.advisoryNotes)) {
Expand All @@ -7828,6 +7851,7 @@ export async function runAiReviewForAdvisory(
impactMap: impactMapEntries,
findings,
metadata: metadataFor(result.advisoryNotes, result.inlineFindings),
valueAssessment: result.valueAssessment ?? undefined,
};
}
if (result.inconclusive) {
Expand Down Expand Up @@ -9038,6 +9062,18 @@ async function maybePublishPrPublicSurface(
repoFullName,
"unifiedComment",
);
// improvementSignal (#4744): the first real caller of #4738's activation wiring (epic #4737's config-as-code
// foundation) -- nothing resolved this feature before this PR (see signals/improvement.ts's own header
// comment). Resolved once, independent of unifiedCommentAllowed above: it gates BOTH the deterministic
// tier's own computation further below (which has no AI dependency at all -- a paused repo, a non-reviewable
// author, or aiReviewMode: "off" still gets it) and, threaded into runAiReviewForAdvisory, the LLM tier's
// prompt addition (#4743). loadRepoFocusManifest is cached, so this second manifest resolution costs no
// extra fetch in the common case where something else already resolved it this pass.
const improvementSignalAllowed = await convergedFeatureActive(
env,
repoFullName,
"improvementSignal",
);
// `settings` is the EFFECTIVE config (`.gittensory.yml` > DB > defaults), resolved by the caller via
// resolveRepositorySettings — so gate on/off and every blocker mode already reflect the repo's config
// file. The gate verdict is the same for every author; confirmedContributor feeds only on-chain scoring.
Expand Down Expand Up @@ -9414,6 +9450,8 @@ async function maybePublishPrPublicSurface(
// inlineFindings is present ONLY on a FRESH review (cache miss) with inline comments enabled; the AI cache
// round-trips notes + reviewerCount + the gate findings (so a cache hit replays consensus/split/inconclusive
// blockers — see below), but NOT inlineFindings, so a cache hit never re-posts inline comments (#inline-comments).
// valueAssessment (#4743/#4744) follows the exact same cache-miss-only shape as inlineFindings/impactMap --
// see runAiReviewForAdvisory's own return-type doc comment.
let aiReview:
| {
notes: string;
Expand All @@ -9424,6 +9462,7 @@ async function maybePublishPrPublicSurface(
metadata?: Record<string, unknown> | undefined;
cacheable?: boolean | undefined;
persistable?: boolean | undefined;
valueAssessment?: { magnitude: ImprovementMagnitude; rationale: string } | undefined;
}
| undefined;
let inlineCommentsEnabledForReview = false;
Expand Down Expand Up @@ -10523,6 +10562,10 @@ async function maybePublishPrPublicSurface(
reviewSelfHostAiModel,
reviewImpactMap,
reviewCultureProfile,
// improvementSignal (#4744): resolved once above (independent of unifiedCommentAllowed), reused
// here so the LLM tier's value-assessment prompt addition (#4743) only fires when this repo has
// actually opted in.
improvementSignal: improvementSignalAllowed,
// #regate-dup-prep: this call's own advisory lock is already claimed (by aiReviewCacheReadDecideAndRun's
// caller, above) — pass it through so runAiReviewForAdvisory trusts it instead of re-claiming (and
// losing) against itself, and does not release it before the cache write below runs.
Expand Down Expand Up @@ -11196,6 +11239,25 @@ async function maybePublishPrPublicSurface(
// winner's hard-duplicate block is suppressed (they recompute the winner from their own open-only sibling
// list). Flag-OFF (default) ⇒ false ⇒ the panels are byte-identical to today.
const duplicateWinnerEnabled = env.GITTENSORY_DUPLICATE_WINNER === "true";
// improvementSignal deterministic tier (#4742/#4744): pure/sync, no AI dependency, so it is computed
// independent of aiReview's own eligibility gates above (a paused repo, non-reviewable author, or
// aiReviewMode: "off" still gets this tier -- the two tiers are deliberately independent, epic #4737).
// Only computed when the feature resolves on for this repo, matching "nothing at all when the feature is
// off" (#4744) and avoiding the extra file resolve on the default (until an operator opts in) path where
// it's off. changedFiles reuses the SAME memoized getReviewFiles() resolver every other gate/panel input
// already calls, so this costs no extra fetch when something else already resolved it this pass.
// complexityDeltas/duplicationDeltas/patchCoverageDeltaPercent have no caller yet (see improvement.ts's own
// header comment) -- only the changedFiles-based axes (test-evidence) can fire today; that is expected,
// not a bug in this PR, and the assessment degrades cleanly ("insufficient-signal"/"none") when they don't.
const structuralImprovementAssessment = improvementSignalAllowed
? buildStructuralImprovementAssessment({
changedFiles: (await getReviewFiles()).map((file) => ({
path: file.path,
additions: file.additions,
deletions: file.deletions,
})),
})
: undefined;
const commentArgs = {
repo,
pr,
Expand All @@ -11208,6 +11270,7 @@ async function maybePublishPrPublicSurface(
gate: gateEvaluation,
review: reviewConfig,
aiReview,
improvementSignal: structuralImprovementAssessment,
duplicateWinnerEnabled,
env,
};
Expand Down Expand Up @@ -11339,6 +11402,8 @@ async function maybePublishPrPublicSurface(
settings,
gate: commentGate,
duplicateWinnerEnabled,
improvementSignal: structuralImprovementAssessment,
valueAssessment: aiReview?.valueAssessment,
});
// Visual before/after capture (visual-capture port). Fires ONLY when (1) the "screenshots" converged
// feature resolves active for this repo (resolveConvergedFeature — the global flag AND (a per-repo
Expand Down
Loading