Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .codex/config.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
[features]
multi_agent = true
codex_hooks = true
30 changes: 0 additions & 30 deletions .codex/hooks.json

This file was deleted.

19 changes: 6 additions & 13 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
# Repository Guidelines

## Repository Purpose
This repository provides implementations for lattice-cryptography operations (polynomail and matrix operations, preimage samplings, BGG+ encodings, and more), written in Rust and CUDA.
This repository provides implementations for lattice-cryptography operations (polynomial and matrix operations, preimage samplings, BGG+ encodings, and more), written in Rust and CUDA.

## Global Requirements
- All documentation in this repository, along with git commit messages and PRs, must be written in English.
- When documenting file paths, use only paths relative to the repository top directory. Do not write absolute paths in documentation.
- Directories named `references` are read-only reference directories for humans and agents. Agents may read them when relevant and must never edit them.
- Integration tests must not be run unless the user has explicitly asked for them in the current session. Prefer targeted unit tests or other narrow validation until such approval is given.
- Integration tests must not be run unless the user has explicitly asked for them in the current task. Prefer targeted unit tests or other narrow validation until such approval is given.
- Rust formatting must use `cargo +nightly fmt --all`.
- Follow a lifecycle defined in `BUILDER.md`.
- Follow the builder/reviewer guidance in `BUILDER.md` and `REVIEWER.md`.

## Codex Workflow
This repository uses a long-running Codex session workflow governed by `BUILDER.md`, `PLANS.md`, and `REVIEWER.md`.
- Before starting any task or reading any other files, read and follow `REVIEWER.md` for explicit review tasks and `BUILDER.md` for all other tasks.
- Follow `PLANS.md` to create and update a plan document for each session.
- Discover the current session id from the handoff or hook payload.
- Treat `## Plan approval` and `## Phase` in the session plan as the workflow state.
- The builder behaves differently by plan approval status:
- - When `## Plan approval` is `unapproved`, stay in planning: interview the user, revise the session plan, and ask for explicit approval.
- - When `## Plan approval` is `approved` and `## Phase` is `implementation`, execute the approved subtasks, run the narrowest relevant local validation after each subtask, and only then check the subtask off. The implementation-phase stop hook checks only unfinished tasks plus formatting/build.
- - When `## Plan approval` is `approved` and `## Phase` is `testing`, run or address the selected unit-test gate before entering review.
- - When `## Plan approval` is `approved` and `## Phase` is `review`, address only the concrete follow-up work created by reviewer feedback, keeping completed historical subtasks intact.
- Keep the session plan in sync with the work; detailed phase transitions and hook behavior live in the documents above.
- Builders should clarify unclear requirements, implement scoped changes once requirements are clear, and run the narrowest relevant validation.
- Reviewers should stay read-only, prioritize correctness and regression risk, and ground findings in concrete files, commands, or logs.
- If the work touches CUDA, GPU kernels, GPU wrappers, GPU tests, or GPU-facing performance-sensitive behavior, read `GPU.md` before editing or reviewing.
118 changes: 65 additions & 53 deletions BUILDER.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,71 @@

Unless the user explicitly asks for review, act as the builder.

At the start of each turn:
1. Obtain the session id from the explicit handoff or hook payload for the current run.
2. Open `plans/active/session-<session_id>.md`.
3. Inspect `## Plan approval` and `## Phase`.
4. If `## Plan approval` is `unapproved`, stay in planning and keep refining the plan with the user.
5. If `## Plan approval` is `approved`, follow the approved-phase rules for the current `## Phase`.
6. Act according to the rules below.

## Planning
- Do not implement code yet while `## Plan approval` is `unapproved`.
- Create or update the session-specific plan at `plans/active/session-<session_id>.md`.
- Discuss the plan with the user and keep interviewing until the scope, constraints, and validation are concrete.
- Keep `## Phase` at `planning` while the plan is still unapproved.
- Update the plan document before ending the turn.
- Ask the user to approve the plan or describe specific revisions.
- The stop hook does nothing special during planning; it simply allows the stop.
- When the user explicitly approves the current plan, update `## Plan approval` from `unapproved` to `approved`, set `## Phase` to `implementation`, record the approval in the plan log, and begin implementation in the same session.

## Implementation
- Implementation corresponds to `## Plan approval` being `approved` and `## Phase` being `implementation`.
- Read the session plan and work through subtasks in order.
- If the current work touches CUDA, GPU kernels, GPU wrappers, GPU tests, or GPU-facing performance-sensitive behavior, read [GPU.md](GPU.md) and follow its principles.
## Builder Lifecycle
- Read `REVIEWER.md` for explicit review requests; otherwise follow this document.
- Clarify requirements before editing when the requested behavior, scope, or validation target is ambiguous.
- Prefer concrete implementation work once the request is clear. Do not stop at a proposal unless the user asked for one or a blocker remains.
- If the current work touches CUDA, GPU kernels, GPU wrappers, GPU tests, or GPU-facing performance-sensitive behavior, read `GPU.md` and follow its principles before editing.
- Run the narrowest relevant local validation after each meaningful change. Do not run integration tests unless the user explicitly requested them for the current task.
- When Rust formatting is needed, use `cargo +nightly fmt --all`.
- After finishing a subtask, run the narrowest relevant local validation immediately.
- Do not run integration tests unless the user has explicitly instructed you to do so in the current session. Until then, keep validation limited to the narrowest relevant tests.
- Only after the related tests pass, mark that subtask checkbox as checked.
- Update the per-subtask validation, progress log, and decision log as work proceeds.
- If build checks, testing, or reviewer feedback create new obligations, do NOT rewrite existing subtasks or erase completed checkmarks.
- Instead, append NEW unchecked follow-up subtasks under `## Follow-up subtasks (append-only)` and continue implementing those follow-up subtasks.
- Expect the outer stop hook to block the current turn when the approved session plan still has unchecked work or when implementation formatting/build checks append new follow-up tasks. If all tracked checkboxes are already checked and formatting/build checks pass or are not selected, the implementation-phase stop hook may accept without running unit tests or the reviewer.
- When implementation is complete and formatting/build checks have passed, update `## Phase` to `testing`, record that transition in the plan log, and stop so the testing-phase stop hook runs the selected final tests.
- If independent subtasks do not share files or mutable context, parallelize them with sub agents.
- If subtasks share files or shared mutable context, do not parallelize them.
- If independent subtasks do not share files or mutable context, parallelize them with subagents. If they share files or shared mutable context, keep the work serialized.
- Do not end the turn before the job is actually complete, including implementation, validation, and any needed documentation updates.

## Design & Code Style
- Modify existing functions and types instead of adding variants (`new_with_*`, `*_with_shared_inputs`, wrapper structs/traits). Extend `new` with `Option` arguments when needed.
- No backward compatibility: delete legacy formats, fallbacks, and version markers outright.
- Reuse existing environment variables; define all env vars in `env.rs` with explanatory comments.
- Inline private functions that are called once or only a few lines long. Keep files under ~2000 lines excluding tests.
- Delete unused code, arguments, and imports immediately; never silence warnings with `_`. Remove all debug-only scaffolding (extra syncs, flags, timing logs) before finishing.
- Rename anything misleading; names must describe what the value or bound is, not which paper theorem it came from.
- GPU-only code lives in files with "gpu" in the name. CUDA headers (`.cuh`) declare only cross-file and Rust-facing functions; bodies go in `cuda/src/*.cu`.

## Parallelism & Performance
- Parallelize every loop with rayon unless ownership or peak memory forbids it. Refactors must never reduce parallelism unless the user explicitly requests lower or configurable parallelism, for example to reduce peak memory usage.
- Never fix races or flakiness by adding mutexes or serializing; find the root cause instead.
- Control concurrency with env-var-configured batch sizes over `par_iter`, not `ThreadPoolBuilder`.
- Prefer in-place ops (`add_in_place`, etc.) and ownership transfer over `clone`; precompute loop-invariant constants once.
- After performance-sensitive changes, compare timings against the previous run; investigate regressions with per-stage `tracing` logs, then remove the temporary logs.

## GPU / CUDA
- Never fall back to CPU to work around a failing GPU path; a GPU failure is an error.
- No device-wide sync (`cudaDeviceSynchronize`); use per-stream events and async APIs, and keep the host non-blocking. Avoid sync-including calls (e.g. `to_compact_bytes`) in hot paths.
- Batch kernel launches and allocations; never launch per element or per limb.
- Multi-GPU: enumerate devices via `detected_gpu_device_ids` (not a fixed `gpu_id` in params) and distribute work evenly; keep all limbs of a matrix on one device; load shared data onto each device once, before loops.
- Matrices stay in evaluation format by default; never compare or concatenate mixed formats without NTT alignment.
- Peak VRAM/RAM must scale with the configured parallelism (env var), never with `num_slots` or total gate count. Matrices of order `d x m_b` or `d x m_g` are acceptable; `m_b^2`, `m_g^2`, and `m_b x m_g` are not; chunk, stream, and store to disk instead.
- Drop large data as early as possible; generate it just before use; pipeline load -> compute -> store.

## Testing
- Testing corresponds to `## Plan approval` being `approved` and `## Phase` being `testing`.
- Treat this as the unit-test gate between implementation and review.
- Keep using the same approved session plan. Do not reset `## Phase` back to `implementation`.
- Expect the outer stop hook to run the selected final tests using the same changed-file selection policy as `scripts/run_tests.sh`.
- If testing-phase final tests fail, append NEW unchecked follow-up subtasks and return to implementation work for those follow-ups.
- When testing-phase final tests pass or are not selected, update `## Phase` to `review`, record that transition in the plan log, and stop so the review-phase stop hook runs the read-only reviewer.

## Review
- Review corresponds to `## Plan approval` being `approved` and `## Phase` being `review`.
- Treat this as the post-testing acceptance loop: address only the concrete follow-up work created by reviewer feedback, keeping completed historical subtasks intact.
- Keep using the same approved session plan. Do not reset `## Phase` back to `implementation`.
- Expect the outer stop hook to run the hooks-disabled read-only reviewer on every stop while the phase remains `review`.
- If the reviewer returns `revision`, append NEW unchecked follow-up subtasks and continue until the review-phase stop hook can finish with reviewer `accept`.
- If reviewer follow-up work changes code or testable behavior, move the plan back to `testing` before final review so the selected final tests run again.

## Strong Rule
- Do not end the turn before the job is actually complete.
- In planning, complete the turn only after the plan has been updated and the user has been asked for approval or revisions.
- In implementation, the outer stop hook owns formatting/build checks and does not run unit tests or the reviewer. Builder turns should stop only after the plan's tracked checkboxes are fully satisfied and current build feedback has been incorporated.
- In testing, the outer stop hook owns the final `scripts/run_tests.sh` selection and does not run the reviewer. Builder turns should stop only after the plan's tracked checkboxes are fully satisfied and current test feedback has been incorporated.
- In review, the outer stop hook owns the reviewer acceptance loop. Builder turns should stop only after the plan's tracked checkboxes are fully satisfied and current reviewer feedback has been incorporated; if those gates reveal remaining work, the stop hook blocks the turn so the same session can continue addressing it.
- Use `scripts/run_tests.sh` as a reference for repository validation expectations and helper behavior.
- GPU unit tests must run outside the sandbox because the local GPU is invisible inside it.
- For CUDA/sync-related changes: compile once (`cargo test -r --no-run --features gpu`), then run the built binary directly N consecutive times with the identical command (300 for sync bugs, 3-5 for round-trip smoke checks). Run all N even if one fails and report failure counts.
- Both `cargo test -r --no-run` and the `--features gpu` variant must be warning-free.
- Test names use the established prefixes (e.g. `test_gpu_*`); tests live in the file defining the tested item.
- Test parameters must be overridable via env vars with small defaults. No fixed seeds: sample randomly per run.
- Expected values come from existing trusted primitives or round-trips, never from hand-rolled reference implementations. Never weaken or modify existing tests, or move GPU work to CPU, to make tests pass.
- Each test uses its own directory under `test_data/`; delete stale checkpoints whenever parameters or circuits change.
- Probabilistic norm tests may rarely fail by design; verify statistically over repeated runs instead of "fixing" them.

## Benchmarks & Measurement
- Benchmark code must call the same functions as production and reproduce its dataflow, including store/load.
- Measurement contract: measure one chunk/wave; latency = one wave; total_time = latency * chunk_count * slots; max_parallelism = the max across stages, never the sum. All times in seconds.
- Log all raw values (per-stage totals, latency, max_parallelism) directly; never leave values to be derived from other logs.
- Estimators use the actual params, never defaults.
- Remote pods (H200 etc.): sync to the latest commit of the local working branch, release build, `RUST_LOG=debug`; record VRAM usage every ~3s to a log; append the command, env vars, and commit to the log; scp logs to local, then stop the pod promptly.
- Append results to the existing CSVs preserving their format, with a date column; verify CSV-vs-log consistency with a script, not by inspection.

## Lattice-Crypto Domain Rules
- Implement strictly per the PDFs in `references/`; never alter a paper's spec to make a test pass; cite the chapter when explaining bounds.
- Error-norm simulators must stay term-by-term consistent with the evaluator implementations; document the correspondence in English comments; watch for both double-counted and missing terms. If a simulated bound is exceeded in practice, tighten the estimate; do not add `crt_depth` margins.
- Scalars such as `q/q_i` and thresholds are defined against the full modulus, regardless of `q_level`.
- Choose `crt_depth` by simulation (binary search on `eval_ok && decryption_ok`), searching near previously found values in the CSVs.
- Checkpoint ID prefixes embed all parameters; derive randomness deterministically (`hash_sampler` + fixed tags) so checkpoints stay reusable and consistent.

## Agent Working Style
- When asked to analyze or find a root cause, do not edit or run code until asked; identify the cause at the file/line and mathematical level first.
- Every claim must cite concrete code locations; verify against actual code, diffs, and logs; never answer from assumption.
- Fix root causes, not symptoms.
- If a spec seems ambiguous, contradictory, or mathematically wrong, ask before implementing; report before changing approach.
- Long jobs: run with `nohup` + a log file, monitor to completion, and report progress and ETA; never change parameters or kill runs unprompted.
- Do not touch untracked files that existed before the task; treat the user's manual edits as authoritative and build on them.
Loading
Loading