BOHICA-LABS / BOHICA-LABS/vsdd-factory
bug(freeze-integrity): no artifact field has the artifact's own bytes in scope — "unchanged since freeze" is not checkable from the artifact
- Dominant language
- Rust
- Stars
- 2
- Forks
- 1
- Avg merge
- 6h 43m
- Merged PRs (30d)
- 29
Description
## What I hit
Three distinct versions of one story artifact. Identical in every predicate an agent can read out of the file. Different content.
| commit | lines | bytes | `version:` | `input-hash:` | sha256 (first 16) |
|---|---|---|---|---|---|
| `26b9343` | 3158 | 382364 | `"1.31"` | `"4775066"` | `afd96ae26b956ce5` |
| `dd390d5` | 3158 | 382364 | `"1.31"` | `"ce0425c"` | `05ae6f752912f948` |
| `71e4827` | 3158 | 382364 | `"1.31"` | `"51d8e1e"` | `8887fb62b74ef5c2` |
Reproducible against any repo with a `.factory` worktree and three successive hash refreshes:
```sh
for c in ; do
git show "$c:stories/.md" > /tmp/s_$c.md
done
wc -l -c /tmp/s_*.md # identical
shasum -a 256 /tmp/s_*.md # all different
grep -H -m1 '^version:' /tmp/s_*.md # identical
grep -H -m1 '^input-hash:' /tmp/s_*.md # different
```
## Why each predicate fails
- **`version:`** is agent-declared. All three are `1.31`. A version bump is a convention someone follows, not a consequence of editing.
- **`input-hash:`** is by design a hash of the artifact's *declared inputs*, not of the artifact. Per the `check-input-drift` skill: "MD5 of those files' contents at production time." It moves when upstream moves. It says nothing about this file's own bytes.
- **line count** and **byte count**: the edit substituted one 7-character hash for another. Both counts are preserved bit-for-bit. This is not a contrived case — every `input-hash` value is the same width, so *every* hash refresh has this property.
The only predicate that caught it is a content hash computed out of band, by the consumer, because no field carries it.
## Why this is worth fixing at the engine level
Any workflow with a freeze step needs to answer "is the artifact I am reviewing the artifact I froze?" That includes fresh-context adversarial passes, gate re-verification, and dispatch-integrity checks. A freeze tuple built from version, line count, or byte count can report FROZEN while the content has moved underneath it — and each of those is the natural thing to reach for, because they are the fields that exist.
In this project the freeze tuple now carries content SHAs for exactly this reason. That was rediscovered locally. It would be better carried once, by the engine.
## On frequency
I keep a running count of near-misses in this project's own session records, and it is in double digits. I am deliberately not publishing that number: it comes from my notes and you have no way to check it. The single instance above is fully reproducible and establishes the mechanism on its own.
## Asks, cheapest first
1. **Document the predicate and ship the primitive.** `compute-input-hash` already walks `.factory` and already parses frontmatter. A `--self-sha` mode would put content-hashing one flag away instead of hand-rolled per consumer.
2. **Or maintain a self-hash field.** The obvious objection is self-reference — writing the field changes the file. Both standard resolutions work: compute over the file with that one field's value blanked, or keep hashes in a sidecar index rather than in the artifact.
3. **Either way, name the predicate in the freeze/re-verify guidance** in the adversarial-review skill. "Frozen at v1.31" reads as sufficient to an agent and is not.
Observed in `run/switchboard-blue` during S-BL.ACCESS-CONNECTOR Step-4.5 convergence, plugin `1.0.0-rc.24`.
Contributor guide
Research direction
Look at the `compute-input-hash` skill in the codebase, which walks `.factory` and parses frontmatter. Understand how artifacts are structured and where content hashing could be added. The change involves modifying the artifact integrity checking logic, possibly adding a `--self-sha` flag or a sidecar index. Review the adversarial-review skill documentation to update freeze/re-verify guidance. Testing will require creating a repo with a `.factory` worktree and simulating hash refreshes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100