Groundskeeper

Go package structure and dependency rules

This document makes package ownership reviewable before the Phase 1 module exists. Directories should be created as implementation reaches them; placeholder Go code is avoided because exported types would prematurely freeze draft contracts.

Ownership

PackageOwns
cmd/guardrailsdprocess composition only: config loading, wiring, server lifecycle, signals
internal/appapplication assembly and readiness; no domain rules
internal/modelcanonical immutable value objects and validation invariants
internal/evaluationorchestration, detector scheduling, composition, span conflict resolution, transformations
internal/policyauthoring parse/validate, CEL environment, DAG compiler, snapshots, trusted binding resolution
internal/correlationPostgreSQL repositories, approved correlation/provenance model, deterministic snapshot compilation
internal/checks/piigeneric and Australian PII detection/evidence, not policy actions
internal/checks/credentialscredential candidates, entropy/context/allowlists; no live remote validation
internal/checks/jailbreakjailbreak and prompt-injection evidence
internal/checks/safetysafety classification evidence
internal/adapter/canonicaldirect API request mapping
internal/adapter/portkeyPortkey webhook/full replacement mapping only
internal/adapter/protocolprovider payload extraction and reconstruction
internal/transport/httpGin routes, auth middleware boundary, limits, problem responses
internal/platform/configoperator-owned runtime configuration
internal/platform/telemetrysafe logs, metrics, traces, audit sink adapters

Keep registries by extension kind rather than a universal plugin registry. Most code remains under internal; do not publish a Go SDK/plugin API until its compatibility contract is deliberately frozen.

Dependency direction

cmd/guardrailsd
      │
      ▼
internal/app ─────▶ transport/http ─────▶ adapter/*
      │                                      │
      ├────────────▶ evaluation ◀────────────┘
      │                  │
      │                  ├────▶ model
      │                  ├────▶ policy ─────▶ model
      │                  └────▶ detector interfaces in evaluation/model
      │
      ├────────────▶ correlation ───────────▶ policy/model snapshot inputs
      ├────────────▶ checks/* ──────────────▶ model
      └────────────▶ platform/*

Domain packages never import Gin, Portkey types, SQL, protobuf transport types, or process-global configuration. Detectors never import the composer. Adapters may depend on canonical model interfaces but the model cannot depend on adapters. PostgreSQL repositories live in internal/correlation, not internal/model or the evaluator's request path. That package compiles approved rows into snapshot inputs; the evaluator depends on the resulting immutable model, never the repository.

HTTP server boundary

internal/transport/http constructs a Gin engine and returns net/http.Handler. cmd/guardrailsd or internal/app owns http.Server configuration including read-header, request-read, response-write, and idle timeouts, maximum body size, graceful shutdown, and readiness. Gin context must not escape route handlers.

Contract generation

OpenAPI, JSON Schema, and protobuf are reviewed source artefacts under api/. Generated code goes to a clearly marked generated tree and is reproducible; hand- written domain types do not alias generated transport types. Contract drift tests map both directions and exercise unknown/invalid values explicitly.

Test placement

  • package-local unit, property, and fuzz tests sit with implementation;
  • gateway/protocol goldens live under test/contract;
  • execution-neutral detector/composer cases live under test/conformance;
  • benchmark corpus manifests live under test/evaldata, while restricted data remains outside Git under its approved governance and access controls.

On this page