Contributing to ytnova
August 16, 2026 ยท View on GitHub
Thank you for your interest in contributing to ytnova! This document provides guidelines for setting up your development environment, running tests, and submitting your changes.
See ARCHITECTURE.md for technical design principles (how the code is built). See SPECIFICATION.md for behavioral requirements (how the UI behaves). See CODE_OF_CONDUCT.md for community expectations.
Pull Request Scope
Submit small, focused pull requests. Each pull request should address a single fix or feature to keep reviews straightforward. Do not submit monolithic PRs. Prefer incremental (stacked/sequenced) PRs that preserve logical checkpoints.
See Submitting Changes for the full PR workflow.
Pull Request Guidelines
- Ensure your PR addresses an existing issue or a well-defined new feature.
- Keep PRs focused on a single issue or feature.
- Provide a clear PR description and link any relevant issues.
- PR title/summary should describe the concrete behavior/problem fixed; do not rely on volatile tracker IDs alone (for example
BUG-14) as the primary description. - Ensure your code passes all quality checks.
- Include or update tests for your changes. New features require tests; bug fixes should include a regression test when possible.
- Be responsive to review feedback and follow-up comments.
Commit Message Guidelines
Use Conventional Commits so history stays searchable and consistent:
- Format:
<type>(<scope>): <description>(scope optional). - Allowed
typevalues:feat,fix,docs,style,refactor,perf,test,build,ci,chore,revert. - Write the description as the durable outcome of the change (not workflow notes).
- Do not use workflow labels like
taskorstep, and do not include numeric workflow IDs. - Keep subjects short and specific (prefer ~72 chars or less).
Note for AI-Assisted Development: For the AI-assisted development workflow, script usage, System Persona prompts, and semantic tool integration (Serena, jCodeMunch), please see ai/WORKFLOW.md. Persona routing, shorthand persona commands, and persona-skill auto-load controls are documented in that same workflow doc. For the continuous audit workflow (during development and PRs) plus final release PASS/FAIL criteria, see AUDIT.md. For maintainer copy/paste prompts, see ai/TASK_PROMPT_TEMPLATE.md for implementation/remediation work and ai/AUDIT_PROMPT_TEMPLATE.md for scope-locked post-implementation audits. For pull-request governance and conflict triage policy, see PR_GATE.md.
Planning and History Docs Policy
docs/ROADMAP.mdanddocs/BUGS.mdare forward-looking (planned/in-progress).- Completed items may be removed from those active planning docs after landing/fix.
docs/CHANGELOG.mdis milestone-level only; do not add every trivial fix.- Git history is the complete detailed archive of all changes.
Development Setup
This project uses a combination of C for the application and Python for the test suite and AI assistance tools.
1. Prerequisites
- A C compiler (
gccorclang) andmake. libncurses-dev,libtinfo-dev,libreadline-dev,libarchive-dev.python3andpython3-venv.cmark(for generating the usage doc and man page).lcov(for baseline CI coverage reports).llvmtools (llvm-symbolizer) for sanitizer/fuzz diagnostics.
On a Debian/Ubuntu-based system, you can install these with:
sudo apt-get update
sudo apt-get install build-essential clang llvm libncurses-dev libtinfo-dev libreadline-dev libarchive-dev python3-venv cmark lcov
2. Initial Python Environment Setup
A helper script is provided to create an isolated Python environment for testing and AI tools. From the root of the project, run:
scripts/setup_dev.sh
This script will create a .venv directory, activate it, and install the pinned Python libraries from scripts/requirements.txt.
2.1 Updating Python Dependencies
Top-level dependencies are declared in scripts/requirements.in.
The pinned lock file is scripts/requirements.txt.
Refresh both with:
make py-requirements
This runs scripts/update_python_requirements.sh, which uses pip-compile --upgrade and writes a deterministic lock file.
After the first run, you must reactivate this environment for any new shell session:
source .venv/bin/activate
3. Enable Repository Git Hooks (Recommended)
This repository ships tracked hooks under .githooks/ so the pre-push checks are maintained in one place.
Enable them once per clone:
make hooks-install
This installs a tracked pre-push gate:
- Pushes with codebase changes (
src/,include/,tests/,scripts/,.githooks/,Makefile): runmake qa-code-quality(which now includesmake qa-clean-code). - Pushes that also update
mainrunmake ci-baselineafterqa-code-quality. - Pushes without codebase changes (for example docs-only updates): skip the local pre-push quality gate.
- Set
YTNOVA_PRE_PUSH_FORCE=1to forcemake qa-code-quality.
make hooks-install also installs repo-local git aliases so fast push is available as native git subcommands in this clone:
git push-fast-up-> fast push with-u origin <current-branch>for first push of a new branch.git push-fast-> fast push for an already-tracked branch.
For amended or rebased commits, pass force-with-lease through the alias:
git push-fast --force-with-lease
To inspect current hook configuration:
make hooks-status
To inspect alias installation state:
git config --local --get-regexp '^alias\\.push-fast'
4. Branch and Merge Gate Policy (Required)
Use branch-first development and keep main protected:
- Create a feature branch from
main(feature/...,fix/...,docs/...). - Push to the feature branch.
- Open a PR into
main. - Merge only when required checks are green.
Configure GitHub branch protection on main:
- Settings -> Branches -> Add branch protection rule for
main. - Enable
Require status checks to pass before merging. - Select required checks from GitHub Actions:
.github/workflows/ci.yml:Docs gate..github/workflows/full-qa.yml:Guard and code-quality gate..github/workflows/ci.yml:Guard fuzz harness sync..github/workflows/ci.yml:File mutation integrity gate..github/workflows/full-qa.yml:Static analyzer gate..github/workflows/full-qa.yml:Runtime and security gate..github/workflows/full-qa.yml:Full pytest gate..github/workflows/full-qa.yml:Sanitizer gate..github/workflows/ci.yml:Full coverage baseline gate..github/workflows/ci.yml:Fuzz baseline gate..github/workflows/pr-conflict-assistant.yml:Up To Date With Main.
- Enable
Require branches to be up to date before merging.
5. Handling Red Checks on Branches
- A red check on an old commit cannot be turned green retroactively.
- Merge gating is based on the latest commit status on the PR branch.
- To clean PR history after fixes, squash/rebase your branch and force-push with lease:
git rebase -i origin/main
git push --force-with-lease
- If you use fast bypass during iteration, run a full gate before final PR update:
git push
Building the Project
The Makefile supports two build modes: Release (default) and Debug.
Release Build
For standard testing and usage, perform a release build. This applies optimizations (-O2) and produces a binary with no runtime debug dependencies.
make clean
make
Debug Build (AddressSanitizer)
When developing new features or debugging crashes (especially segmentation faults), you should compile with debug mode enabled. This links against AddressSanitizer (ASan) and disables optimizations (-O1), providing detailed stack traces on memory errors.
make clean
make DEBUG=1
Note: The debug binary is significantly slower. Do not use this for general performance testing.
Running the Test Suite
Prerequisite: Ensure your Python virtual environment is activated (source .venv/bin/activate).
# Standard run (quiet, shows progress dots) โ auto-rebuilds the binary
make test
# Verbose run (shows individual test names and stdout)
make test-v
For direct pytest CLI usage, test naming conventions, infrastructure details, and harness rules, see ai/TESTING.md.
Audit Workflow (Required)
Use AUDIT.md as the single source of truth.
- During implementation, run focused checks first (
make+ targeted tests for touched scope). - Before merge to
main, require green PR full-QA CI (.github/workflows/full-qa.yml,make qa-allequivalent). Local full audit loop is optional unless explicitly requested. - Treat any PR that triggers
.github/workflows/full-qa.yml(src/**,include/**,tests/**,scripts/**,Makefile,.github/workflows/**) as non-trivial: includemake qa-unsafe-apisin the validation evidence, and includemake qa-fileops-integrityas well when file/archive mutation flows change. - Split-touching PRs must also pass the path-filtered
make qa-split-panel-gatesCI gate before merge. - Use the canonical tool order from
AUDIT.md:clang-tidy,cppcheck,scan-build,valgrind, thenpytestfor regression verification.
Local QA Commands
- Normal development build:
make - Full local QA gate (optional unless maintainer-requested):
make qa-all(includespytest, unsafe C API guard, module-boundary guard, and fuzz smoke) - Split panel regression gate (use when touching split-panel invariants, transition handoff, or split-authority code):
make qa-split-panel-gates - Full local QA gate with captured log (optional unless maintainer-requested):
make qa-all-log(writesqa-all.login repo root; override withQA_LOG=/path/to/file) - Max-depth unattended QA sweep:
make qa-deep(runs composite deep checks and writes structured logs to${TMPDIR:-/tmp}/ytnova-qa-deep/<timestamp>/; override withQA_DEEP_LOG_ROOT=/path) - Optional strict mode:
make QA_ON_BUILD=1(runsqa-allafter build) - GitHub baseline CI (
.github/workflows/ci.yml) runsmake ci-baselineon PRs tomainand pushes tomain. - GitHub split panel regression CI (
.github/workflows/ci.yml) runsmake qa-split-panel-gateson PRs that touch split-panel paths. - GitHub PR full QA CI (
.github/workflows/full-qa.yml) runsmake qa-allon PRs tomainand is the required full pre-merge gate. - GitHub PR sanitizer gate in
.github/workflows/full-qa.ymlruns on the same full-QA-triggering PRs as the other pre-merge full-QA jobs. - GitHub nightly deep Valgrind CI (
.github/workflows/nightly-deep-valgrind.yml) runsmake qa-valgrind-fullon schedule (and manual dispatch).
Individual gates:
make qa-clangmake qa-cppcheckmake qa-scanmake qa-valgrind(non-interactive Valgrind smoke onytnova --version)make qa-valgrind-interactive(manual interactive Valgrind session)make qa-valgrind-full(scripted deep Valgrind session)make qa-pytestmake qa-pytest-coverage(coverage build + pytest + gcov/lcov report)make qa-unsafe-apismake qa-module-boundariesmake qa-clean-codemake qa-dead-history-commentsmake qa-ai-configmake qa-code-quality(runsqa-unsafe-apis,qa-dead-history-comments,qa-clean-code,qa-appstate-contract,qa-ai-config, and the generated catalog/template sync guards)make qa-fuzz(builds and runs all fuzz smoke targets)make qa-deep(max-depth composite audit with per-step timing and AI-handoff artifacts)make fuzz(builds all fuzz binaries underbuild/fuzz/)make fuzz-smoke(runs bounded libFuzzer smoke passes for all harnesses)
Recurring code-quality burn-down cadence
When you are doing deliberate debt burn-down work rather than a one-off bugfix, run the recurring cadence described in docs/AUDIT.md and docs/ai/CODE_QUALITY.md.
The minimum evidence set is:
python3 scripts/report_code_quality_hotspots.py --format json > /tmp/ytnova-hotspots-before.json
python3 scripts/report_code_quality_hotspots.py --baseline /tmp/ytnova-hotspots-before.json --format markdown --top 5
make
source .venv/bin/activate && pytest -q tests/path/to/focused_test.py
make qa-module-boundaries
Also run the matching bundled QA gates for the surfaces you changed (make qa-clean-code, make qa-code-quality, make qa-fileops-integrity, make qa-split-panel-gates, and so on). Record which hotspots shrank, which stayed flat, and any explicitly deferred items.
Architectural Decisions & Constraints
The project enforces strict architectural constraints (single-threaded event loop, hard ncurses dependency, context-passing with no global mutable state). For the full specification of these rules, permitted exceptions, and rationale, see ARCHITECTURE.md.
Submitting Changes
Submit small, focused pull requests. Each pull request should address a single fix or feature to keep reviews straightforward. Do not submit monolithic PRs. Prefer incremental (stacked/sequenced) PRs that preserve logical checkpoints.
- Fork the repository on GitHub.
- Create a new branch for your feature or bugfix (
git checkout -b feature/my-new-feature). - Make your changes and commit them using Conventional Commits (
type(scope): summary). Keep the message specific to the change and use scopes that match the area touched. Examples:fix(ui): keep active panel selection after volume cycledocs(ai): clarify planner/executor packet handoff rulestest(pytest): add regression for split-panel redraw ordering
- Push your branch to your fork (
git push origin feature/my-new-feature). - Open a Pull Request against the
mainbranch of the upstream ytnova repository.
Bugfix Gate (Red -> Green)
For bug fixes, include strict red-green evidence in the PR:
- Add or adjust a regression test first.
- Demonstrate that the regression test fails on current code before implementation changes.
- After implementing the fix, re-run and show that the regression test is green.
Coding Style
Please adhere to the existing coding style found throughout the project. The codebase follows C89/C99 standards with a focus on readability, consistency, and proper resource management.
Security Practices
Contributions must preserve a secure-by-default codebase:
- Do not introduce known vulnerability classes (buffer/integer overflows, format-string misuse, use-after-free/double-free, path traversal, symlink TOCTOU races, command injection).
- Validate and bound-check untrusted input before memory, file, or process operations.
- Prefer standard/POSIX and well-maintained existing primitives over custom security-sensitive implementations.
- Default to fail-closed behavior on invalid or unexpected states.
- Use least-privilege file/process handling; avoid broad permissions or escalation unless explicitly required.
Security evidence is part of the required audit flow: include make qa-unsafe-apis results for every non-trivial PR per AUDIT.md.
If you change safety-sensitive behavior, update TRUST.md so user-facing trust claims stay accurate.
Source Comment Policy
Keep source code self-explanatory where possible. Use comments for durable, non-obvious context:
- Document invariants, ownership/lifetime assumptions, aliasing constraints, and rationale for unusual behavior.
- Do not restate obvious code mechanics line-by-line.
- Do not use source comments as temporary change history ("fixed yesterday", "changed in commit ..."). Run
make qa-dead-history-commentswhen you are touching comment-heavy code or guard wiring. - If a comment becomes stale due to a code change, update or remove it in the same change.
Ncurses Guidelines
Key Bindings
When mapping keys in a terminal environment, many Control combinations generate the same ASCII codes as physical keys. Binding these "Taboo" keys will break standard navigation or cause unexpected behavior.
Also note: Ctrl+Shift+<letter> is not distinct from Ctrl+<letter> in terminal byte streams, so it cannot be used as a separate binding.
Taboo Bindings (Do Not Use)
| Control Key | ASCII Value | Physical Key Collision | Impact |
|---|---|---|---|
^I | 0x09 | Tab | Navigation failure. |
^M | 0x0D | Enter (CR) | Inability to confirm actions. |
^J | 0x0A | Enter (LF) | Inability to confirm actions. |
^[ | 0x1B | Escape | Breaks cancel/exit logic. |
Safe Control Keys
Preferred bindings that generally avoid conflicts:
^A (Home), ^B, ^E (End), ^F, ^G, ^K, ^L (Redraw), ^N, ^O, ^P, ^R, ^T, ^U, ^V, ^W, ^X, ^Y.
Rendering
When working with ncurses rendering, follow these rules:
- Set
WbkgdSet()once per window refresh path, not inside per-line loops. - After setting window background, call
werase()before drawing lines. - Use
wattron()/wattroff()for line-level styling.
These three rules prevent flicker, color bleed, and inconsistent redraw behavior.