Repository navigation
fix: repair #207 after the #259 merge - #269
Merged
Merged
Conversation
…or resolved Since D-447 the operator generates and persists a Talk recording secret when CASSINI_TALK_RECORDING_SECRET is not set, and registers it in Talk. The recorder it starts read the secret from the environment only, so on a zero-config install Talk saw a working backend and every recording failed at authentication with "talk auth mode hpb-internal requires CASSINI_TALK_RECORDING_SECRET to be set". Found on the demo sandbox, which relies on the generated secret. The recorder and its doctor now get the resolved secret in their environment, overriding the operator's own copy of the variable; when the secret came from the environment the two are the same value. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YQZeU8K8CRrdWLBWAEp6yP
…nvKey Review follow-ups: `cassini doctor --target record` checks disk and directories only, so it no longer receives the recording secret; the recorder's environment is built with the package's setEnvKey; the tests now unset the variable when they mean absent, and cover a stale copy in the environment and a whitespace-only secret. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YQZeU8K8CRrdWLBWAEp6yP
fix(operator): hand the recorder the Talk recording secret the operator resolved
- Upgrade github.com/k2-fsa/sherpa-onnx-go and platform bindings to v1.13.7 - Update CUDA base image and GPU build script to sherpa-onnx v1.13.7 - Add changelog fragment for D-725
- Match workspace directive to Go 1.24.0 - Key extract dir by tarball name to avoid cache collision - Key shim clone by sherpa version
…x-v1-13-7 feat(transcribe): upgrade sherpa-onnx to v1.13.7 [D-725]
…scriber [D-695, D-726] (#259) * feat!: retire the LLM cleanup step and make the vocabulary bias the decoder [D-695] The LLM readable-transcript cleanup was shelved, but nothing in the tree said so: the pipeline still called it behind an `IsConfigured()` gate, we still documented a knob for it, and an entire component existed to run it. Configure an LLM and it would start rewriting transcripts again. Remove the step and everything that only existed to serve it: `ReadableCleanup`, `ApplyReadableText`, `redistributeWords`, `writeReadableArtifacts`, the `transcript.readable.v1` producer, `CASSINI_READABLE_STRICT_BATCHES`, the `--strict-readable-cleanup` flag, and the `cassini-readable` component. Summarisation is untouched and is now the only LLM step in the pipeline. Reading stays. The published portable format v1 lists `readableTranscripts` as optional and shipped files carry one, so `internal/portable` and the viewer keep their read paths. Only the producer is gone. Captions are now written on every build. They used to be a by-product of cleanup, so a deployment with no LLM configured got none, which was never intentional: nothing about a caption file needs a model. The vocabulary setting survives with a new job. It used to steer the cleanup prompt and explicitly not affect the transcript; it now biases the speech recogniser through sherpa-onnx hotwords, which is the thing an operator wanted when they typed a name into that box. sherpa reads hotwords only under modified beam search and encodes them with the model's BPE vocabulary, so both move together or neither does, and a build that cannot bias records that in `provenance.speechToText.hints` rather than decoding unbiased in silence. Upstream ships some Parakeet bundles without `bpe.vocab`; one is derived from `tokens.txt` once per model directory so those bundles can take hints too. `WriteManifest` takes a struct now. It had grown to sixteen positional parameters including two device strings and three booleans, and this change had to touch it anyway. The recognizer construction path grew a `passConfig` for the same reason. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AkaR6civoG8pTu9nsgZ3eP * fix(transcribe): require a real bpe.vocab for decoder hints, and measure the cost Deriving a flat-score bpe.vocab from tokens.txt was measurably not safe. On parakeet-tdt-0.6b-v2-int8 with a derived vocabulary, biasing towards "Librocco" turned the baseline's "Libroco" into "Libro" and dropped a clause; the same clip on v3 with the bundle's own bpe.vocab was clean. A flat-score substitute does not tokenise the way the model's real vocabulary does, and a partial hotword match then boosts a prefix the decoder emits on its own. So require the real file. A bundle without one records the vocabulary as not applied, names bpe.vocab, and points at upstream's generate_bpe_vocab.py. That is the "clear disabled state" this feature needs, and it is strictly better than a silent no-op or a confident wrong answer. Add the manual probe harness the measurements came from. It is skipped unless CASSINI_PROBE_PCM is set, so it never runs in CI, and it is how the next person re-measures instead of guessing. Measured cost of biasing on CPU, Parakeet TDT 0.6B v3, real meeting audio: 30 s of audio decoded in 1.79 s greedy and 2.60 s biased; 45 s in 3.19 s and 4.34 s. About 40 percent more, still several times faster than realtime. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AkaR6civoG8pTu9nsgZ3eP * feat(transcribe): decode with beam search on every tier that supports hotwords Silvio's call: switch it all the time rather than adding a setting. "For now we can switch it all the time: it's simple. We'll have numbers after we use it switched this way. And we can revisit this decision." So the decoder no longer depends on whether the vocabulary box happens to be empty. Transducer models always run modified beam search; a vocabulary only adds the context graph on top. One code path, no new switch, and the numbers will come from real use rather than a lab comparison. That makes two things more important, not less, and both are handled: The fast quality tier runs a CTC model, and sherpa-onnx has no hotword support for CTC. "Always beam search" therefore cannot mean "on every tier": fast keeps greedy search, and a vocabulary configured against it is recorded as not applied with a reason naming the tiers that do work. The settings panel says so too. The silent no-op is the failure mode to engineer against, because an always-on decoder would ship that bug to everyone. Getting modeling_unit or bpe_vocab wrong yields a recognizer that starts happily and biases nothing. Both are refused loudly: no bpe.vocab means hints are recorded as not applied, and modeling_unit is set in the same block as the hotwords file so neither can be set without the other. Tests cover both paths. Measured cost, Parakeet TDT 0.6B v3 fp32 on CPU, real meeting audio: 32.9 s clip 1.63 s greedy vs 2.31 s beam; 45 s clip 2.78 s vs 4.10 s. So 1.3x to 1.5x, worst realtime factor 0.091, memory unchanged. Output changes in both directions: beam lost a sentence on the short sparse clip and gained words on the dense one. It is a different decoder, not a better one. Full table in the PR and in the changelog. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AkaR6civoG8pTu9nsgZ3eP * feat!: withdraw the readable-cleanup role from the portable format [D-695] Silvio asked for all references to LLM cleanup of transcriptions gone, not just the producer. The earlier commit kept the format-level read path on the theory that shipped files might carry a cleaned transcript. They do not: all 128 published meetings in the archive were decoded to check, and every transcript role present is raw-asr. The code was preserving a capability no file exercises. So the role goes: the writer in portable_meeting_tags.go, the loader in portable_meeting.go, the readable_transcript bundle file, Provenance. ReadableCleanup, the CASSINI_READABLE_* tag mirrors, and the inspect output. Three judgement calls, all stated in the PR body: The display role STAYS. It looked like part of the same family, but it has an independent producer: cassini-viewer's export builds a display transcript from the word transcript alone (buildDisplayTranscriptFromArtifacts takes readable as an optional second argument and works with null). Removing it would break the static-site export. The schema is DEPRECATED, not deleted. provenance uses additionalProperties: false, so removing readableCleanup from a published, versioned, publicly served v1 schema would make previously valid files fail validation. That is the same failure this change exists to avoid, one layer up. Both the field and the enum value stay, marked deprecated with a description saying why, and the format documentation says the role is withdrawn and that readers skip it. A stray entry is IGNORED, not rejected. The format contract says a reader fails closed on a layout it cannot understand, but this is one it understands perfectly: a body this build no longer writes. Rejecting would turn an older meeting into an error and take its perfectly good raw transcript with it. Two tests hold the line: one proves such a file still validates, the other proves nothing can write a new one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AkaR6civoG8pTu9nsgZ3eP * chore(inspect): rename the derived-transcript label and a stale comment Fallout from withdrawing the readable-cleanup role: the inspect output called every derived entry readable_transcript, which now only ever holds display transcripts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AkaR6civoG8pTu9nsgZ3eP * fix(transcribe,portable): address the codex review of the hints work Nine findings from an adversarial review, in rough order of how much they mattered. Hint provenance was written by the build and then silently dropped at pack time, because portable.ProcessingStep had no field for it. A record that never reaches the published file is worse than no record: the build log claims hints were applied and the meeting cannot corroborate it. ProcessingStep now carries it, the schema declares it, and two tests hold the round-trip. Glossary text could steer sherpa's own grammar. sherpa reads a trailing whitespace-separated ":n" token as a per-phrase boost, so a participant named "Alice :100000" would have overridden the score this build recorded, and a bare ":2" would have contributed no phrase while still being counted as applied. Terms ending in such a token are dropped. The kill switch could not switch anything back. CASSINI_STT_HINTS_DISABLED dropped the hotwords but left beam search on, giving an operator a third behaviour and no route to the output they had before. It now restores greedy search too, which is the one thing a kill switch has to be able to do. The first build after a model download decoded unbiased. EnsureModel resolved ModelPaths against an empty directory and returned that stale value, and BpeVocabFile is only set when the file is on disk, so the bundle looked like it had no BPE vocabulary until the second build. Re-resolve after extraction. A legacy readable-cleanup body was reported as unreadable by inspect. The validator skips such an entry, but the body decoder still validated it as a words transcript, which it is not. Skip it there too, so the guarantee holds at both layers. The settings panel promised more than the code delivers. Biasing needs a bundle that ships bpe.vocab, and the balanced CPU tier downloads an upstream archive that does not, so naming quality tiers was misleading. It now names the real condition and says the build records what happened. CASSINI_STT_HINTS_DISABLED and CASSINI_STT_HINTS_SCORE were documented but unreachable: neither was passed through the deployment compose file. Troubleshooting had no entry for the most likely question this feature creates, and still described cleanup as a thing that could be missing. Not fixed here, filed instead: additional-model passes discard their hints provenance; a custom recognizer backend may ignore DecoderConfig while provenance claims success; a malformed vocabulary is dropped without a record; 100 configured terms evict the automatic participant names; hotwords.txt is retained in promoted .meeting bundles. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AkaR6civoG8pTu9nsgZ3eP --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…-729] - Remove the top-level ops/ directory from gocassini: - Relocate AppAPI register logic and tests to scripts/lib-exapp-register.sh and scripts/test-exapp-register.sh - Relocate batch processing runner to scripts/process-recordings.sh - Remove deploy-exapp.sh and staging tests (moved to private codemyriad-systems repository) - Update stack.sh, deploy-preview.yml, and lint.yml workflow references - Purge all stray Jellyfin scripts, systemd units, and documentation: - Remove bin/proxmox-sync-jellyfin-nvidia.sh, ops/proxmox-sync-jellyfin-nvidia.service, and docs/proxmox-jellyfin-nvidia.md - Remove references in docs/README.md, docs/architecture.md, and docs/exapp-install.md
…ps-directory-and-remove-jellyfin-references
…tory-and-remove-jellyfin-references refactor(ops): remove ops/ directory and purge Jellyfin references [D-729]
docs(changelog): purge out-of-scope mention from d-729 fragment
…D-729] - Require released SemVer tag format or opted-in sha-* pin - Propagate unregister failures rather than ignoring them prior to re-registration - Verify disable state before enabling during enable cycling - Require jq and fail on parsing errors in exapp_assert_pullable
fix(exapp): harden AppAPI registration lifecycle and tag validation [D-729]
fix(exapp): propagate occ exit status in exapp_register_app
Assert that decoder vocabulary, keyless summary settings, STT quality, and the Talk secret all survive the composed child environment. Remove stale documentation that still described portable summaries as future work.
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.
Repairs the integration branch behind #207 after #259 duplicated the readable-cleanup removal with different vocabulary semantics.
What this resolves:
mainwhile preserving feat: summaries in the publishing pipeline [D-621] #207's keyless summaries, in-app LLM settings, portable summary support, and backfill command;Important: please merge this PR with a merge commit, not squash/rebase. Keeping
mainin this branch's ancestry is what makes #207 mergeable again and gives the stacked #261 repair a clean parent.Verified:
go test ./...andgo test -race ./...in both Go modulesshellcheck scripts/process-recordings.sh./scripts/test-info-schema.sh