docs: correct Hoon stdlib signatures that mislead readers into broken code - #267
Open
sigilante wants to merge 3 commits into
Open
docs: correct Hoon stdlib signatures that mislead readers into broken code#267sigilante wants to merge 3 commits into
sigilante wants to merge 3 commits into
Conversation
Four arms whose documented behaviour no longer matches sys/hoon.hoon at urbit/docs.urbit.org@08026c84b2. Every claim below was reproduced on a fake ship (v4.6 pill) rather than inferred from source. !@ "zappat" (rune/zap.md): branches are REVERSED. Upstream 87adc94d16 (2025-07-21, "!@ reverse polarity") changed the compile of %zppt from ?: to ?., so .q is now the does-not-exist branch and .r the exists branch. Verified both directions in dojo: =foo 42 !@(foo 'exists' 'does not exist') -> 'does not exist' !@(baz 'exists' 'does not exist') -> 'exists' The doc's Discussion and both example outputs asserted the opposite, so a reader following them writes inverted logic that still compiles. The examples are rewritten so the branch labels match the new order. No rationale is given upstream (empty commit body), so none is invented here. +trim (stdlib/4b.md): dry tape gate -> wet list gate. Now `|* [a=@ b=(list)]` / `^+ [p=b q=b]` (hoon.hoon:4317), not `|= [a=@ b=tape]` / `^- [p=tape q=tape]`. Both example OUTPUTS also changed, because the product is no longer cast to $tape: (trim 5 "lasok termun") -> [p=[i='l' t="asok"] q=[i=' ' t="termun"]] (trim 5 "zam") -> [p=[i='z' t="am"] q=~] Added a generic-list example and a note that only the inferred type and its printed form changed, not the value. +bif:by (stdlib/2i.md): now takes the key alone and never inserts. Signature went from `|* [b=* c=*]` to `|* b=*` (hoon.hoon:1445). Critically, the old two-argument call does NOT error: with sample b=*, the arguments arrive as the single cell [b c], so the map is split at that cell instead of at the key and the item at .b survives in the product. Verified: (~(bif by a) %b) -> splits at %b, %b excluded (correct) (~(bif by a) b+2) -> splits at [%b 2], returns a pair still containing [p=%b q=2] (silently wrong) The doc's own examples used the b+2 form, so they were demonstrating the broken call. Rewritten to the key-only form with verified output, plus a Discussion note that old callers fail silently rather than loudly. +peg (stdlib/1b.md): undocumented crash on a zero second argument. Source has `?< =(0 b)` alongside `?< =(0 a)` (hoon.hoon:213); the doc showed only the .a guard. Verified both (peg 4 0) and (peg 0 4) crash. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Second batch for PR-3. Sources checked against urbit/docs.urbit.org@08026c84b2. Items are marked below as ship-verified (reproduced on a fake ship, v4.6 pill) or source-verified (read from sys/hoon.hoon only). +mink / +mock / +mack (4n.md) -- ship-verified. The scry argument is now `$@(~ $-(^ (unit (unit))))`, not a bare gate (hoon.hoon:6021, :6182). Passing `~` means "no scry handler": ordinary formulas still evaluate, but a Nock 12 immediately blocks. Verified: (mink [[1 2] [0 2]] ~) -> [%0 product=1] (mink [0 [12 [1 0] [1 0]]] ~) -> [%2 trace=~] +mack correspondingly calls `(mink [sub fol] ~)` rather than `|~(^ ~)`. Documented the sentinel in +mink's Accepts with both cases. NOTE: +mong (4n.md:534) was checked and is UNCHANGED -- it still takes a bare gate (hoon.hoon:6256). Left alone deliberately. +shas (3d.md) -- ship-verified. Now `=/ len (max 32 (met 3 sal))` / `(shay len ...)`, not `(shax ...)` (hoon.hoon:3314). The audit characterised this as "differs for salts over 32 bytes"; that is wrong. Verified that a 1-byte salt and a 40-byte salt both agree with the old formula. The forms diverge only when the XOR result has fewer significant bytes than max(32, (met 3 sal)) -- i.e. when leading bytes cancel to zero. Constructed such a salt and confirmed divergence (27.383... vs 71.053...). +apt:in (2h.md) -- source-verified. Gained strict-inequality checks at every node: `&((gor n.a u.l) !=(...))` where the doc showed a bare `(gor n.a u.l)` (hoon.hoon:1224). NOTE: +apt:by in 2i.md was checked and is ALREADY CORRECT; the audit reported it as drifted. No change made there. +dif:by (2i.md) -- source-verified, knock-on from the +bif change. Dropped its `=+ b=a |@ ++ $` wrapper for a direct `|* b=_a`, and now calls `(bif p.n.b)` with one argument instead of `(bif p.n.b q.n.b)` (hoon.hoon:1478). Not previously connected to the +bif finding. +del:in / +del:by (2h.md, 2i.md) -- source-verified, source block only. Both gained `=> .(b `_?>(?=(^ a) ...)`b)` (hoon.hoon:1254, :1461). The audit claimed this makes a wrong-typed key a mint error rather than a silent no-op. That was NOT reproducible: `(~(del in s) "abc")` and `(~(del by mm) [1 2])` both return the container unchanged with no error. The source block is corrected; the behavioural claim is deliberately NOT documented, since it could not be demonstrated. DEFERRED: +inde / +iny (4f.md, 4i.md). Source has the new `|* [[ope=rule end=rule] sef=rule]` signature, but the shipping v4.6 pill does not: the documented one-argument example still works on the ship and the two-argument form fails. This change is in develop ([%zuse 408]) but not in the released kernel ([%zuse 409]), so the current docs are correct for anyone running released Vere. Blocked on the same 408-vs-409 decision as the kelvin updates. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…n 408
Follow-up to the previous two PR-3 commits. These were deferred because they
could not be verified on the pill I had booted; that pill was one kelvin
behind. Re-verified on a fake ship booted from urbit-408k-rc1.pill, which
reports [%zuse 408] -- the current kernel. (Kelvin counts down, so 408 is
newer than the 409 of the v4.6 pill used earlier.)
+inde (4f.md): signature changed from `|* sef=rule` to
`|* [[ope=rule end=rule] sef=rule]` (hoon.hoon:4910, upstream d5af20fec1,
2025-12-17, shipped to develop in the 408 merge a92492ed4b). The body was
rewritten as well. The documented one-argument call now fails to compile:
(inde (star ...)) -> mull-grow / -find.sef
Signature, body, Accepts and the worked example are all replaced. The new
example was verified verbatim on the ship:
> `tape`(scan "\"\"\"\0afoo\0abar\0a\"\"\"" (inde [(jest '\"\"\"') (jest '\"\"\"')] (star ;~(pose prn (just `@`10)))))
"foo\0abar"
The delimiter form is not invented: it mirrors the kernel's own use in
+quote-innards (hoon.hoon:11842) for parsing \"\"\" block strings, which is
the only call site in the tree. Confirmed `'\"\"\"'` and `(@t 0x22.2222)`
are the same cord before writing the literal form.
+iny (4i.md): source is now just `++ iny inde` (hoon.hoon:5258); the doc
carried a stale 19-line copy of the old +inde body. Replaced with the
one-line source, a pointer to +inde, and a verified example.
+bif:by (2i.md): examples regenerated on 408. Under the newer kernel the cast
product pretty-prints as maps rather than structurally, so the corrected
call now yields exactly what the docs had wrongly attributed to the old
two-argument form:
> `[(map @tas @) (map @tas @)]`(~(bif by a) %b)
[{[p=%e q=5]} {[p=%d q=4] [p=%a q=1] [p=%c q=3]}]
The silent-failure note now carries its own captured output, which shows
[p=%b q=2] still present in the product:
> `[(map @tas @) (map @tas @)]`(~(bif by a) b+2)
[{[p=%e q=5] [p=%b q=2] [p=%d q=4] [p=%a q=1]} {[p=%c q=3]}]
Re-verified unchanged on 408: !@ polarity, +trim product and printing, +peg
crash on a zero argument, +mink's ~ scry sentinel yielding [%2 trace=~].
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Second of three PRs from an audit against
urbit/urbit@08026c84b2. This batch is arms whose documented signature or behaviour no longer matches source. Every claim was reproduced on a fake ship booted fromurbit-408k-rc1.pill([%zuse 408]) unless noted as source-only.Companion PRs: mechanical corrections, and user-manual commands.
!@zappat — branches are reversed87adc94d16(2025-07-21, "!@ reverse polarity") changed the compile of%zpptfrom?:to?...qis now the does-not-exist branch and.rthe exists branch. Verified both directions:The Discussion and both example outputs asserted the opposite, so a reader following them writes inverted logic that still compiles. Examples rewritten so the branch labels match the new order. No rationale is given upstream (empty commit body), so none is invented here.
+trim— dry tape gate → wet list gateNow
|* [a=@ b=(list)]/^+ [p=b q=b](hoon.hoon:4317). The example outputs also changed, since the product is no longer cast to$tape:Added a generic-list example and a note that only the inferred type and its printed form changed, not the value.
+bif:by— takes the key alone, and old callers fail silentlySignature went from
|* [b=* c=*]to|* b=*(hoon.hoon:1445), and it no longer inserts. Critically, the old two-argument call does not error — with sampleb=*the arguments arrive as the single cell[b c], so the map is split at that cell instead of at the key:Note
[p=%b q=2]survives in the second — the key was never removed. The doc's own examples used that broken form, so the page was demonstrating the failure while claiming the correct output.+inde/+iny— new delimiter arguments+indeis now|* [[ope=rule end=rule] sef=rule](hoon.hoon:4910,d5af20fec1). The documented one-argument call fails to compile withmull-grow/-find.sef.+inyis now simply++ iny inde, where the doc carried a stale 19-line copy of the old body.The replacement example is not invented —
+inde's only call site in the tree is+quote-innardsparsing"""block strings (hoon.hoon:11842), so it mirrors that shape, verified verbatim:+mink/+mock/+mack—~scry sentinelThe scry argument is now
$@(~ $-(^ (unit (unit))))(hoon.hoon:6021,:6182). Passing~means "no scry handler": ordinary formulas evaluate, a Nock 12 blocks immediately.+mongwas checked and is unchanged — still a bare gate — so it is deliberately left alone.+shas— salt-length behaviourNow
=/ len (max 32 (met 3 sal))/(shay len ...)(hoon.hoon:3314). Worth stating precisely: a 1-byte salt and a 40-byte salt both still agree with the old formula. The forms diverge only when the XOR result has fewer significant bytes thanmax(32, (met 3 sal))— when leading bytes cancel to zero. Confirmed by constructing such a salt.Smaller
+peg(1b.md) — undocumented crash on a zero second argument; source has?< =(0 b)alongside?< =(0 a). Verified both(peg 4 0)and(peg 0 4)crash.+apt:in(2h.md) — gained strict-inequality checks at every node. (+apt:bywas checked and is already correct.)+dif:by(2i.md) — dropped its=+ b=a |@ ++ $wrapper for|* b=_aand now calls(bif p.n.b)with one argument. Knock-on from the+bifchange.+dif:byitself is correct upstream — verified it still returns the right difference and~(apt by ...)on the result is%.y; only the listing was stale.+del:in/+del:by(2h.md,2i.md) — source blocks gained=> .(b ...). Source-verified only: the coercion does not produce a mint error for a wrong-typed key ((~(del in s) "abc")returns the set unchanged), so no behavioural claim is documented.🤖 Generated with Claude Code