Addresses 4 P1, 3 P2, 1 NIT from a thorough self-review of the v1.2 PR.
**Config-schema validations** (P1):
- `fromStages` entries on `builtin/router` and `builtin/compose` stages
must reference known stage names (no typos).
- `fromStages` must be a subset of the stage's `dependsOn` so the DAG
scheduler guarantees the referenced stages are terminal before the
builtin runs. Without this, `readSiblingArtifacts` silently returns
`[]` for not-yet-completed siblings.
- `allowFork` rejected on any non-command stage — it's a no-op there
and gives a false sense of restriction.
- +15 vitests in `pipeline-dag.test.ts`.
**Top-level exports** (P1):
- `packages/core/src/index.ts` now re-exports the v1.2 surface:
`createCommandExecutor`, `createBuiltinRouterExecutor`,
`createBuiltinComposeExecutor`, `formatForkRefusalMessage`,
`DEFAULT_COMMAND_TIMEOUT_MS`, `DEFAULT_COMMAND_STDOUT_CAP_BYTES`,
`DEFAULT_COMMAND_STDERR_CAP_BYTES`, `COMMAND_KILL_GRACE_MS`,
`parseFindingsJsonl`, `coerceArtifactInput`, plus the matching
types. Package-external consumers couldn't construct
`PipelineEngineDeps.commandExecutor` / `builtinRouter` /
`builtinCompose` before.
**SCM fork-detection tests** (P1):
- scm-github: +2 tests covering `isCrossRepository: true → isFromFork: true`
and the absent/false default.
- scm-gitlab: +2 tests covering same-project (false) and different
source/target project (true) cases.
**Stderr cap** (P2):
- New `DEFAULT_COMMAND_STDERR_CAP_BYTES = 64 * 1024` mirrors the stdout
cap. Without it, a process writing gigabytes to stderr would OOM the
engine — `stderrChunks` was unbounded. Truncation surfaces `[stderr
truncated]` in the error message. +1 vitest.
**Cleanups** (P2 + NIT):
- Dead `ComposeRunInput` type removed (was structurally identical to
`BuiltinRunInput`, never used as a parameter type).
- `readSiblingArtifacts` docstring rewritten to spell out the three
distinct `[]` cases (unknown stage / not-yet-terminal / completed
with zero artifacts) and note the schema-level guarantee that the
second case is impossible at runtime.
All 1360 core + 174 scm-github + 76 scm-gitlab tests pass.