Skip to content

ai: linked SQL and verdicts in the DeploymentAnalyzer input #1033

Description

@babltiga

Part of #1029 (linked deployment changes epic — read it first for the big picture). Needs #1031.

Goal

Show the deployment analyzer the database changes a release actually ships. The analysis input
gains the linked queries' SQL and their prior AI verdicts, rendered under a separate size cap and
placed in a dedicated section of the deployment prompt. Fail-safe behaviour is unchanged.

Today ai/api/DeploymentAnalyzer.java:34-37 defines DeploymentAnalysisInput(organizationId, aiConfigId, provider, environment, version, commitSha, artifactRef, metadataContext, language);
deploygov/internal/DeploymentAnalysisListener.java:70-74 builds it and caps the metadata slice
with MAX_METADATA_CONTEXT_CHARS = 16_000 (:45, renderMetadata :96-104).
ai/internal/DefaultDeploymentAnalyzer.java:26-41 frames a %s-formatted text block and hands it
to strategy.analyze(framed, DbType.CUSTOM, null, language, aiConfigId) (:45) — there is no
{{placeholder}} template and no SystemPromptRenderer involvement for deployments, so "a new
prompt placeholder" here means a new %s slot in that block. Lines :36-38 already tell the model
to treat "schema or data migrations" as elevated risk, blind.

Design constraints agreed on the epic:

  • ai imports nothing new. The context is assembled in deploygov through core.api and
    passed as a string; ai never learns what a deployment link is. deploygov → ai.api stays the
    only arrow (docs/05-backend.md:4326-4334).
  • A lookup failure degrades to a placeholder line — never a failed analysis, never an exception
    out of the listener beyond the existing AiAnalysisException | AiAnalysisParseException catch.
  • Prior verdicts are context, not authority: the prompt labels them as earlier analyses of the
    individual statements; the deployment's own verdict is still the model's.

Steps

  1. ai/api/DeploymentAnalyzer.java — add String linkedChangesContext to
    DeploymentAnalysisInput (null or blank = none). Record, so the change is a compile-time
    fan-out: update DeploymentAnalysisListener, DefaultDeploymentAnalyzerTest,
    DeploymentAnalysisListenerTest, and any other constructor call (grep -rn "DeploymentAnalysisInput(").
  2. deploygov/internal/DeploymentAnalysisListener.java — static final int MAX_LINKED_CHANGES_CONTEXT_CHARS = 24_000 beside the metadata cap, and a renderLinkedChanges
    that, for each link in sequence_order, reads QueryRequestLookupService.findById (SQL,
    queryType, status, datasourceId) and AiAnalysisLookupService.findByQueryRequestId
    (riskLevel, riskScore, summary, failed) and emits one block per link:
    #<seq> [<queryType>] status=<status> datasource=<name> prior_ai_risk=<LEVEL>/<score> on one
    line, the summary on the next, then the SQL — each SQL individually capped so one 50 kB
    migration cannot starve the rest, and the whole string truncated with the same
    "\n… (truncated)" marker renderMetadata uses. A missing analysis renders
    prior_ai_risk=(none), a failed one (analysis failed), a missing query (query no longer exists). Wrap the whole render in a RuntimeException catch that returns
    "(linked changes could not be loaded)" and logs at WARN. Both caps are constants (the
    deploygov: DeploymentReviewEscalationJob, reviewer nudges and DeploygovProperties #985 DeploygovProperties can absorb them later if anyone asks).
  3. ai/internal/DefaultDeploymentAnalyzer.java — one new %s section between the release
    metadata and the risk guidance:
    Linked database changes (each is a governed AccessFlow query request; prior_ai_risk is an earlier per-statement analysis, not a verdict on this deployment): followed by
    blankToNone(input.linkedChangesContext()). Extend the guidance line to say that a linked
    change already rated HIGH/CRITICAL, a DDL against a production-like environment, or a deploy
    that ships no linked change but whose metadata mentions migrations, is elevated risk. Keep the
    null schema-context argument and its comment (:42-44) — the linked SQL is already inside
    framed; passing it twice bills the org twice.
  4. docs/05-backend.md (:4326-4334) and docs/18-deployment-governance.md §3 (:153)
    — describe the new input field, both caps, the prompt section and the degradation rules;
    deploygov: linked-changes documentation sweep #1036 does the wider sweep, but the analyzer contract is documented in this PR.

Acceptance criteria

  • DefaultDeploymentAnalyzerTest: the framed prompt contains the linked section verbatim when
    the context is present and (none) when null/blank; the strategy still receives null schema
    context; the rate limiter is still enforced first.
  • DeploymentAnalysisListenerTest: rendering order follows sequence_order; per-SQL and total
    caps truncate with the marker; missing analysis / failed analysis / deleted query render their
    placeholders; a RuntimeException from a lookup yields the "could not be loaded" line and the
    analysis still completes; a request with no links passes null; the existing skipped / failed
    event paths are byte-for-byte unchanged.
  • mvn -f backend/pom.xml -q test -Dtest='ApplicationModulesTest,ApiPackageDependencyTest'
    passes — ai.api has no new import, and ai has no deploygov dependency.
  • Coverage ≥ 90 % lines / ≥ 80 % branches on the touched classes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions