Conversation
The scorecard's stability item asks for the tool that tells a reviewer
the public surface moved, before a user finds out. C++ has no such tool
in the toolchain. A compiler is perfectly happy to see a method deleted,
a parameter added or a noexcept dropped, and the person who finds out is
whoever upgrades and rebuilds.
api/surface.txt is every name include/zu.hpp publishes and the shape it
publishes it in, 466 lines of it, generated by docs/surface.py out of
the same Doxygen run as the reference and reviewed like any other file.
The gate rebuilds it from the header and fails when the two disagree.
It says what went, what arrived and what changed shape separately,
because those are three different pieces of news: a name that arrived is
a minor release and a name that went is not.
Identity is what decides which overload a call picks, so the name, the
parameter types and the const or ref qualifier. Everything else on a
line is shape: the return type, noexcept, = delete, the default
arguments. A parameter renamed is not a change at all, because there is
no call that names one. That is a departure from zu-go's file, which
keys on the name alone, and the reason is overloads: to_string is ten
functions here and a key that could not tell them apart would report
nine of them as gone the day the tenth moved.
Generating it found that the reference had been missing the whole
expected mirror. EXPAND_ONLY_PREDEF means a #define Doxygen read in the
file is not a value it will evaluate an #if against, so every
`#if ZU_HAS_EXPECTED` block was skipped and ninety two try_ members were
published nowhere. They were warned about nowhere either, because a
member the preprocessor threw away cannot be undocumented, which is the
same vacuous shape as the include guard that emptied the reference
before it. Both feature macros are predefined now and Connection alone
goes from 28 published members to 47. Two comments in the formatter
section were being read for the first time and needed \<format\> and
\<ostream\> escaped.
The std::formatter specializations are read out of the header rather
than the XML, because the Doxyfile expands ZU_FORMATTER to nothing on
purpose and std::format("{}", status) is still a call a user writes.
docs/test_surface.py is the twenty two cases the gate rests on, run by
ctest as surface-cases, on XML written out by hand rather than on
Doxygen. Getting one of those judgements wrong does not make the gate
fail, it makes it pass, or makes it report a renamed parameter as forty
names leaving and forty arriving, which is a gate a reviewer learns to
skip and comes to the same thing.
The release publishes surface.txt beside the reference. Two of them from
two releases diff into the answer somebody upgrading is actually asking
for, which no amount of generated HTML will give them.
44 of 44 green on Linux, which is the 41 that were there plus reference,
surface and surface-cases. The two failures worth having were exercised
rather than reasoned about: with the include guard back in PREDEFINED
the surface tool reports that nothing at all came out of the XML and
names the cause, and with the identity rule widened to the whole line
four of the twenty two cases fail.
tamnd
added a commit
to tamnd/zu
that referenced
this pull request
Aug 23, 2026
…667) tamnd/zu-c#12 landed api/surface.txt and the gate that reads it, so the last item on zu-c's card is held and the card is full. The number in the table is 100 rather than 90 because the column is a percentage of what the client's own tier asks of it, and zu-c is asked for neither api-map nor perf: it has no second surface to map, the header is the surface, and the numbers it would publish are the engine's rather than its own. Ninety points out of a denominator of ninety is a hundred percent, and it is the first client with nothing owed. That makes five tier 1 clients at their tier's threshold, which is the count the three boxes on DX4 wait on.
22 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The last item on zu-c's scorecard.
stabilityasks for the tool that tells a reviewer the public surface moved, before a user finds out.C++ has no such tool in the toolchain. A compiler is perfectly happy to see a method deleted, a parameter added or a
noexceptdropped, and the person who finds out is whoever upgrades and rebuilds. What the other clients do about that is keep the surface in a file, so this does the same: zu-node has an api-extractor report, zu-go has anapi/surface.txtin the shape of theapi/go1.N.txtfiles the language itself is held to.What is in it
api/surface.txtis every nameinclude/zu.hpppublishes and the shape it publishes it in, 466 lines, sorted by the name so that everything about one class is one block. It is generated bydocs/surface.pyout of the same Doxygen run as the reference, and reviewed like any other file.The gate rebuilds it from the header and fails when the two disagree, saying what went, what arrived and what changed shape separately, because those are three different pieces of news.
cmake --build build --target surface-updatewrites the file again when the move was deliberate.What identifies a line
The judgement the whole thing rests on. Identity is what decides which overload a call picks: the name, the types of the parameters, and the const or ref qualifier. Everything else on a line is shape, and shape changing reads as a change rather than as a replacement: the return type,
noexcept,= delete, the default arguments. A parameter renamed is not a change at all, because there is no call in C++ that names one.That is a departure from zu-go's file, which keys on the name alone, and the reason is overloads.
to_stringis ten functions in this header, and a key that could not tell them apart would report nine of them as gone the day the tenth moved.A whole parameter added does read as one name going and one arriving, since that genuinely is a different overload.
staticis in the key for the same reason.What generating it found
The reference had been missing the entire
expectedmirror.EXPAND_ONLY_PREDEFmeans a#defineDoxygen read in the file is not a value it will evaluate an#ifagainst. So every#if ZU_HAS_EXPECTEDblock was being skipped, and ninety twotry_members were published nowhere. They were warned about nowhere either, because a member the preprocessor threw away cannot be undocumented, which is the same vacuous shape as the include guard that emptied the whole reference two weeks ago. Both feature macros are predefined now.Connectionalone goes from 28 published members to 47.Two comments in the formatter section were being read for the first time as a result, and needed
\<format\>and\<ostream\>escaped.The
std::formatterspecializations are read out of the header rather than out of the XML, because the Doxyfile expandsZU_FORMATTERto nothing on purpose so that ten macro invocations do not arrive in the reference as ten classes nobody declared.std::format("{}", status)is still a call a user writes.The gate on the gate
docs/test_surface.py, run by ctest assurface-cases, is the twenty two cases the rules rest on, on XML written out by hand rather than on Doxygen. Getting one of those judgements wrong does not make the gate fail. It makes it pass, or makes it report a renamed parameter as forty names leaving and forty arriving, which is a gate a reviewer learns to skip and comes to the same thing.Both failure modes were exercised rather than reasoned about. With the include guard back in
PREDEFINEDthe tool reports that nothing at all came out of the XML and names the cause. With the identity rule widened to the whole line, four of the twenty two cases fail.One more thing worth saying out loud, and it is in the module docstring: Doxygen extracts a member only if somebody documented it, so a member with no comment would be missing from the XML and would be missing from
surface.txt, which is a name leaving the file without leaving the header. What catches that is the other gate,WARN_IF_UNDOCUMENTEDandreference.py. The two are a pair and turning either one off makes the other quieter than it looks.Where it runs
CI runs
surface-casesbeforesurface, in the existing docs job, since neither needs the engine and the whole job is under a minute. The release runs the gate again and publishessurface.txtbeside the reference: two of them from two releases diff into the answer somebody upgrading is actually asking for, which no amount of generated HTML will give them.The two tests share a resource lock with
reference, because both empty the reference directory and run Doxygen into it andctest -jwould have them deleting each other's output.Verification
44 of 44 green on a Linux box, which is the 41 that were there plus
reference,surfaceandsurface-cases. Also configured and run with-DZU_CPP_DOCS=ONand no engine at all, which is the shape CI uses.