fix(v4.0.0): POST leaves nothing, as v3 really does; and what the review of step 6b found

Captain Bob was told that v3 leaves the words POST's cases define in the
dictionary, and ruled that v4 should.  That was false: v3's run_test_suite
puts the dictionary back after each word's cases (test_common.c:333,
:365).  Shown that, he ruled that POST leaves nothing.  The boot now
seals the system, runs POST, and has the node do COLD, whose printing is
not shown; PARITY:V4_SYSTEM is the system as sealed.

A case the node does not come back from ends POST there, named, with how
many were not run: it would have stalled the boot for hours, where the
capsule had ended it.  The runner's test of it now uses a word that
really never ends.

hosted-check also requires that RS1 and T{ are unknown after boot, and
boots a program whose POST has failing cases (tests/post_cases_fail.c):
PARITY:FAIL, POST: FAILED, no prompt, none of a case's printing shown.

Comments and documents that still named the POST capsule or its two
hooks are brought up to date; NUCLEUS.md 6.3 says what v3 does, with the
lines, and how the wrong ruling came about.

make -C v4 test, sanitize and hosted-check pass; amd64, aarch64 and
riscv64 boot, POST 538 of 538, word_count=314, dict_hash
0x220ab283a504a3b3 on all six: logs/20261007-112638, -112901, -113220.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-07 11:40:20 -04:00
co-authored by Claude Opus 5.5
parent eda6577a53
commit 18adf59091
17 changed files with 669 additions and 65 deletions
+23 -15
View File
@@ -361,10 +361,11 @@ static const char *say(const char *input)
}
/* POST's RUNNER (v4/system/post.c), with these tests as its host: a line is
* sent to the node as the console sends one, and what the node prints is
* handed back and not shown. `post_lost` is the text of a line that is
* never to come back, and `post_state_fails` makes the line that sets the
* state end in an error; `post_said` is what the runner printed. */
static const char *post_lost;
* handed back and not shown. `post_step_limit` is how long a line may
* take before the node is given up on, and `post_state_fails` makes the
* line that sets the state end in an error; `post_said` is what the runner
* printed. */
static long post_step_limit = 40000000;
static int post_state_fails;
static char post_said[4096];
static unsigned post_said_len;
@@ -373,12 +374,11 @@ static int post_line(void *self, const char *text, unsigned text_len, char *o, u
int ended;
(void)self;
*len = 0;
if (post_lost && strlen(post_lost) == text_len && memcmp(post_lost, text, text_len) == 0) return -1;
if (post_state_fails && text_len == 25 && memcmp(text, "DECIMAL FORTH DEFINITIONS", 25) == 0) text = "NOSUCHWORD-FOR-STATE ";
if (!v4_message_text(&to_node, 0, 1, V4_MSG_TEXT, text, text_len)) return -1;
to_sent = 0; from_node.count = 0;
shown_len = 0; shown_dropped = 0;
ended = run_line(40000000);
ended = run_line(post_step_limit);
if (ended != 1) return -1;
*len = shown_dropped ? (unsigned)sizeof shown + 1u : shown_len;
memcpy(o, shown, shown_len < cap ? shown_len : cap);
@@ -1259,22 +1259,30 @@ int main(void)
CHECK(post_one("many", "MANY", 0, V4_POST_STACK, 0, 0, big) == 0 && strstr(post_said, "POST FAIL: many ") != NULL, "a case that prints more than the runner keeps fails, by name");
CHECK(post_one("after.many", "1 2 +", 0, V4_POST_STACK, three, 1, "") == 1, "and the next case is judged as usual");
/* a line that never comes back */
post_lost = "LOST-LINE";
/* output on more than one line of a case */
CHECK(post_one("two.out", "65 EMIT", "66 EMIT", V4_POST_STACK, 0, 0, "AB") == 1 && post_one("two.out2", "65 EMIT", "66 EMIT", V4_POST_STACK, 0, 0, "AA") == 0,
"what a case prints on its second line follows what it printed on its first");
/* a case the node does not come back from: POST stops there */
CHECK(is(say(": SPIN BEGIN 0 UNTIL ;\n"), " ok\nok> "), "a word that never ends");
{
static const char *const la[] = { "1 2 +" }, *const lb[] = { "LOST-LINE" }, *const lc[] = { "65 EMIT" };
static const char *const la[] = { "1 2 +" }, *const lb[] = { "SPIN" }, *const lc[] = { "65 EMIT" };
static const v4_post_case three_cases[] = {
{ "first", la, 1u, V4_POST_STACK, three, 1u, "", 0u },
{ "lost", lb, 1u, V4_POST_STACK, 0, 0u, "", 0u },
{ "last", lc, 1u, V4_POST_STACK, 0, 0u, "A", 1u },
{ "spins", lb, 1u, V4_POST_STACK, 0, 0u, "", 0u },
{ "never.run", lc, 1u, V4_POST_STACK, 0, 0u, "A", 1u },
};
v4_post_tally t;
post_said_len = 0; post_said[0] = 0;
CHECK(v4_post_run(&post_host, three_cases, 3, &t) == 0 && t.tests == 3 && t.pass == 2 && t.fail == 1
&& strstr(post_said, "POST FAIL: lost ") != NULL && strstr(post_said, "PARITY:V4_POST tests=3 pass=2 fail=1\n") != NULL,
"a line that does not come back fails its case; the others are still judged, and the run is not a pass: \"%s\"", post_said);
post_step_limit = 2000000;
CHECK(v4_post_run(&post_host, three_cases, 3, &t) == 0 && t.tests == 2 && t.pass == 1 && t.fail == 1,
"the run is not a pass, and the case after it is not run: %u run, %u passed, %u failed", t.tests, t.pass, t.fail);
CHECK(strstr(post_said, "POST FAIL: spins ") != NULL && strstr(post_said, "POST: the node did not come back from spins; 1 not run\n") != NULL
&& strstr(post_said, "never.run") == NULL && strstr(post_said, "PARITY:V4_POST tests=2 pass=1 fail=1\n") != NULL,
"it is named as the case the node did not come back from, with how many were not run: \"%s\"", post_said);
post_step_limit = 40000000;
}
post_lost = 0;
boot(); /* the node was left spinning */
}
/* ---- nothing of POST is on the node (NUCLEUS.md 6.3) ---- */