# α Close-Out — Cycle #250 (PR #259)

## Cycle summary

| | |
|---|---|
| Issue | #250 — `cn deps lock` vendors every package in index, ignores `deps.json` pins |
| PR | #259 — approved Round 1, released as 3.56.2 |
| Review rounds | 1 (A) — within target of ≤2 |
| Findings total | 0 |
| Mechanical ratio | n/a (0 / 0) |
| Diff shape | **L7** — removed a silent-success fallback. Malformed manifests and stale version pins now surface at lock time instead of being masked into quiet over-installs. |
| Cycle process level | **L6** — Go code L5-clean on first push; 2 pre-review CI iterations needed to converge bug-masked test harnesses; β review clean Round 1 (no cross-surface drift reached review). |

## Findings

**No new findings.**

## Cycle Iteration

§9.1 triggers — none fired:

- [ ] review rounds > 2 (actual: 1, A)
- [ ] mechanical ratio > 20% (actual: 0%, 0 findings)
- [ ] avoidable tooling/environmental failure
- [ ] loaded skill failed to prevent a finding

Cycle iteration section omitted per §9.1 ("if the cycle went cleanly, cycle iteration may be omitted"). Pre-review CI iterations (see "What didn't" below) were bug-masking discovery rather than rework — draft-until-green absorbed them exactly as designed.

## What worked

1. **Parse/Read purity slot pre-opened.** `ParseLockfile` and `ParsePackageIndex` already existed in `internal/pkg/pkg.go`; adding `ParseManifest` was a one-shape-fits-all slotting, not a design decision. eng/go §2.17 was a generation constraint, not a review afterthought.

2. **OCaml parity shortcut.** `src/ocaml/cmd/cn_deps.ml`'s `lockfile_for_manifest` already does the correct thing. The Go fix isn't a fresh design — it's Go catching up to OCaml semantics, a reference implementation the cycle can lean on.

3. **Revert-spike validation of the test suite.** After writing the six new tests, I `git stash`-ed just the code fix (not the tests) and ran the tests against the buggy code. All six failed with error messages that mapped 1:1 to issue #250's reported symptoms — lockfile len 6 instead of 1, `cnos.core` appears 3×, `cnos.eng` installed when not pinned, etc. Cheap concrete proof that the tests actually gate on the bug, not on incidental behavior. AC4 ("test covers a single-pin lockfile — fails today") was demonstrated, not just asserted.

4. **The fix flushed three pre-existing bug-masked defects.** Because the silent fallback was removed, pre-review CI caught:
   - Tier 1 install kata (`scripts/kata/06-install.sh`) was pinning to binary-version `"dev"` (cnos.core @ dev isn't in the index).
   - Tier 2 CI hub setup (`.github/workflows/ci.yml`) was using object-schema `{"name":"version"}` (parser expects array) and pinning `cnos.core@3.54.0` while src is at `3.56.1`.
   - `cnos.kata/lib.sh` `write_deps_json` helper was emitting the same wrong object schema; R3/R4 pinned `cnos.core:3.54.0` hardcoded.
   
   All three were silently passing pre-fix because lock ignored the manifest and dumped the whole index. Three one-commit repairs bundled into the same PR. This is exactly what L7 diff-shape enables: friction-class elimination surfaces dormant defects as a byproduct.

5. **β review was efficient.** Round 1 APPROVE with a 5-point module-truth audit ("no sibling iterate-the-whole-index call sites remain", Go/OCaml parity confirmed, Parse vs Read boundary preserved, errors-are-values preserved, determinism preserved). Zero findings, zero additional rounds.

## What didn't — pre-review friction

Two push iterations between the fix being ready and CI going green:

- Push 1 (`ae1436d`) — Go tests green, Tier 1 kata failed (latent defect #1 surfaced).
- Push 2 (`dc5b985`) — Tier 1 fixed, Tier 2 kata failed (latent defect #2+#3 surfaced).
- Push 3 (`44d431a`) — Tier 2 fixed, all 7 checks green; β engaged.

Each iteration was a discovery, not a rework. The cycle owner didn't introduce these defects; they were pre-existing and masked. But each surfaced only serially because the kata layers depend on each other (Tier 2 depends on Tier 1's install path; the cnos.kata runtime kata depends on Tier 2's vendor setup). Can't predict layer N+1 until layer N passes.

**Skill gap observation (not a finding).** Loaded skills were `cdd` and `eng/go`. `eng/go` §2.12 (schema/compatibility, additive evolution) is explicit about *code* that handles manifests. It does not scope to *test harnesses that produce manifest JSON for the same parsers*. If `eng/go` §2.12 had covered CI shell test harnesses as well as Go code, the `write_deps_json` schema mismatch would have been part of the authoring-time audit, not CI discovery.

Not a β finding (β's review was clean), but a candidate for γ triage: extend `eng/go` §2.12 schema scope to include sibling shell harnesses that round-trip through the same parsers, or introduce a dedicated `eng/ci-harness` skill. I'd favor the minimum: a one-line addendum to §2.12 noting that test-harness JSON producers are contract surfaces too.

## Design decision worth recording (not a finding)

**Errors explicit, not lenient.** The fix chooses to surface unresolved pins and missing manifests as hard errors rather than re-introduce a different silent fallback (e.g., "if pin doesn't match, pick any version"). The issue's AC2 requires exact match; the OCaml side already errors on missed lookup; the three bug-masked CI defects demonstrate that silent leniency actively hides contract violations. The error-explicit contract is stricter than pre-fix behavior, which is the point — a loose `cn deps lock` + loose `cn deps restore` was exactly the bug.

Operators using `cn setup` in environments where the binary version isn't in the local package index (dev checkouts, CI without `-ldflags`) will now see an explicit error and must either build with `-X main.version=<version>` or pin `deps.json` by hand. The Tier 1 install kata encodes the workaround mechanically. Whether `cn setup` itself should resolve against the local index rather than pinning to the binary version is a separate design question — candidate for follow-up issue, not this cycle.

## Summary for γ triage

| Item | Severity | Candidate |
|------|----------|-----------|
| `eng/go` §2.12 schema scope addendum: schema audit must extend to sibling shell test harnesses that produce JSON for the same parsers. Mechanizes the pattern that flushed 3 bug-masked CI defects this cycle. | B (skill gap) | MCA — one-line addendum to `src/packages/cnos.eng/skills/eng/go/SKILL.md` §2.12. Cheap, durable. |
| `cn setup` default-pins to binary version; in dev/CI environments without `-ldflags`, this yields an unresolvable pin. Worked around mechanically in Tier 1 kata. | B (known debt, noted in PR body) | Candidate follow-up issue: `cn setup` resolves against local index when present, falls back to binary version otherwise. Separate cycle. |
| Cycle flushed 3 pre-existing test-harness defects as byproduct. All fixed in the same PR; no carry-forward. | — | None. Positive data point for the "L7 diff-shape reveals dormant incoherence" claim. |

α recommendation: ship the §2.12 schema-scope addendum as an immediate output this cycle (§10.1). The `cn setup` default-pin question belongs in a separate issue — out of scope for #250 per the issue's "Not in scope".

— alpha@cdd.cnos
