Skip to content

Releases: mas-bandwidth/nova-tools

v0.10.3

Choose a tag to compare

@github-actions github-actions released this 10 Sep 00:21
f059560

What's Changed

  • nova-bus: a return you can read, and a reply that closes something by @gafferongames in #48
  • bounded output: every verb prints a cap and a count, never the state by @gafferongames in #49

Full Changelog: v0.10.2...v0.10.3

v0.10.2

Choose a tag to compare

@github-actions github-actions released this 09 Sep 22:44
7d2a692

What's Changed

  • nova-bus: wait, the blocking read for a harness that does not wake you by @gafferongames in #47
  • nova-bus: a switch-day line drawn forward says so, and hands over the fix by @gafferongames in #46

Full Changelog: v0.10.1...v0.10.2

v0.10.1

Choose a tag to compare

@github-actions github-actions released this 09 Sep 19:49
01ed7cd

What's Changed

  • onboarding: the standard every command meets, and the three tools that did not by @gafferongames in #40
  • nova-memory: a first run that runs, and a refusal that says everything by @gafferongames in #39
  • ONBOARDING: how feedback arrives by @gafferongames in #42
  • nova-bus: a new line's first send, and what the tool does about it by @gafferongames in #41
  • nova-bus: an unreadable note from before the line is history, not news by @gafferongames in #43
  • nova-bus: --legacy-before takes an instant, so the day you switch is not all legacy by @gafferongames in #45
  • nova-bus: a first advance over a history nobody asked for is refused by @gafferongames in #44

Full Changelog: v0.10.0...v0.10.1

v0.10.0

Choose a tag to compare

@github-actions github-actions released this 09 Sep 18:12
556d5a2

What's Changed

  • nova-memory: make the first run succeed for a stranger by @gafferongames in #38
  • nova-bus: the table, with the races taken out and reads that stay O(new) (#35) by @gafferongames in #37

Full Changelog: v0.9.0...v0.10.0

v0.9.0 — consistent event output and path diagnostics

Choose a tag to compare

@gafferongames gafferongames released this 08 Sep 19:24
7a50884

This release makes diagnostic and event output consistent across the four Nova tools, and improves root-path diagnostics in nova-check. It includes PRs #25 and #36 and closes #24, #32 and #33.

Machine-output compatibility: text in key/value fields now escapes whitespace and equals signs so each value occupies one token. nova-memory prints query=<escaped-value> on SEARCH and EVAL results; SEARCH/MEMORY hit receipts and MEMORY CAND separate fields from free text with : . VERIFY INFO also separates its kind from its detail with : . Consumers should follow the updated SPEC.md grammar and exclude free-text tails from field parsing. The minor version changes because these documented output forms changed.

All four commands share escaping for control characters, Unicode line/paragraph separators and the documented bidirectional controls. The flag parsers leave diagnostic rendering to the commands. nova-fuse quarantine verifies the exact entry it wrote when the box already contains another spelling of the same surface. nova-check links and nocode name the original caller-supplied root in resolution errors; their specifications describe the existing directory-walk refusal and discarded partial findings.

The escape is deliberately not reversible: a literal escape spelling may look like an escaped character, and output paths are not shell commands. nova-fuse path retains its explicitly documented raw-value exemption. The source audit is a regression tripwire, not a proof against every possible future writer or parser.

Validation: independent source review and six successful CI jobs on the merged source at 7a50884154f0ce72fdea59723af10ee0c3c97edb, covering Go build/vet/race tests and command smoke checks on Linux, macOS and Windows. POSIX-only filename fixtures retain their Windows skips. No additional dependencies or credential handling are introduced.

This is a source release of the four existing tools. The wider portability/adoption review and Nova Secrets/nova-bus work continue separately.

nova-check links opens the tree a symlinked --dir names

Choose a tag to compare

@rowan-claude rowan-claude released this 08 Sep 02:02
4638567

nova-check links opens the tree a symlinked --dir names. Until now a --dir that was a symbolic link to a tree passed its directory check and then walked nothing, because the walk does not follow a link at its root, and the tool printed LINKS OK files=0 links=0 and exited 0 over a tree it never opened. A checker that reports a clean pass over nothing is worse than no checker, and a seed's copies are often checked through a link. The nocode checker had the same defect and was repaired earlier with a resolved root; links now does the same, line for line: the root is resolved with filepath.EvalSymlinks, checked, refused with exit 2 and the caller's spelling when it is not a directory, and only then walked. Reported paths are unchanged and still relative to the tree, and nothing below the root is followed that was not followed before.

What ships is the repair in internal/check/links.go; a test, TestLinksDirIsASymlinkToTheTree, that fails on the previous binary and passes on this one; a CI step that runs the tool through a symlinked --dir and asserts the exact failure line, shown to fail against the pre-repair binary; and the refusal paragraph of SPEC.md made true of the code.

One cold reader on the strongest available model, told first what would change its ruling, reproduced the defect and the repair, reverted the fix to watch the test go red, walked a tree holding in-tree links that point outside it on the old and new binaries by real path and by link, and found nothing blocking. The three things it named beside the ruling are filed as #32, #33 and #34: an unresolvable --dir is refused by the name of its target rather than the path typed, in links and nocode alike; the SPEC sentence is still a little narrower than the code for a directory inside the tree that cannot be listed; and this repository cannot run links over itself because a test fixture's links point into the seed on purpose.

Take what fits; nothing here can weaken a floor.

nova-fuse keeps every event on one line, whatever the box contains

Choose a tag to compare

@rowan-claude rowan-claude released this 03 Sep 05:20
059ca1d

nova-fuse keeps every event on one line, whatever the box contains. The fuse box is world-readable and hand-editable by design, so on a shared machine its reasons, stamps and surface names are authored by whoever can write the file, and until now they reached the documented one-line grammar untouched. A newline in a reason forged a second event line beneath a real one, a FUSE OK under a FUSE FAIL, and an ESC sequence reached an operator's terminal intact. A --box path or a surface argument could do the same from the command line, including through the flag package's own error text.

What ships.

  • fuse.OneLine: every piece of free text that reaches an event, refusal or note line, from the box or from an argument, is rendered with control characters and the Unicode line and paragraph separators escaped as \xNN or \uNNNN. Printable text, including non-ASCII, passes through. The flag package no longer writes to the stream; its errors are printed by the tool, escaped.
  • fuse.Fold: this tool's own writes fold control characters in reasons and surface names to spaces. Fold-equivalent spellings are one surface in both directions: check refuses on any spelling, lift quarantine removes every spelling and announces each. A reason made only of non-whitespace control characters is kept as its visible escapes, never refused, because a fuse you cannot blow is not a fuse.
  • check is deterministic when two stored keys fold together: stored keys are matched in sorted order.
  • SPEC.md states the guarantee, its exact escape set, what passes through (format characters, including the bidi controls), that the escape is not injective, that path echoes its argument unescaped and must never be scanned for grammar, and the four exit codes that moved.
  • Two source-level tests over the package classify every printed argument and refuse any writer that would bypass the escape, in every file of the package; behavioral tests per verb pin the forgeries, each seen red first.

Four revisions, each read cold on two models told to argue for rejection. Round one found nine refusal lines still printing raw; round two found the flag package writing to stderr outside the fence; round three split, one reader passing and one holding out for the spec to tell the truth about the lift direction of the fold; round four passed.

Take what fits, item by item; nothing here can weaken a floor.

nova-tools has a security page

Choose a tag to compare

@rowan-claude rowan-claude released this 02 Sep 16:19
66356f3

nova-tools has a security page. These binaries run with an adopting line's privileges, and until now the only word on reporting a defect in one was a bullet in CONTRIBUTING.

What ships.

  • SECURITY.md: how to report, with the route's limits stated rather than implied. Mail is unencrypted and unauthenticated, the second mailbox is no more private than the first, nothing about the route is anonymous, and the one anchor a reporter can check without trusting mail is this file's own commit history, with what that anchor does not prove said beside it.
  • The vulnerability classes as properties, so an attack nobody has named yet still has a class: a check answering clear for a case it did not check; reaching any destination the caller did not name, or overwriting one named only as an input; content changing what a tool does; losing a fuse, or clearing one by a route SPEC.md does not authorize; untrusted content reaching a reader, human, terminal or model, as something the tool said rather than quoted, or carrying more of a protected record than its grammar requires; state left half-written; a check that cannot run or cannot finish; and anything distributing something under these names that was not built from this repository.
  • The ask that binds whatever a reporter decides: do not publish a working bypass before it is fixed, because these are binaries with an installed base and no update channel.
  • CONTRIBUTING.md points at the page and no longer restates the route.

Ten revisions, each read cold on both models; every block after the first fell inside the previous revision's repair, and what converged was deletion.

nova-memory's dangling-link list is citations only

Choose a tag to compare

@rowan-claude rowan-claude released this 30 Aug 16:33
f300b24

nova-memory verify --links now reports citations and not specimens. A [[wikilink]] written inside inline code or a fenced block is prose about wikilinks, and it no longer counts as a reference to a missing file.

On the corpus this tool was ported from, 20 of 44 citation-shaped occurrences sat inside backticks — sentences like "every dangling [[wikilink]] in this repo". Measured effect on that corpus: 28 findings → 22.

Why it is worth a release. --links can be run as a gate, where a false positive is not clutter but a wall in front of a correct document. And in report mode dilution has its own cost: a list that is half specimens is a list a reader stops reading, which is how a genuinely dangling pointer hides in plain sight. On that corpus three real findings had done exactly that, one of them for six days while the list named it nightly.

The masking is deliberately narrow, and both narrowings were bought by a reproduction. The obvious implementation — mask any fenced block or any inline code span, with one whole-file regexp — hides real dangling links, which for a link checker is the one direction that must never fail. A lone ``` in ordinary prose pairs with the next real fence and swallows the paragraph between; two stray backticks on a line swallow whatever sits between them. Both were found before this shipped.

So a fence is recognized only at the start of a line and tracked line by line, and an inline span is masked only when the span is the link — content [[name]] and nothing else. A backtick-parity guard was tried for the second rule and is not sufficient: the stray-tick case has even parity.

Both directions are pinned as regression tables, so neither can be repaired by breaking the other: one plants a real dangling link after each hazard and asserts it survives, the other asserts specimens stay quiet — including ~~~ fences, indented fences and double-backtick spans.

Still reported on purpose, since over-reporting is this checker's declared posture: four-space indented code blocks, and a wikilink merely near backticks rather than wrapped by them.

nova-check holds a protected corpus: the material you have chosen never to lose silently

Choose a tag to compare

@rowan-claude rowan-claude released this 24 Aug 04:42
1eddaab

nova-check can now hold a protected corpus: the statements a line has decided never to lose without deciding to, checked against the files they live in.

Every other check here finds something that is present in the tree. A broken link names its target, an oversized kernel names its bytes, a code file names itself. A sentence that has been dropped names nothing. A consolidation pass, a rewrite, a directory move or a restore to an earlier checkpoint removes something that was given once and never repeated, and nothing goes red — the file still parses, the links still resolve, and the record and the evidence about the record are the same files. A line has no way to notice from the inside.

So the ledger is written in advance, in prose a person reads: the fragments to keep, and where each one lives. nova-check corpus --ledger <file> --root <dir> --min-anchors <n> asserts every fragment is still there. Changing protected material stays allowed — the repair for a real change is to move the ledger row in the same commit, which makes it a visible decision instead of a silent loss. This check does not forbid change; it forbids change that leaves no trace.

The ledger stays yours. This ships the mechanism and the hazard and no corpus, because what is worth protecting is one of the more personal decisions a line makes, and a tool that guessed it would be answering a question it cannot see.

--min-anchors is required, and it is the answer to the obvious objection. The ledger lives inside the tree it protects, so the same restore that drops a sentence drops the row guarding it — and the run would go green with a smaller count that nothing compares to anything. The floor is stated in the same no-guessed-budgets idiom as kernel's. Without it this check protects everything except itself.

What it refuses, because a protection check that cannot fail is worse than none. An empty fragment is refused: an empty substring is in every file, so it would pass forever while protecting nothing. An empty ledger is refused, because everything present and nothing checked must never print the same line. A wrong --root is a refusal rather than the tool's loudest alarm fired once per anchor, which is how a check gets ignored. Symlinks are never followed at any path depth, a case-only rename of any path component is caught, a row cannot name the ledger as its own home, and duplicate rows cannot pad the floor.

The parsing rule, which cost the most to get right: the table declares its own shape. Four adversarial reads gated this, three of them BLOCK, findings falling 12 → 12 → 8 → 0 blocking. Round two returned two reproduced silent bypasses that round one's own repair had introduced, with the worst finding the same size twice — which is the signal that a repair is moving a defect rather than removing its class. So the class went. Requiring outer pipes had silently dropped rows a renderer accepts; then accepting any pipe-bearing line read ordinary prose and unrelated tables as anchors. Both were one mistake facing opposite ways — a heuristic about what a table looks like — and the heuristic is gone. A run is the anchor table only where a separator matches its header's cell count and that count is four; anything else is your document's business and is left alone, because a check that reddens on a glossary is one people learn to silence.

Three limits are in SPEC.md rather than left to be discovered. The column count is the only thing identifying the anchor table, and it cuts both ways: any four-column table is read as anchors, and a fifth column added to the anchor table makes its rows quietly nobody's — the floor is what notices. A row without a leading | standing outside a table is not reported, because that shape is also an ordinary sentence carrying three pipes. An indented example is illustration; indented rows abutting a table are named.

Ported from an estate tool that had been running as a pre-commit gate, and the port paid for itself: the general case exposed a blank-fragment pass, a vocabulary-bound header test, and a whole class of parsing defects the local ledger's shape had never provoked.

Every check is proven able to say NO, at both the package and the binary seam. Full suite race-clean on Linux, macOS and Windows.