Closes #176#187
Conversation
…tes, gate blind spots, VAD note Five verified automation gaps that guard our invariants (#134 audit), one workflow-surface fix-unit. Creates the `release-invariants` job that #177 extends. 1. release-invariants CI job (ci.yml, macos): compiles livecap-app in RELEASE (`cargo test --release --no-run` + `cargo build --release`) and `strings`- asserts the debug-only env-escape names are ABSENT — LIVECAP_BLEED_DUMP_DIR / LIVECAP_CAPTURE_VISIBLE / LIVECAP_AUTOSTART / LIVECAP_UI_PROBE all live only in `#[cfg(debug_assertions)]` items, so release compiles them out (#146/#161). CI only tested the debug profile before, so a dropped guard was invisible. 2. SHA-pin every third-party action in ci.yml + release.yml to a full commit SHA with a version comment (supply-chain: release.yml materializes the Apple signing secrets). dtolnay/rust-toolchain pinned to a master SHA with an explicit `toolchain: stable` input (channel can't be inferred from a SHA ref). 3. release.yml runs the same gates (no-stub-gate, color-guard, cargo test, pnpm test) before the tag build — tag pushes bypass branch protection, so a release is now always cut from a green tree. 4. no-stub-gate.sh: extend the pattern to stub/dummy/unimplemented/XXX (the free phrase "not implemented" is deliberately excluded — it false-positives on shipped platform-unsupported error prose, e.g. error.rs; `unimplemented` covers the deferred-code case). Add a fixtures/ self-test that fails if the pattern ever stops matching a known-bad marker. 5. color-guard.sh: extend CSS matching to hsl/hwb/oklch/oklab/lch/lab/color-mix/ color() + a curated named-color set, and add a second pass flagging hex/rgb()/ hsl()-family literals on TS lines that set an inline style. Documented limits (named colors in TS, cross-line/runtime values, value-line comments). 6. Reconcile the vad.rs NOTE (and the same false claim in force_cut_wav.rs): the synthetic generator IS classified as speech by this Silero build (a passing test proves it), so the "never detected" claim was wrong. Add a vacuity guard to longer_redemption_does_not_fragment_more so a Silero change that stops detection fails loudly instead of passing 0<=0. Seeded-violation proofs for every changed gate are in the PR description. No new dependencies; no caption/audio content logged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Epic Alignment: FAIL
The release-invariants job correctly creates the #177 extension point, but the no-stub gate misses a required #176 marker and allows its own self-test to be disabled.
Checked (evidence)
- Structural gate: live PR body includes filled EPIC Alignment, Self-Verification, and N/A Design Fidelity sections.
- Contract: live #176 requires all listed deferred-work markers plus a self-test that proves the gate fires.
- Workflow review: ci.yml/release.yml pin all shown third-party actions to 40-hex SHAs; release quality gates precede signing/build.
- Riskiest part: scripts/no-stub-gate.sh governs deferred-work enforcement, but its marker set and missing-fixture path leave bypasses.
- Kill-list: scanned full diff — hits listed below.
- CI: gh pr checks 187 → color-guard, no-stub-gate, packages-linux pass; app-macos and release-invariants pending.
Findings
-
[required] Enforce the ticket-required “not implemented” marker.
- File: scripts/no-stub-gate.sh:12
- Why it fails: #176 Scope item 4 explicitly requires not implemented, but PATTERN omits it; documenting a false-positive exception leaves production comments containing that marker undetected.
- Do instead: add a whitespace-tolerant not-implemented pattern and narrowly allow the legitimate platform-error occurrence (for example, an explicit gate allow marker on that one line), rather than removing the marker globally.
-
[required] Fail closed when the gate self-test fixture is absent.
- File: scripts/no-stub-gate.sh:28
- Why it fails: deleting or renaming scripts/fixtures/no-stub-selftest.txt makes the gate print a warning and exit successfully, disabling the self-test #176 requires.
- Do instead: make a missing fixture an error with a non-zero exit; the gate must not pass without its regression proof.
Decision
The infrastructure direction is sound, but these two bypasses leave the changed no-stub gate short of the ticket contract.
RE2 — APPROVE at PR #187 head (conditioned on
|
… carve-out; fail on a missing fixture Address RE1 review on PR #187: (1) Restore the ticket-required whitespace-tolerant `not[[:space:]]+implemented` marker instead of dropping it globally, and NARROWLY allow only the legitimate platform-error phrasing via an `ALLOW='not[[:space:]]+implemented[[:space:]]+for[[:space:]]'` carve-out (crates/livecap-core/src/error.rs's "…not implemented for the current platform" is a shipped capability statement, not a stub). A bare "not implemented" / "not implemented yet" still fires. Re-added the marker to the self-test fixture (now 10 markers). (2) A MISSING self-test fixture is now a hard failure (exit 1), not a warn-and-pass — the gate must never run without its own regression proof. Proofs (local): current tree passes (error.rs exempted); `not implemented yet` and `summary is not implemented` in src/ both FAIL; missing fixture FAILS; weakening PATTERN still trips the self-test. bash -n clean, bash-3.2-safe. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Epic Alignment: FAIL
The re-review resolves the missing-fixture failure, but the global allow pattern still weakens the #176 “not implemented” enforcement beyond the one verified legitimate error message.
Checked (evidence)
- Re-review range: 30ba71a..8fa7c42.
- Prior finding resolved: scripts/no-stub-gate.sh:25-29 now fails non-zero when the fixture is absent.
- Prior finding partially resolved: scripts/no-stub-gate.sh:12 now matches whitespace-tolerant not implemented and the fixture covers it.
- Riskiest part: scripts/no-stub-gate.sh:42 globally filters matching lines using ALLOW, which can hide future deferred-work prose.
- Kill-list: scanned new range — hit listed below.
- CI: gh pr checks 187 → no-stub-gate, packages-linux, color-guard pass; app-macos and release-invariants pending.
Findings
- [required] Scope the not-implemented exception to the one legitimate platform-error occurrence.
- File: scripts/no-stub-gate.sh:42
- Why it fails: ALLOW matches any application line containing “not implemented for ”, so a new deferred marker such as “feature is not implemented for this mode yet” is silently removed from HITS. The ticket calls for the marker globally; only the known error text needs an exception.
- Do instead: use an explicit per-line no-stub allow marker on the verified error message (and make the gate honor that marker), or another exact file/text-specific exemption. Do not use a content pattern that broadly filters all production matches.
Decision
The gate now has a hard self-test dependency, but its marker exception must be narrowed before it can provide the required enforcement.
RE2 — APPROVE at
|
…stub-allow escape hatch
Address RE1 re-review (#985): the `ALLOW='not implemented for'` global filter let
future deferred prose ("not implemented for this mode yet") bypass the gate.
Replace it with an explicit PER-LINE escape hatch — a line carrying `no-stub-allow`
is exempt — mirroring color-guard's `color-guard-allow`. Scope the one verified
exemption to error.rs precisely: reword its doc to the accurate "unavailable on
the current platform" (matching the SystemAudioUnavailable variant) and carry the
"not implemented for non-macOS targets" capability note in a `// … no-stub-allow`
comment on one line.
Proofs (local): current tree passes (error.rs line exempted; self-test 10);
RE1's `// not implemented for this mode yet` (no marker) FAILS; a `no-stub-allow`
line is exempt; error.rs compiles. bash -n clean, bash-3.2-safe.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Epic Alignment: PASS
#176 creates the release-invariants gate needed before #177 and hardens the required CI/gate surfaces without expanding into later-ticket code.
Checked (evidence)
- Re-review range: 8fa7c42..1fa6790.
- Prior finding resolved: scripts/no-stub-gate.sh:43 now honors only the explicit per-line no-stub-allow marker; the former global “not implemented for” filter is removed.
- Contract coverage: crates/livecap-core/src/error.rs:11-13 carries the sole audited capability-text exemption; other not-implemented prose remains gated.
- Riskiest part: the gate exemption; it is visible on the one exempted line and mirrors the existing color-guard escape-hatch pattern.
- Kill-list: scanned new range — clean.
- CI: gh pr checks 187 → app-macos, color-guard, no-stub-gate, packages-linux, release-invariants all pass.
Findings
None.
Decision
The delta closes both no-stub-gate bypasses, and the new release-profile invariant has passed end-to-end on macOS.
RE2 — APPROVE at
|
Closes #176
Harden the automation that guards our invariants: a release-mode privacy gate, SHA-pinned actions, release-workflow quality gates, wider no-stub / color gates (with their own self-tests), and an honest VAD test note. One workflow-surface fix-unit.
EPIC Alignment
Part of EPIC #134 (v1.3 audit follow-up), Batch 44 (standing-order … #174 → #176, then #177). This ticket CREATES the
release-invariantsCI job; #177 EXTENDS it, so #176 must merge first (RE2's Batch 36 boundary note). Infra/CI + gate scripts + a VAD test note; touches.github/workflows/*,scripts/*,crates/livecap-core/src/vad.rs,crates/livecap-core/tests/force_cut_wav.rs. Does not touchresample.rs/render.ts/parse.ts/pipeline.rs(reserved for #178/#179 — the pipeline.rs cfg guard is only asserted on, never edited), dashboard, or settings.Self-Verification (the six parts)
1 —
release-invariantsCI job (ci.yml, macos-14). CI only ever compiled/tested the debug profile, so a dropped#[cfg(debug_assertions)]guard (a bad merge on the #64 bleed dump or a #108 dev flag) was invisible until tag time — a #161-class covert-audio/env regression through green CI. The new job buildslivecap-appin release (cargo test --release -p livecap-app --no-run+cargo build --release -p livecap-app) and asserts the debug-only env-escape names are absent from the binary viastrings:LIVECAP_BLEED_DUMP_DIR,LIVECAP_CAPTURE_VISIBLE,LIVECAP_AUTOSTART,LIVECAP_UI_PROBE. They exist only inside#[cfg(debug_assertions)]items, so a release build compiles the names out entirely.2 — SHA-pin all third-party actions (ci.yml + release.yml). Every
uses:moved from a mutable tag/branch to a full commit SHA with a# v4-style comment. This matters most in release.yml, which materializes the Apple signing secrets and produces the signed DMG — a compromised@v4/@stable(the 2025 tj-actions pattern) could otherwise run there.dtolnay/rust-toolchain@stable(a moving branch) is pinned to amastercommit SHA with an explicittoolchain: stableinput, since the channel can't be inferred from a SHA ref. (A dependabotgithub-actionsconfig to keep them fresh is a sensible follow-up; kept out of this PR to stay scoped.)3 — release.yml runs the CI gates before the tag build. Tag pushes bypass branch protection, so nothing enforced that a tagged commit passed CI. Added a step (after
pnpm build, before signing) running./scripts/no-stub-gate.sh,./scripts/color-guard.sh,cargo test --workspace, andpnpm test— a release is now always cut from a green tree.4 — no-stub-gate.sh now matches its namesake and its cousins:
\bstub,\bdummy,unimplemented, whitespace-tolerantnot[[:space:]]+implemented, and\bXXX\b(added toTODO|FIXME|HACK|placeholder|\bmock). The leading-boundary form catches camelCase (stubTranslateBatch). A per-line escape hatch (no-stub-allow, mirroring color-guard'scolor-guard-allow) exempts a specific line — used only for the one verified capability description incrates/livecap-core/src/error.rs(whose doc is reworded to the accurate "unavailable on the current platform", with the "not implemented for non-macOS targets" note carried in a// … no-stub-allowcomment). This is explicit and per-line, so future deferred prose ("not implemented for this mode yet") without the marker still fires — no global phrase bypass. Ascripts/fixtures/no-stub-selftest.txt(one marker per line, 10) drives a self-test: the gate fails if its pattern ever stops matching a known-bad marker, and a missing fixture is a hard failure (exit 1) so the gate can never run without its regression proof.5 — color-guard.sh gains two coverage channels. CSS matching now includes
hsl()/hsla()/hwb()/oklch()/oklab()/lch()/lab()/color-mix()/color()and a curated CSS named-color set (CSS-wide keywords liketransparent/currentColor/inheritdeliberately absent, so they still pass). A second pass oversrc/**/*.tsflags hex/rgb()/hsl()-family literals on lines that set an inline style (.style.,.setProperty(,style=) — the surfacedashboard.ts:203-215uses (tokenized today). Documented limits (in the script header): named colors in TS (barered/bluecollide with identifiers), cross-line/runtime-built values, and value-line comments — all covered by the/* color-guard-allow */escape hatch.6 — VAD note reconciled honestly.
vad_state_is_maintained_across_chunksasserts the synthetic generator IS detected as speech and passes (verified:cargo test -p livecap-core --lib vad::→ 3/3), directly contradicting the in-file NOTE (and the identical claim inforce_cut_wav.rs) that "this Silero build never classifies the generator's output as speech." Corrected both to state the truth, and added a vacuity guard tolonger_redemption_does_not_fragment_more(assert!(!segments_400.is_empty())) so a Silero change that stops detection fails loudly instead of passing0 <= 0.Security invariants. No new dependencies. No caption/audio content logged (the release-invariants gate reads only env-var names via
strings; the workflowrun:blocks use only static values — no untrusted-input interpolation). Scoped to CI/gates + the VAD note; pipeline.rs is asserted-on, not edited.Seeded-violation proof (AC — one per changed gate, run locally)
LIVECAP_BLEED_DUMP_DIRpresent (baseline)env::var_os("LIVECAP_BLEED_DUMP_DIR")(dropped guard)export function stubTranslateBatch(){…}insrc/\bstub) ✅\bstubfrom the pattern// not implemented for this mode yetinsrc/(no marker)no-stub-allowline is exempt ✅color: oklch(0.6 0.1 20)in styles.cssbackground: blackin styles.cssel.style.background = "#1e1e1e"in a.tssegments_400.is_empty()assert!fires — no vacuous0<=0pass ✅Clean tree: both gates pass;
livecap-core60 tests green (incl. the 3 vad tests); both workflows are valid YAML with everyuses:pinned to a 40-hex SHA; scripts passbash -n(and stay bash-3.2-compatible for the macOS release job). The actual release-mode compile +stringsassertion on the reallivecap-appbinary runs in the newrelease-invariantsCI job on this PR.Design Fidelity
N/A — no UI/webview/CSS surface changed (CI workflows, gate scripts, and a Rust test note only).
Deviations
error.rscapability description) via an explicit per-lineno-stub-allowescape hatch (per RE1) — consistent with color-guard'scolor-guard-allow— rather than a global phrase filter, so future deferred prose still fires. Theerror.rsdoc is reworded to the accurate "unavailable".dtolnay/rust-toolchainto amasterSHA +toolchain: stableinput rather than thestablebranch SHA, per dtolnay's documented pin-by-SHA guidance (a SHA ref can't carry the channel).app-macos) so its release-profile build +stringsgate is independently visible and [audit][security-hygiene] Debug-gate LIVECAP_MODEL_BASE_URL (documented as a dev knob but honored in release) — #161 sibling #177 can extend it, per the ticket's create-then-extend boundary.🤖 Generated with Claude Code