A spec was a promise; sixteen of them had become descriptions of code that already shipped, sitting beside four that describe work still outstanding, with nothing in the file telling the two apart. Half the statuses were also wrong — audio-equalizer read "Accepted" with the EQ live on both platforms, the native video spec said the flag stays off after the default was flipped on. The shipped designs move into docs/architecture, which is the maintained description of the build, and the spec files go. Git history keeps the originals; what a future change still needs is carried across: - 01-rust-backend: favourites rewritten (the old section named a file that no longer exists and called shipped buttons "planned"), domain vocabulary owned by Rust (SearchScope, exclusions, the bitrate ladder), background workers - 02-svelte-frontend: app shell and chrome, library mosaic, series/episode navigation, downloaded browse, safe-area insets, native-video store, logging - 03-data-flow: locally-indexed search - 05-platform-backends: audio settings on ExoPlayer, the equalizer's band vocabulary, native video compositing, the background-audio handoff - 06-downloads-and-offline: one storage model, offline catalog visibility - 09-security: path confinement and input binding docs/specs/README.md now says what the directory is for and where each shipped design went. Deferred work the specs recorded is kept beside the code it concerns rather than lost: season-bounded autoplay, the two dead search commands, why indexing is a full crawl. requirements.md had fourteen stale statuses — Android audio parity still read "Linux only", DR-150 still said the native-video default was off, DR-190 was Proposed after DR-196 implemented it, and five tooling requirements were Proposed after landing. Three unbuilt specs suggested requirement ids that have since been allocated to other work; each now carries a warning.
216 lines
7.4 KiB
Markdown
216 lines
7.4 KiB
Markdown
# Development Scripts
|
|
|
|
Collection of utility scripts for building, testing, and deploying JellyTau.
|
|
|
|
## Testing Scripts
|
|
|
|
### `test-all.sh`
|
|
Run all tests (frontend + Rust backend).
|
|
```bash
|
|
./scripts/test-all.sh
|
|
```
|
|
|
|
### `test-frontend.sh`
|
|
Run frontend tests only.
|
|
```bash
|
|
./scripts/test-frontend.sh # Single pass (same as `bun run test`)
|
|
./scripts/test-frontend.sh --watch # Watch mode
|
|
./scripts/test-frontend.sh --ui # Open UI
|
|
```
|
|
|
|
`bun run test` is `vitest run` — one pass, exit code, done. It used to be bare
|
|
`vitest`, which parked in watch mode; CLAUDE.md's "Before Committing" list tells
|
|
people to run it, so it had to terminate. The interactive modes moved to their
|
|
own entry points:
|
|
|
|
| Command | Runs |
|
|
|---------|------|
|
|
| `bun run test` | `vitest run` — single pass |
|
|
| `bun run test:watch` | `vitest` — watch mode |
|
|
| `bun run test:ui` | `vitest --ui` |
|
|
| `bun run test:coverage` | `vitest run --coverage` |
|
|
|
|
`test-frontend.sh` forwards any extra arguments to vitest and switches to the
|
|
long-running form automatically when it sees `--watch`, `-w`, or `--ui`.
|
|
|
|
### `test-rust.sh`
|
|
Run Rust tests only.
|
|
```bash
|
|
./scripts/test-rust.sh # Run all tests
|
|
./scripts/test-rust.sh -- --nocapture # Show println! output
|
|
```
|
|
|
|
## Android Scripts
|
|
|
|
### `build-android.sh`
|
|
Build the Android APK.
|
|
```bash
|
|
./scripts/build-android.sh # Debug build
|
|
./scripts/build-android.sh release # Release build
|
|
```
|
|
|
|
### `deploy-android.sh`
|
|
Install APK on connected Android device.
|
|
```bash
|
|
./scripts/deploy-android.sh # Deploy debug APK
|
|
./scripts/deploy-android.sh release # Deploy release APK
|
|
```
|
|
|
|
### `build-and-deploy.sh`
|
|
Build and deploy in one command.
|
|
```bash
|
|
./scripts/build-and-deploy.sh # Build + deploy debug
|
|
./scripts/build-and-deploy.sh release # Build + deploy release
|
|
```
|
|
|
|
### `check-android.sh`
|
|
Check Android development environment setup.
|
|
```bash
|
|
./scripts/check-android.sh
|
|
```
|
|
|
|
### `logcat.sh`
|
|
View Android logcat filtered for the app.
|
|
```bash
|
|
./scripts/logcat.sh
|
|
```
|
|
|
|
## Traceability & Documentation
|
|
|
|
### `extract-traces.ts`
|
|
Extract requirement IDs (TRACES) from source code and generate a traceability matrix mapping requirements to implementation locations.
|
|
|
|
```bash
|
|
bun run traces # Generate markdown report
|
|
bun run traces:json # Generate JSON report
|
|
bun run traces:markdown # Save to docs/traceability.md
|
|
bun run traces:coverage # Coverage gate — exits non-zero below the ratchet
|
|
bun run traces:validate # Dangling-ID gate — every traced ID must be defined
|
|
```
|
|
|
|
The script scans all TypeScript, Svelte, and Rust files (plus `scripts/`)
|
|
looking for `TRACES:` comments and generates a comprehensive mapping of:
|
|
- Which code files implement which requirements
|
|
- Line numbers and code context
|
|
- Coverage summary by requirement type (UR, IR, DR, JA)
|
|
|
|
**`bun run traces:coverage` is the supported way to check requirement coverage
|
|
locally** — it runs the same computation CI does. Coverage denominators are
|
|
derived from `docs/requirements.md` at run time; they are never hardcoded. An ID
|
|
that appears in a `TRACES:` comment but is not defined in `requirements.md` is
|
|
reported as *orphaned* and does not count toward coverage (see DR-093).
|
|
|
|
**`bun run traces:validate` is the dangling-ID gate.** It fails if any traced ID
|
|
— including `UT`/`IT`, which coverage deliberately ignores — is not defined as a
|
|
table row in `requirements.md`, printing each offender with the files that
|
|
reference it. Without it the extractor accepted any well-formed ID silently, so
|
|
typos and renames that missed a call site went unreported for months.
|
|
|
|
> **Removed:** `check-req-coverage.sh`, `check-test-coverage.sh`, and
|
|
> `find-req-implementations.sh` were deleted in July 2026. They read an
|
|
> undocumented `@req:` tag convention parallel to `TRACES:`, grepped `src-tauri/`
|
|
> unscoped (hanging on ~40 GB of `target/` artifacts), and in one case reported
|
|
> "all requirements implemented" from an empty result set. `extract-traces.ts` is
|
|
> the single source of truth for requirement coverage. See
|
|
> it reported `Total Requirements: 1` and then "All requirements have
|
|
> implementations!". Nothing referenced it. Use `bun run traces:coverage`.
|
|
|
|
Example TRACES comment in code:
|
|
```typescript
|
|
// TRACES: UR-005, UR-026 | DR-029
|
|
function handlePlayback() { ... }
|
|
```
|
|
|
|
See [docs/traceability.md](../docs/traceability.md) for the latest generated mapping.
|
|
|
|
### CI/CD Validation
|
|
|
|
The traceability system is integrated with Gitea Actions CI/CD:
|
|
- Automatically validates TRACES on every push and pull request
|
|
- Enforces a minimum coverage threshold (a ratchet: raise it, never lower it)
|
|
- Fails on dangling IDs — traced but undefined in `requirements.md`
|
|
- Warns if new code lacks TRACES comments
|
|
- Generates traceability reports automatically
|
|
|
|
For details, see:
|
|
- [Traceability CI Guide](../docs/traceability-ci.md) - Full CI/CD documentation
|
|
- [TRACES Quick Reference](../docs/traces-quick-ref.md) - Quick guide for adding TRACES
|
|
|
|
## Linting & Formatting
|
|
|
|
There is no script wrapper for these — they are plain package.json entries:
|
|
|
|
```bash
|
|
bun run lint # eslint .
|
|
bun run lint:fix # eslint . --fix
|
|
bun run format # prettier --write .
|
|
bun run format:check # prettier --check .
|
|
```
|
|
|
|
Config lives in `eslint.config.js` (flat config: typescript-eslint +
|
|
eslint-plugin-svelte, tuned for Svelte 5 and TS `strict`), `.prettierrc`, and
|
|
`.prettierignore`. `src/lib/api/bindings.ts` is excluded from both — it is
|
|
generated by tauri-specta on every Rust build.
|
|
|
|
`bun run lint` is currently **error-clean but not warning-clean**: several rules
|
|
are deliberately set to `warn` because the existing tree has more hits than a
|
|
tooling change should touch (unused bindings, `any` at the IPC boundary, unkeyed
|
|
`{#each}`). Each one is annotated in `eslint.config.js` with why, and the
|
|
intended end state is `error`. Drive them down; do not delete them.
|
|
|
|
`no-console` is switched **off** for now — see the note in `eslint.config.js`.
|
|
|
|
## Git Hooks
|
|
|
|
### `install-hooks.sh`
|
|
Point git at the repo's tracked hooks directory (`core.hooksPath`).
|
|
```bash
|
|
bun run hooks:install # or: ./scripts/install-hooks.sh
|
|
```
|
|
|
|
### `hooks/pre-commit`
|
|
Runs the fast half of CLAUDE.md's "Before Committing" list so it is enforced
|
|
rather than remembered:
|
|
|
|
- `bun run check` (svelte-check)
|
|
- `bun run test` (vitest, single pass)
|
|
- `scripts/check-frontend-boundary.sh`
|
|
- `cargo fmt --all -- --check`, **only when staged files touch `src-tauri/`**
|
|
|
|
`cargo clippy` and `cargo test` are deliberately *not* in the hook — minutes per
|
|
commit is how you teach people to reach for `--no-verify`. They run in CI, and
|
|
locally via `bun run test:all`.
|
|
|
|
```bash
|
|
git commit --no-verify # skip the hook for one commit
|
|
git config --unset core.hooksPath # uninstall
|
|
```
|
|
|
|
The hook skips itself during a merge, rebase, or cherry-pick, and when nothing
|
|
is staged.
|
|
|
|
## Utility Scripts
|
|
|
|
### `clean.sh`
|
|
Clean all build artifacts.
|
|
```bash
|
|
./scripts/clean.sh
|
|
```
|
|
|
|
## NPM Script Aliases
|
|
|
|
You can also run these via npm/bun:
|
|
```bash
|
|
bun run test # Frontend tests (single pass)
|
|
bun run test:all # All tests
|
|
bun run test:rust # Rust tests
|
|
bun run lint # ESLint
|
|
bun run format:check # Prettier (check only)
|
|
bun run hooks:install # Install the git hooks
|
|
bun run android:build # Build Android APK
|
|
bun run android:deploy # Deploy to device
|
|
bun run android:dev # Build + deploy debug
|
|
bun run android:check # Check environment
|
|
bun run clean # Clean artifacts
|
|
```
|