Open Questions - phax/peppol-cli GitHub Wiki

Open Questions

Numbered so they can be referenced from other pages and from issues. Anything resolved here graduates to an ADR in Decisions and stays listed below with its answer, so the reasoning is not lost.

1. GraalVM native image

Separate discussion โ€” deliberately not decided as part of the initial scope.

JVM startup cost is paid on every invocation, which is exactly the wrong shape for a CLI used interactively, in shell completion and in loops over a CSV. A native image would give near-instant startup and a single binary with no JRE requirement.

Against it: an additional and considerably slower build, per-platform build infrastructure (macOS arm64/x64, Linux, Windows), and reflection configuration for everything reflective โ€” picocli, JAXB-generated data types, XML signature handling, the JCE/TLS stack and DNS resolution are all candidates for trouble. Some of those are notoriously awkward under native-image.

No project in this ecosystem currently builds a native image, so this would be new ground.

Sub-questions: is native image an additional artefact or the primary one? Which platforms are supported? Does the effort still pay off given Java 25's ahead-of-time class loading and linking (see ADR-005)? > TODO(verify): measure plain JVM startup for a trivial command before treating startup time as a problem worth this much effort

2. Configuration file format

Candidates and the trade-off are set out in Configuration: TOML (readable, comments, typed, new dependency), Java properties (no new dependency, ecosystem-native, poor at nesting), YAML (familiar, but whitespace-sensitive and easy to get subtly wrong), JSON (no comments โ€” disqualifying for a hand-edited file).

Depends on: which dependency is acceptable, and whether profiles need nesting deeper than one level. > TODO(verify): whether the ph-commons configuration facility already provides a suitable file format and precedence handling that should simply be reused

3. CLI framework choice โ€” resolved: picocli

See ADR-006. Consistent with norma-cli, kaltblut-cli, ph-redact-cli, the en16931-*-cli tools and phoss-peppol-mcp (picocli 4.7.7).

Remaining detail: pin the version locally or inherit it from a shared parent POM property.

4. MLS: parse only, or generate too? โ€” resolved: parse only, generation deferred

Parsing and validating an MLS response is useful for diagnostics and low-risk, so peppol mls parse and peppol mls validate are accepted.

Generating one is a different matter: an MLS response is a statement made by a receiving party about a message it processed. A CLI that can emit one invites hand-crafted statuses being sent outside the AP that actually handled the message, which is a correctness and accountability problem rather than a convenience.

Decision: parse only. peppol mls generate is deferred โ€” there is no present need for it. The builders (PeppolMLSBuilder and friends) are in place, so it can be reconsidered cheaply if implementers testing their own MLS handling ask for it, most likely behind an explicit "for testing" flag. > TODO(verify): the exact MLS specification name and version

5. Code list cache update strategy โ€” resolved: bundled only

Code lists ship with the distribution and are updated by upgrading the tool. No download, no cache refresh, no TTL.

This follows from the data's shape rather than from preference: the code lists are exposed at runtime only as generated enums, and there will be no shared library for reading code list data at runtime. peppol codelist diff and peppol codelist update are therefore rejected in the Feature Catalogue.

The upside is real: every code list command works offline, unconditionally, with nothing to invalidate and no unattended run whose behaviour depends on a background download. peppol codelist version reports the bundled version per kind, so a user can always see what they have โ€” and each code list is versioned independently, so the versions are allowed to differ and the tool must not treat that as an error.

Remaining minor question: should the tool warn when its bundled code lists are older than some threshold? That needs no new mechanism, only a build-time timestamp. > TODO(decide): warn on stale bundled code lists, or leave it to the user to notice?

6. Minimum Java version โ€” resolved: Java 25

See ADR-005. Note that the shared parent POM currently defaults to Java 17, so this project overrides the java.version property.

Remaining detail: whether the distribution archive should bundle a runtime (via jlink) so users do not have to install Java 25 themselves.

7. Licence โ€” resolved: Apache License 2.0

See ADR-008. The repository already contains the Apache 2.0 LICENSE file, and every project this one builds on uses the same licence.

Remaining, and genuinely separate from the choice itself: a licence review of the transitive dependency set once the module list is fixed. Everything directly planned is Apache 2.0 (picocli, ph-commons, peppol-commons, peppol-directory-client, phorm-client), but the SOAP/JAX-WS stack pulled in by peppol-sml-client and the dnsjava dependency are the ones to check, since neither is a phax project. > TODO(verify): run a licence report over the resolved dependency tree before the first release.

8. Windows support level

Options: (a) tier 1 โ€” tested in CI, .cmd/.ps1 launcher, PowerShell completion, Windows path and console handling, %APPDATA% config location; (b) best effort โ€” it should work, but is untested and unsupported; (c) not supported.

Specific Windows concerns: ANSI colour support in the console host, %APPDATA% versus XDG config discovery, path separators in bulk CSV input, keystore access, and whether the Windows certificate store should be used as a truststore source.

Current inclination: (a), because support engineers are a target audience and frequently work on Windows. > TODO(decide): confirm the intended support level, since it determines CI cost from the start

9. Document type aliases: derived or curated?

Typing a 200-character document type identifier is the single worst part of the current tooling experience, so aliases are clearly worth having. The question is where they come from.

Derived from code list display names โ€” free, always complete, and automatically covers new document types. But verified problems: 16 of the 321 display names in v9.7 are duplicated (mostly busdox-docid-qns versus peppol-doctype-wildcard variants), and display names are not guaranteed stable across code list versions. An alias that silently changes meaning after an upgrade is worse than no alias.

Curated in the CLI โ€” a hand-maintained table of short, stable names (bis3-invoice, bis3-creditnote) for the dozen or so document types people actually type. Stable by construction and unambiguous, but needs maintenance and will not cover everything.

Both โ€” a curated table taking precedence, falling back to derived display names, with ambiguity always an error rather than a guess. Probably the right answer; it needs a decision on who maintains the curated table and whether it belongs in peppol-commons rather than in the CLI, since the problem is not CLI-specific.

See the alias rules in CLI Conventions and the feature entries in Feature Catalogue.

10. SMP write scope โ€” resolved: phoss-SMP, and the area name says so

SMP 1.4.0 ยง3 defines no create/update/delete interface, so the write API peppol-smp-client speaks is in practice the phoss-SMP one. Rather than hide that behind a generic smp area, the write commands live under their own phoss-smp area โ€” see CLI Conventions and the Feature Catalogue. peppol smp โ€ฆ stays the specified read interface that works against any conformant SMP.

That makes the portability boundary visible instead of documented-in-a-footnote, and leaves room for a future peppol <other>-smp area without renaming anything. Other implementations that happen to expose the same API are likely to work, but the tool promises nothing about them.

Both resolved. The area is spelled phoss-smp, with phosssmp accepted as an alias. And the tool does detect an incompatible SMP up front, via the /smp-status preflight โ€” chiefly the smp.writable-rest-api.enabled field โ€” while treating an absent status response as inconclusive rather than negative. Both are recorded in the Feature Catalogue.

11. Additional questions raised while writing this wiki

These came out of drafting and need an owner:

  1. Default network. Resolved: --network defaults to prod. Almost all use is looking up real participants, so production is what the user meant; --network test is the deliberate act. The consequence is that write safety rests entirely on the write rails โ€” confirmation, --dry-run, and naming the resolved network in the prompt โ€” rather than on the network selector. See CLI Conventions.
  2. Write command safety. Is --dry-run the default for write commands, with --commit to execute? This matters more now that the network defaults to prod.
  3. Command naming for the flagship check. peppol smp can-receive reads well; is there a more conventional name for what operators actually call this check?
  4. JSON Schema publication. Publish a schema per command, or document the shapes in the wiki only?
  5. Telemetry. Proposed answer: none, ever, with no opt-in. Worth recording as an ADR so it is never revisited casually.
  6. Deprecation handling. Does using a deprecated participant scheme or document type warrant a warning at exit 0, or its own exit code?
โš ๏ธ **GitHub.com Fallback** โš ๏ธ