flan/vendor/agent/flan_agent.web.c
Joseph Ferano 57fe91f303 Five records become one, and every citation lands somewhere
FIX.org, NEXT.md, DISCUSS.org, docs/DISCUSS.md and the session handoff at the
root are one TODO.org now: 293 entries under seven subsystem headings, each
carrying an org keyword that says where it stands. A DONE entry is a few lines
saying what was decided and what that rules out; the reasoning that would not
compress — the embedding spike and the four reports the hand-written x86
backend was built from — moved into docs/BUILT.md instead, and its entries
point there in one line.

Every entry was checked against the tree before it got a keyword, and the
prose was wrong in both directions. Things the deleted files called open were
built: the first-evaluation stall, main being redefinable, macro parameter
lists, the type-limit constants, the array constructors, the byte fills,
inc/dec, the discard's fontification, the Emacs buffers, rt_die's _exit, the
backtrace surface, and the acceptance failure that could print and still exit
zero. Things they called done were not: the backend reports' no-plan buckets
had gone stale in the other direction, the value-dependent defvar was
superseded rather than built, and macro-expansion source locations are on an
unmerged lane, so that entry is NEXT and names the branch.

Every comment that cited one of the five by name now cites a heading that
exists, in TODO.org or in docs/BUILT.md. The session reports under
docs/handoffs/ keep naming the files they worked on, because rewriting them
would falsify what those sessions did; each carries a note saying where the
content went.
2026-09-21 21:05:48 +07:00

77 lines
4.0 KiB
C

/* The dev agent in a browser: the three calls, doing nothing, and saying so.
*
* Build selects this file over flan_agent.c on --target=web, and only there
* (see Build.select_csrcs). The reason is not the compile error that led here
* — emscripten's headers do not pull <sys/time.h> in transitively, so
* flan_agent.c fails on `struct timeval` at line 426 — because an #include
* would have fixed that and fixed nothing real. The reason is structural:
*
* THE AGENT IS A SOCKET SERVER, AND A BROWSER HAS NO SOCKETS.
*
* flan_agent_start binds an AF_UNIX socket and hands it to a listener thread.
* There is no such address family under emscripten, nothing to listen on, and
* nothing that could connect if there were. Adding the include produces an
* agent that compiles, links, starts, and can never accept a connection.
*
* ── Why a no-op here, when `barf` on the web signals instead ────────────
*
* TODO.org, "Writing a file is desktop-only and signals on web", rejected a
* silent no-op for `barf` in as many words: a no-op write is how a save file
* disappears with nothing said. The two look contradictory and are not, and
* the difference is what the caller loses.
*
* `barf` is asked to make something durable. A no-op returns success to a
* program that now believes the bytes are on disk; the loss is real, it is the
* user's, and it is discovered later or never. So the web signals a condition
* and the program decides.
*
* The agent is asked to accept redefinitions from an editor. On the web there
* is no editor, no socket, and no session — `--dev` is refused by name on
* every wasm target, so a web build has no cells to install a redefinition
* into even if one arrived. There is nothing to lose because there was never
* anything there. sand.flan already says the same thing about a *native*
* release build, at the call site:
*
* "Building without --dev is fine — nothing has cells to install into, so a
* module is refused on the listener thread and the loop never notices."
*
* A web build reaches that same outcome by a shorter route. The no-op is not
* hiding a failure; it is the truthful implementation of "nothing is
* available here", which is the case where Odin's own `.Unsupported` stubs are
* right and the case decision 2 was careful to say it was not.
*
* ── Why not refuse vendor:agent on a web target ─────────────────────────
*
* It was the other candidate and it is ruled out by arithmetic, not taste.
* Flan has no conditional compilation, so a program cannot say "skip this on
* web". sand.flan calls (agent/start ...) unconditionally, Reach cannot prune
* a package something reachable calls into, and a build-time refusal would
* therefore mean sand.flan does not build for the browser at all without being
* edited into a second program. Refusing is only honest when the caller has a
* way to not ask; here it has none.
*
* ── What the return values say ──────────────────────────────────────────
*
* start returns -1, which is the same "could not listen" flan_agent.c returns
* for a path it cannot bind, so a caller that checks gets the answer it
* already knows how to read. poll and wait return 0 — no redefinitions
* installed — which is the truth and is what the native build returns on every
* frame that nothing arrived on. */
#include <stdint.h>
int32_t flan_agent_start(const uint8_t *path, int64_t len) {
(void)path; (void)len;
return -1;
}
/* The zero-argument form, which on a native build picks a socket path for
* itself. There is still nothing to bind here, so it answers exactly what the
* explicit form does and prints nothing: a path chosen for a socket that
* cannot exist would be a sentence about nothing. */
int32_t flan_agent_start_auto(void) { return -1; }
int32_t flan_agent_poll(void) { return 0; }
int32_t flan_agent_wait(int32_t ms) { (void)ms; return 0; }