log: view — ?<rev>, submodule descent, ticket links in summariesview/log.js was ported from be/views/log/log.js under LITE-007/LITE-020 and carries the row shape, the grey off-spine rows and the hidden commit <hex> click target. Three legs of the be view never arrived: the ?<ref> tip form (log:?main), the LOG-002/SUBS-045 SUBMODULE descent (log:<sub>/<path> logs the sub's OWN history and its rows still click), and the BRO-012 ticket-code split (a BEE-012 in a commit summary is an F token that opens the ticket). Today bee log dog/INDEX.md from quickjab prints NOTHING, bee log ?main prints nothing, and a ticket code in a summary is dead text. This ticket lands the three, bee-style: ?<rev> like cat/list/tree, the mount table for the sub, the door for the ticket.
Measured 2026-08-16 with ~/src/quickjab/build/bin/bee (jsrc = ~/src/bee, HEAD b3b14e1); the be source is ~/src/journal/be/views/log/log.js (= ~/src/beagle-ext/views/log/log.js), its tests ~/src/journal/be/test/log/{links,sub,subnav,ticketmemo,nonspine.js}.
bee log 2 ?main --plain and bee log 2 view/log.js?main --plain print nothing, exit 0: logQuery knows <n>, <hex> and <path> only (view/log.js:433:eo), so ?main is a path text that hashes to no path_hl.~/src/quickjab: bee log 3 dog/INDEX.md --plain prints nothing, exit 0; cd dog && bee log 3 INDEX.md prints two rows. The parent's index has no path_hl for a path INSIDE the gitlink (index/index.js:175:Yx drops gitlinks), and fileLog never descends. Same for dog/abc/S.h (a sub of a sub).bee log 2 nosuch.c) prints nothing, exit 0 — silent, where cat says there is no ....bee log 40 --plain | grep BEE-0 shows 0582f637 12:36 BEE-011,012: dealing with ambiguous file names — the BEE-011 is plain S text; door.js resolves a ticket code as a target already (door.js:180:WK ticketCode/ticketPaths), the pager follows an F token through _uriAt (pager.js:522:tt) and http through refUrl (http.js:209:dX), so only the SPAN is missing.parseArg/resolveTip (log.js:52:eo-112: ?<ref> = the ref's tip, #N = cap, #hashlet = tip), recurse.resolveRepoForPath + subPrefix (log.js:500-507, 362-373: descend the mount, prefix every row's nav URI so a click re-enters the sub from the parent), summarySpans (log.js:430:eo-456: the shared tokenizer's F keys, each with a hidden U ticket URI).index/read.js argSplit/repoRel/revCommit (what cat uses for <path>?<rev>), index/mount.js deepest/subsOf/within, index/hook.js fTokens (the DOG-034 lexer, the ONE F scanner), door.js openTarget(target, pos), http.js:505:dX-521 (a URL path inside a sub is already re-rooted to the sub for list/cat).The be log: contract, spelled the bee way, through the ONE view shape (arg, opts) -> hunks so CLI, pager and http get it together.
bee log [<n>] [<hex>|<path>][?<rev>]: ?<rev> names the tip — a branch, tag or hexlet through rd.revCommit; bare log ?main walks main's ancestry, log <path>?<rev> the file's revisions reachable from that tip only. The tip is brought up if unindexed (BEE-005 bringUp {tip}), never refused.bee log <sub>/<path> from the parent logs the SUB's own history: the deepest worktree holding the path (mnt.deepest) is the repo the view opens, the arg is re-rooted, the banner keeps the spelling typed. Recurses (dog/abc/S.h)./quickjab/log/dog/INDEX.md rows). The commit <hex> target must resolve in the sub's ambient, not the parent's.F token: BEE-011,012: yields F(BEE-011),S(,012:); a click opens the ticket through the door's ticket-code resolver (door.js:180:WK), over http the F becomes an href like any reference. Codes that resolve to no ticket stay S (be's rule) — OR every F the lexer mints becomes a span and the door decides at follow time; ruled below.test/index pins).--plain bytes of every existing case unchanged (the git log parity diffs in test/logspine and test/first).~/src/bee, by gritzko's explicit say-so for THIS ticket (2026-08-16); no VC operation of any kind — no git add, commit, stash, checkout. Build ninja -C ~/src/quickjab/build, test ctest --test-dir ~/src/quickjab/build -j16; ~/bin/bee is a stale bundle, never the oracle.test/first/test/index for how fixtures are built with git), a branch off HEAD for ?<rev>, and a summary carrying a ticket code that a todo/TKT/TKT-1.mkd in the fixture answers.index/hook.js fTokens (or tok.parse with the same F rule) is the scanner. No second ref resolver: the door's.bringUp), the ?<rev> tip off revCommit, and fileLog/ancestry are not rewritten.BEE-020:<line> links; no wiki [brackets] in code (meta/work.mkd politeness).--plain byte pin is genuinely wrong; say so and ask.Proposed by the planning session; the agent confirms or amends with a reason.
?<rev> over be's #frag: bee's views spell a revision as ?<rev> (cat, list, tree), the count is <n> (LITE-045); # is the permalink/anchor character in bee. #N/#hashlet are NOT ported.be DAG quirk, not git's, and bee's spine test pins first-parent parity.mnt.deepest(root + "/" + rel), the same probe http.js:510:dX uses; the view re-roots from and the arg, then runs unchanged. The banner is log <arg as typed>.commit <hex> (a verb line the door already opens); the HUNK carries pos: { repo, path } of the repo it walked and the pager hands it to open(target, pos) — door.openTarget takes a pos today (door.js:471:WK). http already runs the view inside the re-rooted pos (http.js:524:dX) and pathIn gives a hexlet no prefix (http.js:183:dX) — so a sub page's commit <hex> href lands in the PARENT: fix by prefixing the hexlet with pg.prefix and re-rooting <prefix>/<hexlet> in the URL parser, or leave and open a ticket. Agent picks, states why.
pg.prefix like any other path (http.js:180:dX) and the router re-roots it. The re-rooting probe was mnt.deepest, which realpaths and so answers null for a path the worktree does not carry — a hexlet, and equally a file GONE at the rev asked for. So the probe became mnt.serves(root, rel) (index/mount.js:110:M5): deepest, climbing to the nearest LIVE ancestor. That is one general rule instead of a hexlet special case, it fixes /<repo>/cat/<sub>/<deleted>?<rev> along the way, and view/log.js descends by the very same call — one probe, two callers.F token the lexer mints in a summary becomes an F span, unresolved or not (the door refuses at follow time with words; http refUrl yields no href for a miss). Cheaper than be's per-row resolve (LOG-005 had to memoize it) and consistent with how a cat page treats refs. Off-spine rows keep grey Q for the rest of the row, the F keeps its own slot.test/index/run.sh:181:ZR ("git says nothing either") and :320 are earlier rulings and were not to be edited; the pathThere refusal was reverted, test/logport L6/port-6 pin the empty answer. gritzko may reopen; the refusal is a 10-line re-add.
test/index/run.sh (see Blockers 1). "Exists" is read as: at the walked tip's tree, or in the worktree; so an untracked-but-real file keeps its empty log.Amendments the implementation forced:
logQuery needed NO change: the <n> split is orthogonal to the URI slots, so ?<rev> lands in log()'s own rd.argSplit (view/log.js:322:eo) and logQuery's target passes through verbatim. The banner stays the spelling typed, as ruled.rd.argSplit THROWS on a name the URI leaf refuses (a raw space: a b.txt), which would have cost such a file its log. log() falls back to "the arg is all path" — http.js:198:dX's own out. cat/list/tree still throw for such a name; not this ticket's to fix (Blockers 3).log <path>?<rev> needs a SIEVE, not just a seed: the index holds every tip ever brought up, and fileLog is a path_hl prefix scan over all of them. The tip's own CPAR closure (ancestry uncapped, no rewrite) filters the revs — paid only when a ?<rev> is given, so the bare form's cost is exactly what it was.ninja -C ~/src/quickjab/build && ctest --test-dir ~/src/quickjab/build -j16 — 148/148 at HEAD b3b14e1test/logport/run.sh (+ port.js, pty.js), RED first — 12 checks, 7 failing on the base build (see Outcome)view/log.js: ?<rev> through rd.argSplit + rd.revCommit + bringUp {tip}, the descent via mnt.servesview/log.js hunk: summary through hk.fTokens -> F spans; hunk pospager.js _followRow/_followCur/_follow/mouse: the hunk's pos goes to open; http.js sub-page hexlet hrefs (decision 4)README.mkd log lines rewritten (6 forms); view/log.js header trimmed 43 -> 8 lines; INDEXES.mkd untouchedctest: 149/149 green after decision 6 was dropped (JSRCindex was red on its two pins while it stood)test/index/run.sh:181:ZR ("an unknown path is simply an empty log (git says nothing either)", log nosuch/file.txt -> rc 0, no bytes) and test/index/run.sh:320:ZR ("a partial absent at HEAD is an empty log, not an error", log old.c where gone/old.c was deleted at HEAD). Both are behavioural pins, not --plain byte pins, and both say the opposite of goal 4 / decision 6. Left UNTOUCHED; JSRCindex is red because of them and nothing else. R5 also exposes a real gap of its own: resolve.pick matches the TIP tree only, so a DELETED file named by a partial resolves nowhere and now gets the refusal instead of its two revisions — worth its own ticket either way.?<rev> bring-up leaves that branch's rows in the index for good, so a LATER bare log <path> lists revisions off it. Pre-existing (a branch switch + bee index does the same), but log ?<ref> makes it a one-command trap. The sieve of amendment 9 could be applied to the bare form too — with a CPAR-only closure (membership, no ODB read) it costs no object reads — but that is a walk at query time, which the constraints forbid here. Ticket-worthy.rd.argSplit throwing on a raw space means bee cat "a b.txt" / list / tree refuse a name log now serves. One try in read.js would settle it for all four; out of scope.~/src/bee, nothing committed):
view/log.js +95/-60 — header 43 -> 8 lines, putSummary/TAG_F, the descent + ?<rev> in log(), reachable, hunk(uri, parts, pos) (the pathThere refusal reverted with decision 6)index/mount.js +17 — serves(root, rel), the climbing deepesthttp.js +7/-6 — pathIn prefixes a hexlet too, the router probes mnt.serves, the now-dead HEXARG droppedpager.js +8/-3 — _followRow / _followCur / _follow / the mouse press hand the hunk's pos to the doorREADME.mkd +10/-3 — the log entry, six formstest/logport/{run.sh,port.js,pty.js} NEW, 3 legs / 35 checks, 441 linesJSRClogport new and green (35 checks); JSRCindex was red on its two pins while decision 6 stood, green after the revert. Everything else untouched and green, JSRChttp included.test/logport on the base build, before a line of source moved): 7 of 12 checks failed — log ?side empty, log f.txt?side empty, log sub/g.txt empty, log sub = the parent's gitlink bump line, log nosuch.c rc 0 and silent, and both js legs dead (view("sub/g.txt") -> 0 hunks, openTarget("log sub/g.txt") -> null). Full transcript kept in the session scratchpad.~/src/quickjab/build/bin/bee, jsrc ~/src/bee):$ cd ~/src/quickjab && bee log 3 dog/INDEX.md --plain
ca7e2386 Sat15 DOG-038: reStructuredText tokenizer — RSTT over .rst, RST stays Rust dog (Victor Grishchenko)
1c07623b Fri14 DOG-035: pup run ToC — sparse page index, "TC"-tagged 7-byte trailer dog (Victor Grishchenko)
1c8c4583 Thu13 DOG-032: tunable mempage length dog (Victor Grishchenko)
$ cd ~/src/bee && bee log 2 ?main --plain b3b14e13 19:42 switch to a compact(er) backward-compatible permalink syntax (Victor Grishchenko) ce5a9e9a 19:14 prettify bee see code (Victor Grishchenko)
and the fixture, from the parent, descending into the submodule:
$ bee log --plain sub 697dc664 03Jan23 s2 tip (T) cca8319c 02Jan23 s1 bump (T) b57fc386 01Jan23 s0 seed (T) $ bee log --plain 'f.txt?side' 2be5f10e 04Feb23 sx side edit (T) efe4ed46 03Feb23 TKT-12: parent edit (T) dc976337 01Feb23 p0 seed (T) $ bee log --plain nosuch.c JS exception: log: there is no nosuch.c (rc 1, stdout empty)
F token (dog/tok/LINK.rl:70 [0-9]{2,}, and door.ticketCode agrees), so the fixture's ticket is TKT-12, not the TKT-1 the plan named.