mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
fix(daemon): resolve P2 daemon feedback flagged on PR #1317
Two cleanups on Phase 10's daemon surface that the Phase 11 review
caught (lefarcen):
1. Module-URL-anchored fixture paths in synthetic-good.ts and
synthetic-bad.ts. The previous version used
path.join(__dirname, '..', 'v1', ...) which silently breaks if
the directory tree shifts. Replaced with new URL('../v1/...',
import.meta.url) so a fixture move surfaces as a clear ENOENT
pointing at this exact import. readFileSync accepts URL objects
directly so no path conversion is needed at the call site;
FIXTURE_PATH stays exported in string form for callers that
still need it.
2. Surface shipPayload in the shipped ConformanceOutcome. The
parser already hands the artifact bytes back via onArtifact, but
the previous shipped variant dropped them and the body silenced
the lint with void shipPayload. Added an artifact field
(ShipArtifactPayload | null) and removed the lint trick. A new
assertion in critique-conformance.test.ts pins MIME + non-empty
body on the synthetic-good shipped path.
16/16 daemon tests still green. Daemon typecheck clean.
This commit is contained in:
@@ -11,21 +11,23 @@
|
||||
*/
|
||||
|
||||
import { readFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import url from 'node:url';
|
||||
|
||||
const __filename = url.fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
/**
|
||||
* Module-URL-anchored fixture path (mirrors `synthetic-good.ts`; see
|
||||
* lefarcen P2 on PR #1317 for the rationale).
|
||||
*/
|
||||
export const SYNTHETIC_BAD_FIXTURE_URL = new URL(
|
||||
'../v1/malformed-unbalanced.txt',
|
||||
import.meta.url,
|
||||
);
|
||||
|
||||
export const SYNTHETIC_BAD_FIXTURE_PATH = path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'v1',
|
||||
'malformed-unbalanced.txt',
|
||||
export const SYNTHETIC_BAD_FIXTURE_PATH = url.fileURLToPath(
|
||||
SYNTHETIC_BAD_FIXTURE_URL,
|
||||
);
|
||||
|
||||
export function syntheticBadTranscript(): string {
|
||||
return readFileSync(SYNTHETIC_BAD_FIXTURE_PATH, 'utf8');
|
||||
return readFileSync(SYNTHETIC_BAD_FIXTURE_URL, 'utf8');
|
||||
}
|
||||
|
||||
export async function* syntheticBadStream(): AsyncIterable<string> {
|
||||
|
||||
@@ -16,26 +16,34 @@
|
||||
*/
|
||||
|
||||
import { readFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import url from 'node:url';
|
||||
|
||||
const __filename = url.fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
/**
|
||||
* Resolve the fixture relative to *this module's URL* rather than `cwd`.
|
||||
* `new URL(relative, import.meta.url)` is the module-anchored equivalent
|
||||
* of `path.join(__dirname, relative)` and is the form
|
||||
* lefarcen P2 on PR #1317 asked for: a directory move of either this
|
||||
* file or the fixture would surface as a clear ENOENT pointing at this
|
||||
* exact line rather than a stale `path.join('..', 'v1', ...)` that
|
||||
* silently resolves to the wrong place.
|
||||
*/
|
||||
export const SYNTHETIC_GOOD_FIXTURE_URL = new URL(
|
||||
'../v1/happy-3-rounds.txt',
|
||||
import.meta.url,
|
||||
);
|
||||
|
||||
/** Path of the bundled fixture so test harnesses can `readFile` it directly. */
|
||||
export const SYNTHETIC_GOOD_FIXTURE_PATH = path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'v1',
|
||||
'happy-3-rounds.txt',
|
||||
/** String form of the fixture path so tests and tooling can still `path.join` against it. */
|
||||
export const SYNTHETIC_GOOD_FIXTURE_PATH = url.fileURLToPath(
|
||||
SYNTHETIC_GOOD_FIXTURE_URL,
|
||||
);
|
||||
|
||||
/**
|
||||
* Read the canonical happy-path transcript synchronously. The file ships
|
||||
* with the daemon source so the call cannot fail in a packaged build.
|
||||
* with the daemon source so the call cannot fail in a packaged build;
|
||||
* `readFileSync` accepts URL objects directly.
|
||||
*/
|
||||
export function syntheticGoodTranscript(): string {
|
||||
return readFileSync(SYNTHETIC_GOOD_FIXTURE_PATH, 'utf8');
|
||||
return readFileSync(SYNTHETIC_GOOD_FIXTURE_URL, 'utf8');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -72,7 +72,22 @@ export type ConformanceDegradedReason =
|
||||
| 'incomplete_panel';
|
||||
|
||||
export type ConformanceOutcome =
|
||||
| { kind: 'shipped'; round: number; composite: number; events: PanelEvent[] }
|
||||
| {
|
||||
kind: 'shipped';
|
||||
round: number;
|
||||
composite: number;
|
||||
events: PanelEvent[];
|
||||
/**
|
||||
* Artifact bytes the parser handed back via the `onArtifact`
|
||||
* callback for the SHIP event. Callers that want to pin
|
||||
* MIME / byte-length / hash on the nightly cycle read this
|
||||
* directly. Always set on `shipped` because the parser rejects
|
||||
* a missing-artifact SHIP with `MissingArtifactError` upstream
|
||||
* (lefarcen P2 on PR #1317: previously captured-but-never-
|
||||
* returned, masked by a `void shipPayload` lint trick).
|
||||
*/
|
||||
artifact: ShipArtifactPayload | null;
|
||||
}
|
||||
| { kind: 'degraded'; reason: ConformanceDegradedReason; events: PanelEvent[] }
|
||||
| { kind: 'failed'; cause: 'no_ship' | 'unexpected_error'; events: PanelEvent[]; error?: string };
|
||||
|
||||
@@ -153,6 +168,7 @@ export async function runAdapterConformance(
|
||||
round: event.round,
|
||||
composite: event.composite,
|
||||
events,
|
||||
artifact: shipPayload,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -172,11 +188,6 @@ export async function runAdapterConformance(
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
};
|
||||
}
|
||||
// Silence the unused-locals lint: shipPayload is filled by the
|
||||
// onArtifact callback but only the parser-yielded SHIP event drives
|
||||
// routing here, so the body is informational for callers that need
|
||||
// it later (e.g. a follow-up that asserts artifact bytes round-trip).
|
||||
void shipPayload;
|
||||
|
||||
return { kind: 'failed', cause: 'no_ship', events };
|
||||
}
|
||||
|
||||
@@ -51,6 +51,13 @@ describe('adapter conformance harness (Phase 10)', () => {
|
||||
// for downstream inspection.
|
||||
expect(outcome.events.length).toBeGreaterThan(0);
|
||||
expect(outcome.events.find((e) => e.type === 'ship')).toBeTruthy();
|
||||
// The shipped outcome must surface the artifact bytes the parser
|
||||
// handed back via onArtifact, so a nightly cycle can pin MIME /
|
||||
// byte-length / hash without re-parsing the transcript (lefarcen
|
||||
// P2 on PR #1317).
|
||||
expect(outcome.artifact).not.toBeNull();
|
||||
expect(outcome.artifact?.mime).toMatch(/^text\/(html|markdown)/);
|
||||
expect(outcome.artifact?.body.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('synthetic-bad emits degraded with the parser-derived reason and marks the adapter', async () => {
|
||||
|
||||
Reference in New Issue
Block a user