0.10.0 — five declarations, each added because its absence was a wrong answer - #25
Merged
Conversation
…ong answer Closes #22, #23, #24. ⭐⭐ WHAT THE FIVE HAVE IN COMMON. Not one of them was a facility nobody had asked for. Each was reached by a C library above this interface, found to have nothing here to reach, and answered ANYWAY --- wrongly, and without telling its caller. A specification that has no operation for X does not cause consumers not to do X. It causes them to do X badly, out of sight. `kal_fs_lock' / `kal_fs_unlock' + KAL_FS_PROP_LOCKS openkal-musl answered `fcntl(F_SETLK)' with success and took no lock: two programs held one exclusive lock and neither could find out. Measured against a host. ⭐ AND THIS IS THE OPPOSITE OF THE PERMISSION ENTRY, which is why clause 11 now has them next to each other. Permission was declined because the environments do not agree that an identity exists. Every environment this specification targets locks a byte range and spells it almost identically. What was missing was a word, not a capability. ⭐ Release upon the holder's end is REQUIRED rather than observed, and that requirement is why this cannot be composed above the line: a caller can build exclusion out of KAL_OPEN_EXCLUSIVE and a name, and nothing then releases that name when its holder dies.⚠️ The holder is the `kal_file' and NOT the program. One environment's oldest form releases every lock a program holds upon a node as soon as it closes ANY descriptor for it --- so a library that opened one file twice destroyed its own lock. An implementation shall not expose that; the environments that have the older form also have a newer one whose holder is exactly the open file. `kal_process_spawn_bound' + KAL_PROCESS_PROP_BOUND_LIFETIME Clause 7.1 declines to replace a running image, and that stands. The consequence this specification had NOT recorded is that a C library asked for `execve' composes it, and the composition leaves THREE images where a system with the operation has two --- and a signal reaches the middle one. Measured with a host as control: identical status words, opposite outcomes; the caller is told the program died on the signal it sent while the program runs to completion, unsupervised. `kal_process_terminate' was not at fault. What was missing was a way to SAY the thing `execve' means. `kal_task_parallelism' KAL_TASK_PROP_PARALLEL says WHETHER and not HOW MANY, so `hardware_concurrency' answered 1 with no error and a program sizing a pool of workers got one worker. ⭐ Zero is "cannot say" and is distinct from one: an environment with one processor and an environment that will not answer call for different behaviour. `kal_fs_set_modified_at' `kal_fs_set_modified' is stated on an open FILE and a directory is opened as a `kal_dir', so this interface had NO route to a directory's time at all --- while `kal_fs_info' reports one. A consumer that stamps a lock directory drove one implementation to open the directory for READING and set the time on that, outside anything stated here.⚠️ A divergence caused by a missing declaration is a defect of the specification, and is recorded as one. `kal_fs_capacity' + KAL_FS_PROP_CAPACITY `std::filesystem::space' had nothing beneath it. --- what this does NOT do --------------------------------------------------⚠️ THE TWO SPAWN ADDITIONS DO NOT COMBINE, AND THAT IS DELIBERATE. There is no form that both grants directories and binds a lifetime. Declaring every combination is how an interface acquires four spawns and then eight, so the combination is declared when something needs it. What a caller must not do meanwhile is take `kal_process_spawn_with' and assume the binding. Clause 8 is satisfied: five declarations added, none altered, no layout touched. Clause 6.2 is satisfied by the property words --- an operation present and not performable here is not a defect, because a caller can ask first, which is exactly the argument clause 11 already records for the link operations.
This was referenced Aug 30, 2026
Merged
0.7.0 --- openkal 0.10's five operations, four implemented and one refused
mcpplibs/openkal-macos#16
Merged
…rations⚠️ ⚠️ CI CAUGHT WHAT THE ADDITION ITSELF DID NOT: a specification may add a capability position, and the suite that checks capability words carries its own list of which positions are assigned. Adding the position and not the list makes every implementation that claims it non-conforming: DID NOT HOLD [abi] the capability word contains no position the specification has not assigned Reported by openkal-macos and openkal-linux, on the release that assigned them. ⭐ The check is exactly right and the omission is mine --- it is the check that exists so an implementation cannot extend the interface rather than implement it, and it cannot tell an extension from a position the suite has not been told about. `kal::fs::locks`, `kal::fs::capacity` and `kal::process::bound_lifetime` are added to the modules, and to the three masks. --- and the operations are OBSERVED, not merely declared --------------------⚠️ Five declarations were added with no criterion between them. A specification that adds an operation and no way to tell whether an implementation performs it has added a name. ⭐⭐ THE LOCK OBSERVATION NEEDS NO SECOND PROGRAM, AND THAT IS THE WHOLE OF ITS DESIGN. openkal states that the holder is the open FILE. One environment's oldest form holds it by the PROCESS and releases every lock upon a node as soon as the program closes any descriptor for it --- so a library that opened one file twice destroyed its own lock. An implementation built on THAT form passes "a lock is taken" and "a lock is released" and fails on exactly one observation: a second open file of the same name is refused, not granted which this suite makes, in one program, with two `kal_file' handles. `kal_fs_capacity': what is available is no more than what is held, and a caller may ask for one of the two. `kal_fs_set_modified_at': a DIRECTORY, which is the reason the declaration exists --- and a file by the same operation, so that the new form is not a directory-only path. `kal_task_parallelism': the same answer each time, and one where contexts do not run at once. ⭐ Zero means "cannot say" and the suite does not require a number, because an implementation that will not say must be able to say so. `kal_process_spawn_bound':⚠️ where the position is NOT claimed, the operation shall REFUSE rather than start something else. A caller that asked for a bound lifetime asked for it; a program started without the binding is not the program it asked to start, and quietly starting one is the failure the operation exists to remove. openkal-macos and openkal-windows both take this path, so it is the observation that governs two of the five implementations.
… have `here()' is defined in the fs section. The process section has its own way to name the working directory --- `kal::fs::working()' --- and the observation I added called the other one, so the suite did not compile at all.⚠️ AND IT COMPILED HERE, which is why it reached CI. A local build of this package links against no implementation, so it stops at the link and never reports what the compile of one section said. The build that catches this is the one an implementation runs, and openkal-linux ran it on both compilers within minutes of the push.
…orted⚠️ ⚠️ THE SPECIFICATION HAS TWO SURFACES AND I ADDED TO ONE OF THEM. `KAL_LOCK_SHARED', `KAL_LOCK_EXCLUSIVE' and `KAL_LOCK_WAIT' are macros in `fs.h'. A consumer that writes `import openkal.fs' cannot see a macro --- so those three positions were nameable by half the consumers of this specification and not by the other half. error: use of undeclared identifier 'KAL_LOCK_EXCLUSIVE' ⭐ REPORTED BY THE SPECIFICATION'S OWN CONFORMANCE SUITE, WHICH IS ONE OF THE CONSUMERS THAT CANNOT SEE MACROS. The suite imports the modules, so it is exactly the reader that finds this --- and it found it on the release that added them. They join `open_flags' in a kind of their own, for the reason that one has: an intent and a capability word are different things, and a word that serves as both can be passed to the wrong operation. `kal::fs::lock_range' goes with them, as `kal::fs::open_file' goes with `open_flags'.⚠️ The rule this leaves behind: a position added to the C header is not added until it is in the module too. The property words got both because they were added as a pair; these did not.
The entry names `kal_fs_set_modified_at' and `kal_fs_capacity' and justified only the first. Found on a last read of the diff before merging: an entry that names two additions and argues for one is how an addition arrives unargued. Says why capacity belongs to `openkal.fs' and not `openkal.space' --- room on a volume is a property of the names a caller can already reach --- what its absence cost, which was a fixed number reported to a program checking for room, and why it answers bytes rather than the block count and block size every environment states in units of its own.
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.
Closes #22, #23, #24.
⭐⭐ What the five have in common
Not one of them was a facility nobody had asked for. Each was reached by a C
library above this interface, found to have nothing here to reach, and answered
anyway — wrongly, and without telling its caller.
A specification that has no operation for X does not cause consumers not to do X.
It causes them to do X badly, out of sight.
kal_fs_lock/kal_fs_unlockfcntl(F_SETLK)returned success and took no lock — two programs held one exclusive lock and neither could find outkal_process_spawn_boundkillon a composedexecvereached the waiting copy; the caller was told the program died while it ran to completion, unsupervisedkal_task_parallelismhardware_concurrency()answered 1, with no errorkal_fs_set_modified_atkal_fs_capacitystd::filesystem::spacehad nothing beneath itEach measured against a host as control, not reasoned.
⭐ The lock entry is the opposite of the permission entry
Clause 11 now has them next to each other. Permission was declined because the
environments do not agree that an identity exists. Every environment this
specification targets locks a byte range and spells it almost identically. What
was missing was a word, not a capability.
And release upon the holder's end is required rather than observed — which is
why this cannot be composed above the line. A caller can build exclusion out of
KAL_OPEN_EXCLUSIVEand a name; nothing then releases that name when its holderdies.
kal_file, not the program. One environment's oldestform releases every lock a program holds on a node as soon as it closes any
descriptor for it, so a library that opened one file twice destroyed its own
lock. An implementation shall not expose that.
The two spawn additions do not combine. There is no form that both grants
directories and binds a lifetime; declaring every combination is how an interface
acquires four spawns and then eight. A caller must not meanwhile take
kal_process_spawn_withand assume the binding.Conformance
kal_fs_props/kal_process_propsposition — exactly the argument clause 11already records for the link operations.
SURFACE.txt, the three modules andconformance/src/declarations.call carrythe new names;
check-declarationsreports 101 entities on both sides.The rest of the graph moves with it
openkalis the shared dependency of every package, and a version requirementhere is exact. An implementation left behind is not on its own older contract —
nothing resolves at all. Branch
declarations-0.10exists in all fiveimplementations so this job builds against them:
spawn_boundrefused — no primitive arms it from inside the started imagespawn_boundrecorded as next, not claimed until measuredopenkal.fs