There’s some runtime type checking in there which may cause the system to behave consistently, if not usefully. I haven’t run through test cases to see. (Maybe I can take a closer look tomorrow.)

Xyz is a text based rulebook producing text.
Xyz has outcomes xyz (failure) and abc (success).
Xyz "why": rule succeeds with result "def".
Xyz "anon": xyz.
When play begins:
let BB be the text produced by the Xyz rules for "why";
if rule succeeded, say "success!";
if rule failed, say "failed!";
say "[BB]";
follow Xyz for "anon";
if rule succeeded, say "success!";
if rule failed, say "failed!";
if the outcome of the rulebook is the xyz outcome, say "it's the xyz";
if the outcome of the rulebook is the abc outcome, say "it's the abc";
say "[outcome of the rulebook]";

but throw in one

let CC be the text produced by the Xyz rules for "anon";

and you make Quixe cry.

Quixe init: Error: Function returned undefined value. Function returned undefined value.

So I actually shouldn’t have said you’re unable to return the type you’re obliged to. You can… by ignoring the named outcomes. So it seems in the category of causing problems if you try to do this and doesn’t seem to have any plausible benefit.

(Well, unless I’m missing something and there really is a magic way to use both at once that I couldn’t see.)

This is easier to analyze if you use a number-based rulebook producing a number. (That way you avoid invalid text address errors.)

Xyz is a number based rulebook producing a number.
Xyz has outcomes waltz (failure) and tango (success).
Xyz rule for 1 (this is the xyz1 rule):
rule succeeds with result 111.
Xyz rule for 2 (this is the xyz2 rule):
waltz.
Xyz rule for 3 (this is the xyz3 rule):
tango.
Zapping is an action applying to a number.
Understand "zap [number]" as zapping.
Carry out zapping:
say "Zap [number understood]...";
let res be the number produced by the xyz rules for the number understood;
say "Result [res].";
if the outcome of the rulebook is the waltz outcome, say "Outcome: waltz.";
if the outcome of the rulebook is the tango outcome, say "Outcome: tango.";

>zap 1
Zap 1...
Result 111.
>zap 2
Zap 2...
Result 415911.
Outcome: waltz.
>zap 3
Zap 3...
Result 415917.
Outcome: tango.

This is correct except that the internal result values leak out. (I’m sure that 415911 and 415917 are the I6 string addresses of the internal result constants RBNO_13 and RBNO_14.)

If you look at the I6 code, you’ll see that the rules compile as

It can’t respond with a number and an outcome because those values are going to the same place! But there’s a type code, so the system should be able to prevent those internal values from leaking out. But obviously there’s a bug.

I’m pretty sure that the intended behavior is that if you return a named outcome, the “number produced” should be zero. Or, in your example, the “text produced” should be the empty string.

This is conceivably useful; you can imagine a rulebook which either produces a value or uses a named outcome as a sort of exception. And indeed you can do this now – check the named outcomes first!

if the outcome of the rulebook is the waltz outcome:
say "Outcome: waltz.";
else if the outcome of the rulebook is the tango outcome:
say "Outcome: tango.";
else:
say "Result [res].";