Three absences that a C library above this interface cannot compose around. All
three came out of mcpplibs/openkal-linux#13 — six rounds with a consumer porting
a POSIX-style CLI onto the native path — and all three are recorded in
openkal-musl's limits table today as refusals rather than as gaps, because a
facility that reports success and does nothing is the one answer that leaves a
program wrong without telling it. That issue is closed; these are what it produced
and did not answer.
None of them is urgent. Each is filed so that the next implementation meets it in
the specification rather than in a consumer's test suite.
1. A stream at position n in a program being started
What a program observes. A started program receives standard input, output and
error and nothing else. A descriptor 4 that is not close-on-exec is not there,
and fcntl(F_SETFD, 0) upon one therefore changes nothing.
Why it cannot be composed. kal_spawn_streams has exactly three positions, and
there is no general form for placing a stream at an arbitrary position. The port
already refuses posix_spawn_file_actions_adddup2 above position two rather than
accepting it, so the two halves agree with each other; what is lost is implicit
inheritance, which POSIX gives and no composition here can reconstruct.
What would answer it. A form in which the caller names positions and streams
together rather than filling three fixed slots — the same shape kal_spawn already
takes for base and work.
2. Starting a program upon a stream whose handle is zero
What a program observes. A caller that redirects its own output onto its own
standard input and then starts a program gets ENOSYS.
Why it cannot be composed. kal_spawn_streams reserves zero to mean inherit,
and kal_stream reserves nothing — so an implementation whose streams are the
environment's own descriptors hands out zero for standard input. The two meanings
coincide at position zero and cannot be told apart anywhere else. The port refuses
here rather than answering wrongly, because accepting it would hand a program the
stream its caller had just redirected away.
What would answer it. Either a distinguished value for no stream / inherit
that no kal_stream can ever be, or a statement that zero is never a valid stream
handle — one sentence in the interface, and the ambiguity is gone.
3. Whether a node may be executed
What a program observes. access(path, X_OK) answers yes for anything that
exists, and starting a name that exists and cannot be run still ends the caller
with 127.
Why it cannot be composed. kal_node_info carries writable and no other
permission, so it is there is the whole of what a port can answer. The two halves
are one gap: the enquiry cannot tell, and neither can the check a spawn makes before
starting.
What would answer it. This one has a cheaper half. The interface needs no
permission model — that was declined for good reason and the reasoning stands (a FAT
volume, a UEFI system partition and a Windows ACL do not share one). But an
implementation knows when the thing it is asked to start cannot be started:
openkal-linux's own execve is the call that fails. Reporting that distinctly,
rather than as the caller's 127, would answer the second half without the interface
acquiring a mode word. The first half — an enquiry that answers before the attempt —
needs a word here, and may not be worth one.
⭐ Grouped rather than split into three because they share a shape: each is a place
where a declaration would settle what no composition above the line can. Two of
the four defects the same consumer found — a directory's modification time and the
working directory a started program runs in — had exactly this shape, and both went
away when the declaration arrived (kal_fs_set_modified_at in 0.10, kal_spawn's
second directory in 0.11) rather than when someone found a cleverer composition.
Three absences that a C library above this interface cannot compose around. All
three came out of
mcpplibs/openkal-linux#13— six rounds with a consumer portinga POSIX-style CLI onto the native path — and all three are recorded in
openkal-musl's limits table today as refusals rather than as gaps, because a
facility that reports success and does nothing is the one answer that leaves a
program wrong without telling it. That issue is closed; these are what it produced
and did not answer.
None of them is urgent. Each is filed so that the next implementation meets it in
the specification rather than in a consumer's test suite.
1. A stream at position n in a program being started
What a program observes. A started program receives standard input, output and
error and nothing else. A descriptor 4 that is not close-on-exec is not there,
and
fcntl(F_SETFD, 0)upon one therefore changes nothing.Why it cannot be composed.
kal_spawn_streamshas exactly three positions, andthere is no general form for placing a stream at an arbitrary position. The port
already refuses
posix_spawn_file_actions_adddup2above position two rather thanaccepting it, so the two halves agree with each other; what is lost is implicit
inheritance, which POSIX gives and no composition here can reconstruct.
What would answer it. A form in which the caller names positions and streams
together rather than filling three fixed slots — the same shape
kal_spawnalreadytakes for
baseandwork.2. Starting a program upon a stream whose handle is zero
What a program observes. A caller that redirects its own output onto its own
standard input and then starts a program gets
ENOSYS.Why it cannot be composed.
kal_spawn_streamsreserves zero to mean inherit,and
kal_streamreserves nothing — so an implementation whose streams are theenvironment's own descriptors hands out zero for standard input. The two meanings
coincide at position zero and cannot be told apart anywhere else. The port refuses
here rather than answering wrongly, because accepting it would hand a program the
stream its caller had just redirected away.
What would answer it. Either a distinguished value for no stream / inherit
that no
kal_streamcan ever be, or a statement that zero is never a valid streamhandle — one sentence in the interface, and the ambiguity is gone.
3. Whether a node may be executed
What a program observes.
access(path, X_OK)answers yes for anything thatexists, and starting a name that exists and cannot be run still ends the caller
with 127.
Why it cannot be composed.
kal_node_infocarrieswritableand no otherpermission, so it is there is the whole of what a port can answer. The two halves
are one gap: the enquiry cannot tell, and neither can the check a spawn makes before
starting.
What would answer it. This one has a cheaper half. The interface needs no
permission model — that was declined for good reason and the reasoning stands (a FAT
volume, a UEFI system partition and a Windows ACL do not share one). But an
implementation knows when the thing it is asked to start cannot be started:
openkal-linux's ownexecveis the call that fails. Reporting that distinctly,rather than as the caller's 127, would answer the second half without the interface
acquiring a mode word. The first half — an enquiry that answers before the attempt —
needs a word here, and may not be worth one.
⭐ Grouped rather than split into three because they share a shape: each is a place
where a declaration would settle what no composition above the line can. Two of
the four defects the same consumer found — a directory's modification time and the
working directory a started program runs in — had exactly this shape, and both went
away when the declaration arrived (
kal_fs_set_modified_atin 0.10,kal_spawn'ssecond directory in 0.11) rather than when someone found a cleverer composition.