Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,39 @@ jobs:
# C++ modules in `namespace kal::kit` and exports no name beginning with
# `kal_`; a C++ name is mangled to `_ZN3kal3kit…`, so an implementation
# that linked the kit still passes `check-surface.sh --complete`.
# ⭐⭐ A PUBLISHED PACKAGE MAY NOT REACH ANOTHER BY PATH.
#
# kit/mcpp.toml is published as openkal-kit, out of this repository's own
# tarball. While it read `openkal = { path = ".." }` that was true here and
# true inside the tarball, and it made the package unusable with any
# implementation: a consumer naming both openkal-kit and an implementation
# reached the specification two ways --- by path from one, by version from
# the other --- and the build refused, correctly, because two routes to one
# package are two copies of it.
#
# ⚠️ NO CONTINUOUS INTEGRATION HERE COULD HAVE CAUGHT IT. Every workflow in
# this ecosystem substitutes working trees, so both routes become paths and
# agree. The defect appears only where an implementation names the
# specification by VERSION, which is the published shape and exactly what
# no job reproduces. It was found in a sandbox against the published
# packages, after release.
#
# This check is structural rather than behavioural for that reason: it
# cannot reproduce the graph, but it can require the form that avoids it.
- name: The kit names the specification by version
run: |
set -euo pipefail
if grep -nE '^openkal = \{[^}]*path' kit/mcpp.toml; then
echo "::error::kit/mcpp.toml reaches the specification by path."
echo " openkal-kit is published from this tarball, and a path"
echo " there is a second route to a package every consumer"
echo " already reaches by version."
exit 1
fi
grep -qE '^openkal = "[0-9]' kit/mcpp.toml \
|| { echo "::error::kit/mcpp.toml does not name openkal by version at all"; exit 1; }
echo " the kit reaches the specification the way a consumer does: $(grep -E '^openkal = ' kit/mcpp.toml)"

- name: The kit, composed from the interfaces above
if: matrix.implementation == 'openkal-linux'
run: |
Expand Down
30 changes: 26 additions & 4 deletions kit/mcpp.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
namespace = "mcpplibs"
name = "openkal-kit"
version = "0.1.0"
version = "0.1.1"
description = "Facilities composed from openkal's interfaces. Not part of the specification, and structurally incapable of being mistaken for it."
license = "Apache-2.0"
authors = ["mcpplibs"]
Expand Down Expand Up @@ -50,10 +50,32 @@ repo = "https://github.com/mcpplibs/openkal"
kind = "lib"

[dependencies]
openkal = { path = ".." }
# ⚠️⚠️ BY VERSION, NOT BY PATH, AND THE DIFFERENCE IS NOT COSMETIC.
#
# This line read `{ path = ".." }`, which is true inside this repository and
# inside the tarball this package is published from --- and which made the
# package unusable with any implementation. A consumer naming both openkal-kit
# and an implementation reached the specification two ways, and the build
# refused, correctly:
#
# error: dependency 'mcpplibs.openkal' is requested as both a path dep (by
# 'mcpplibs.openkal-kit@0.1.0') and a version dep (by
# 'mcpplibs.openkal-musl@0.4.0'). Pick one.
#
# Two routes to one package are two copies of it, and two copies of a
# specification are two sets of its modules. Measured in a sandbox against the
# published packages, which is the only place this could be observed: no
# continuous integration in this ecosystem resolves a published package,
# because they all substitute working trees by design.
openkal = "0.8.0"

[build]
include_dirs = ["../include"]
# ⚠️ NO `include_dirs` HERE EITHER. It named `../include`, which reaches out of
# this package into whatever happens to sit above it. With the specification
# named by version that directory is the tarball's own copy while the headers
# actually compiled against come from the resolved dependency --- two header
# sets for one contract. openkal publishes `include` as its own `include_dirs`,
# and a dependency's public directories reach a consumer; measured before this
# line was removed, with the specification placed outside this package.

# AN IMPLEMENTATION, FOR THE TESTS AND FOR NOTHING ELSE.
#
Expand Down
12 changes: 12 additions & 0 deletions tools/run-kit-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,25 @@ sed -i.bak -E "s|^${package} = \{ version = \"[^\"]*\"(.*)$|${package} = { path
"$kit/mcpp.toml"
rm -f "$kit/mcpp.toml.bak"

# ⚠️ AND THE KIT REACHES THE SPECIFICATION BY VERSION TOO, WHICH IT DID NOT USED
# TO. While that line read `path = ".."` it already named this working tree and
# needed no substitution. It now names a published version --- because a path
# there made the package unusable alongside any implementation --- so without
# this line these tests would run against the PUBLISHED specification while
# claiming to test the one written here, and a change to the specification would
# be invisible to them.
sed -i.bak -E "s|^openkal = .*$|openkal = { path = \"$here_native\" }|" "$kit/mcpp.toml"
rm -f "$kit/mcpp.toml.bak"

# ⚠️ ASSERTED RATHER THAN ASSUMED. A substitution that matched nothing leaves the
# manifest naming a version, the resolver fetches a published implementation, and
# the run reports on that one while appearing to report on this branch.
grep -q "path = \"$impl_native\"" "$kit/mcpp.toml" \
|| { echo "the implementation substitution matched nothing in kit/mcpp.toml" >&2; exit 2; }
grep -q "path = \"$here_native\"" "$impl/mcpp.toml" \
|| { echo "the specification substitution matched nothing in $impl/mcpp.toml" >&2; exit 2; }
grep -q "path = \"$here_native\"" "$kit/mcpp.toml" \
|| { echo "the specification substitution matched nothing in kit/mcpp.toml" >&2; exit 2; }

echo "--- the kit's dependencies ---"
sed -n '/^\[dependencies\]/,/^$/p;/dev-dependencies/,+2p' "$kit/mcpp.toml"
Expand Down
Loading