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
72 changes: 36 additions & 36 deletions apps/gittensory-ui/src/lib/selfhost-env-reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "AI_EMBED_API_KEY",
firstReference: "src/server.ts:425",
firstReference: "src/server.ts:428",
},
{
name: "AI_EMBED_BASE_URL",
firstReference: "src/server.ts:422",
firstReference: "src/server.ts:425",
},
{
name: "AI_EMBED_MODEL",
Expand Down Expand Up @@ -43,7 +43,7 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "BACKUP_ACKNOWLEDGED",
firstReference: "src/server.ts:364",
firstReference: "src/server.ts:367",
},
{
name: "BROWSER_WS_ENDPOINT",
Expand Down Expand Up @@ -79,23 +79,23 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "CRON_INTERVAL_MS",
firstReference: "src/server.ts:885",
firstReference: "src/server.ts:904",
},
{
name: "DATABASE_PATH",
firstReference: "src/server.ts:247",
firstReference: "src/server.ts:250",
},
{
name: "DATABASE_URL",
firstReference: "src/selfhost/preflight.ts:201",
},
{
name: "DISCORD_REPO_WEBHOOKS",
firstReference: "src/selfhost/discord-notify.ts:31",
firstReference: "src/services/notify-discord.ts:41",
},
{
name: "DISCORD_WEBHOOK_URL",
firstReference: "src/selfhost/discord-notify.ts:40",
firstReference: "src/services/notify-discord.ts:78",
},
{
name: "FOREGROUND_LIVENESS_ENABLED",
Expand All @@ -111,11 +111,11 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "GITHUB_CACHE_TTL_SECONDS",
firstReference: "src/server.ts:493",
firstReference: "src/server.ts:496",
},
{
name: "GITTENSORY_REPO_CONFIG_DIR",
firstReference: "src/server.ts:281",
firstReference: "src/server.ts:284",
},
{
name: "GITTENSORY_VERSION",
Expand All @@ -127,11 +127,11 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "MAINTENANCE_ADMISSION_ENABLED",
firstReference: "src/selfhost/maintenance-admission.ts:123",
firstReference: "src/selfhost/maintenance-admission.ts:129",
},
{
name: "MIGRATIONS_DIR",
firstReference: "src/server.ts:377",
firstReference: "src/server.ts:380",
},
{
name: "OBSERVABILITY_SMOKE_POLL_MS",
Expand Down Expand Up @@ -191,7 +191,7 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "ORB_BROKER_URL",
firstReference: "src/server.ts:934",
firstReference: "src/server.ts:953",
},
{
name: "ORB_COLLECTOR_TOKEN",
Expand All @@ -207,7 +207,7 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "ORB_RELAY_MODE",
firstReference: "src/server.ts:936",
firstReference: "src/server.ts:955",
},
{
name: "OTEL_EXPORTER_OTLP_ENDPOINT",
Expand Down Expand Up @@ -239,11 +239,11 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "PGVECTOR_ENABLED",
firstReference: "src/server.ts:227",
firstReference: "src/server.ts:230",
},
{
name: "PORT",
firstReference: "src/server.ts:684",
firstReference: "src/server.ts:703",
},
{
name: "PUBLIC_API_ORIGIN",
Expand All @@ -259,7 +259,7 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "QDRANT_URL",
firstReference: "src/server.ts:512",
firstReference: "src/server.ts:515",
},
{
name: "QUEUE_BACKGROUND_CONCURRENCY",
Expand All @@ -271,7 +271,7 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "REVIEW_AUDIT_DIR",
firstReference: "src/server.ts:557",
firstReference: "src/server.ts:560",
},
{
name: "SELFHOST_BUNDLE_ALL",
Expand Down Expand Up @@ -307,23 +307,23 @@ export const SELFHOST_ENV_REFERENCE_ROWS: SelfHostEnvReferenceRow[] = [
},
{
name: "SETUP_OUTPUT_PATH",
firstReference: "src/server.ts:801",
firstReference: "src/server.ts:820",
},
];

export const SELFHOST_ENV_REFERENCE_MARKDOWN = [
"| Name | First reference |",
"| --- | --- |",
"| `AI_COMBINE` | `src/selfhost/ai.ts:936` |",
"| `AI_EMBED_API_KEY` | `src/server.ts:425` |",
"| `AI_EMBED_BASE_URL` | `src/server.ts:422` |",
"| `AI_EMBED_API_KEY` | `src/server.ts:428` |",
"| `AI_EMBED_BASE_URL` | `src/server.ts:425` |",
"| `AI_EMBED_MODEL` | `src/selfhost/ai.ts:832` |",
"| `AI_ON_MERGE` | `src/selfhost/ai.ts:938` |",
"| `AI_PROVIDER` | `src/selfhost/ai-config.ts:43` |",
"| `ANTHROPIC_AI_BASE_URL` | `src/selfhost/ai.ts:836` |",
"| `ANTHROPIC_AI_MODEL` | `src/selfhost/ai.ts:57` |",
"| `ANTHROPIC_API_KEY` | `src/selfhost/ai.ts:835` |",
"| `BACKUP_ACKNOWLEDGED` | `src/server.ts:364` |",
"| `BACKUP_ACKNOWLEDGED` | `src/server.ts:367` |",
"| `BROWSER_WS_ENDPOINT` | `src/selfhost/stubs/puppeteer.ts:11` |",
"| `CLAUDE_AI_EFFORT` | `src/selfhost/ai.ts:108` |",
"| `CLAUDE_AI_MODEL` | `src/selfhost/ai.ts:49` |",
Expand All @@ -332,20 +332,20 @@ export const SELFHOST_ENV_REFERENCE_MARKDOWN = [
"| `CODEX_AI_MODEL` | `src/selfhost/ai.ts:53` |",
"| `CODEX_AI_TIMEOUT_MS` | `src/selfhost/ai.ts:112` |",
"| `CODEX_HOME` | `src/selfhost/ai.ts:274` |",
"| `CRON_INTERVAL_MS` | `src/server.ts:885` |",
"| `DATABASE_PATH` | `src/server.ts:247` |",
"| `CRON_INTERVAL_MS` | `src/server.ts:904` |",
"| `DATABASE_PATH` | `src/server.ts:250` |",
"| `DATABASE_URL` | `src/selfhost/preflight.ts:201` |",
"| `DISCORD_REPO_WEBHOOKS` | `src/selfhost/discord-notify.ts:31` |",
"| `DISCORD_WEBHOOK_URL` | `src/selfhost/discord-notify.ts:40` |",
"| `DISCORD_REPO_WEBHOOKS` | `src/services/notify-discord.ts:41` |",
"| `DISCORD_WEBHOOK_URL` | `src/services/notify-discord.ts:78` |",
"| `FOREGROUND_LIVENESS_ENABLED` | `src/selfhost/foreground-liveness.ts:41` |",
"| `GITHUB_APP_ID` | `src/selfhost/orb-collector.ts:59` |",
"| `GITHUB_APP_PRIVATE_KEY` | `src/selfhost/orb-collector.ts:166` |",
"| `GITHUB_CACHE_TTL_SECONDS` | `src/server.ts:493` |",
"| `GITTENSORY_REPO_CONFIG_DIR` | `src/server.ts:281` |",
"| `GITHUB_CACHE_TTL_SECONDS` | `src/server.ts:496` |",
"| `GITTENSORY_REPO_CONFIG_DIR` | `src/server.ts:284` |",
"| `GITTENSORY_VERSION` | `src/selfhost/health.ts:29` |",
"| `HOME` | `src/selfhost/ai.ts:274` |",
"| `MAINTENANCE_ADMISSION_ENABLED` | `src/selfhost/maintenance-admission.ts:123` |",
"| `MIGRATIONS_DIR` | `src/server.ts:377` |",
"| `MAINTENANCE_ADMISSION_ENABLED` | `src/selfhost/maintenance-admission.ts:129` |",
"| `MIGRATIONS_DIR` | `src/server.ts:380` |",
"| `OBSERVABILITY_SMOKE_POLL_MS` | `scripts/smoke-observability-traces.mjs:8` |",
"| `OBSERVABILITY_SMOKE_TIMEOUT_MS` | `scripts/smoke-observability-traces.mjs:6` |",
"| `OLLAMA_AI_API_KEY` | `src/selfhost/ai.ts:829` |",
Expand All @@ -360,27 +360,27 @@ export const SELFHOST_ENV_REFERENCE_MARKDOWN = [
"| `ORB_AIR_GAP` | `src/selfhost/orb-collector.ts:161` |",
"| `ORB_ANONYMIZE` | `src/selfhost/orb-collector.ts:174` |",
"| `ORB_APP_ID` | `src/selfhost/orb-collector.ts:59` |",
"| `ORB_BROKER_URL` | `src/server.ts:934` |",
"| `ORB_BROKER_URL` | `src/server.ts:953` |",
"| `ORB_COLLECTOR_TOKEN` | `src/selfhost/orb-collector.ts:205` |",
"| `ORB_COLLECTOR_URL` | `src/selfhost/orb-collector.ts:172` |",
"| `ORB_ENROLLMENT_SECRET` | `src/selfhost/orb-collector.ts:165` |",
"| `ORB_RELAY_MODE` | `src/server.ts:936` |",
"| `ORB_RELAY_MODE` | `src/server.ts:955` |",
"| `OTEL_EXPORTER_OTLP_ENDPOINT` | `src/selfhost/otel.ts:47` |",
"| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | `src/selfhost/otel.ts:45` |",
"| `OTEL_SERVICE_ENVIRONMENT` | `src/selfhost/otel.ts:60` |",
"| `OTEL_SERVICE_NAME` | `src/selfhost/otel.ts:59` |",
"| `OTEL_TRACES_EXPORTER` | `src/selfhost/otel.ts:40` |",
"| `OTEL_TRACES_SAMPLER` | `src/selfhost/otel.ts:74` |",
"| `OTEL_TRACES_SAMPLER_ARG` | `src/selfhost/otel.ts:76` |",
"| `PGVECTOR_ENABLED` | `src/server.ts:227` |",
"| `PORT` | `src/server.ts:684` |",
"| `PGVECTOR_ENABLED` | `src/server.ts:230` |",
"| `PORT` | `src/server.ts:703` |",
"| `PUBLIC_API_ORIGIN` | `src/selfhost/preflight.ts:192` |",
"| `QDRANT_API_KEY` | `src/selfhost/qdrant-vectorize.ts:50` |",
"| `QDRANT_DIM` | `src/selfhost/qdrant-vectorize.ts:71` |",
"| `QDRANT_URL` | `src/server.ts:512` |",
"| `QDRANT_URL` | `src/server.ts:515` |",
"| `QUEUE_BACKGROUND_CONCURRENCY` | `src/selfhost/queue-common.ts:102` |",
"| `REDIS_URL` | `src/selfhost/preflight.ts:144` |",
"| `REVIEW_AUDIT_DIR` | `src/server.ts:557` |",
"| `REVIEW_AUDIT_DIR` | `src/server.ts:560` |",
"| `SELFHOST_BUNDLE_ALL` | `scripts/build-selfhost.mjs:13` |",
"| `SELFHOST_SERVICE` | `scripts/smoke-observability-traces.mjs:5` |",
"| `SELFHOST_SETUP_TOKEN` | `src/selfhost/preflight.ts:186` |",
Expand All @@ -389,5 +389,5 @@ export const SELFHOST_ENV_REFERENCE_MARKDOWN = [
"| `SENTRY_RELEASE` | `src/selfhost/otel.ts:62` |",
"| `SENTRY_SERVER_NAME` | `src/selfhost/sentry.ts:383` |",
"| `SENTRY_TRACES_SAMPLE_RATE` | `src/selfhost/sentry.ts:171` |",
"| `SETUP_OUTPUT_PATH` | `src/server.ts:801` |",
"| `SETUP_OUTPUT_PATH` | `src/server.ts:820` |",
].join("\n");
13 changes: 13 additions & 0 deletions scripts/gen-selfhost-env-reference.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const DEFAULT_OUTPUT_PATH = "apps/gittensory-ui/src/lib/selfhost-env-refe
export const DEFAULT_SOURCE_ROOTS = [
"src/selfhost",
"src/server.ts",
"src/services/notify-discord.ts",
"scripts/build-selfhost.mjs",
"scripts/migrate-selfhost-sqlite-to-postgres.ts",
"scripts/smoke-observability-traces.mjs",
Expand Down Expand Up @@ -69,13 +70,25 @@ function collectEnvReads(source, fileName) {
const name = bindingElementName(element);
if (name) addRead(name, element.propertyName ?? element.name);
}
} else if (ts.isCallExpression(node) && isStaticEnvHelperCall(node)) {
addRead(node.arguments[1].text, node.arguments[1]);
}
ts.forEachChild(node, visit);
};
visit(sourceFile);
return reads;
}

function isStaticEnvHelperCall(node) {
return (
ts.isIdentifier(node.expression) &&
node.expression.text === "envString" &&
node.arguments.length >= 2 &&
isEnvContainer(node.arguments[0]) &&
ts.isStringLiteralLike(node.arguments[1])
);
}

function bindingElementName(element) {
const candidate = element.propertyName ?? element.name;
if (ts.isIdentifier(candidate) || ts.isStringLiteralLike(candidate)) return candidate.text;
Expand Down
17 changes: 16 additions & 1 deletion src/review/guardrail-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,26 @@ export const ENGINE_DECISION_GUARDRAIL_GLOBS = [
"src/review/outcomes-wire.ts", // the pr_outcome + reversal telemetry that feeds self-tuning
];

// Self-host runtime and persistence surface. These paths do not necessarily decide the verdict directly, but they
// decide whether the review stack can boot, store, queue, notify, migrate, and export safely. Keep this scoped to
// operational chokepoints so ordinary feature/review logic can still auto-merge when it is clean.
export const SELFHOST_RUNTIME_GUARDRAIL_GLOBS = [
"src/selfhost/**",
"src/server.ts",
"src/db/**",
"Dockerfile",
"docker-compose*.yml*",
"docker-compose*.yaml*",
"compose*.yml*",
"compose*.yaml*",
"systemd/**",
];

/**
* Resolve hard-guardrail path globs. Kept async to avoid touching the processor call graph, but this no longer
* reads external policy storage; self-host review policy belongs in container-private `.gittensory.yml`, and these
* engine-level guardrails are always-on invariants.
*/
export async function loadHardGuardrailGlobs(_env: Env, _repoFullName: string): Promise<string[]> {
return [...DEFAULT_CRUCIAL_GUARDRAIL_GLOBS, ...CONFIG_AS_CODE_GUARDRAIL_GLOBS, ...ENGINE_DECISION_GUARDRAIL_GLOBS];
return [...DEFAULT_CRUCIAL_GUARDRAIL_GLOBS, ...CONFIG_AS_CODE_GUARDRAIL_GLOBS, ...ENGINE_DECISION_GUARDRAIL_GLOBS, ...SELFHOST_RUNTIME_GUARDRAIL_GLOBS];
}
20 changes: 4 additions & 16 deletions src/review/outcomes-wire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
// once a repo's merge precision actually drops below the floor over a real sample.

import { recordAuditEvent } from "../db/repositories";
import { notifyDiscordReview } from "../selfhost/discord-notify";
import { incr } from "../selfhost/metrics";
import type { GitHubWebhookPayload } from "../types";
import { errorMessage, nowIso } from "../utils/json";
Expand Down Expand Up @@ -338,21 +337,10 @@ export async function recordPrOutcome(
),
);

// Per-repo Discord notification on the FINAL disposition (self-host; no-op unless a webhook is configured).
// Reason = the AI's recorded gate verdict for this PR, falling back to the plain disposition.
const fallbackReason = merged
? "Pull request merged into the base branch."
: botWasActor
? "Closed by Gittensory after review."
: "Pull request closed without merging.";
await notifyDiscordReview({
repoFullName,
prNumber: pr.number,
author: pr.user?.login ?? "unknown",
outcome: decision,
reason: await resolveDispositionReason(env, targetId, fallbackReason),
url: `https://github.com/${repoFullName}/pull/${pr.number}`,
});
// Discord/Slack action notifications are emitted by the action executor, which knows the exact bot action that
// was attempted and can audit the delivery. This outcome recorder only stores realized ground truth. Emitting
// another webhook from the GitHub `pull_request.closed` event duplicated bot-action notifications and could
// route through stale/global self-host webhook config.
}

// ── 2) reversals — a human undid a bot action ────────────────────────────────────────────────────────────────
Expand Down
Loading
Loading