Thanks Max,
I'm thinking the same to add attribute and property with corresponding tags and then
add whatsits on the 255 box shipout. I just need to think about discardable items.
If one wants to mark up tex sources for xml or tagged pdf a common issue how to safely
mark start and end of semantic text without effecting output.
For example  if there would be few primitives which could add an attribute or/and properties
to next (yet to be created) non discardable item like
\luaAddFeaturesNodeNext {{attr=1, properties={"<section>}}}
\section{foo}
\luaAddFeaturesNodePrev{{attr=1, properties={"</section>}}}
It could save a lot of headache.
Of course this is not an easy task because of page breaks.


You can set an attribute on the previous node, then add the node itself
in pre_output_filter:

    \directlua{%
        user_nodes = {}
        % Better to use luatexbase.new_attribute and luatexbase.add_to_callback
        attribute_number = 1234
        % "pre_shipout_filter" is better if you're using LaTeX or OpTeX
        callback.register("pre_output_filter", function(head)
            % Better if this recurses through any nested lists
            local n = head
            while n do
                local attr
                attr, n = node.find_attribute(n.next, attribute_number)
                if not n then break end
                head, n = node.insert_after(head, n, user_nodes[attr])
            end
            return head
        end)
    }

    aa
    \vskip11.1pt
    \showthe\lastskip
    \directlua{%
        % I'm using a rule to make the effect obvious
        local x = node.new("rule")
        x.width = 655360
        x.height = 655360
        x.depth = 0
        table.insert(user_nodes, x)
        node.set_attribute(
            tex.nest[tex.nest.ptr].tail,
            attribute_number,
            \luaescapestring{#}user_nodes
        )
    }%
    \showthe\lastskip
    bb
    \bye

It's a little risky to mess with tex.nest.tail, but just setting an
attribute should be mostly safe.

Thanks,
-- Max