fix(fallow): resolve audit findings for portrait --resolution PR

Three findings, all resolved:

- packages/producer/src/server.ts `render` (CRAP 31.6, cyclo 10 — minor):
  pre-existing complexity; the PR only threads
  `outputResolutionAspectAgnostic` through parseRenderOverrides /
  RenderInput and does not touch `render`. Line-shift fingerprint —
  exempted via health.ignore with justification comment.

- packages/producer/src/services/distributed/plan.ts `plan` (CRAP 36.7,
  cyclo 33 — major): pre-existing complexity; the PR only adds one
  optional field spread inside `plan` and does not add branches.
  Line-shift fingerprint — exempted via health.ignore with justification.

- packages/producer/src/services/render/stages/compileStage.ts
  `runCompileStage` (cyclo 23, cognitive 19 — minor): this one is a
  real complexity bump from the two-branch aspect-agnostic re-target
  block added in the fix. Extracted the block into a local helper
  `adaptAspectAgnosticResolution` so `runCompileStage` stays under both
  the cyclomatic (20) and cognitive (15) thresholds.

Verified locally with `fallow audit --base origin/main --fail-on-issues`
(exit 0, "No GitHub PR/MR findings") and `tsc --noEmit` on the producer
package.

Co-Authored-By: Claude <noreply@anthropic.com>

— Via
This commit is contained in:
Via
2026-07-16 06:52:11 +00:00
co-authored by Claude
parent 46e9ecf3f2
commit 7e58d050f8
2 changed files with 55 additions and 26 deletions
+12
View File
@@ -743,6 +743,18 @@
// work on this same branch (commits 444639d75, b57b31beb, 6f2e9848c,
// eba8a0fa2), unrelated to the Grade group (Plan 5) currently landing.
"packages/studio/src/components/editor/propertyPanelSections.tsx",
// Portrait --resolution alias fix (via/resolution-portrait-fix):
// server.ts `render` (cyclo 10 / CRAP 31.6) and distributed/plan.ts
// `plan` (cyclo 33 / CRAP 36.7) are both pre-existing complexity —
// the PR only threads `outputResolutionAspectAgnostic` through the
// parseRenderOverrides/RenderInput/DistributedRenderConfig shape and
// adds one field spread inside `plan`. Neither function body gained
// branches, but the line-shift fingerprint re-flags the inherited
// complexity. The new re-target logic itself is extracted into
// `adaptAspectAgnosticResolution` in compileStage.ts to keep that
// stage's runCompileStage under the cyclo/cognitive thresholds.
"packages/producer/src/server.ts",
"packages/producer/src/services/distributed/plan.ts",
],
},
}
@@ -37,7 +37,7 @@
import { join } from "node:path";
import type { EngineConfig } from "@hyperframes/engine";
import { suggestMatchingPreset } from "@hyperframes/core";
import { suggestMatchingPreset, type CanvasResolution } from "@hyperframes/core";
import type { CompiledComposition } from "../../htmlCompiler.js";
import { compileForRender } from "../../htmlCompiler.js";
import type { ProducerLogger } from "../../../logger.js";
@@ -110,6 +110,41 @@ export interface CompileStageResult {
deCompileGate?: string;
}
/**
* Aspect-agnostic aliases (`--resolution 1080p` / `hd` / `4k` / `uhd`) all
* normalize to a landscape preset up-front (see `normalizeResolutionFlag`),
* which was historically fine because 16:9 was the only shipped orientation.
* Once portrait + square presets landed, that early normalization started
* rejecting portrait/square compositions with a cryptic "aspect ratio does
* not match" from `resolveDeviceScaleFactor` — a common enough hit that a
* field report (CLI 0.7.59) surfaced it. When the flag was aspect-agnostic,
* re-target the preset to the sibling that matches the composition's
* orientation while preserving the tier (HD vs 4K). Explicit
* orientation-bearing presets stay strict — a `--resolution portrait` on a
* landscape composition still errors, honoring the user's stated intent.
*
* Extracted so `runCompileStage` keeps its complexity envelope tight; the
* two-branch shape lives here.
*/
function adaptAspectAgnosticResolution(
requested: CanvasResolution | undefined,
aspectAgnostic: boolean | undefined,
width: number,
height: number,
log: ProducerLogger,
): CanvasResolution | undefined {
if (!requested || !aspectAgnostic) return requested;
const flipped = suggestMatchingPreset(width, height, requested);
if (!flipped || flipped === requested) return requested;
log.info("Adapted aspect-agnostic --resolution to composition orientation", {
compositionWidth: width,
compositionHeight: height,
requestedResolution: requested,
effectiveResolution: flipped,
});
return flipped;
}
export async function runCompileStage(input: CompileStageInput): Promise<CompileStageResult> {
const {
projectDir,
@@ -274,31 +309,13 @@ export async function runCompileStage(input: CompileStageInput): Promise<Compile
height: compiled.height,
};
const { width, height } = composition;
// Aspect-agnostic aliases (`--resolution 1080p` / `hd` / `4k` / `uhd`) all
// normalize to a landscape preset up-front (see `normalizeResolutionFlag`),
// which was historically fine because 16:9 was the only shipped orientation.
// Once portrait + square presets landed, that early normalization started
// rejecting portrait/square compositions with a cryptic "aspect ratio does
// not match" from `resolveDeviceScaleFactor` — a common enough hit that a
// field report (CLI 0.7.59) surfaced it. When the flag was aspect-agnostic,
// re-target the preset to the sibling that matches the composition's
// orientation while preserving the tier (HD vs 4K). Explicit
// orientation-bearing presets stay strict — a `--resolution portrait` on a
// landscape composition still errors, honoring the user's stated intent.
const requestedResolution = job.config.outputResolution;
let effectiveResolution = requestedResolution;
if (requestedResolution && job.config.outputResolutionAspectAgnostic) {
const flipped = suggestMatchingPreset(width, height, requestedResolution);
if (flipped && flipped !== requestedResolution) {
log.info("Adapted aspect-agnostic --resolution to composition orientation", {
compositionWidth: width,
compositionHeight: height,
requestedResolution,
effectiveResolution: flipped,
});
effectiveResolution = flipped;
}
}
const effectiveResolution = adaptAspectAgnosticResolution(
job.config.outputResolution,
job.config.outputResolutionAspectAgnostic,
width,
height,
log,
);
const deviceScaleFactor = resolveDeviceScaleFactor({
compositionWidth: width,
compositionHeight: height,