Skip to content

feat(nickel): NickelEvaluator + LiveNickel + MockNickel — closes Plan §6.5#10

Merged
UnbreakableMJ merged 3 commits into
mainfrom
feat/nickel-adapter
Apr 27, 2026
Merged

feat(nickel): NickelEvaluator + LiveNickel + MockNickel — closes Plan §6.5#10
UnbreakableMJ merged 3 commits into
mainfrom
feat/nickel-adapter

Conversation

@UnbreakableMJ

Copy link
Copy Markdown
Contributor

First M1 Week 2 adapter probe path. Thinnest possible shim around the nickel binary: argv-array subprocess invocation, stdout capture, delegation to pearlite_schema::from_resolved_toml. No Nickel parsing in Rust per Plan §6.5 hard rule.

Public surface

  • trait NickelEvaluatorevaluate(&self, &Path) -> Result<String, NickelError>.
  • struct LiveNickel — production, default nickel from PATH; with_binary() for test injection.
  • struct MockNickel — feature-gated behind test-mocks, in-memory BTreeMap<PathBuf, String>.
  • fn load_host(&Path, &dyn NickelEvaluator) -> Result<DeclaredState, NickelError>.
  • enum NickelErrorNotInPath carries a runnable hint, EvaluationFailed carries verbatim stderr, Schema is transparent to pearlite-schema.

CI

taiki-e/install-action in the T2 Unit job now installs nickel-lang so live tests actually exercise nickel rather than silent-skip.

Tests (5 passing)

  • mock: canned_output_round_trips_to_declared_state, missing_path_yields_mock_missing_error
  • live: nickel_not_in_path_error_class, version_probe_succeeds, minimal_host_evaluates

Live tests silent-skip when nickel isn't on PATH (dev convenience); CI installs nickel so they actually exercise.

Verification

  • cargo test -p pearlite-nickel — 5 passed; 0 failed
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo fmt --all --check
  • scripts/ci/check-spdx.sh
  • pearlite-audit check . — 1 check, 0 violations

🤖 Generated with Claude Code

UnbreakableMJ and others added 3 commits April 27, 2026 19:35
…d_host

Plan §6.5 — first M1 Week 2 adapter probe path. The thinnest possible
shim around the `nickel` binary: argv-array subprocess invocation,
stdout capture, delegation to pearlite_schema::from_resolved_toml.
No Nickel parsing in Rust per Plan §6.5 hard rule.

Public surface (re-exported from lib.rs):

- pub trait NickelEvaluator { fn evaluate(&self, &Path) -> Result<String, NickelError>; }
- pub struct LiveNickel { binary: PathBuf }
- pub struct MockNickel — feature-gated behind test-mocks, in-memory
  canned-output map BTreeMap<PathBuf, String>.
- pub fn load_host(host_file: &Path, eval: &dyn NickelEvaluator)
  -> Result<DeclaredState, NickelError>.
- pub enum NickelError — NotInPath (hints `paru -S nickel-lang`),
  Io, EvaluationFailed { code, stderr }, NotUtf8, Schema (transparent
  to pearlite_schema::SchemaError), MockMissing.

LiveNickel:
- Default constructor resolves `nickel` from $PATH.
- with_binary() lets tests inject a known-good path.
- Spawn translates ErrorKind::NotFound to NickelError::NotInPath
  with a runnable hint.
- Captures stderr verbatim; surfaces with exit code on non-zero.

CI:
- Add nickel-lang to taiki-e/install-action's tool list in T2 Unit so
  the live tests actually exercise nickel rather than silent-skipping.

Tests (5 passing locally; live tests silent-skip when nickel isn't on
PATH — CI installs it so they exercise there):

- mock: canned_output_round_trips_to_declared_state.
- mock: missing_path_yields_mock_missing_error.
- live: nickel_not_in_path_error_class — pointed at a bogus path.
- live: version_probe_succeeds — nickel --version contains "nickel".
- live: minimal_host_evaluates — fixture host_minimal.ncl evaluates
  to TOML that parses as DeclaredState.

Fixture: fixtures/nickel/host_minimal.ncl mirrors the schema fixture.

Cargo.toml: pearlite-schema dep pinned to "0.1" per the cargo-deny
wildcard rule (PR #9 precedent). New `test-mocks` feature.

Verification:
- cargo test -p pearlite-nickel  (5 passed; 0 failed)
- cargo clippy --workspace --all-targets -- -D warnings  (zero warnings)
- cargo fmt --all --check
- scripts/ci/check-spdx.sh
- pearlite-audit check .  (1 check, 0 violations)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The library crate `nickel-lang` has no binaries; the CLI binary lives
in the `nickel-lang-cli` crate. taiki-e/install-action's fallback to
cargo-binstall correctly reported "no binaries specified" and failed
the T2 Unit job.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
extractions/setup-just@v3 hit "no release for just matching version
specifier" on every recent PR run — the action's default version
resolution is broken. taiki-e/install-action is already used in every
job for cargo tooling; adding `just` to its tool list is the
consistent fix and avoids the second action entirely.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@UnbreakableMJ
UnbreakableMJ merged commit d067e5b into main Apr 27, 2026
3 checks passed
@UnbreakableMJ
UnbreakableMJ deleted the feat/nickel-adapter branch April 27, 2026 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant