feat(ql3): establish 3.0 incubation baseline

This commit is contained in:
whyour
2026-08-12 00:25:26 +08:00
parent 4bf92dcfeb
commit c699c32461
2817 changed files with 779642 additions and 653 deletions
@@ -0,0 +1,254 @@
require('ts-node/register/transpile-only');
const assert = require('node:assert/strict');
const { test } = require('node:test');
const { Sequelize } = require('sequelize');
const {
defineSchemaMigrationModel,
} = require('../../back/data/schemaMigration');
const {
taskExecutionRevisionMigration,
} = require('../../back/migrations/0012-task-execution-revisions');
const {
LOCAL_EXECUTION_CONTEXT_RECIPE_TABLE,
localExecutionContextRecipeMigration,
} = require('../../back/migrations/0013-local-execution-context-recipes');
const { runMigrations } = require('../../back/migrations/runner');
const {
LegacySequelizeLocalExecutionContextRecipeRepository,
LocalExecutionContextRecipeCorruptError,
} = require('../../back/runtime/adapters/legacy-sequelize/localExecutionContextRecipeRepository');
const {
LegacySequelizeTaskExecutionRevisionRepository,
} = require('../../back/runtime/adapters/legacy-sequelize/taskExecutionRevisionRepository');
const {
LocalTaskExecutionRevisionPublisher,
} = require('../../back/runtime/application/localTaskExecutionRevisionPublisher');
const {
RecipeLocalExecutionContextMaterializer,
} = require('../../back/runtime/application/recipeLocalExecutionContextMaterializer');
const {
createLocalExecutionContextRecipe,
localExecutionContextRecipeDigest,
} = require('../../back/runtime/domain/localExecutionContextRecipe');
function contextRecipe() {
return createLocalExecutionContextRecipe([
{ name: 'MODE', kind: 'public', value: 'edge' },
{ name: 'TOKEN', kind: 'secret', secretRef: 'secret://token' },
]);
}
function revision(recipe = contextRecipe()) {
return {
projectId: 'default',
taskId: 'task-recipe',
taskRevision: 'revision-1',
executorType: 'local_process',
execution: {
command: { kind: 'argv', file: '/bin/true', args: [] },
environmentPolicy: 'isolated',
terminationGraceMs: 100,
},
contextRef: recipe.contextRef,
};
}
function candidate() {
return {
runId: 'run-recipe',
attemptId: 'attempt-recipe',
projectId: 'default',
taskId: 'task-recipe',
taskRevision: 'revision-1',
executorType: 'local_process',
priority: 0,
queuedAtMs: 1_760_000_000_000,
attemptCreatedAtMs: 1_760_000_000_000,
};
}
async function createRepositories(t) {
const database = new Sequelize({
dialect: 'sqlite',
storage: ':memory:',
logging: false,
});
t.after(() => database.close());
await runMigrations({
database,
migrationModel: defineSchemaMigrationModel(database),
migrations: [
taskExecutionRevisionMigration,
localExecutionContextRecipeMigration,
],
logger: { info() {} },
});
return {
database,
recipes: new LegacySequelizeLocalExecutionContextRecipeRepository(database),
revisions: new LegacySequelizeTaskExecutionRevisionRepository(database),
};
}
test('uses stable content-address and digest vectors without persisting Secret values', () => {
const recipe = contextRecipe();
assert.equal(
recipe.contextRef,
'localctx:sha256:d70176732d42e2701d95adce0371b765226a3d5085e17d14816615c933fc5c7f',
);
assert.equal(
localExecutionContextRecipeDigest(recipe),
'a1acbef2b7b882a0e6f204bd79f303a10fa6043753251ebb222adb31d42b2597',
);
assert.equal(
createLocalExecutionContextRecipe([...recipe.environment].reverse())
.contextRef,
recipe.contextRef,
);
assert.equal(JSON.stringify(recipe).includes('in-memory-secret'), false);
});
test('concurrent immutable recipe publication converges and resolves exactly', async (t) => {
const { recipes } = await createRepositories(t);
const recipe = contextRecipe();
const results = await Promise.all(
Array.from({ length: 12 }, (_, index) =>
recipes.insert(recipe, 100 + index),
),
);
assert.equal(results.filter((result) => result === 'inserted').length, 1);
assert.equal(results.filter((result) => result === 'idempotent').length, 11);
const stored = await recipes.resolve(recipe.contextRef);
assert.deepEqual(stored.environment, recipe.environment);
assert.ok(Object.isFrozen(stored));
assert.ok(Object.isFrozen(stored.environment));
assert.equal(await recipes.resolve(`${recipe.contextRef}-missing`), null);
await assert.rejects(
recipes.insert({ ...recipe, contextRef: 'localctx:sha256:wrong' }, 200),
/not content-addressed/,
);
});
test('fails closed on persisted recipe corruption and cluster dialect use', async (t) => {
const { database, recipes } = await createRepositories(t);
const recipe = contextRecipe();
await recipes.insert(recipe, 100);
await database
.getQueryInterface()
.bulkUpdate(
LOCAL_EXECUTION_CONTEXT_RECIPE_TABLE,
{ content_digest: '0'.repeat(64) },
{ context_ref: recipe.contextRef },
);
await assert.rejects(
recipes.resolve(recipe.contextRef),
LocalExecutionContextRecipeCorruptError,
);
assert.throws(
() =>
new LegacySequelizeLocalExecutionContextRecipeRepository({
getDialect: () => 'postgres',
}),
/PostgreSQL adapter/,
);
});
test('publishes recipe before revision and materializes it with ephemeral Secrets', async (t) => {
const { recipes, revisions } = await createRepositories(t);
const recipe = contextRecipe();
const publisher = new LocalTaskExecutionRevisionPublisher(recipes, revisions);
assert.deepEqual(
await publisher.publish({
revision: revision(recipe),
contextRecipe: recipe,
createdAtMs: 100,
}),
{ contextRecipe: 'inserted', revision: 'inserted' },
);
assert.deepEqual(
await publisher.publish({
revision: revision(recipe),
contextRecipe: recipe,
createdAtMs: 101,
}),
{ contextRecipe: 'idempotent', revision: 'idempotent' },
);
assert.equal(
(await revisions.resolve(revision(recipe))).contextRef,
recipe.contextRef,
);
const materializer = new RecipeLocalExecutionContextMaterializer(
recipes,
{
async prepare() {
return {
logArtifactId: `local-${'c'.repeat(30)}`,
output: { async write() {} },
dispose() {},
};
},
},
{
async resolve() {
return ['in-memory-secret'];
},
},
);
const context = await materializer.prepare({
candidate: candidate(),
contextRef: recipe.contextRef,
});
assert.deepEqual(
{ ...context.context.environment },
{
MODE: 'edge',
TOKEN: 'in-memory-secret',
},
);
});
test('a missing or failed recipe publication can never create a dangling revision', async () => {
const calls = [];
const publisher = new LocalTaskExecutionRevisionPublisher(
{
async resolve() {
return null;
},
async insert() {
calls.push('recipe');
throw new Error('recipe write failed');
},
},
{
async resolve() {
return null;
},
async insert() {
calls.push('revision');
return 'inserted';
},
},
);
const recipe = contextRecipe();
await assert.rejects(
publisher.publish({
revision: revision(recipe),
contextRecipe: recipe,
createdAtMs: 100,
}),
/recipe write failed/,
);
assert.deepEqual(calls, ['recipe']);
await assert.rejects(
publisher.publish({
revision: { ...revision(recipe), contextRef: 'localctx:sha256:other' },
contextRecipe: recipe,
createdAtMs: 100,
}),
/does not match/,
);
assert.deepEqual(calls, ['recipe']);
});