push · git:20260811.c51bc1a · 2026-08-11 · sha256 4caaf691b2cd1169
push git:20260811.c51bc1aA
Immutable. This exact content is served forever at /api/v1/blob/4caaf691b2cd1169.
---
name: push
description: The authoritative pre-push procedure for the cgg repo. Run before every `git push` (and before opening a release). It defines how to refresh every autogenerated README component (mermaid graphs, self-stats, benchmark table, language count/table), how to keep the Limitations and Potential-future-improvements sections honest against the code, the rule that EVERY factual claim in README.md must be neurosymbolically validated — proven by a deterministic symbolic check (cgg itself, rg/grep, cargo test, docs-check.py, `cgg --help`), not asserted from memory — that every CHANGELOG entry must carry a measured `### Performance` block (scripts/perf-compare.sh), that silent/transient functionality bugs get bold prominent disclosure, and how version numbers are incremented (Cargo.toml workspace + internal pins, Cargo.lock, CHANGELOG.md). Trigger when about to push, cut a release, or bump a version in the cgg repo.
---
# push — the cgg pre-push contract
A push is a publish. The README is cgg's public contract: agents read
it, users trust its numbers, and the autogenerated blocks are assumed
to match the binary that produced them. This skill is the gate that runs
**before `git push`** so nothing stale, unproven, or mis-versioned
leaves the repo.
It composes with two existing pieces and adds the parts they don't cover:
- `.githooks/pre-commit` regenerates the two embedded mermaid blocks and
the self-stats line, runs the test suite, and runs `docs-check.py`.
- The `docs-sync` skill is the per-edit drift checklist for prose/tables.
This skill is the **whole-README, whole-repo final pass** plus the
**versioning procedure**. Do all of it before pushing.
## 0. Preconditions
```bash
cargo build --release -p cgg # the binary every regen below uses
```
If the build fails, stop — every downstream number would be wrong.
## 1. Refresh every autogenerated README component
The README contains four machine-generated regions. Never hand-edit
them; regenerate from the freshly built binary so they describe the code
you are about to push.
| Region | Marker / location | Regenerate with |
| --- | --- | --- |
| cgg-walk graph | `<!-- cgg:begin:walk -->` … `:end:walk` | `cgg ./crates/cgg-walk -t mermaid -o walk.mmd` then `scripts/update-readme-graphs.py walk walk.mmd …` |
| cgg-lang graph | `<!-- cgg:begin:lang -->` … `:end:lang` | `cgg ./crates/cgg-lang/src/{detect,parser,lib}.rs -t mermaid -o lang.mmd` then `scripts/update-readme-graphs.py … lang lang.mmd` |
| self-analysis stats | `<!-- cgg:begin:self-stats -->` … `:end:self-stats` | `cgg ./crates --filter 'cgg::analyze_in_pool$' -n 1 …` piped to `scripts/update-readme-stats.py` |
| benchmark table | the per-language table under "## Self-analysis"/benchmark | `scripts/benchmark.sh` (clones repos; multi-minute) then `scripts/update-readme-stats.sh` / `scripts/patch-readme-stats.py` |
The first three are exactly what `.githooks/pre-commit` runs — so a
normal `git commit` already refreshes them. **Verify, don't assume:** the
graphs and self-stats can be stale on disk if a prior commit used
`--no-verify` or `CGG_SKIP_PRECOMMIT=1`. Run the regen and confirm
`git diff README.md` shows either nothing or only the expected
regenerated lines.
The **benchmark table is NOT touched by the hook.** If your change could
move per-language numbers (new language, resolver change, stdlib tuning,
perf work), re-run `scripts/benchmark.sh` and patch the table. If it
can't, say so explicitly in the push notes rather than shipping numbers
you didn't re-measure — silent staleness reads as "freshly measured."
## 2. Keep Limitations and Potential-future-improvements honest
These two prose sections rot silently because no generator owns them.
Before every push, re-derive each bullet from the code:
- **Every "future improvement" must still be unimplemented.** For each
bullet, find the symbolic proof that it has NOT happened (or has only
partially happened). If the code now does it, move it out of the
list — to the feature table, the CHANGELOG, or delete it. Partial
progress gets rewritten to name exactly what remains (e.g. "8 stdlib
lists remain: csharp, fortran, java, …"), never left as a blanket
claim.
- **Every "limitation" must still be true.** A limitation that the code
has since fixed is a lie in the contract. Prove each one still holds
(no watch mode → no `watch`/`notify` in `cli.rs`; Tcl/Hack absent →
not in `plugins.rs`; macros not expanded → no preprocessor sim).
Validation patterns (these are the symbolic half of §3, applied to prose):
```bash
rg -n 'trait_impl_target' crates/cgg/src/main.rs # is dispatch still Rust-only?
git log --oneline -- crates/cgg-core/src/stdlib/ # which stdlib lists got cleaned?
rg -niE 'watch|daemon|notify' crates/cgg/src/cli.rs # watch mode landed yet?
rg -n 'register\(' crates/cgg-lang/src/plugins.rs # which languages exist?
```
## 3. Neurosymbolic validation of ALL README claims (mandatory gate)
**Rule: no claim ships unproven.** Before push, every factual assertion
in `README.md` must be validated *neurosymbolically* — the neural half
(reading the prose, deciding what it asserts) is paired with a
**symbolic** half (a deterministic check that proves it against the
actual code or tooling). An assertion you can only support "from
memory" or "it was true last release" is not validated; soften it,
remove it, or go prove it.
Symbolic oracles available in this repo — prefer them in this order:
1. **cgg itself** — the strongest oracle. Counts, edges, cross-file
numbers, "resolves method dispatch", "finds cross-file edges":
run cgg on a fixture/the repo and read the real numbers.
2. **`cgg --help`** — the source of truth for the CLI flag table. Every
row in "## CLI" must exist in `--help`; this is enforced by
`docs-check.py` and must pass.
3. **`cargo test --workspace`** — behavioral claims backed by tests
(detection rules, resolver behavior, format output).
4. **`rg`/`grep` over `crates/`** — existence claims: a language is
supported, a flag exists, an FFI form is detected, a resolver phase
runs in a given order.
5. **`scripts/docs-check.py`** — the consistency invariants (plugin
count == README "(N)" heading == language-table rows == benchmark
`REPOS` count; every README flag exists in `--help`). **Must exit 0.**
6. **`scripts/benchmark.sh`** — the only oracle for the benchmark
numbers. If you didn't run it, you didn't validate them.
Claim classes and their required proof:
| Claim in README | Symbolic proof required |
| --- | --- |
| "Supports N languages" / language table | `rg -c 'register\(' plugins.rs`, registry test, `docs-check.py` |
| Any CLI flag / default | appears in `cgg --help` |
| Counts in self-stats / benchmark | regenerated by the binary / `benchmark.sh` |
| "resolves X" / "links cross-file" / FFI | a cgg run that produces the edge, or a passing test |
| Pipeline phase order | matches `cgg::analyze_in_pool` in `crates/cgg/src/lib.rs` (NOT `main.rs` — that is a 98-line shim since the library split) |
| A limitation / future gap | the absence proof from §2 |
If a claim has no available oracle, it does not belong in the README as
a fact — rephrase it as clearly-marked intent or cut it.
## 4. Version increment policy
cgg is pre-1.0 and follows a loose SemVer (see `CHANGELOG.md` preamble:
the default graph only ever *grows*). Increment by the largest category
the change touches:
- **PATCH** (`0.2.0 → 0.2.1`) — bug fixes, doc-only changes, stdlib list
tuning, internal refactors. No new user-visible surface.
- **MINOR** (`0.2.0 → 0.3.0`) — additive contract surface: a new
language, a new flag, a new output format, a new resolver phase, new
audit fields. This is the common case for feature work.
- **MAJOR** (`→ 1.0.0`) — reserved for the 1.0 stability commitment.
Pre-1.0, behavior changes that would otherwise be "breaking" ship as
MINOR **with a `### Compatibility / migration` note in the CHANGELOG**;
the default graph must remain a superset of the prior release.
When you bump, change **all** of these in one commit, then validate:
1. `Cargo.toml` → `[workspace.package] version` (one line).
2. `Cargo.toml` → the five internal pins under `[workspace.dependencies]`
(`cgg-core`/`cgg-lang`/`cgg-resolve`/`cgg-format`/`cgg-walk`). They
must match the workspace version.
3. `Cargo.lock` → refresh by running `cargo build` (rewrites the six
`cgg*` entries). Stage the result; the pre-commit hook does not.
4. `CHANGELOG.md` → add `## [x.y.z] - YYYY-MM-DD` (today's date) at the
top, with `### Added` / `### Changed` / `### Fixed` / `### Compatibility`
subsections as applicable. Match the existing entry's voice.
5. `CHANGELOG.md` → **a `### Performance` block is mandatory in every
entry.** See §4a.
Symbolic check after bumping:
```bash
rg -n '0\.2\.0' Cargo.toml # must return nothing for the old version
cargo build --release -p cgg # Cargo.lock now consistent
cgg --version # prints the new version
```
## 4a. Performance is a release-note requirement
**Every CHANGELOG entry carries a `### Performance` block. No
exceptions, including for releases that "shouldn't" affect latency —
that claim is exactly the one worth checking.**
cgg's pitch is that it is fast enough to run before every edit. A
release that quietly regresses latency breaks that pitch silently, and
four releases shipped before this rule with no numbers at all.
Generate the numbers, never estimate them:
```bash
scripts/perf-compare.sh # vs the last `chore: release` commit
scripts/perf-compare.sh <ref> <runs> # explicit baseline / sample count
```
It builds the baseline in a **separate git worktree**, so it works with
a dirty tree and never touches your working copy. Output is a markdown
table ready to paste.
The block must state, alongside the table:
- **Machine load at measurement time.** The script prints it. A loaded
box changes the answer materially — the same two commits measured
−4.1% at load 3.3 and −1.9% at load 36.
- **Whether the comparison is like-for-like.** If the new version
enables work by default that the baseline lacked, the delta is the
cost of new default behaviour, not overhead. Say which.
- **An explanation for every regression over ~5%** on a repo whose
baseline exceeds 150 ms. Below that, jitter reads as several percent
and the script flags it `⚠noise`.
- **Test-suite and pre-commit-hook timings**, since those are the
latency contributors developers feel most often.
A regression you can explain is fine to ship. A regression you did not
measure is not.
## 4b. Functionality bugs get bold disclosure
**A bug that changed results silently is disclosed prominently, in full,
and near the top of its CHANGELOG entry — not buried in a list.**
The class that matters most is a bug producing a *plausible wrong
answer*. A crash announces itself. A graph that is quietly missing edges,
or that differs run to run, does not: every number published while it was
live was wrong without saying so, and nobody had cause to re-check.
Rules:
1. **Transient / nondeterministic bugs lead the `### Fixed` section**,
with a blockquote callout above it so a scanner cannot miss it. Same
input, different answer is the most serious class cgg has.
2. **Quantify the blast radius.** Not "fixed a resolver bug" — state
what it did and how much: *"1,404 of 2,858 edges on phoenix"*,
*"1460/1463/1466/1469 across ten runs"*. A reader needs to know
whether their own results were affected.
3. **Say which releases were affected**, and say so explicitly if
previously published numbers (README tables, benchmark rows) were
wrong as a result.
4. **Never report a delta against a nondeterministic baseline as a
finding.** Check the baseline is stable first; if it is not, report
the range, not the difference. A single draw compared against a fixed
value is not a measurement — it produced a spurious "−5 edges" in
this project's own notes before being caught.
5. **State the mechanism**, so a reader can judge whether their codebase
hits it — e.g. *"routine in C/C++, where many directories carry their
own `common.h`"*.
6. **Add the regression test in the same commit**, and name it in the
entry. A silent bug that had no test is two defects.
Being unflattering in a release note is cheap. A user discovering the
bug themselves, after trusting a number cgg gave them, is not.
## 5. Final push sequence
```bash
# 1. build + regen autogen (§1) + validate claims (§2,§3)
# 2. bump version if warranted (§4)
scripts/perf-compare.sh # §4a — paste into the CHANGELOG
cargo test --workspace # green (also gated by the hook)
scripts/docs-check.py # exit 0 (also gated by the hook)
git add -A
git commit -m "…" # pre-commit hook re-regens graphs/stats, re-runs tests + docs-check
git push origin main
```
Let the pre-commit hook run — do not `--no-verify` a push. If the hook
restages README.md, that is the autogen blocks correcting themselves;
inspect the diff, it should be only generated regions.
## What this skill does NOT do
- It does not replace `docs-sync` (the per-edit drift checklist) — it
assumes that ran and does the final whole-repo sweep.
- It does not auto-bump the version — versioning is a judgment call
(§4); decide the category, then apply it everywhere at once.
- It does not invent benchmark numbers — unmeasured numbers are not
shipped; either re-run `benchmark.sh` or state that they were not
re-measured.