Skip to content

nvx-rs: make the error codes and Error's constructors private (SL6.8c) - #1552

Merged
Pedro Henrique Penna (ppenna) merged 3 commits into
feature/nvx-refactorfrom
agents/slim-sl6-8c-error-codes-private
Nov 12, 2026
Merged

Pedro Henrique Penna (ppenna) merged 3 commits into
feature/nvx-refactorfrom
agents/slim-sl6-8c-error-codes-private

Conversation

@ppenna

@ppenna Pedro Henrique Penna (ppenna) commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Part of #1126 (SL6.8c, "Callers tell nvx's errors apart by their kinds; the error codes are private"). Parent #1088, umbrella #1076.

SL6.8c needs SL6.4 (#1533), SL6.5b (#1549) and SL6.7b (#1539), all merged.

What and why

Callers act on nvx's failures by an error's kind, message and source, but ErrorCode, Error::code and Error's constructors were public: the stable codes, which serve the CLI's output, were part of the library's API, and any caller could fabricate nvx's errors. This PR does SL6.8c's Scope: nvx's public error is Error, ErrorKind and Result, nvx alone makes its errors, and the CLI prints the same code, message and exit status for every error. Three commits:

  1. nvx-rs: delete the error codes and the constructor that nothing makes (a3a1db81): once the codes and constructors are crate-private, the warning-denied build of the cli feature, which builds every producer of a code, finds three codes and one constructor that nothing makes or calls: template-ineligible and template-tombstoned, which the template store reported until SL6.2a deleted it, sandbox-leased, which the sandbox store reported until SL6.1 deleted it, and Error::not_found. They go first, with their rows in the README's and doc/usage.md's tables of codes, so that the change of visibility leaves every feature set's build clean. No NVX program reports them, so the CLI's output doesn't change. The API snapshots lose 4 lines on each platform.
  2. tests: stop building nvx's errors and listing its codes through its API (8484381f): the two tests that reached the API that goes keep their assertions without it (Test changes, below). It changes no production code, so it passes on its own, before the visibility change.
  3. nvx-rs: make the error codes and Error's constructors private (b92df2b8):
    • The codes: ErrorCode, with as_str and kind, becomes pub(crate) where it is, and loses #[non_exhaustive], which only bound other crates, and ErrorCode::ALL, which only tests read. The crate root re-exports it to the crate only (pub(crate) use, with host), for the host and the CLI, which name it there. Error::code becomes pub(crate).
    • The constructors: Error::new, its constructor of each kind and with_source become pub(crate), gated by the features of their callers: unsupported and io build with host or the Linux guest, exited, protocol, timed_out and other with host, and new, unavailable and with_source in every feature set.
    • The CLI keeps its codes: it prints error[CODE]: MESSAGE and PROG: error[CODE]: MESSAGE with the same codes, messages and exit statuses, through the same Exit mappings; no file of host::cli changes but a doc link. Most finer codes come from the CLI alone, and the CLI reads Error::code, as nvx-init's boot and the host's unit tests do, so the builds without cli allow ErrorCode's variants and Error::code to be unused (cfg_attr(not(feature = "cli"), allow(dead_code, reason = …)), as host::config::reject_container_path does). The builds with cli allow nothing, and find no unused code or helper.
    • What stays public doesn't change: Error keeps kind, message, into_parts, its display and its source, and ErrorKind its variants, as_str and its display. No error's kind, message or source changes.
    • Docs: the docs of Error, Error::kind, ErrorKind and into_parts name kinds and no codes, as do those of SnapshotKey::from_bytes and SnapshotManifest::parse, which linked ErrorCode::FormatUnsupported (now ErrorKind::Io, its kind, as before), and the docs of the CLI's hidden module no longer link the private ErrorCode. The README's Errors section describes the error by its kind, which only nvx makes, and its Error codes section the codes that the CLI prints, which the library keeps private; doc/usage.md and a comment of test_usage_documents_every_error_code_of_nvx_rs follow. No example built or matched nvx's errors by code: host-workflows matches kinds already.
    • The public API snapshots lose 41 lines on each platform: ErrorCode with its variants, ALL, as_str and kind, and Error's constructors and code. With the first commit's 4, they lose 45 lines on each platform and gain none: nvx::Error lists into_parts, kind and message only.

BOOT_CONTRACT_VERSION and CONTROL_CONTRACT_REVISION don't change.

Size

Measured against 14ea1a45a6d (feature/nvx-refactor with SL6.5b), by #1076's rules.

Core lines Counted files
Estimate (#1126) 0 0
Measured 10 1
  • nvx-rs/src/error.rs: 10 core lines. It adds 29 code lines: 13 make items pub(crate) and 6 gate the constructors by their callers' features, which don't count; the 8 lines of the two allow(dead_code) attributes for the builds without cli, and 2 lines of ErrorCode::kind, whose arms the deleted codes shorten, do. It deletes 61 code lines: the three codes, ALL and not_found. The orchestrator's stop for this slice, deletions included, is 200 core lines.
  • nvx-rs/src/lib.rs: 0. Its 3 lines make the re-export crate-private and gate it by host.
  • The rest of the production diff is docs. 12 files change: +122 and −227 lines, tests, docs and snapshots included.

Old tests of the area

  • Kept, unchanged, and passing: the CLI's integration tests that check its printed codes, messages and exit statuses, 54 of them (below), every other test of tests/cli.rs and tests/cli/, the CLI's unit tests that check codes (host::cli's args, download, sandbox, session, snapshots, store and others), the unit tests that check the codes that the host makes (host::snapshot::{key, manifest}, host::config, host::network, host::vm), every_kind_has_a_code_of_its_own_spelling, and scripts/test_nvx_tools.py's test_usage_documents_every_error_code_of_nvx_rs, which compares the README's codes with doc/usage.md's and their statuses.
  • Rewritten: the four tests of error and the helper cold_run_expected (Test changes).
  • Retired: none.
The 54 CLI tests that check printed codes, messages and exit statuses, all passing unchanged
  • nvx-rs/tests/cli.rs: an_error_after_a_workloads_output_starts_a_line_of_its_own, an_error_is_one_line_whatever_the_values_that_its_message_names, exec_and_stop_tell_a_directory_without_a_sandbox_from_a_stopped_sandbox, a_sandbox_whose_configuration_names_another_layer_role_does_not_start, a_distro_manifest_path_whose_lookup_fails_refuses_provision_and_start, runtime_records_of_earlier_stores_are_refused_without_migration, network_policy_files_compile_into_the_typed_policy, a_run_passes_openvmm_no_handle_of_its_caller, artifacts_default_to_the_checkout_that_holds_the_executable, top_level_usage_errors_exit_with_status_2, usage_errors_print_the_one_line_usage_of_their_parser, run_guides_failed_cold_boots_on_cpus_that_no_built_in_profile_serves
  • nvx-rs/tests/cli/download.rs: run_downloads_the_release_of_a_checkout_without_artifacts, run_downloads_before_checking_mount_sources_that_installation_can_create, run_downloads_nothing_over_some_artifacts, commands_download_nothing_for_options_that_they_refuse, restores_download_nothing_for_snapshots_that_they_cannot_open, start_downloads_the_release_of_a_checkout_without_artifacts, the_variable_turns_downloads_off_with_0, roots_that_are_no_git_checkout_download_nothing, download_installs_into_git_checkouts_of_nvx_alone, download_installs_the_packages_of_this_host
  • nvx-rs/tests/cli/dry_run.rs: dry_runs_print_the_openvmm_command_and_launch_nothing, the_openvmm_command_of_a_run_splits_back_into_its_arguments
  • nvx-rs/tests/cli/egress.rs: egress_compile_prints_the_library_lowering
  • nvx-rs/tests/cli/exec_lock.rs: exec_processes_contend_but_other_sandboxes_and_stop_proceed, a_retry_that_waits_for_the_lifecycle_lock_past_the_deadline_is_busy, exec_cannot_recreate_admission_after_cleanup_removes_provisioned_state, a_replaced_exec_lock_entry_is_refused_before_contacting_the_vm
  • nvx-rs/tests/cli/formats.rs: old_configuration_formats_are_refused_without_migration, invalid_recorded_roots_are_refused_before_spawn
  • nvx-rs/tests/cli/lifecycle.rs: managed_execs_exit_with_the_workload_status, managed_execs_stream_their_standard_input_and_output, provision_refuses_shares_of_its_own_files, provision_refuses_a_share_that_holds_the_state_directory_that_it_would_create, provision_refuses_a_share_that_holds_a_state_directory_that_only_a_verbatim_path_names, provision_refuses_a_share_of_the_roots_openvmm_whatever_the_variable_names, start_refuses_recorded_shares_of_its_own_files, start_refuses_a_share_that_came_to_reach_its_own_files
  • nvx-rs/tests/cli/one_shot.rs: one_shot_runs_exit_with_the_workload_or_openvmm_status, forwarding_failure_stops_the_verified_vm_during_connect_and_handshake, terminal_ctrl_c_cancels_boot_and_handshake_and_restores_the_terminal, windows_terminal_ctrl_c_helper, cold_runs_refuse_existing_and_missing_parent_reports_before_launch, a_cold_spawn_without_a_child_removes_its_private_directory, a_foreground_output_error_keeps_the_requested_native_report
  • nvx-rs/tests/cli/sandbox_run.rs: runs_refuse_shares_of_their_own_files, a_run_refuses_a_share_of_the_openvmm_that_the_variable_names, a_run_refuses_a_share_of_its_vm_directory, a_run_whose_guest_exits_during_startup_fails_as_a_start_does, a_run_whose_workload_the_guest_refuses_stops_its_vm
  • nvx-rs/tests/cli/usage.rs: usage_errors_exit_2_and_name_the_option
  • nvx-rs/tests/cli/validation.rs: unbalanced_disk_paths_fail_before_launch_or_provision, validation_errors_exit_1_before_any_side_effect

Between them they check the codes argument-invalid, argument-missing, argument-unrecognized, artifact-missing, endpoint-closed, exec-refused, exited, format-unsupported, io, outcome-report-exists, sandbox-busy, sandbox-not-provisioned, unavailable and unsupported, with exit status 2 for usage errors and 1 for others.

Test changes

python scripts/check_test_changes.py --base 14ea1a45a6d lists 5 changes to existing tests and 1 added item, hence tests-modified:

  • nvx-rs/tests/cli/openvmm.rs, cold_run_expected: it projects a cold-run fixture onto the public VM contract, and built nvx's Unsupported errors for the two fixtures that it cannot project, which it can no longer do. It now refuses them with errors of its own (Result<Self, Box<dyn std::error::Error>>), as a caller that built nvx's errors must, and still passes on the public contract's own errors with ?. Its callers, dry_run::dry_runs_print_the_openvmm_command_and_launch_nothing, dry_run::the_openvmm_command_of_a_run_splits_back_into_its_arguments, one_shot::one_shot_runs_exit_with_the_workload_or_openvmm_status and one_shot::both_cold_modes_keep_their_foreground_output_and_owned_exit_status, show the error only when they report an unexpected refusal, and pass unchanged.
  • nvx-rs/src/error/tests.rs, the unit tests of the error's owner:
    • added: CODES, the 27 codes in the order of the README's table, in place of ErrorCode::ALL, which goes;
    • codes_are_unique_lowercase_words_joined_by_hyphens and the_readme_documents_every_code_with_its_kind iterate CODES in place of ErrorCode::ALL, with the same assertions;
    • errors_keep_their_kind_message_and_cause makes its error with Error::new(ErrorKind::Io, …) in place of Error::io(…), which builds only with host or the guest, so that cargo test --lib --no-default-features still runs it; same assertions;
    • codes_determine_kinds checks that a kind's constructor gives its kind's code through Error::unavailable, which every feature set builds, in place of Error::unsupported; its other assertions don't change.

doc/acceptance-case-matrix.md lists none of these tests, nor names them as coverage; check_matrix.py passes.

Validation

local_gates.py --files (from dev) selects test-changes, markdown-links, test-layout, code-quality, the check-nvx-rs steps, nvx-cli and the microVM tests; I ran them from this branch's action definitions, with Rust 1.95.0, locally on Windows and on nvx-kvm-test (Azure Linux 3, kernel 6.6, linux-kvm, virtual machine), in a temporary worktree. They ran on SL6.5a2's and SL6.5b's earlier heads first. Before this merge turn, I restacked the branch onto SL6.5b's final head, 03b7ccb22dc: NVXC's chain had already deleted guest-features-missing, so ErrorCode::kind and the tests' list of codes drop it, and the warning-denied builds of every feature set found nothing more to delete. feature/nvx-refactor's 14ea1a45a6d is that SL6.5b, with the same tree, and git range-diff shows = for the three commits moved onto it, so the results on that restack, 944b37e636c, hold for this head, b92df2b8db1:

Check Windows (local) Linux (KVM, kernel 6.6)
cargo fmt --all --check passed passed
Clippy -D warnings: --all-targets --all-features, --lib, --lib --no-default-features, serde, cli and testing alone, and --lib --tests --no-default-features passed, natively and for --target x86_64-unknown-linux-gnu, and --all-targets with default features passed
Guest Clippy, --target x86_64-unknown-linux-musl --no-default-features --features guest --all-targets -D warnings passed passed
cargo test --locked --all-features passed: lib 1065 passed, 18 ignored; cli 113 passed, 2 ignored; every other integration test and the doc tests lib 1740 passed, 28 failed, 59 ignored: the same 28 guest:: tests fail at the base, 03b7ccb22dc, on this host's kernel 6.6. With --no-fail-fast, cli 123 passed, and every other integration test and the 14 doc tests passed
Guest tests, musl cargo test --no-default-features --features guest --no-fail-fast lib 851 passed, 4 failed, 32 ignored: the same 4 as at the base; guest_tools 33, host_modules 22, nvxs 7 and the 13 doc tests passed
cargo test --locked, cargo build --locked --lib --no-default-features, cargo test --locked --lib --no-default-features passed (lib 518 passed, 10 ignored; 191 passed) passed
cargo check --all-targets --all-features --target aarch64-apple-darwin passed; its one warning, in host/snapshot/tests.rs, is the base's
RUSTDOCFLAGS=-D warnings cargo doc --locked --no-deps --all-features passed, and for --target x86_64-unknown-linux-gnu
MSRV: cargo +1.89 check --locked --all-targets --all-features passed
python scripts/public_api.py passed passed
check_test_layout.py, check_markdown_links.py, check_test_changes.py, check_matrix.py <worktree> 99d2022085f, Ruff check and format, Pyright for Linux and Windows, and test_usage_documents_every_error_code_of_nvx_rs passed
  • Each commit on its own, on 14ea1a45a6d: Clippy -D warnings for --all-targets --all-features, --lib --no-default-features and --lib --tests --no-default-features, and the error module's tests, pass after each of the three commits.
  • microVM scenarios on KVM, python3 scripts/nvx.py test-microvm --backend kvm on b92df2b8db1, with NVX_AUTO_DOWNLOAD=0, this head's release nvx-rs, and the artifacts of CI run 43316146269, SL6.5b's run at 03b7ccb22dc, whose tree is this base's, with the OpenVMM pin 14dc4116ec7: the kernel, the Alpine initramfs, the Ubuntu distro layer and scratch template, and OpenVMM, each checked by SHA-256 against the run's artifacts and OpenVMM's provenance. All 12 passed, as on the earlier heads:
    • the public sandbox scenarios, CI's public managed sandbox acceptance: managed-exec-config, sandbox-gpt-layer, sandbox-lifecycle, sandbox-proxy-only, sandbox-ram-upper, snapshot-core, snapshot-tiers, untiered-network-policy and vm-lifecycle. Their failure cases check the codes that the CLI prints: snapshot-core refuses restores with error[unsupported], error[exited] and error[sandbox-busy], and sandbox-lifecycle, managed-exec-config and untiered-network-policy check theirs;
    • the snapshot scenarios scratch-snapshot and snapshot-rollback, and l3-l4-egress-port-ranges, which checks error[unsupported] for each invalid port range.
  • On SL6.5b's earlier head, the nvx-cli gate's 22 unit-test modules ran on Windows: 1803 tests, 73 skipped; one subtest, test_private_network_ingress_script_checks_policy_and_traffic [tcp-missed], timed out after 10 s under the load of the full run, and passes alone.
  • A code-review subagent reviewed the whole diff and found no significant issue; the restack changed only the lines of guest-features-missing.
  • CI: run 43320760302, on this head, runs the whole matrix: nvx-rs on Linux and Windows, the nvx-cli gates, the packages and platforms, and the microVM tests on KVM, MSHV and WHP.

Left to CI: openvmm-ci, which this PR's unchanged pin skips.

@ppenna Pedro Henrique Penna (ppenna) added tests-modified Changes existing tests, test data, or test wiring feat-nvx-refactor labels Nov 12, 2026
@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

This pull request changes existing tests

It modifies or removes 5 existing test asset(s), listed below. Review each with care: a change to a test can hide a regression that the test caught. See doc/contribute.md#changes-to-existing-tests.

Test code

Change What Before After
modified helper fn cold_run_expected in cli/openvmm (tests), impl Options`` nvx-rs/tests/cli/openvmm.rs:356 nvx-rs/tests/cli/openvmm.rs:356
modified test fn errors_keep_their_kind_message_and_cause in error::tests nvx-rs/src/error/tests.rs:4 nvx-rs/src/error/tests.rs:35
modified test fn codes_determine_kinds in error::tests nvx-rs/src/error/tests.rs:22 nvx-rs/src/error/tests.rs:53
modified test fn codes_are_unique_lowercase_words_joined_by_hyphens in error::tests nvx-rs/src/error/tests.rs:70 nvx-rs/src/error/tests.rs:101
modified test fn the_readme_documents_every_code_with_its_kind in error::tests nvx-rs/src/error/tests.rs:90 nvx-rs/src/error/tests.rs:121

Relocated unchanged: 0; added: 1. Compared the merge base 14ea1a45a6df with b92df2b8db15.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues are recorded for the error API visibility changes.

No open issues 🎉

What changed in this PR

Implements SL6.8c of #1126 in the NVX library-slimming workstream. Library callers distinguish errors through ErrorKind, messages and sources, while error construction and stable CLI codes become crate-private.

Changes:

  • Makes ErrorCode, Error::code and error constructors crate-private, with feature gates matching their callers.
  • Removes three unused error codes and the unused not_found constructor without changing CLI diagnostics or exit statuses.
  • Adapts tests, updates documentation and removes the private API from Linux and Windows snapshots.
File Description
scripts/​test_nvx_tools.py Updates a comment to describe CLI codes rather than the public enum.
nvx-rs/​tests/​cli/​openvmm.rs Uses boxed errors instead of constructing library errors in fixtures.
nvx-rs/​src/​lib.rs Restricts the ErrorCode re-export to crate-internal host use.
nvx-rs/​src/​host/​snapshot/​manifest.rs Documents parse failures by their public error kind.
nvx-rs/​src/​host/​snapshot/​key.rs Documents decoding failures by their public error kind.
nvx-rs/​src/​host/​cli/​mod.rs Removes a documentation link to the now-private code type.
nvx-rs/​src/​error/​tests.rs Keeps the code inventory test-local and adapts constructor checks.
nvx-rs/​src/​error.rs Narrows visibility, gates constructors and removes unused error items.
nvx-rs/​README.md Separates public error kinds from private CLI codes.
nvx-rs/​public-api/​windows.txt Records the reduced Windows error API.
nvx-rs/​public-api/​linux.txt Records the reduced Linux error API.
doc/​usage.md Clarifies library error kinds and removes obsolete CLI codes.

Review effort: Balanced

@ppenna
Pedro Henrique Penna (ppenna) force-pushed the agents/slim-sl6-5b-export-paths-only branch from 21ce29a to 03b7ccb Compare November 12, 2026 22:01
Base automatically changed from agents/slim-sl6-5b-export-paths-only to feature/nvx-refactor November 12, 2026 22:27
SL6.8c (#1126) makes ErrorCode and Error's constructors crate-private.
Once they are, the warning-denied build of the cli feature, which
builds every code of the crate that makes errors, finds three codes and
one constructor that nothing makes or calls any more: only the public
API and the tests named them. This deletes them first, so that the
change of visibility leaves every feature set's build clean:

- template-ineligible and template-tombstoned, which the template store
  reported until it left (SL6.2a, #1121), and sandbox-leased, which
  the sandbox store reported until it left (SL6.1, #1121). No NVX
  program reports them, so the CLI prints the same code for every
  error that it reports.
- Error::not_found, which nothing calls.

The README's and doc/usage.md's tables of the codes lose the three
rows, as the test that compares the README with ErrorCode::ALL, and the
test that compares the two tables, require.

The public API snapshots lose 4 lines on each platform, the four items,
and gain none.

Part of #1126 (SL6.8c).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SL6.8c (#1126) makes Error's constructors and ErrorCode crate-private,
and ErrorCode::ALL, which only tests read, goes once the warning-denied
builds find it unused. Two tests reached them, which they cannot once
those are private, so each keeps its assertions without them:

- cold_run_expected, which projects a cold-run fixture onto the public
  VM contract, built nvx's Unsupported errors for the two fixtures that
  it cannot project. It now refuses them with errors of its own, as a
  caller that built nvx's errors must, and still passes on the public
  contract's own errors. The dry-run and one-shot tests show either
  only when they report an unexpected refusal.
- The error module's tests list the codes themselves, in the order of
  the README's table, in place of ErrorCode::ALL, for
  codes_are_unique_lowercase_words_joined_by_hyphens and
  the_readme_documents_every_code_with_its_kind. They make their errors
  with Error::new and Error::unavailable, which every feature set
  builds, in place of Error::io and Error::unsupported, which only the
  host and guest builds will: errors_keep_their_kind_message_and_cause
  and codes_determine_kinds check the same kinds, codes, messages and
  causes.

Part of #1126 (SL6.8c).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Callers act on nvx's failures by an error's kind, message and source,
but ErrorCode, Error::code and Error's constructors were public: the
codes, which serve the CLI's output, were part of the library's API,
and any caller could fabricate nvx's errors. They become crate-private
where they are, so that nvx alone makes its errors, and its public
error is Error, ErrorKind and Result:

- ErrorCode, with as_str and kind, and Error::code become pub(crate),
  and the crate root re-exports ErrorCode to the crate only, for the
  host and the CLI, which name it there. ErrorCode loses
  #[non_exhaustive], which only bound other crates, and ErrorCode::ALL,
  which only tests read.
- Error::new, its constructor of each kind, and with_source become
  pub(crate), gated by the features of their callers: unsupported and
  io build with the host or the guest, exited, protocol, timed_out and
  other with the host, and new, unavailable and with_source with every
  feature set.
- The CLI keeps its codes, and prints each error's code with the same
  messages and exit statuses. Most finer codes come from the CLI alone,
  and the CLI reads Error::code, as nvx-init and tests do, so the
  builds without the cli feature allow both to be unused.
- Error keeps kind, message, into_parts, its display and its source,
  and ErrorKind its variants, as_str and its display. Their docs, and
  those of SnapshotKey::from_bytes and SnapshotManifest::parse, name
  kinds and no codes, and the docs of the CLI's hidden module no longer
  link the private ErrorCode.

The README's Errors section describes the error by its kind, which only
nvx makes, and its Error codes section the codes that the CLI prints,
which the library keeps private. doc/usage.md, and a comment of the
test that compares the two tables, follow.

The public API snapshots lose 42 lines on each platform, ErrorCode with
its variants and methods, and Error's constructors and code, and gain
none.

Part of #1126 (SL6.8c).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues remain for the change narrowing the public error API to kind-based classification.

No open issues 🎉

Review effort: Balanced

@ppenna
Pedro Henrique Penna (ppenna) merged commit f5cc2aa into feature/nvx-refactor Nov 12, 2026
86 checks passed
@ppenna
Pedro Henrique Penna (ppenna) deleted the agents/slim-sl6-8c-error-codes-private branch November 12, 2026 22:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat-nvx-refactor tests-modified Changes existing tests, test data, or test wiring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants