Repository navigation
Fixed
- A child's stderr is escaped before it reaches a terminal. The text pin
printed when a release did not run, and the text in the embedder's errors for
a refused model, a failed availability probe and a failed embed call, carried
the child's stderr raw, so an ESC, a C1 control (U+009B is the 8-bit CSI) or a
DEL in it reached the terminal. All four now go throughjsonForTerminal,
which moved tosrc/terminal_text.ts(still exported fromrelease_pin.ts).
The text is now a quoted JSON string in those messages. - The Telegram poll loop waits after a refusal from the Bot API. A
getUpdatesanswered{ok:false}(401 for a revoked token, 409 for a second
poller, 429) has noresult, so the loop ran again at once, onecurlspawn
after another. It now logs one line with the error code and the description
(escaped), waits as it does after an error (3 s, and longer when it keeps
failing: see the next Telegram entry), and asks again. AsendMessagethe API
refuses is logged too, and was silent. - An unreadable model folder is a refusal, not "no embedder".
scripts/embed_minilm.pytested the weights path withexists(), which says
no when the stat fails for any reason, so a model directory that could not be
searched exited 1 ("missing model") and auto ingest wrote hash vectors. It now
stats the path: not there (missing, a dangling symlink, under a file) is still
exit 1; anything else it cannot examine is exit 3 with a "cannot read" line. - Text from the network and from children is shown from a closed set.
jsonForTerminalescaped the C0 controls, DEL and the C1 controls and let
everything else through, so a right-to-left override (U+202E), the line and
paragraph separators, zero-width characters and a byte order mark reached a
terminal or a pasted log unmarked. It now keeps a character only if it is the
space or a letter, mark, number, punctuation mark or symbol, and writes every
other code point as\uXXXX(a surrogate pair above U+FFFF). Spaces other
than U+0020 are escaped too (a no-break or an ideographic space), and so are
the zero-width joiner (U+200D) and non-joiner: a joined emoji sequence,
Persian text and Chinese text with U+3000 show\u200d,\u200cand
\u3000where they have them. The result is still a JSON string literal and
parses back to its input. - The Telegram gateway prints nothing from the network raw, and backs off.
A reply that was not JSON (a proxy's error page, a captive portal) made
JSON.parsethrow aSyntaxErrorwhose message quotes the start of the body
as it was, and the poll loop printed that, and curl's stderr, unescaped. A
body that is not JSON is now reported by its size alone, never quoted: such a
page can echo the request path, and with it the bot token, cut, re-cased or
encoded past any redaction. A curl that fails is reported by its exit code
alone, and a refusal'serror_codeonly when it is a number. The one piece
of the API's own text that is printed, a refusal's description, is a JSON
string cut at 300 characters, with the token removed in any case and every
run of 16 or more of its alphabet (letters, digits,-,_) shown as
<redacted>. That does not decode: a description that spells the token in
HTML entities or percent-escapes, or cuts it under 16 characters, still
shows it. The poll loop prints whatever it caught as a JSON string without
the token (the stack trace is no longer printed). A refusal that does not go
away (a revoked token, a 404) was asked again every 3 s for ever: the wait now
doubles for each failed round in a row
(an error counts too), up to five minutes, and starts over when the API
accepts agetUpdates. A 429 waits as long as itsparameters.retry_after
says, at least one second and up to the same five minutes.stop()ends a
wait, so a long one does not hold the process. - A refusal's advice fits an unreadable model file too. The error for a
refused model told every case to put back the filesmodels/minilm/VERSION
records, which is wrong when the script could not read a file (exit 3 since
this release) or the file is not a regular file. It now says the files were
refused or could not be read, and gives one instruction for a hash that does
not match and one for a file that cannot be read. It is still keyed on the
exit code alone.
Changed
- An npm or Docker install embeds with hash vectors. The npm package and the
Dockerfiles have never carriedmodels/minilm/, sochamber ingestand
chamber_askon those installs uselocal-hash-v1vectors without a warning,
unless a local Ollama server answers on 127.0.0.1:11434 or
CHAMBER_EMBEDDER=ollamais set.
This is now written in the README and indocs/KNOWN_LIMITATIONS.md, which
said both model files "ship in the repo". For MiniLM, use a clone of the repo,
pip install --require-hashes -r scripts/requirements-embed.txt, and
CHAMBER_PYTHON. Nothing about the package contents changed. - The MCP Registry description says what the check does.
server.json's
description is now "Checks a claim's numbers, names and file names against
your indexed notes. Local; no model." (91 characters).mcp-publisherrefuses
more than 100, and a test now holds that.package.json's description is
unchanged. - The HTTP server image has a healthcheck.
deploy/Dockerfilenow carries a
HEALTHCHECKthat fetches/healthonPORT(it needs no token), every 15 s
with a 5 s timeout and 3 retries, asdeploy/docker-compose.ymlalready did.
A baredocker runor another orchestrator now gets a health status; the
compose file's own healthcheck is unchanged. The stdio image in the root
Dockerfilehas no port and no healthcheck.
Install: npx -y @bu7umaid/chamber@0.2.2