Command ✗
Criteria are fixed as you gave them. Before writing alternatives, I'll check what each history-related option would actually expose and what the recomputes need.
## Step 1: criteria (fixed, as you gave them)
| # | Criterion | Weight |
|---|---|---|
| C1 | A stranger can check that every experiment was registered before it ran, using the commit hashes the record cites | HIGH |
| C2 | Nothing from your private projects or old drafts goes public | HIGH |
| C3 | Every headline number recomputes from a clone without a GPU | MEDIUM |
| C4 | Release effort | LOW |
## Step 2: alternatives
**ALTERNATIVE A: Push the real history after a read-only audit** (the plan already written in `docs/RELEASE_NOTES.md` §5)
- **CORE DIFFERENCE:** Strangers get every git object in the private history, so every cited sha resolves. The audit can only stop the push, never rewrite anything.
- **SKELETON:**
```
# in the private copy, read-only
git log -p --all > /tmp/full.patch
grep -nEi "<private project names>|<home path>|<personal folder>" /tmp/full.patch
git rev-list --objects --all | git cat-file --batch-check # list every blob ever committed
review each superseded doc version (ECOSYSTEM.md before 2026-09-05, draft files)
if any hit is unacceptable: STOP. No rewrite: filter-repo would orphan the cited shas
else:
git tag -a v0.3.0 <release commit>
git push public main --tags
```
- **BUYS:** Every sha in FINDINGS, BLUEPRINT and CHANGELOG, plus the 62 distinct `git_commit` stamps in 207 result files, resolves. The ancestry chain shows registration came before landing.
- **COSTS:** Every old draft goes public by definition. RELEASE_NOTES §3.2 already records that `docs/ECOSYSTEM.md` held private working-copy paths and personal folder names until it was rewritten on 2026-09-05, so those versions are in the history.
**ALTERNATIVE B: Your snapshot plus a git-object proof bundle for the cited commits**
- **CORE DIFFERENCE:** Keep the one-commit snapshot and the cleaned log. Also publish the raw git objects (commit object, tree path, and registration-file blob) for each commit the record cites, so a stranger can recompute each sha and confirm the registration text sat in the tree the run launched from.
- **SKELETON:**
```
# in the private copy
shas = full shas of: doc-cited short shas (FINDINGS/BLUEPRINT/OQ/DECISIONS/CHANGELOG)
∪ results/**/"git_commit" with "-dirty" stripped # 62 distinct stamps measured
for s in shas:
git cat-file commit $s > proofs/commit/$s # raw message bytes are part of the hash
git cat-file tree $s^{tree} > proofs/tree/<sha> # root: filenames + blob shas only
git cat-file tree $s:docs > proofs/tree/<sha>
git cat-file blob $s:docs/BLUEPRINT.md > proofs/blob/<sha> # plus OPEN_QUESTIONS.md where it registered
publish proofs/ + tools/verify_proofs.py + short→full sha map
# verify_proofs.py: git hash-object -t {commit,tree,blob} --stdin == filename;
# commit.tree -> root tree -> docs tree -> blob chain links;
# the registration block quoted in today's BLUEPRINT appears in the blob at the launch sha
```
- **BUYS:** The check C1 names (registration text present at the sha the run's meta stamps) works for a stranger, while drafts outside those exact commits stay private.
- **COSTS:** The bundle must publish those commits' raw messages and full filename lists byte-exact. You can't clean them, because the hash covers the bytes. It's also the most work.
## Step 3: scoring (EXPECTED CASE)
| | Current (snapshot + log file) | A: full history | B: snapshot + proof bundle |
|---|---|---|---|
| **C1** (HIGH) | WEAK: all 62 meta stamps and every doc-cited sha dangle, and the log file is self-asserted text that no object backs. | STRONG: every cited sha resolves, and ancestry orders registration before landing (dates are still self-asserted). | ADEQUATE: each cited launch sha is shown to contain the registration text, but there is no ancestry between cited commits, so "amended before read" can only be checked for commits in the bundle. |
| **C2** (HIGH) | ADEQUATE: history is gone, but today's tree still ships ECOSYSTEM.md's sibling-project section and personal folder (§3.2), ESPALIER_MEMORY.md, `docs/OQ19_ORACLE_CEILING_DRAFT.md` and 30 files with a first name in a path (§3.1). | WEAK: every superseded draft goes public, including pre-09-05 ECOSYSTEM.md with private paths (FACT per §3.2), and a hit can't be fixed without breaking C1. | ADEQUATE: same tree as current, plus the raw messages and filename lists of ~60-100 specific commits, small enough to read one by one before publishing. |
| **C3** (MEDIUM) | ADEQUATE: the CPU recomputes (REPRODUCE §2/§7) read committed state files and `tests/test_evidence_bytes.py` uses only HEAD and the index, but the tools that read the raws can't run from a clone (§6, 13.4 GB gitignored). | ADEQUATE: same tree, same limit; history adds nothing to the recomputes. | ADEQUATE: same tree, same limit. |
| **C4** (LOW) | ADEQUATE: export plus hand-cleaning of 130 messages. | ADEQUATE: the push is trivial, but a real audit of 130 commits' diffs isn't. | WEAK: a bundle builder, a verifier script, a sha map and a raw-message review, on top of the current approach's work. |
Fairness check: not triggered. The current approach is weaker than both alternatives on C1, which is HIGH.
## Step 4: verdict
- **VERDICT:** PIVOT to B (keep the snapshot, add the proof bundle)
- **CONFIDENCE:** MEDIUM
- **EVIDENCE:** INFERENCE. The C1 losses and A's C2 exposure are FACT from the repo's own documents. B's C2 cost (how clean the cited commits' raw messages and filenames are) can't be measured here because the history is private.
- **REASONING:**
- On C1, the snapshot alone fails your own top criterion. The record cites commits by hash on purpose (`CONTRIBUTING.md:50`, `CHANGELOG.md:5-6`), and RELEASE_NOTES §3.1 already refused a cleanup because it would orphan 31 cited shas. A squash orphans all of them, plus 62 run stamps.
- On C2, the squash buys less than it seems to. Most of the remaining private-project and draft exposure is in today's tree, not the history, so it needs a tree trim either way.
- B matches the current approach on C2 and C3 and beats it on C1, at a LOW-weight effort cost.
- A has the best C1 but the worst C2. It wins only if you decide old drafts are acceptable, which contradicts your criterion 2 as written.
- No conclusion here rests on charitable scores.
- **What the original reasoning missed:** For this repo, the hashes are the evidence, not housekeeping. Also, none of the three options proves *time* to a stranger, since git dates are self-asserted. B and A prove what the launch tree contained, and only outside timestamping (for example OpenTimestamps or a Zenodo deposit) would prove when, and only for future runs.
- **What already assumes history is present:**
- `docs/RELEASE_NOTES.md` §1, §3.1, §3.8 and §5 steps 5-8 (tag on 8542ef5)
- `CHANGELOG.md`'s hash-keyed entries
- `CONTRIBUTING.md:50`
- sha citations in FINDINGS.md, BLUEPRINT.md, OPEN_QUESTIONS.md and DECISIONS.md
- the `git_commit` field in 207 result files
- ESPALIER_MEMORY's "LANDED at <sha>" rows
- Under any snapshot release, RELEASE_NOTES §3.8's line "neither can be changed without a history rewrite" becomes stale and needs a dated note.
**Two things to fix whichever way you go:**
- Today's tree carries the C2 exposures listed in the C2 row above: ECOSYSTEM.md's sibling-project section (§3.2 calls it "trimmable by the owner at will"), ESPALIER_MEMORY.md, the `cc/` and `tools/cc/` harness, and the OQ-19 draft.
- The 30 files with a first name in a path can't be edited without breaking sha bindings (§3.1).
**NEXT SMALLEST MOVE:** In the private copy, read-only and roughly 30 minutes:
1. Expand the cited short shas plus the 62 stamps to full shas.
2. Run `git cat-file -p <sha>` and `git ls-tree -r --name-only <sha>` on each.
3. Grep the output for private-project names and home paths.
If it's clean, B costs little extra on C2 and you should build it. If it isn't, the choice comes down to how much C1 you'll give up, and that call is yours.
Short prompt ✓
Your criteria make the history question a conflict between #1 and #2, so I'll check what private material is in today's files and what the recompute path needs.
Your criteria change my verdict from **pivot** to **split**. Neither of the two options meets both of your HIGH criteria.
## Both options fail a HIGH criterion
**The full history fails #2.** Today's files already contain private material:
- `docs/ECOSYSTEM.md` is literally a "map of sibling projects", surveyed on 2026-08-28/29. It is probably in almost every commit, including the freeze commits.
- `docs/session-archive.md`, `ESPALIER_MEMORY.md`, `memory/`, `cc/` and `tools/cc/` are harness and session material. `ESPALIER_MEMORY.md` names the `espalier-harness` repo, and `DECISIONS.md` D-4 names the "determinism-layer" project.
- `docs/OQ19_ORACLE_CEILING_DRAFT.md` is an unfrozen draft rebuilt from a session transcript.
Every older version of these files is in the history too.
**Rewriting the history fails #1.** Removing those files with filter-repo changes the hash of every commit from the first one onward. I found 26 distinct commits cited next to freeze, registration or launch wording in `BLUEPRINT.md`, `FINDINGS.md`, `README.md` and the tests. All of them would point at nothing, and a commit map is only your word for the mapping.
**The one-commit copy fails #1**, for the reasons in my first answer.
## Split: a clean public tree plus a proof bundle
Git can prove a file was in a commit without revealing the rest of that commit. A commit's hash covers its tree. Each tree lists names and content hashes for its entries, and a file's hash covers its bytes.
For each cited freeze or launch commit you'd publish:
- the raw commit object;
- the tree objects on the path to each registered file (e.g. root → `docs/` → `BLUEPRINT.md`);
- the registered files' contents;
- the commit objects that link each freeze commit to the commits that land its results, so the order is visible.
A stranger then re-hashes everything with a short script and gets exactly the hashes your record cites. Private files show up only as a name and a hash; their contents are never published. The run payloads already store `git_commit`, so they tie into the same chain.
What this exposes, which you need to decide on:
1. **Commit messages are published as written.** They're inside the commit object and can't be cleaned without changing the hash. Messages after 2026-10-01 follow your strict format; earlier ones need review in your private copy.
2. **Private file names show up in the tree listings**, e.g. `docs/ECOSYSTEM.md` (names only).
3. **The registered files are published as they were at each freeze.** `BLUEPRINT.md` grows over time, so these are its earlier versions. If it only ever had text appended, each earlier version is a prefix of today's file and reveals nothing new. Check that in your private copy. If it was ever edited in place, those older versions are the "old drafts" #2 forbids, and you'll have to choose which criterion gives way for those commits.
**The limit on #1:** hashes prove the record is consistent, not when it was written. Someone could still claim you rebuilt the whole chain afterwards. Nothing can fix that for past runs. For future ones, timestamp each freeze commit (e.g. with OpenTimestamps), or push a tag to the public repo before the run starts.
## Cleaning today's files (needed whichever way you publish)
- **Remove:** `docs/ECOSYSTEM.md`, `ESPALIER_MEMORY.md`, `docs/session-archive.md`, `memory/`, `cc/`, `tools/cc/`, `espalier.toml`, the harness docs (`HOOKS`, `HOOK_ASSUMPTIONS`, `docs/external/`) and the OQ-19 draft.
- **Then repair what pointed at them:** the harness tests (`tests/test_critic_lane.py`, `tests/test_harness_doc_claims.py`), the findings lint for any `- source:` paths among them, and `CONTRIBUTING.md`, which already cites `CLAUDE.md` and `.claude/agents/`, neither of which is in this snapshot.
- **The registered text itself has private details.** `docs/BLUEPRINT.md` lines 13066–13182 contain 12 `<home>\...` paths, and more lines mention scratchpads and transcripts. You can't edit those without breaking both the hash proof and your "dated erratum only" rule. My suggestion: these are machine paths, not private projects, so accept them under #2.
## #3: met except for one headline number
`docs/REPRODUCE.md` rebuilds F-19, F-20, F-21 and F-22 from committed files on CPU, and `tools/e6_gate.py` recomputes the conversion verdicts. **F-23 can't be recomputed without a GPU box.** It's in the README headline table, and it needs the Llama-3.1-8B checkpoint plus raw arrays that aren't committed. Either label it "needs the model download" or commit the minimum inputs, if the Llama license allows that. `REPRODUCE.md` was also last run against commit 8542ef5 (2026-09-05). The real test for #3 is running it end to end in a fresh clone of the cleaned tree. I haven't done that, and I haven't run the full test suite (about 25 minutes here). Only the evidence-bytes test (4 passed) and the findings lint (OK) were run on this snapshot.
## #4: effort
This is the most work of the three options. I'd estimate one to two days: cleaning and fixing the tests, writing the export step (in your private copy) and the verifier script, and running the fresh-clone check.
**Verdict: split.** Publish a cleaned one-commit tree plus a hash-proof bundle for the 26 cited commits. Drop the cleaned-up commit-log file: it doesn't help #1, and `CHANGELOG.md` already does that job. Before building anything, check two things in your private copy: whether `BLUEPRINT.md` only ever grew by appending, and whether the commit messages before 2026-10-01 are fit to publish. If either check fails, #1 and #2 really do conflict for those commits, and you'll need to decide which one wins.
Plain request ✓
Measured against your criteria, the one-commit snapshot fails your first HIGH criterion by design. The cited hashes would not exist in the published repo, so no stranger could check them. The real question is whether the full history passes criterion 2. The current files suggest some of it may not, but you can resolve that with an audit.
## Scoring the options
| | 1. Registration order checkable (HIGH) | 2. Nothing private (HIGH) | 3. CPU recompute (MED) | 4. Effort (LOW) |
|---|---|---|---|---|
| One-commit snapshot + cleaned log | **Fails.** The 47 hashes cited in the docs and the `git_commit` values in 207 result files point to nothing. | Only today's files go out | Same either way | Low |
| Full history, unchanged | **Passes**, if the history clears criterion 2 | **Unknown until audited** | Same | Low |
| Full history rewritten with `git filter-repo` | **Fails.** Every hash changes, and the cited ones sit inside sha-pinned result files you can't edit without breaking their own checks. | Passes | Same | High |
Criterion 3 doesn't separate the options: CPU recompute depends on today's files either way. Criterion 4 is your lowest priority, so it shouldn't decide anything.
That leaves a single gate: **does the private 130-commit history pass criterion 2?** If yes, push it unchanged and you're done. If no, criteria 1 and 2 conflict, and the only way to satisfy both is the more involved option at the end.
## Criterion 2 is already at risk in today's files
The snapshot has the same problem, so you need these decisions under either option:
- **80 files in `results/` and `data/` contain absolute paths** like `<home>\Desktop\Research\sideband\...`. These are sha-pinned evidence, so editing them breaks their own checks. Either you accept that a username and folder layout go public, or no option works.
- **`ESPALIER_MEMORY.md`, `docs/session-archive.md`, `cc/` and `tools/cc/`** describe your espalier-harness project: a pinned install from `github.com/Mike-Byrne-AI/espalier-harness`, "Eleven other deployments on this box", and the old Desktop project path. If espalier is private, these files are what criterion 2 is meant to keep out.
- **`docs/OQ19_ORACLE_CEILING_DRAFT.md` is literally an old draft.** It's labelled "UNFROZEN DRAFT. NOT A REGISTRATION". Does "old drafts" in criterion 2 include it? It's also referenced from the record.
## Two caveats on criterion 1, even with full history
- **Git shows the order of commits, not when they happened.** The parent chain is bound by the hashes, so commits can't be reordered without changing them. But a whole history could be built after the fact before it's first published. `docs/METHOD.md` already says ordering is "attested, not provable". Say so in the release notes, and archive the release with a third party such as Software Heritage or Zenodo so the timestamp is external from now on.
- **159 of the 244 `git_commit` values in `results/` end in `-dirty`.** The run started from that commit, but with uncommitted changes. The check a stranger can still make is that the registration commit is an ancestor of the run's commit (`git merge-base --is-ancestor <registration> <run-commit>`). It proves the registration existed when the run started, not that the code that ran was committed. Ship a script that runs this check for every experiment. Without one, "a stranger can check" really means "a stranger could, with enough effort".
## Recommended next steps
1. **Audit the private copy before deciding anything.** I can't do this from here, because this checkout only has today's commit. In the private copy:
- `git log --all --name-only --format= | sort -u` lists every path that ever existed.
- `gitleaks detect` (or `trufflehog git file://.`) scans all commits for secrets.
- `git log --all --format=%B` lets you grep the messages for other project names.
- `git log --all --diff-filter=D --name-only` shows files that were deleted along the way.
2. **Make the three calls above** on the absolute paths, the espalier files, and the OQ-19 draft.
3. **If the audit is clean, push the full history unchanged**, tag it, archive it, and ship the ancestry-check script.
4. **If the audit isn't clean**, there is a way to keep both criteria: a commit's hash depends on the hashes of its trees and files, not on their contents. So you could publish all commit and directory objects, withhold the contents of private files, and ship a script that verifies the hash chain. A normal Git host won't take a repo with missing objects, so it would go out as an archive plus the script. It's real work, but effort is your lowest priority. The limit: anything private inside commit messages or file names can't be hidden this way. If the audit finds that, criteria 1 and 2 can't both be met for those commits, and you'll have to choose which one wins there.
Should I write the audit script and the ancestry-check script? You'd run the audit in the private copy. One input I don't have: does the record map each experiment to the commit where it was registered? If not, that mapping comes first.