fix(MULTIVERSION-0001): prevent version jobs from overwriting repo-wide NULL rules entry
Version jobs now write rules only to the version-specific (repo, versionId) row. Previously every version job unconditionally wrote to the (repo, NULL) row as well, causing whichever version indexed last to contaminate the repo-wide rules that the context API merges into every query response. Adds a regression test (Bug5b) that indexes the main branch, then indexes a version with different rules, and asserts the NULL row still holds the main-branch rules. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -869,15 +869,17 @@ describe('IndexingPipeline', () => {
|
|||||||
|
|
||||||
await pipeline.run(job as never);
|
await pipeline.run(job as never);
|
||||||
|
|
||||||
// Repo-wide row (version_id IS NULL) must exist.
|
// Repo-wide row (version_id IS NULL) must NOT be written by a version job —
|
||||||
|
// writing it here would contaminate the NULL entry with version-specific rules
|
||||||
|
// (Bug 5b regression guard).
|
||||||
const repoRow = db
|
const repoRow = db
|
||||||
.prepare(
|
.prepare(
|
||||||
`SELECT rules FROM repository_configs WHERE repository_id = '/test/repo' AND version_id IS NULL`
|
`SELECT rules FROM repository_configs WHERE repository_id = '/test/repo' AND version_id IS NULL`
|
||||||
)
|
)
|
||||||
.get() as { rules: string } | undefined;
|
.get() as { rules: string } | undefined;
|
||||||
expect(repoRow).toBeDefined();
|
expect(repoRow).toBeUndefined();
|
||||||
|
|
||||||
// Version-specific row must also exist.
|
// Version-specific row must exist with the correct rules.
|
||||||
const versionRow = db
|
const versionRow = db
|
||||||
.prepare(
|
.prepare(
|
||||||
`SELECT rules FROM repository_configs WHERE repository_id = '/test/repo' AND version_id = ?`
|
`SELECT rules FROM repository_configs WHERE repository_id = '/test/repo' AND version_id = ?`
|
||||||
@@ -888,6 +890,69 @@ describe('IndexingPipeline', () => {
|
|||||||
expect(rules).toEqual(['This is v2. Use the new Builder API.']);
|
expect(rules).toEqual(['This is v2. Use the new Builder API.']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('regression(Bug5b): version job does not overwrite the repo-wide NULL rules entry', async () => {
|
||||||
|
// Arrange: index the main branch first to establish a repo-wide rules entry.
|
||||||
|
const mainBranchRules = ['Always use TypeScript strict mode.'];
|
||||||
|
const mainPipeline = makePipeline({
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
path: 'trueref.json',
|
||||||
|
content: JSON.stringify({ rules: mainBranchRules }),
|
||||||
|
sha: 'sha-main-config',
|
||||||
|
language: 'json'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
totalFiles: 1
|
||||||
|
});
|
||||||
|
const mainJob = makeJob('/test/repo'); // no versionId → main-branch job
|
||||||
|
await mainPipeline.run(mainJob as never);
|
||||||
|
|
||||||
|
// Confirm the repo-wide entry was written.
|
||||||
|
const afterMain = db
|
||||||
|
.prepare(
|
||||||
|
`SELECT rules FROM repository_configs WHERE repository_id = '/test/repo' AND version_id IS NULL`
|
||||||
|
)
|
||||||
|
.get() as { rules: string } | undefined;
|
||||||
|
expect(afterMain).toBeDefined();
|
||||||
|
expect(JSON.parse(afterMain!.rules)).toEqual(mainBranchRules);
|
||||||
|
|
||||||
|
// Act: index a version with different rules.
|
||||||
|
const versionId = insertVersion(db, { tag: 'v3.0.0', state: 'pending' });
|
||||||
|
const versionRules = ['v3 only: use the streaming API.'];
|
||||||
|
const versionPipeline = makePipeline({
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
path: 'trueref.json',
|
||||||
|
content: JSON.stringify({ rules: versionRules }),
|
||||||
|
sha: 'sha-v3-config',
|
||||||
|
language: 'json'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
totalFiles: 1
|
||||||
|
});
|
||||||
|
const versionJob = makeJob('/test/repo', versionId);
|
||||||
|
await versionPipeline.run(versionJob as never);
|
||||||
|
|
||||||
|
// Assert: the repo-wide NULL entry must still contain the main-branch rules,
|
||||||
|
// not the version-specific ones.
|
||||||
|
const afterVersion = db
|
||||||
|
.prepare(
|
||||||
|
`SELECT rules FROM repository_configs WHERE repository_id = '/test/repo' AND version_id IS NULL`
|
||||||
|
)
|
||||||
|
.get() as { rules: string } | undefined;
|
||||||
|
expect(afterVersion).toBeDefined();
|
||||||
|
expect(JSON.parse(afterVersion!.rules)).toEqual(mainBranchRules);
|
||||||
|
|
||||||
|
// And the version-specific row must contain the version rules.
|
||||||
|
const versionRow = db
|
||||||
|
.prepare(
|
||||||
|
`SELECT rules FROM repository_configs WHERE repository_id = '/test/repo' AND version_id = ?`
|
||||||
|
)
|
||||||
|
.get(versionId) as { rules: string } | undefined;
|
||||||
|
expect(versionRow).toBeDefined();
|
||||||
|
expect(JSON.parse(versionRow!.rules)).toEqual(versionRules);
|
||||||
|
});
|
||||||
|
|
||||||
it('persists rules from CrawlResult.config even when trueref.json is absent from files (folders allowlist bug)', async () => {
|
it('persists rules from CrawlResult.config even when trueref.json is absent from files (folders allowlist bug)', async () => {
|
||||||
// Regression test for MULTIVERSION-0001:
|
// Regression test for MULTIVERSION-0001:
|
||||||
// When trueref.json specifies a `folders` allowlist (e.g. ["src/"]),
|
// When trueref.json specifies a `folders` allowlist (e.g. ["src/"]),
|
||||||
|
|||||||
@@ -276,10 +276,13 @@ export class IndexingPipeline {
|
|||||||
|
|
||||||
// ---- Stage 6: Persist rules from config ----------------------------
|
// ---- Stage 6: Persist rules from config ----------------------------
|
||||||
if (parsedConfig?.config.rules?.length) {
|
if (parsedConfig?.config.rules?.length) {
|
||||||
// Repo-wide rules (versionId = null).
|
if (!normJob.versionId) {
|
||||||
|
// Main-branch job: write the repo-wide entry only.
|
||||||
this.upsertRepoConfig(repo.id, null, parsedConfig.config.rules);
|
this.upsertRepoConfig(repo.id, null, parsedConfig.config.rules);
|
||||||
// Version-specific rules stored separately when indexing a version.
|
} else {
|
||||||
if (normJob.versionId) {
|
// Version job: write only the version-specific entry.
|
||||||
|
// Writing to the NULL row here would overwrite repo-wide rules
|
||||||
|
// with whatever the last-indexed version happened to carry.
|
||||||
this.upsertRepoConfig(repo.id, normJob.versionId, parsedConfig.config.rules);
|
this.upsertRepoConfig(repo.id, normJob.versionId, parsedConfig.config.rules);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user