Very odd bug -- mine or Inform's?

I was writing up a quick extension for in-game footnotes (like in HHGG), and I’ve run into a very weird thing. After spending all evening on it and testing on both 6L38 and 6M62, I just can’t figure out what’s wrong here. This is the code:

[spoiler][code]“Strange Behavior” by “Otis T. Dog”

Chapter I - Footnotes

Section I - The citation enumerator

The citation enumerator is a thing. It has a number called counter. The counter of the citation enumerator is 1.

To decide which number is the next available footnote number:
let produced number be the counter of the citation enumerator;
increment the counter of the citation enumerator;
decide on produced number.

Section II - The footnote kind

A footnote is a kind of thing. A footnote has a number called citation index. A footnote has some text called citation text. The citation text of a footnote is usually “This footnote left (un)intentionally blank. Please report the bug to the author.”

A footnote can be cited or uncited. A footnote is usually uncited.

A footnote can be read or unread. A footnote is usually unread.

Section III - Footnote actions

To alert the reader to (discovered note - a footnote):
now the citation index of the discovered note is the next available footnote number;
say " (footnote [citation index of the discovered note])";
now the discovered note is cited.

To display (requested note - a footnote):
say “[citation text of requested note]”;
now requested note is read;
repeat with subnote running through uncited footnotes part of requested note:
alert the reader to the subnote;
say “[line break]”.

Rule for printing the name of a footnote (called perused note):
if the perused note is uncited:
alert the reader to perused note;
otherwise:
do nothing.

Section IV - The footnote verb

Viewing footnote number is an action out of world applying to one number. Understand “footnote [number]” or “read footnote [number]” or “show footnote [number]” as viewing footnote number.

Check viewing footnote number (this is the can’t view uncited footnotes rule):
let footnote found be false;
repeat with item running through cited footnotes:
if the citation index of the item is the number understood:
now footnote found is true;
if footnote found is false, say “You can’t view a footnote until it is mentioned in play.” instead.

Report viewing footnote number (this is the display requested footnote to reader rule):
repeat with item running through cited footnotes:
if the citation index of the item is the number understood:
display item.

Chapter II - Test Scenario

Cube Farm is a room. “What a terrible place to be.[footnote farm]”

Footnote farm is a footnote. It has citation text “Do they actually grow cubes here? There is certainly enough fertilizer around here, metaphorically speaking.”

Your desk is here. It is a fixed in place supporter. The description of the desk is “The cheapest desk the company could get away with. You’re surprised it has drawers.[footnote desk] Right now it’s covered in clutter.”

Understand “drawer” or “drawers” or “clutter” as the desk.

Footnote desk is a footnote. It has citation text “Not like you actually keep anything in there, though.”

Your chair is here. It is a portable enterable supporter. The description of the chair is “There are rollers. They are broken.[footnote rollers]”.

Footnote rollers is a footnote. It has citation text “Which is typical.”

Metanote is a footnote. It is part of footnote rollers. It has citation text “Notes within notes.”

Metametanote is a footnote. It is part of metanote. It has citation text “… within notes.”

After waving hands:
say “CITED:[line break]”;
repeat with X running through cited footnotes:
say “[citation text of X][if X is cited] (#[citation index of X])[end if][line break]”;
say “[line break]UNCITED:[line break]”;
repeat with X running through uncited footnotes:
say “[citation text of X][line break]”.

After jumping:
repeat with X running through things:
if the player can see X:
say “[X] - [description of X][line break]”.

test me with “footnote 1 / look / wave / footnote 2 / x desk / wave / footnote 2 / footnote 3 / jump / footnote 3”[/code][/spoiler]

The theory of how it’s supposed to work is pretty straightforward – the first time a footnote’s name is printed, it becomes “cited” and “(footnote X)” (where X is a sequentially-generated number) is shown. It seems like it should work, and, obviously, the one in the room description works fine.

The footnotes present in the description of a thing, however, don’t work. They somehow become cited before they should, it seems, making it so that “(footnote X)” isn’t printed. There’s only one place in the code that this should be possible, however, and that’s right after the place where “(footnote X)” is printed!

I wrote some cross-check commands: >WAVE will display the cited/uncited status of footnotes. >JUMP will display the description strings of objects visible to the player.

As the test-me shows, >WAVE indicates the expected “cited” status at any point, and >JUMP shows that the “(footnote X)” string prints fine in at least some cases… the issue seems to be oddly specific to the context of the examining action. The desired behavior occurs as expected for the looking, viewing footnote number, and jumping actions.

Does anyone have any idea what’s causing this? I’m totally stumped.

Text substitutions with side effects can be dangerous, because they get executed every time the text is expanded…even if it isn’t being printed directly.

Inform expands the name of an object before actually printing it, for example, to decide whether to say “a” or “an”. Similarly, the description is expanded to decide whether it’s empty or not; if so, the generic “You see nothing interesting…” message is printed instead.

Is there something special about the context of the examining action with respect to what you’re talking about? I’m asking because it seems to work fine in other contexts – even with an apparently-identical use of the same description string for the object (as in >JUMP).

Yes. The EXAMINE description is expanded to check whether it’s empty, as Draconis said.

You can use the test “if expanding text for comparison purposes…” to check for this situation and avoid setting the cited flag.

Thank you for that pointer, zarf – I see that phrase is used once in the Standard Rules (6L38), for the “Before printing the name of a thing…” rule near the top of Section SR3/1. It does not seem to be mentioned in WWI or RB.

I’m still a little unclear about what’s going on here, though. Is it the part of the “standard examining rule” that reads:

if the noun provides the property description and the description of the noun is not "":

which is the difference? The “description of the noun is not…” comparison invokes the “rule for printing the name of a footnote” by trying to resolve the substituted description string, even though it wouldn’t actually be expected to print anything at that point?

That phrase does the trick, zarf. Thanks again.

And thank you for trying to explain it, Draconis. I didn’t connect the dots between my code and what you were saying because I was confident in WWI’s specific indication that the printing the name of something activity occurs “whenever the name of a thing or room is printed”, and I didn’t realize that activity would be triggered by just any substitution.

Yes. Any comparison of a text to another text has to expand the substitutions in both.