Skip to content

SPEC-004 says matching conditional tables apply in manifest order; the implementation applies them in selector text order #728

Description

@speak-agent

Observation

SPEC-004 §3.1.1 states that several matching [target.<selector>.<section>] tables apply in manifest order, the later one replacing the earlier one. §9 item 2 states that vectors are appended in the order of the matching [target.<selector>.build] tables. The implementation does not follow either statement:

  • modules/manifest/src/toml.cppm builds conditionalConfigs by iterating a TOML table.
  • mcpp.libs.toml's Table is std::map<std::string, Value, std::less<>>, so the iteration is in the lexical order of the selector text, not in source order (modules/libs/src/toml.cppm: "Key order carries no meaning in TOML").

For a manifest in which two selectors both match, and both state the same dependency or the same scalar, the table whose selector sorts later wins, whatever its position in the file. Vectors are appended in that order too. Every conditional key is affected. The mismatch was found while implementing #717, whose unit test first asserted manifest order and failed.

Why this is not only an implementation defect

TOML gives the keys of a table no order, so a rule that depends on source order cannot be implemented by a conforming TOML reader. The specification has to state an order that the data model carries, or refuse the ambiguous case.

Options

  1. Refuse a conflict between two matching rows. When two matching rows state the same identity or scalar with different values, refuse the manifest and name both selectors. Vectors from several matching rows are appended in a stated, documented order, for example the lexical order of the selector.
  2. State lexical selector order as the rule. This is deterministic, but it makes the answer depend on how a selector is spelled.

Option 1 matches SPEC-004 §4.4 (a condition is not written twice) and the refusal of contradictory statements elsewhere.

Activity

  1. speak-agent commented on Sep 28, 2026

    @speak-agent
    MemberAuthor

    Fixed in 2026.9.28.2 (#730), decision D7 of the 2026-09-28 ecosystem design. Matching [target.<selector>.<section>] tables now apply in order of selector specificity, so the more specific one applies later and wins: a bare triple ranks above any cfg(...), an OS (which fixes the OS and its family) above a family, and cfg(all(...)) counts the triple components it fixes; the selector text breaks a tie. One module, mcpp.manifest.cfg_selector, holds the vocabulary and the ranking, and both the mcpp.toml and the xpkg reader order their tables with it. SPEC-004 §3.1.1 states the rule.

    Readings: unit ConditionalOrder.* fails under the lexical order and passes; the sandbox section of tests/release/verify-published.sh builds a manifest whose cfg(all(os = "linux", arch = "x86_64")) table states -DPICK=2 and whose linux table states -DPICK=1, and fails on 2026.9.28.1 (the lexical order applied linux last). In mcpp-index, only compat.libarchive has two target_cfg predicates, and they never match one target.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions