ADR 0006 — SDF preprocessing model and interim-to-release cutover
Status: Accepted 2026-04; amended 2026-05-02 (see § Amendment).
Amendment (2026-05-02)
The original Decision treated subprocess invocation of OpenSTA from the shipped Jacquard runtime as license-incompatible, requiring Phase 3 (native Rust SDF→IR converter) to land before first release. On review of GPL-3 § 5 ("aggregate") and the FSF interpretation of subprocess/IPC boundaries, this restriction is more conservative than necessary. The relevant facts:
- The interface is arms-length: standard EDA interchange formats (Liberty / Verilog / SDF / SPEF / SDC) in, our own IR JSON (ADR 0002) out. No shared data structures, no headers, no linking.
- We do not bundle OpenSTA in any Jacquard distribution. The user installs OpenSTA themselves; user-side combination of separately-distributed programs is not "distribution of a combined work" under GPL-3.
- The original "no runtime subprocess" rule was effectively a commercial-perception buffer, not a strict licensing requirement.
Revised bright lines (these supersede the original "Shipped release" sub-section):
- No linking of GPL code into the Jacquard binary. Unchanged.
- No bundling of OpenSTA (or any GPL tool) in Jacquard distribution artefacts (release tarballs, Homebrew formulae, Docker images that ship as Jacquard releases). If a packager wants to bundle, they take on GPL distribution obligations themselves.
- Subprocess invocation of user-installed OpenSTA from the shipped runtime is permitted.
jacquard sim input.sdfmay keep itsopensta-to-irsubprocess hook in shipped releases, provided OpenSTA is discovered on PATH rather than bundled.
Phase 3 reclassification. Native Rust SDF→IR converter is no longer release-gating. It remains a goal — for ergonomics (no OpenSTA install required) and for downstream commercial integrators whose legal teams treat any GPL touchpoint as risk — but ships when bandwidth allows, not as a release blocker. Roadmap consequences are tracked in ../plans/post-phase-0-roadmap.md § Phase 3.
Corequisite — OpenSTA detection and version check (release-blocking). Relaxing the no-runtime-subprocess rule is conditional on the shipped runtime giving users a meaningful error when OpenSTA is missing or out-of-date. Today (src/sim/setup.rs:248-264), missing OpenSTA only emits a warn! and the simulation proceeds with no timing data loaded — acceptable during development, ships as a UX bug. Concretely, before first release we must:
- Hard-fail (not warn) when
--sdfis requested and OpenSTA cannot be located. - Probe OpenSTA's version on first invocation and fail with a remediation message if it is older than the version pinned in
vendor/opensta/(per ADR 0005). - Warn-but-proceed if the detected version is newer than the latest tested version, naming the version in the warning.
- Document the OpenSTA dependency in
docs/usage.md.
Tracked as WS-RH.1 in ../plans/post-phase-0-roadmap.md § Release hardening.
Code-comment cleanup follow-up. The INTERIM per ADR 0006 / Pre-release only tags in src/sim/setup.rs (lines ~176, ~228, ~286) and src/bin/jacquard.rs (~187) describe a premise that no longer applies. Folded into WS-RH.1 (../plans/post-phase-0-roadmap.md § Release hardening) rather than spun out as a separate cleanup commit.
The original Context, Decision (Phase 0 + Phase 3), and Walk-back sections below are retained for historical record. Where they conflict with the bright lines above, the bright lines win.
Context
Jacquard's hand-rolled SDF parser (src/sdf_parser.rs) has accumulated reactive maintenance over time — empty () delays, (COND …) pin specs, escape handling, edge-qualified timing checks, TIMINGCHECK-stripping workarounds for OpenLane2 output. Each production failure has been a one-off patch. The timing-correctness review flagged this as issue #3, and a native Rust grammar-based replacement is the Phase 3 deliverable.
Concurrently, ADR 0001 establishes OpenSTA as the timing correctness oracle (subprocess, never linked, GPL), and ADR 0002 introduces a timing IR that decouples parsing from consumption.
Two facts together shape the decision:
- No release pressure. Release can happen after Phase 3 lands. We are not forced to keep the hand-rolled parser alive while waiting on Phase 3.
- Permissive-license constraint applies to the shipped binary. Subprocess invocation of GPL tooling is acceptable — does not trigger reciprocal obligations — and during pre-release development, even in-runtime subprocess invocation does not violate the constraint because no runtime binary is being distributed.
Given these, maintaining the hand-rolled parser through Phase 0–2 is unnecessary. OpenSTA's mature dialect coverage can substitute, via subprocess, while we build toward a native Rust replacement at our own pace.
Decision
Phase 0
- Delete
src/sdf_parser.rsand the SDF→Jacquard-internal-types code path. All paths that previously consumed SDF now consume timing IR. - Ship
opensta-to-iras a standalone preprocessing tool that consumes Liberty + Verilog + SDF + SPEF + SDC and emits timing IR. Subprocess-based on OpenSTA. Production-quality: stable CLI, documented exit codes, clear diagnostics. - Canonical runtime path is
jacquard sim --timing-ir <path>, consuming pre-converted IR. This path works without OpenSTA on the user's machine — pre-converted IR is sufficient. - Interim ergonomic path: during development (pre-release only),
jacquard sim input.sdfsubprocessesopensta-to-irinternally to produce IR on the fly. This is a contributor convenience, not a shipping feature. Flag exists in code aspre-release onlywith a clear comment tying back to this ADR.
Phase 3
- Native Rust SDF→IR converter replaces the OpenSTA subprocess call inside
jacquard sim input.sdf. Grammar-based (nom / pest), validated against OpenSTA on the corpus per ADR 0001. - Lands before first release.
Shipped release
- No OpenSTA invocation from the
jacquardruntime binary. The native Rust converter handles SDF inputs directly. opensta-to-irremains as an alternative preprocessing tool. Users who want OpenSTA-computed timing may use it; subprocess model preserves permissive licensing.
Walk-back options (if assumptions change)
- If OpenSTA dialect coverage proves insufficient during Phase 0 — e.g., a current Jacquard-supported SDF fails to parse — add dialect shims to
opensta-to-ir's post-processing. Reinstating the hand-rolled parser is the last resort, not the first. - If the Phase 3 Rust rewrite stalls — ship the first release with preprocessing-only (no
jacquard sim input.sdfpath), remove the interim subprocess, and land the native converter in a later release. No information lost; users preprocess manually. This is already the post-release shape foropensta-to-ir; it's only thejacquard sim input.sdfconvenience that would be deferred. - If OpenSTA becomes unmaintainable or disappears — the submodule pin (ADR 0005) remains authoritative for the integrated version. A forked submodule can maintain any necessary patches.
Consequences
- Jacquard's repository stops carrying a hand-rolled SDF parser as a reactive-maintenance target. Bugs in SDF interpretation between Phase 0 and Phase 3 are OpenSTA's problem (upstream) or
opensta-to-irpost-processing's problem, not Jacquard's core codebase's problem. - Pre-release ergonomic one-step workflow for contributors is preserved.
- Contributors running Jacquard on a new design (no pre-converted IR) must have OpenSTA installed during Phase 0 through Phase 3. For existing primary-corpus designs, pre-converted IR is checked in; no OpenSTA needed.
- Release-time check is unambiguous: either the runtime subprocess is replaced by native code, or it is removed entirely. Both outcomes satisfy the permissive-licensing constraint for the shipped binary.
- Test corpus regenerable: if OpenSTA updates change IR output, golden files are regenerated deliberately (reviewable diff), not silently.
Links
../project-scope.md— licensing constraint, preprocessing-tools pattern.../timing-correctness.md— P1 (oracle), R1 (IR).- ADR 0001 — OpenSTA as oracle (subprocess model).
- ADR 0002 — timing IR (format consumed).
- ADR 0005 — OpenSTA vendoring (submodule for reproducibility + stress corpus).
../plans/phase-0-ir-and-oracle.md— WS2 productionisation, WS3 deletion + interim hook.