feat: harden podman deployment orchestration

This commit is contained in:
Yahya Alhinai
2026-06-28 01:44:26 +00:00
parent 5185845090
commit c818d5081e
37 changed files with 1796 additions and 273 deletions
+11
View File
@@ -24,6 +24,13 @@ export async function getDb(): Promise<Db> {
return client.db();
}
export async function closeMemory(): Promise<void> {
if (!clientPromise) return;
const client = await clientPromise;
clientPromise = null;
await client.close();
}
export interface PodCollections {
pods: Collection<Pod>;
observations: Collection<EngineerContext>;
@@ -88,6 +95,10 @@ export async function initMemory(): Promise<void> {
['observations.podId', () => c.observations.createIndex({ podId: 1, observedAt: -1 })],
['observations.engineerId', () => c.observations.createIndex({ engineerId: 1 })],
['collisions.podId', () => c.collisions.createIndex({ podId: 1, detectedAt: -1 })],
[
'collisions.memorySignature',
() => c.collisions.createIndex({ podId: 1, memorySignature: 1 }),
],
['interventions.collisionId', () => c.interventions.createIndex({ collisionId: 1 })],
['outcomes.interventionId', () => c.outcomes.createIndex({ interventionId: 1 })],
];
+2 -1
View File
@@ -1,5 +1,6 @@
import type { EngineerContext, Collision, Intervention, InterventionOutcome } from '@podman/shared';
import { collections } from './db.js';
import { enrichCollisionMemory } from './vectors.js';
/**
* Continual-learning memory: persist observations, collisions, interventions,
@@ -22,7 +23,7 @@ export async function recordObservation(ctx: EngineerContext): Promise<void> {
export async function recordCollision(collision: Collision): Promise<void> {
await persist('collision', async () =>
(await collections()).collisions.insertOne({ ...collision }),
(await collections()).collisions.insertOne(await enrichCollisionMemory(collision)),
);
}
+118 -5
View File
@@ -1,10 +1,123 @@
import type { Collision } from '@podman/shared';
import { env } from '../env.js';
import { getDb } from './db.js';
type StoredCollision = Collision & {
memorySignature?: string;
memoryText?: string;
embedding?: number[];
};
interface VoyageEmbeddingResponse {
data?: Array<{ embedding?: number[] }>;
}
function normalize(value: string | undefined): string {
return (value ?? '').trim().toLowerCase();
}
function signature(collision: Collision): string {
return [normalize(collision.file), normalize(collision.symbol)].filter(Boolean).join('#');
}
function memoryText(collision: Collision): string {
return [
`file: ${collision.file}`,
collision.symbol ? `symbol: ${collision.symbol}` : undefined,
`engineers: ${collision.engineers.join(', ')}`,
`severity: ${collision.severity}`,
collision.githubState?.unpushed ? 'unpushed local changes present' : undefined,
]
.filter(Boolean)
.join('\n');
}
async function embed(text: string, inputType: 'document' | 'query'): Promise<number[] | null> {
if (!env.VOYAGE_API_KEY) return null;
try {
const res = await fetch('https://api.voyageai.com/v1/embeddings', {
method: 'POST',
headers: {
Authorization: `Bearer ${env.VOYAGE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
input: text,
model: env.VOYAGE_EMBEDDING_MODEL,
input_type: inputType,
}),
});
if (!res.ok) {
console.warn(`[memory] voyage embedding failed: ${res.status} ${await res.text()}`);
return null;
}
const body = (await res.json()) as VoyageEmbeddingResponse;
return body.data?.[0]?.embedding ?? null;
} catch (err) {
console.warn(`[memory] voyage embedding failed: ${(err as Error).message}`);
return null;
}
}
export async function enrichCollisionMemory(collision: Collision): Promise<StoredCollision> {
const text = memoryText(collision);
const embedding = await embed(text, 'document');
return {
...collision,
memorySignature: signature(collision),
memoryText: text,
...(embedding ? { embedding } : {}),
};
}
async function recallByVector(collision: Collision): Promise<Collision | null> {
const queryVector = await embed(memoryText(collision), 'query');
if (!queryVector) return null;
try {
const db = await getDb();
const [match] = await db
.collection<StoredCollision>('collisions')
.aggregate<StoredCollision>([
{
$vectorSearch: {
index: 'collision_embedding',
path: 'embedding',
queryVector,
numCandidates: 50,
limit: 5,
filter: { podId: collision.podId },
},
},
{ $match: { id: { $ne: collision.id } } },
{ $project: { _id: 0, embedding: 0 } },
])
.toArray();
return match ?? null;
} catch (err) {
console.warn(`[memory] vector recall unavailable: ${(err as Error).message}`);
return null;
}
}
async function recallBySignature(collision: Collision): Promise<Collision | null> {
const db = await getDb();
const sig = signature(collision);
const match = await db.collection<StoredCollision>('collisions').findOne(
{
podId: collision.podId,
id: { $ne: collision.id },
$or: [{ memorySignature: sig }, { file: collision.file }],
},
{ sort: { detectedAt: -1 }, projection: { _id: 0, embedding: 0 } },
);
return match ?? null;
}
/**
* Vector-based recall of prior collision patterns (Loop A).
* Stub: returns null until Voyage + Atlas Vector Search are wired.
* Recall prior collision patterns. Exact Mongo recall is always available;
* Voyage + Atlas Vector Search is used first when configured.
*/
export async function recallSimilar(_collision: Collision): Promise<Collision | null> {
// TODO(memory): embed collision.file via Voyage, query Atlas vector index
return null;
export async function recallSimilar(collision: Collision): Promise<Collision | null> {
return (await recallByVector(collision)) ?? recallBySignature(collision);
}