6955547cec5bacda90c8b8699b0d2d136f4754ea
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9831624079 |
feat(ptt): close P0 unit-boundary gaps (SDD-088 / SDD-090 / SDD-091)
The P0 audit on v0.9.4-docs found three SDD items whose specified
software units were inlined into other types rather than packaged as
named units at the SDD-defined boundary:
* SDD-088 PttController — backend ownership + binding mutex +
capability watch lived split between AudioEngine and
ChanoraSession. Extracted into chanora_core::ptt::PttController.
AudioEngine now owns only the cpal streams and the missed-key-up
watchdog (SDD-092); the platform input backend, the active
PttBinding, and the capability watch::Sender live in the
controller. ChanoraSession::start_audio constructs the controller
against the engine's gate; disconnect/reconnect/restart paths
tear it down through stop().await before the engine.
* SDD-090 PttSanitizer — banned-field check was inlined as
PttBanCheckVisitor inside RedactingLogLayer::on_event. Extracted
into a generic PttSanitizer<L> tracing_subscriber::Layer that
decorates an inner Layer (canonical pairing:
RedactingLogLayer::with_sanitizer). The inner layer keeps its
own structural ban check as defence-in-depth for bare-install
callers.
* SDD-091 PttCapabilityBadge — Voice Bar badge was anonymous
Padding/Tooltip/Row inside _AudioControlsState.build. Extracted
into a public PttCapabilityBadge widget and added the
SDD-091-specified per-platform explanation sheet that opens on
the info-icon tap when the resolved capability is L0Focused.
New l10n strings (en + zh) cover the sheet copy.
Tests:
* 2 new unit tests for PttController (arm + descriptor watch)
* 1 new unit test for PttSanitizer (end-to-end through a real
tracing subscriber proving banned drop + safe forward)
cargo test --workspace: 55 passed / 0 failed / 3 ignored
cargo deny check: advisories ok, bans ok, licenses ok, sources ok
flutter analyze: no issues
tools/validate_docs.py: zero undefined refs, zero direct-layer
violations (pre-existing 35 old-package-name warning unchanged)
No SDD/SAD/SRS doc changes — the contracts already named these
units; this commit aligns code unit boundaries with those contracts.
|
||
|
|
7b21916049 |
feat(ptt): code-side initial split — transmit_active / capability badge / sanitizer
Implements the gen2 v0.9.3 doc baseline's first slice of code work:
* SRS-201: split the audio engine's `ptt` AtomicBool into the
authoritative `transmit_active` flag. The legacy `set_ptt` /
`ptt` accessors are retained as `#[doc(hidden)]` thin wrappers
so the existing bridge command and the existing Flutter
hold-to-talk UI keep compiling.
* SAD-075 / SDD-089 acknowledged at the type level: only
`AudioEngine::set_transmit_active` (or its legacy alias)
mutates the flag; the encoder feed reads it once per outbound
frame and never writes.
* SDD-082: new `chanora_audio::ptt` module ships the
`PttCapabilityLevel` enum (`L0Focused`, `L1GlobalShortcut`,
`L2GlobalHoldToTalk`, `L3GlobalWithMouseButtons`,
`L4DeviceAware` reserved) with a stable `as_str` mapping and
an `is_global` classifier.
* SDD-087: `PttBackendDescriptor::focused()` constant value for
the universal Focused-PTT fallback. The struct shape carries
only privacy-safe fields (`level`, `backend_id`,
`bound_input_class`) — a key code cannot fit through this
surface by construction (DEC-027).
* SAD-077 / SDD-090: `RedactingLogLayer` now hosts the
`PttBanCheckVisitor` and the `PTT_BANNED_FIELDS` constant
(`key_code`, `scan_code`, `virtual_key`, `vk`, `keysym`,
`keysym_string`, `key_sequence`, `key_press_history`,
`key_timing`). Any record whose field set names a banned key
is dropped before reaching the in-memory log sink or the
user-initiated diagnostic export. The check is structural and
runs ahead of formatting / redaction.
* `SessionEvent::PttCapability` carries the diagnostics-safe
descriptor through the broadcast event stream;
`chanora_core::ChanoraSession::start_audio` publishes the
Focused-PTT descriptor when the audio engine starts (SRS-196
/ SDD-091).
* `BridgeEvent::PttCapability` mirrors the event across the
FFI boundary. flutter_rust_bridge codegen regenerated.
* Flutter `_AudioControls` renders a capability badge above the
PTT button: a globe icon for Global levels, a focus-frame
icon for `L0Focused`, plus a Tooltip exposing the bound input
class. New ARB key `pttCapabilityBadge(level, backend)` in
`app_en.arb` and `app_zh.arb`.
Per-platform global PTT backends (`WindowsRawInputBackend`,
`MacOSEventTapBackend`, `LinuxGnomeWaylandBackend`) and the
`MissedKeyUpWatchdog` task land in a separate follow-up commit;
this milestone ships only PTT-L0 universally so the application's
runtime capability reporting is honest from day one.
Tests
-----
* `chanora_audio` rises from 1 to 4 unit tests covering
`PttCapabilityLevel::as_str`, `is_global`, and the
`PttBackendDescriptor::focused()` shape contract.
* `chanora_diagnostics` rises from 9 to 11 unit tests covering
the new `PttBanCheckVisitor` over every banned field name and
the `PTT_BANNED_FIELDS` stability assertion.
* Workspace total: 53 unit + integration tests, all green with
`CHANORA_DISABLE_KEYRING=1` (was 49 at v1.0.0-rc.2).
* `flutter analyze`: clean.
* `cargo deny check`: advisories ok, bans ok, licenses ok,
sources ok.
* `cargo about generate`: zero warnings (license inventory
regenerated).
* `tools/dump_flutter_licenses.sh`: 94 packages, zero without
LICENSE.
* Linux x86_64 release bundle builds clean.
No Android live verification in this commit per the user's note
that the test device was removed. Android arm64-v8a continues to
build via the same `cargo ndk` path; runtime reporting on Android
is `L0Focused` for the foreseeable future.
|
||
|
|
d2d9ba0a5b |
feat(diagnostics): A.3 — redacted in-memory log sink + user-initiated export
Replaces the diagnostics scaffold with the production redaction policy + a user-initiated export path that satisfies DEC-016 (no automatic uploads). * `chanora_diagnostics::Redactor` applies the six policy rules to every captured log line: `$HOME` paths → `[home]`; IPv4 + IPv6 literals → `[ip]`; email-shaped strings → `[email]`; long base64-ish tokens → `[token]`; substrings registered with `KnownSecretRegistry` → `[REDACTED]`. The registry implements SS-AUD-003 defence-in-depth: storage adapters can register secrets as they cross out of the keyring so an accidental `Debug` print is still scrubbed at write time. * `InMemoryLogSink` is a bounded ring buffer (cap 500 lines in the bridge) that always passes lines through the redactor before storing them. `RedactingLogLayer` plugs it into `tracing- subscriber` alongside the existing logcat / fmt layers. * `DiagnosticExport::from_sink` builds a plaintext blob — already redacted — combining free-form metadata (crate version, target os/arch) with the retained log tail. `bridge::api:: export_diagnostics()` is the Flutter-facing entrypoint (`#[frb(sync)]`). * `bridge_init` now installs the redaction layer on both Android and desktop hosts, switching from the global `fmt::init()` shortcut to a layered `Registry` so the in-memory sink can sit side-by-side with the platform sink. * Flutter adds a bug-report icon to the AppBar; tapping it opens a scrollable monospace dialog with Copy and Close actions. New `diagnosticsAction` / `copyAction` / `closeAction` strings land in `app_en.arb` + `app_zh.arb`. Tests cover the redaction matrix (IPv4, IPv6, email, long tokens, known secret), the ring buffer capacity, and the full `DiagnosticExport::to_text()` round-trip — 9/9 green. Live-verified on Moto G: the dialog rendered a multi-line transcript with `[ip]`, `[token]`, `[home]` substitutions, the metadata block showed `target_os=android` `target_arch=aarch64`, and Copy placed the same text on the clipboard. |
||
|
|
974dda9601 |
feat(scaffold): create product workspace + Rust crates + Flutter app
Implements the canonical implementation directory layout adopted by
DEC-022 (register v0.9.5). Closes the scaffolding phase; no PoC code
has been promoted in yet (per proof-of-concept-plan.md §4 a PoC is
not product code unless explicitly promoted).
Rust workspace
==============
Top-level Cargo.toml declares seven workspace members:
core/chanora_core top-level Rust API + orchestration
crates/chanora_protocol tsclientlib isolation (SAD-067, SysDes-011/029)
crates/chanora_state state sync, reducers, deltas
crates/chanora_audio capture, DSP, Opus, jitter, mixer, playback
crates/chanora_storage non-secret DB + platform secure store
crates/chanora_diagnostics logs, redaction, export
crates/chanora_bridge typed Flutter/Rust DTOs
Workspace-wide pins:
license = "MIT OR Apache-2.0" (DEC-020)
rust-version = "1.95"
edition = "2021"
The Flutter app (apps/chanora_flutter) is NOT a Cargo workspace
member; it is owned by the Flutter / Gradle toolchain and is in the
workspace exclude array along with every poc/* spike.
Each crate ships:
* a Cargo.toml referring to workspace.dependencies pins;
* a lib.rs with #![forbid(unsafe_code)] + #![warn(missing_docs)],
a typed Error enum, and the public types relevant to the
subsystem's role per SAD §7.2;
* minimal unit tests so
running 1 test
test tests::defaults_match_decisions ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 1 test
test tests::it_compiles ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 1 test
test tests::session_can_be_constructed ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 1 test
test tests::marker_matches_poc ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 1 test
test tests::it_compiles ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 1 test
test tests::state_transitions_compile ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 1 test
test tests::it_compiles ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s is non-empty.
chanora_core's CoreError type-wraps every subsystem error via
#[from] so callers can match on origin without parsing strings.
chanora_audio's AudioEffects struct defaults all four effects to
true, matching DEC-007 (AEC), DEC-008 (AGC), DEC-009 (NS),
DEC-010 (HPF). A unit test pins this so a future regression that
flips a default fails immediately.
chanora_diagnostics exports REDACTION_MARKER = "[REDACTED]",
identical to the PoC's marker so audit grep patterns survive the
promotion.
chanora_bridge's BridgeError is Serialize + Deserialize so it can
flow across the FRB 2.x boundary (DEC-014).
Empirical verification: cargo check --workspace clean, cargo test
--workspace clean (7 unit tests + 7 doc-test runners, all passing)
against Rust 1.95.0 stable.
Flutter app
===========
apps/chanora_flutter created with .
DEC-004 applied: minSdk overridden to 28 in
android/app/build.gradle.kts with a comment that points back at the
decision register and forbids lowering it without re-opening DEC-004.
DEC-015 applied: shipped English + Simplified Chinese at MVP.
- pubspec.yaml gains flutter_localizations + intl + generate:true.
- l10n.yaml emits lib/l10n/generated/AppL10n (no synthetic package
— that was removed in Flutter 3.41+).
- lib/l10n/app_en.arb is the source of truth; lib/l10n/app_zh.arb
mirrors the key set in zh-Hans. ARB metadata explicitly
reaffirms ADR-008: server-provided content (channel names,
nicknames, welcome banners) is preserved verbatim and never
translated.
lib/main.dart and test/widget_test.dart were rewritten from the
template counter into a minimal localized scaffold that proves
both locales render correctly.
Empirical verification: reports no issues;
runs the two locale smoke tests and both pass.
|