fix: normalize ambience loudness for v0.2.5
This commit is contained in:
+167
-9
@@ -4,12 +4,23 @@ import { readFileSync, readdirSync } from "node:fs";
|
||||
import { expect, it } from "vitest";
|
||||
import { ENVIRONMENTS } from "../src/content";
|
||||
|
||||
// 과거 ASR/보존 검사는 해당 버전의 정확한 바이트를 읽는다. 새 음원의 인수로 재사용하지 않는다.
|
||||
const readHistoricalBytes = (path: string) =>
|
||||
readFileSync(
|
||||
path.startsWith("public/ambience/")
|
||||
? path.replace(
|
||||
"public/ambience/",
|
||||
".agent/evidence-v0.2.5/baseline/ambience/",
|
||||
)
|
||||
: path,
|
||||
);
|
||||
|
||||
// 생성기 자기 보고 대신 배포 바이트의 형식·파형·권리 추적 정보를 독립 측정한다.
|
||||
it("여덟 현장 녹음은 고유 PCM16 WAV·짧은 fade·완전한 provenance/notice를 가진다", () => {
|
||||
const manifest = JSON.parse(
|
||||
readFileSync("public/ambience/manifest.json", "utf8"),
|
||||
);
|
||||
expect(manifest.version).toBe("0.2.3");
|
||||
expect(manifest.version).toBe("0.2.5");
|
||||
expect(
|
||||
manifest.files.map((f: { environmentId: string }) => f.environmentId),
|
||||
).toEqual(ENVIRONMENTS.map((e) => e.id));
|
||||
@@ -177,13 +188,16 @@ it("선택 구간은 승인 계획의 불변 provenance이며 manifest와 고지
|
||||
}
|
||||
});
|
||||
|
||||
it("최종 ASR 증거는 정확한 WAV와 연결되며 청취·법적 인수로 주장하지 않는다", () => {
|
||||
it("v0.2.3 최종 ASR 증거는 정확한 WAV와 연결되며 청취·법적 인수로 주장하지 않는다", () => {
|
||||
const directory = ".agent/evidence-v0.2.3/privacy-screening";
|
||||
const screening = JSON.parse(
|
||||
readFileSync(`${directory}/final-asr.json`, "utf8"),
|
||||
);
|
||||
const manifest = JSON.parse(
|
||||
readFileSync("public/ambience/manifest.json", "utf8"),
|
||||
readFileSync(
|
||||
".agent/evidence-v0.2.5/baseline/ambience/manifest.json",
|
||||
"utf8",
|
||||
),
|
||||
);
|
||||
expect(screening.tool).toMatchObject({
|
||||
name: "faster-whisper",
|
||||
@@ -212,7 +226,9 @@ it("최종 ASR 증거는 정확한 WAV와 연결되며 청취·법적 인수로
|
||||
});
|
||||
expect(screening.method.manifestSha256).toBe(
|
||||
createHash("sha256")
|
||||
.update(readFileSync("public/ambience/manifest.json"))
|
||||
.update(
|
||||
readFileSync(".agent/evidence-v0.2.5/baseline/ambience/manifest.json"),
|
||||
)
|
||||
.digest("hex"),
|
||||
);
|
||||
expect(screening.limitations).toMatchObject({
|
||||
@@ -261,7 +277,7 @@ it("최종 ASR 증거는 정확한 WAV와 연결되며 청취·법적 인수로
|
||||
).toBe(record.sha256);
|
||||
});
|
||||
|
||||
it("101개 음성·다섯 현장음 및 이전 evidence 바이트를 보존한다", () => {
|
||||
it("v0.2.3 역사 snapshot은 당시 101개 음성·다섯 현장음 보존을 증명한다", () => {
|
||||
const baseline = JSON.parse(
|
||||
readFileSync(
|
||||
".agent/evidence-v0.2.3/privacy-screening/baseline.json",
|
||||
@@ -273,7 +289,7 @@ it("101개 음성·다섯 현장음 및 이전 evidence 바이트를 보존한
|
||||
changedAmbience = 0;
|
||||
for (const [path, before] of Object.entries(baseline.wavSha256)) {
|
||||
const actual = createHash("sha256")
|
||||
.update(readFileSync(path))
|
||||
.update(readHistoricalBytes(path))
|
||||
.digest("hex");
|
||||
if (/public\/ambience\/(mall|market|cafe)\.wav$/.test(path)) {
|
||||
expect(actual).not.toBe(before);
|
||||
@@ -288,19 +304,19 @@ it("101개 음성·다섯 현장음 및 이전 evidence 바이트를 보존한
|
||||
for (const [path, before] of Object.entries(baseline.priorAgentFiles)) {
|
||||
if (baseline.mutableAgentFiles.includes(path)) continue;
|
||||
expect(
|
||||
createHash("sha256").update(readFileSync(path)).digest("hex"),
|
||||
createHash("sha256").update(readHistoricalBytes(path)).digest("hex"),
|
||||
path,
|
||||
).toBe(before);
|
||||
}
|
||||
});
|
||||
|
||||
it("재시도는 market/cafe만 바꾸고 mall 및 실패·no-VAD 증거를 바이트 그대로 보존한다", () => {
|
||||
it("v0.2.3 재시도는 market/cafe만 바꾸고 mall 및 실패·no-VAD 증거를 바이트 그대로 보존한다", () => {
|
||||
const directory = ".agent/evidence-v0.2.3/privacy-screening";
|
||||
const baseline = JSON.parse(
|
||||
readFileSync(`${directory}/retry-market24-cafe0/baseline.json`, "utf8"),
|
||||
);
|
||||
const hash = (path: string) =>
|
||||
createHash("sha256").update(readFileSync(path)).digest("hex");
|
||||
createHash("sha256").update(readHistoricalBytes(path)).digest("hex");
|
||||
const prior = `${directory}/prior-attempt-market60-cafe180`;
|
||||
expect(hash(`${prior}/final-asr.json`)).toBe(
|
||||
"01c8a92fab9f8df7a5f778c5f7e478ce96bcedc33e11a1055bd29154a08b706b",
|
||||
@@ -352,3 +368,145 @@ it("재시도는 market/cafe만 바꾸고 mall 및 실패·no-VAD 증거를 바
|
||||
]);
|
||||
expect([voices, preservedAmbience]).toEqual([101, 6]);
|
||||
});
|
||||
|
||||
// 이번 릴리스는 8 배경을 모두 바꾸되 원본·선택 구간·권리와 101 voice/660 역사 파일을 보존한다.
|
||||
it("v0.2.5는 이전 증거·음성 바이트와 모든 출처 필드를 그대로 보존한다", () => {
|
||||
const baseline = JSON.parse(
|
||||
readFileSync(".agent/evidence-v0.2.5/baseline.json", "utf8"),
|
||||
);
|
||||
for (const [path, expected] of Object.entries({
|
||||
...baseline.immutable,
|
||||
...baseline.voiceWavs,
|
||||
}))
|
||||
expect(
|
||||
createHash("sha256").update(readFileSync(path)).digest("hex"),
|
||||
path,
|
||||
).toBe(expected);
|
||||
const prior = JSON.parse(
|
||||
readFileSync(
|
||||
".agent/evidence-v0.2.5/baseline/ambience/manifest.json",
|
||||
"utf8",
|
||||
),
|
||||
);
|
||||
const current = JSON.parse(
|
||||
readFileSync("public/ambience/manifest.json", "utf8"),
|
||||
);
|
||||
for (const [index, before] of prior.files.entries()) {
|
||||
const after = current.files[index];
|
||||
for (const key of [
|
||||
"environmentId",
|
||||
"pageUrl",
|
||||
"directUrl",
|
||||
"creator",
|
||||
"license",
|
||||
"licenseUrl",
|
||||
"attribution",
|
||||
"expectedSourceSha256",
|
||||
"sourceBytes",
|
||||
"sourceSha256",
|
||||
"directMediaDurationSeconds",
|
||||
"sourceVerification",
|
||||
"selectedSegmentStartSeconds",
|
||||
"outputLicense",
|
||||
])
|
||||
expect(after[key], key).toEqual(before[key]);
|
||||
expect(after.sha256).not.toBe(before.sha256);
|
||||
}
|
||||
});
|
||||
|
||||
// 새 바이트의 ASR은 과거 승인으로 대체하지 않는다. 성공을 강제하려고 결과를 지우면 실패한다.
|
||||
it("거부된 loudnorm WAV의 ASR 실패와 privacy 인수 경계를 보존한다", () => {
|
||||
const screening = JSON.parse(
|
||||
readFileSync(".agent/evidence-v0.2.5/final-asr.json", "utf8"),
|
||||
);
|
||||
const manifestBytes = readFileSync(
|
||||
".agent/evidence-v0.2.5/review-fixes/rejected-loudnorm-bundle/manifest.json",
|
||||
);
|
||||
const manifest = JSON.parse(manifestBytes.toString());
|
||||
expect(screening.method.manifestSha256).toBe(
|
||||
createHash("sha256").update(manifestBytes).digest("hex"),
|
||||
);
|
||||
expect(screening.requiredEmptyPassed).toBe(false);
|
||||
expect(screening.limitations).toMatchObject({
|
||||
humanListeningAcceptance: false,
|
||||
legalPrivacyClearance: false,
|
||||
textIsVerifiedTranscript: false,
|
||||
});
|
||||
for (const entry of manifest.files) {
|
||||
const record = screening.files.find(
|
||||
(r: { environmentId: string }) => r.environmentId === entry.environmentId,
|
||||
);
|
||||
expect(record).toMatchObject({
|
||||
sha256: entry.sha256,
|
||||
sourceSha256: entry.sourceSha256,
|
||||
selectedSegmentStartSeconds: entry.selectedSegmentStartSeconds,
|
||||
});
|
||||
expect(record.segments).toHaveLength(
|
||||
entry.environmentId === "market" ? 1 : 0,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// 원래 true 요구 테스트와 FAIL 로그는 release-approval/before-ambience.test.ts.txt 및
|
||||
// 02-original-ASR-FAIL.log에 보존했다. 현재 검사는 실패 진단의 불변성을 강제한다.
|
||||
// 실제 릴리스 OR 계약은 release-approval.test.ts에서 별도로 검사한다.
|
||||
it("v0.2.5 exact WAV의 ASR 실패 진단은 원문 바이트·market segment를 보존한다", () => {
|
||||
expect(
|
||||
createHash("sha256")
|
||||
.update(
|
||||
readFileSync(".agent/evidence-v0.2.5/review-fixes/final-asr.json"),
|
||||
)
|
||||
.digest("hex"),
|
||||
).toBe("98acdb16bc5dce57bb3609b705b63125e5511c2d5f7b26bdde54f4b7bd9a5e49");
|
||||
const screening = JSON.parse(
|
||||
readFileSync(".agent/evidence-v0.2.5/review-fixes/final-asr.json", "utf8"),
|
||||
);
|
||||
const prior = JSON.parse(
|
||||
readFileSync(".agent/evidence-v0.2.5/final-asr.json", "utf8"),
|
||||
);
|
||||
const bytes = readFileSync("public/ambience/manifest.json");
|
||||
const manifest = JSON.parse(bytes.toString());
|
||||
expect(screening.tool).toEqual(prior.tool);
|
||||
expect(screening.model).toEqual(prior.model);
|
||||
for (const key of [
|
||||
"device",
|
||||
"computeType",
|
||||
"cpuThreads",
|
||||
"numWorkers",
|
||||
"randomSeed",
|
||||
"parameters",
|
||||
"vadModelSha256",
|
||||
])
|
||||
expect(screening.method[key]).toEqual(prior.method[key]);
|
||||
expect(screening.method.manifestSha256).toBe(
|
||||
createHash("sha256").update(bytes).digest("hex"),
|
||||
);
|
||||
expect(screening.requiredEmptyEnvironmentIds).toEqual([
|
||||
"mall",
|
||||
"market",
|
||||
"cafe",
|
||||
]);
|
||||
expect(screening.requiredEmptyPassed).toBe(false);
|
||||
expect(screening.limitations).toMatchObject({
|
||||
humanListeningAcceptance: false,
|
||||
legalPrivacyClearance: false,
|
||||
textIsVerifiedTranscript: false,
|
||||
});
|
||||
for (const entry of manifest.files) {
|
||||
const row = screening.files.find(
|
||||
(r: { environmentId: string }) => r.environmentId === entry.environmentId,
|
||||
);
|
||||
expect(row).toMatchObject({
|
||||
sha256: entry.sha256,
|
||||
bytes: entry.bytes,
|
||||
sourceSha256: entry.sourceSha256,
|
||||
selectedSegmentStartSeconds: entry.selectedSegmentStartSeconds,
|
||||
});
|
||||
expect(row.segments).toHaveLength(entry.environmentId === "market" ? 1 : 0);
|
||||
if (["mall", "cafe"].includes(entry.environmentId)) {
|
||||
expect(row.segments).toEqual([]);
|
||||
expect(row.text).toBe("");
|
||||
expect(row.info.duration_after_vad).toBe(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user