<!-- sections: [Summary, Findings, Friction log, Observations and patterns, Engineering-level reading] -->
<!-- completed: [Summary, Findings, Friction log, Observations and patterns, Engineering-level reading] -->

---
cycle: 369
role: alpha
issue: "https://github.com/usurobor/cnos/issues/369"
date: "2026-05-17"
merge_sha: "ff54f2a045d5b8b8574ef6f335d7f30c5f8b23fd"
base_sha_origin_main: "704365d23378fcbfcf1e33679025809af6b81100"
head_sha_cycle_at_merge: "227d23739ae32fac9a27e91ec60e89ef3b4a8424"
verdict: "R1 REQUEST CHANGES (γ-side D1) → R2 APPROVED unconditionally"
rounds: 2
---

# α Close-out — #369

## Summary

Two-round cycle delivering the `schemas/cdd/` subsystem (Phase 2 of #366): three CUE schemas (`contract.cue`, `receipt.cue`, `boundary_decision.cue`), one README pinning the `cue vet` invocation pattern and the recursive scope-lift invariant, and four YAML fixtures (one valid receipt + three doctrine-load-bearing invalid receipts). Schema-typing of the receptor frozen at doctrine level by #367's `RECEIPT-VALIDATION.md`. Mode: docs + schema, no code, no validator behavior change (AC8 enforces zero touch on `cn-cdd-verify/`); disconnect class docs-only (no tag, no VERSION bump; the merge commit `ff54f2a0` is the disconnect signal per #367 precedent).

Authored across nine α commits on `cycle/369`: scaffold/schemas + fixtures (`9fb4143b`), README (`b303a9db`), self-coherence in six sections (`b6314106`, `8fe40357`, `33369237`, `c92698d5`, `d5a2d842`, `b62b2598`), heading-rename to canonical `## CDD Trace` form (`ff450f6d`), and review-readiness signal (`6835197d`). β R1 REQUEST CHANGES on a single γ-side D-finding (`.cdd/unreleased/369/gamma-scaffold.md` missing, rule 3.11b binding); γ executed recovery path (a) at `227d2373`; β R2 APPROVED unconditionally with all four pre-merge-gate rows green. γ-acting-as-δ merged at `ff54f2a0` (γ holds the merge boundary because Phase 4 δ split has not landed per `gamma-scaffold.md:115`). Post-merge CI: 8 of 9 jobs green on the merge commit; the lone red job is `notify` (Telegram, pre-existing infrastructure failure — same red on `f82b0b7d` and `704365d2`, both unrelated unmerged commits, so not introduced by this cycle).

Surface containment held exactly: nine new files under `schemas/cdd/` (8) + `.cdd/unreleased/369/` (1 at signal time; β/γ added their files later). Zero touch on `cdd-verify/`, `operator/SKILL.md`, `gamma/SKILL.md`, `epsilon/SKILL.md`, `ROLES.md`, `CDD.md`, `COHERENCE-CELL.md`, `RECEIPT-VALIDATION.md`. The optional `RECEIPT-VALIDATION.md` trailing-pointer exception was declined (safe path).

## Findings

α-side cycle findings, factual only:

**F1 — §Skills commit landed as `gamma@cdd.cnos`; harness-side worktree-config reset between session-start identity write and the commit.** α's session-start identity write was `git config user.email "alpha@cdd.cnos" && git config user.name "alpha"` (no `--worktree` flag). Immediate verification (`git config --get user.email`) returned `alpha@cdd.cnos`. Between the §Gap commit (which landed correctly as alpha) and the §Skills commit (`8fe40357` after path-(a) rebase), the *shared* `.git/config` layer was overwritten — the next read returned `gamma@cdd.cnos`, and the §Skills commit landed with the gamma author. The repo has `extensions.worktreeConfig=true` at the shared layer; sibling worktrees (`/root/cnos-cycle-369`, `/root/cnos-cycle-370`, and `/root/cnos` itself) each carry their own per-worktree `config.worktree` file. Plain `git config user.email X` (no `--worktree`) writes to the shared layer, which any sibling-worktree process can overwrite asynchronously.

α applied path (a) retroactively: configured the cycle-branch worktree identity at `--worktree` scope (`git config --worktree user.email "alpha@cdd.cnos"`), then ran `git rebase -i {merge-base} --exec 'git commit --amend --reset-author --no-edit'` to rewrite the cycle's commits with the canonical author, followed by `git push --force-with-lease origin cycle/369`. All nine α commits on the cycle branch now show `alpha@cdd.cnos`; verified at signal time via `git log --format='%ae' origin/main..HEAD`. Path (a) was chosen over path (b) (configure correctly going forward + leave existing commits as legacy) because the cycle history at this point was small (six commits ahead of merge-base), the role-identity-is-git-observable property (`alpha/SKILL.md` §2.6 row 14, `CDD.md` §1.4) wanted to hold for the cycle as a whole, and the force-push surface was the cycle branch (not main).

Surfaces carrying the class:

- `alpha/SKILL.md` §2.6 row 14 — describes the retroactive fix (path a) and the alternative (path b) but does not prescribe the *preventive* write at session start (the `--worktree`-from-first-command rule).
- `operator/SKILL.md` §Git identity for role actors — names the canonical role-email form, does not name the worktree-config blast radius.
- `.git/config` `extensions.worktreeConfig=true` — the detection signal exists at the repo level; one `git config --get extensions.worktreeConfig` at session start determines whether the role must use `--worktree`.

Class: shared-`.git/config` silent overwrite under `extensions.worktreeConfig=true`. Same class as #370 R1 row 1 (β's merge-test worktree-config-leak, cycle #301 O8 repeat) and #370's α close-out F4 (α's close-out re-dispatch identity drift). **Third confirmed surface in two cycles**: β-side merge-test recipe, α-side close-out re-dispatch, and now α-side mid-cycle commit sequence. The reset class is "shared-config silent overwrite by some other process," not "stale config at session start." The overwriting actor is not always identifiable from the artifact; in this cycle, the most-likely candidate was a sibling-worktree `git config` write executed by a parallel-cycle process or the dispatching harness itself between α's commits. β cannot derive this from the diff because the rewritten commits show only the final canonical authorship; γ-scaffold cannot derive it because the scaffold is pre-dispatch. This is unique α-side authoring-time signal.

**F2 — `## CDD-Trace` → `## CDD Trace` rename caught pre-signal because cycle #370 surfaced it as F1 in parallel.** α's first-draft §CDD-Trace section header used the SKILL.md-prose form (`## CDD-Trace`, hyphen). The `cn-cdd-verify` validator's literal grep at lines 495 and 573 is `^## CDD Trace` (space). The drift is the same class #370 R1 F1 surfaces. Cycle #370 was running in parallel with this cycle on the same dispatch harness; #370's R1 verdict (REQUEST CHANGES, F1 = CDD-Trace convention drift) landed on `origin/main` before this cycle's review-readiness signal. α read #370's R1 verdict during polling and the parallel knowledge surfaced the validator-source read α had not otherwise scheduled. α renamed the §CDD-Trace header (commit `ff450f6d`) and updated the manifest comment to match the canonical convention before signaling review-readiness. This cycle's CI was green on the rename SHA; no β-side finding on CDD-Trace was raised.

The friction-of-record: α-side authoring discipline does not yet cross-check the validator source at section-naming time. The rule that would have caught this without #370's cross-cycle signal is mechanical (`grep '^# Required sections' src/packages/cnos.cdd/commands/cdd-verify/cn-cdd-verify` + `grep -q "^## "` patterns in the same file). α did not run that check at section-header authoring; only the parallel-cycle signal surfaced the constraint. **The cross-cycle signal is fragile**: if #370 had been sequential-after-#369 rather than parallel, this cycle's R1 verdict would have carried the same F1. The class is currently being closed cycle-by-cycle through review-time findings; the mechanical preventive (a pre-review-gate row reading the validator source) is still unwritten.

**F3 — readiness-signal SHA initially named inline; corrected to implementation-SHA convention pre-signal.** First-pass `§Review-readiness` named the current-HEAD SHA inline ("`Round 1 | base SHA: ... | head SHA: <HEAD-at-write> | ...`"). This recursively self-stales — the readiness-signal commit advances HEAD past the SHA it just recorded. The convention in `alpha/SKILL.md` §2.6 (derived from #301 F3 / α O3) prescribes either (a) name the *implementation* SHA (last implementation commit before this signal) or (b) omit the SHA and let polling carry HEAD. α applied form (a) in commit `b62b2598` ("drop hard-coded implementation SHAs … polling carries HEAD"). The rename was reverted between commits to use the cleaner form (`implementation SHA: b62b2598 … branch HEAD on origin/cycle/369 — β polls and uses whatever HEAD it finds`). β R1 §2.1 verified the convention was honored.

α applied the rule correctly on first re-read of `alpha/SKILL.md` §2.6. The friction was that the SKILL.md convention reads cleanly when read in advance but not when read against in-progress prose — the rule is a generation constraint, and α's authoring pattern read the SKILL surface as a review-time convention. Not a finding in the strict sense (no review-time finding was raised), but the pattern is worth surfacing: SHA-convention rules in `alpha/SKILL.md` §2.6 are most useful when treated as pre-write checklists, not post-write linters.

**F4 — late-authored `gamma-scaffold.md` (β R1 D1) is γ-side, not α-side.** The β R1 REQUEST CHANGES verdict fired on rule 3.11b: `gamma-scaffold.md` missing on the cycle branch at α's review-readiness signal. The artifact is γ's pre-dispatch coordination surface, not an α deliverable. γ executed recovery path (a) at `227d2373` (authored `gamma-scaffold.md` on the cycle branch after the fact; the file includes a §Process note flagging the late-authoring as a γ-axis process gap). β R2 APPROVED unconditionally on the single-row re-check. α's review-ready surface was unchanged between R1 and R2 — the only file added between `6835197d` and `227d2373` was `gamma-scaffold.md` itself, and α did not author it.

Noting here for the closeout-thread completeness, **not** as an α-side finding. The class belongs to γ-PRA (candidate next-MCA per `gamma-scaffold.md` §Process note: pre-dispatch row in `gamma/SKILL.md` §2.5 Step 3a/3b blocking dispatch on artifact presence).

**F5 — none beyond F1, F2, F3.** All ten ACs met at R1 with independently re-runnable oracles; β R1 §2.0 verified each. R2 introduced no new findings. Surface containment held exactly; no mid-cycle scope drift; the seven debt items in `self-coherence.md` §Debt are explicit forward-handoff to Phase 3, not gaps. Pre-merge-gate row 9 (polyglot re-audit) was exercised: CUE, YAML, Markdown each toolchain-validated independently; shell + CI absent from diff so no audit gap. Caller-path trace (row 12) explicitly addressed the no-callable-modules class (schemas are validators-of-data, not validators-themselves; their callers are `cue vet` invocations documented in `schemas/cdd/README.md §How to run`).

## Friction log

**1. Identity-truth write at session start used the wrong scope, and the resulting drift surfaced inside the §Skills commit rather than at the canonical pre-review-gate row 14 check.** α's session-start ritual was `git config user.email "alpha@cdd.cnos" && git config user.name "alpha"` followed by `git config --get user.email` for immediate verification. The verification returned the expected value, which satisfies the literal text of `alpha/SKILL.md` §2.6 row 14. But the rule's *property* (the role-identity-is-git-observable property must hold for every cycle commit) requires the identity write to survive across the commit sequence, not just to verify correctly at session start. With `extensions.worktreeConfig=true` enabled at the shared layer, the survival window is narrowed to "until the next sibling-worktree process writes to the shared `.git/config`." α's mental model treated the write as a one-time setup; the actual class is a per-commit invariant that must be either pinned (with `--worktree`) or re-verified before every commit.

The friction was that path (a) recovery was clean *because* the cycle was small. Six α commits to rebase + force-push. If the leak had surfaced after 30+ commits, path (a)'s cost would have been substantially higher and path (b) (configure forward, accept legacy commits as split-form) would have been the pragmatic-but-noisy choice. The discipline scales asymmetrically: pinning identity at `--worktree` scope from the first command costs one extra flag; recovering after a leak costs a force-push and a rebase exec across N commits. The asymmetry is what makes the `--worktree`-from-first-command rule load-bearing even when the leak risk per session is low.

**2. The parallel cycle #370 surfaced #369's F2 (CDD-Trace) before β R1 reviewed.** Cycle #370's R1 verdict landed on `origin/main` between α's §CDD-Trace commit (`d5a2d842`) and α's review-readiness signal. α's polling discipline (`alpha/SKILL.md` §2.7, "poll every 60 seconds") was for `beta-review.md` on the *current* cycle branch, not for cross-cycle signals on main. The cross-cycle read was opportunistic — α happened to refresh `git fetch origin main` while waiting on β R1, saw the #370 verdict, read its F1, and applied the heading rename pre-emptively. The discipline that catches this in general is unwritten: when two cycles run in parallel on the same dispatch harness, the friction one surfaces becomes the authoring constraint the other inherits — but only if the role checks. α-side authoring time does not currently include "read parallel-cycle β verdicts on main" as a polling target.

The friction was that the cross-cycle signal is **load-bearing once observed** but **not scheduled by any SKILL surface**. α's `alpha/SKILL.md` §2.7 poll-cadence is per-cycle. If #370 had landed *after* α's review-readiness signal here, the same F1 would have fired against this cycle and α would have repeated the rename in a fix-round commit. The friction is that the discipline is opportunistic-not-mechanical.

**3. The `## CDD-Trace` rename revealed a deeper drift inside the validator source itself.** The validator's grep at `cn-cdd-verify:495,573` is `^## CDD Trace` (space, canonical). The validator's *own comment* at line 480 uses `CDD-Trace` (hyphen, drifted). `alpha/SKILL.md:217,352` uses `§CDD-Trace` (hyphen, drifted). The released-precedent self-coherence on main (`.cdd/releases/docs/2026-05-15/367/self-coherence.md`) uses `## CDD Trace` (space, canonical, but α did not grep released precedents). So three surfaces carry the drift, and the lone canonical-form surface is the validator's grep itself. The validator-comment-vs-validator-grep mismatch within a single file is the more interesting signal: it tells α-side authoring that the validator's own author may have copied the SKILL.md shorthand into the comment and then written the grep against the canonical form independently. The internal mismatch is a stronger signal of "the SKILL.md shorthand is the drifted surface, not the validator," than the cross-file comparison would be.

α did not edit any of these surfaces (out of scope per AC9). The friction was that surfacing the drift class while leaving the drifted surfaces in place creates an obligation for a follow-up cycle to reconcile them. That reconciliation belongs to γ-PRA (candidate scope: a single-cycle skill patch on `alpha/SKILL.md` §2.5 + `cn-cdd-verify:480` aligning all three drifted surfaces to the canonical `CDD Trace` form, with `## CDD Trace` as the section header convention). The drift class is now confirmed across two cycles (this one and #370); the reconciliation is overdue.

**4. AC4 structural enforcement required scratch fixtures beyond the named three-invalid corpus.** The issue's hard-gate AC7 names three doctrine-load-bearing invalid fixtures (`invalid-override-masks-verdict`, `invalid-fail-no-boundary-decision`, `invalid-gamma-preflight-authoritative`). AC4's structural-rejection table has more cases than three: PASS+override → must fail; FAIL+accept → must fail; override+no-override-block → must fail; override-on-non-override-action → must fail; action=none enum-violation → must fail; count-refs-length mismatch → must fail. Six rejection cases against three named fixtures. α resolved by writing six scratch fixtures and running `cue vet` against each, capturing the error string for §ACs evidence, then *not* committing the scratch fixtures (the named-three-invalid corpus is the issue's hard-gate requirement; the scratch fixtures' rejection evidence lives in the self-coherence narrative). The friction was that the AC oracle granularity (3 fixtures) does not match the structural-claim granularity (6 cases); the gap is bridged by α's transcript evidence, not by committed test artifacts.

β R1 §2.0 AC4 re-ran four of the six scratch cases independently and verified the rejection mechanics. The discipline held; the friction is that the bridge between AC-oracle-granularity and structural-claim-granularity is α-side narrative work, not committed test artifacts. If Phase 3 (or any downstream phase) decides the bridge should be persisted, the natural form is a per-AC test-corpus expansion under `schemas/cdd/fixtures/edge-cases/` with a README mapping each fixture to its AC row. Not in scope this cycle; flagged for Phase 3 inheritance.

## Observations and patterns

**O1 — Pattern: `extensions.worktreeConfig=true` plus a non-`--worktree` identity write produces drift that survives the initial verification, across all three roles.** β surfaced this in #370 R1 row 1 (merge-test worktree) citing #301 O8. α surfaced this in #370 F4 (close-out re-dispatch). α surfaced this in #369 F1 (mid-cycle commit sequence). Three role-surfaces, two cycles, one shared-config blast radius. The detection cost is bounded (one `git config --get extensions.worktreeConfig` at session start); the preventive cost is bounded (`--worktree` flag on every identity write); the recovery cost is asymmetric (path-(a) force-push and rebase, scaling with cycle size). The class is now well-characterized across roles; the mechanical preventive is not yet written into `alpha/SKILL.md` §2.6, `beta/SKILL.md`, `gamma/SKILL.md`, or `operator/SKILL.md`. Candidate γ-PRA scope: a one-line addition to `operator/SKILL.md §Git identity for role actors` prescribing the `--worktree`-from-first-command rule when `extensions.worktreeConfig=true`. Same class as the cross-toolchain non-determinism the eng-skills handle for code; here the eng-equivalent for git identity is unwritten.

**O2 — Pattern: cross-cycle parallel-running cycles produce one-way authoring constraints, but only via opportunistic polling.** Cycle #370's R1 F1 (CDD-Trace convention drift) became this cycle's pre-signal authoring constraint because α happened to read #370's β-review while waiting on this cycle's β-review. The constraint did not arrive via any SKILL-prescribed channel. If the read had been missed, this cycle would have repeated #370's R1 finding. The class is "parallel-cycle finding-as-authoring-constraint." Same class as the γ-scaffold-as-generation-constraint pattern (#367 O3, #370 O6) but with the source being a *parallel-running cycle's β-review on main*, not the same cycle's γ-scaffold. The pattern generalizes only if the polling discipline includes parallel-cycle β-review reads; currently `alpha/SKILL.md` §2.7 names polling for the *current* cycle's `beta-review.md` only. γ-PRA candidate scope: a sub-row under §2.7 saying "if a sibling cycle's branch is open on the same dispatch harness, also poll its β-review for cross-cycle findings of validator-literal / convention class."

**O3 — Pattern: validator-literal contracts are the binding authority; SKILL-prose shorthand is normative guidance.** When `cn-cdd-verify:495` greps `^## CDD Trace` (space), that grep is the contract. When `alpha/SKILL.md:217,352` writes `§CDD-Trace` (hyphen), that prose is guidance. Authoring discipline must read the validator source when the validator's contract is a literal match — the SKILL.md enumeration is a *guide*, not the *contract*. This cycle's F2 caught the drift only by cross-cycle signal; the canonical detection (grep the validator source at section-header-authoring time) is unwritten. Same class as #370's O1. Confirming in this cycle: validator-literal-vs-SKILL-prose drift is a structural class, not cycle-specific. Phase 3 inherits this directly: if Phase 3 modifies `cn-cdd-verify` to add new validator literals, those literals must be reconciled against `alpha/SKILL.md`'s enumeration at the same commit, or the drift class re-opens.

**O4 — Pattern: SHA-convention rules in `alpha/SKILL.md` §2.6 are generation constraints, not review-time linters.** The recursive-self-stale class (#301 F3) and the implementation-SHA convention are SKILL surfaces that read cleanly when read in advance but require pre-write application. α's authoring pattern is to write the prose first and then re-read the SKILL surface against the draft; the convention is most useful when read before the draft. The class is "SKILL surface as generation constraint vs review-time check." Same class as #367 O3 (γ-scaffold-as-generation-constraint) and #370 O4 (AC oracles as per-section authoring constraints). The generalization: SKILL surfaces that name conventions are most useful when treated as pre-write checklists; the cost is one re-read per authoring section, the benefit is closing the class before it surfaces at review. This cycle applied the rule correctly on first re-read; the failure mode is when α's authoring pattern reads the SKILL surface only at the end of a section, not before.

**O5 — Pattern: peer-set = ∅ is a valid pre-review-gate row 7 outcome, but it requires explicit justification.** This cycle's pre-review-gate row 7 was PASS with peer set = ∅ — there are no sibling consumers of the receipt-shape contract because Phase 3 has not landed yet. The temptation in row 7 is to read "peer set = ∅" as "row passes trivially." The correct reading is that an empty peer set is the *strongest* claim α can make and requires the *most* evidence: every consumer that *could* exist must be enumerated and then explicitly exempted. α's self-coherence §Self-check peer audit named `schemas/skill.cue` as the candidate peer (same `schemas/` namespace), classified it as not-a-peer (different subsystem), and named the receipt-shape harnesses as not-yet-existing (Phase 3 wires them). The empty-set claim was earned, not assumed. Pattern: an empty peer set is a strong claim; it must be authored with the rigor of a non-empty enumeration. Same class as the receptor-before-membrane discipline at the design layer (#367 O2) — both require explicit deferral surfaces that justify the absence.

## Engineering-level reading

**For Phase 3 (`cn-cdd-verify` refactor) inheriting α's #369 implementation:**

- The receipt schema's required-field set (`boundary_decision: #BoundaryDecision`, `protocol_gap_count: int & >=0` with structural `len()` consistency, `protocol_gap_refs: [...#ProtocolGapRef]`, seven evidence refs as required `string`) is the validator's input contract. V dereferences these from the receipt; V does not re-read evidence outside the receipt (consistent with #370's AC3 signature variant: V is 2-arg, not 3-arg). Phase 3's structural reader implementation reads the schema once at boot and dereferences receipt instances against it; the schemas are not re-loaded per receipt.
- The `#Receipt` is **open** (`...` at end). This was a deliberate authoring decision (`self-coherence.md` §Self-check item 3). Open is what makes `invalid-gamma-preflight-authoritative.yaml` fail for the AC5 reason (missing required `boundary_decision`) rather than for an unrelated "field not allowed" reason (the fixture sets a `preflight_only: true` extension key that an open schema accepts but a closed schema would reject first). Phase 3's reader should not close `#Receipt` without a paired update to the invalid-fixture corpus.
- The `transmissibility` derivation is encoded in CUE (`receipt.cue:99–118`) as an if-chain over `validation.verdict × boundary_decision.action`. The mapping table appears twice (CUE + README §Scope-Lift Invariant Projection 2) — α did not add a `[[name]]`-style sync marker because the precedent (`schemas/skill.cue` + `schemas/README.md`) does not use one. Phase 3 must keep both sides in sync if the table changes; the schema is the load-bearing surface, the README is documentation.
- The `#ProtocolGapRef.source` enum (`"receipt" | "artifact" | "issue" | "review" | "closeout"`) is **α-chosen, not doctrine-sourced**. Phase 6 (ε relocation) may want the four-class taxonomy of *what kind of gap* (`cdd-skill-gap | cdd-protocol-gap | cdd-tooling-gap | cdd-metric-gap`) rather than the source dimension. Schema evolution: widening the enum is v1-compatible; narrowing/renaming is v1-breaking. Phase 6 makes the call; Phase 3 should not pre-emptively retype this field.
- The `boundary_decision.actor` field is typed as `string`, not as a typed role-identity regex. Phase 3's structural reader is the right surface for role-identity policy (which actors may write which decisions; how role pinning interacts with override actor) — encoding role-identity policy in CUE regex would mix policy into the data schema. Phase 3 should add structural reader checks at the V-implementation surface, not at the schema surface.
- The seven required evidence refs are typed `string` (no `#EvidenceRootRef`-style typed-ref schema). Phase 3 may want to tighten these to typed refs once `evidence_graph.cue` exists (deferred to a later cycle per issue body). The v1 receipt's `string` form is intentional — α did not author `evidence_graph.cue` because the issue scoped it out.

**For the `extensions.worktreeConfig=true` identity-truth class (cross-role doctrine candidate):**

- The mechanical preventive is one line: when `git config --get extensions.worktreeConfig` returns `true`, every identity write must carry `--worktree`. The detection cost is one config-read at session start; the preventive cost is one flag per write; the recovery cost (path a) scales with cycle size. The asymmetry argues for the preventive being a hard rule, not opportunistic.
- Three role-surfaces have now surfaced the class: β (merge-test worktree, #370 R1 row 1), α (close-out re-dispatch, #370 F4), α (mid-cycle commit sequence, #369 F1). The blast radius is "any role's commit on any worktree under `extensions.worktreeConfig=true`," and the overwriter is "any process that writes to the shared `.git/config` between the role's identity write and the role's first commit." Without `--worktree`, the role's identity is at the mercy of every sibling-worktree process for the duration of the session.
- The SKILL surfaces that need updating are `operator/SKILL.md §Git identity for role actors` (canonical role-email form does not mention worktree-config blast radius) and `alpha/SKILL.md §2.6 row 14` (describes retroactive path-a, does not prescribe the preventive). β-side and γ-side surfaces likely need the same update.

**For the validator-literal-vs-SKILL-prose drift class (cross-cycle doctrine candidate):**

- Three drifted surfaces (`alpha/SKILL.md:217`, `alpha/SKILL.md:352`, `cn-cdd-verify:480`) all use `CDD-Trace` (hyphen). One canonical surface (`cn-cdd-verify:495,573`) uses `CDD Trace` (space). One released-precedent surface (`.cdd/releases/docs/2026-05-15/367/self-coherence.md`) uses `CDD Trace` (space). The validator's grep is the binding contract; the SKILL prose and validator comment are drifted normative surfaces.
- Mechanical reconciliation: rename all three drifted surfaces to the canonical space form in one skill patch. Cost: three single-line edits + one CI re-run. Benefit: closes the class for all future cycles. The single skill patch is a candidate γ-PRA cycle scope (docs-only, no version bump).
- The cross-cycle signal that surfaced this in #369 (parallel #370 R1 F1) is fragile — sequential ordering of the two cycles would have re-fired the same finding here. The unwritten preventive (a pre-review-gate row reading the validator source for `grep -q "^## "` patterns and cross-checking against `alpha/SKILL.md`'s section enumeration) is the mechanical version of the constraint α applied opportunistically. Same shape as the `eng/{language}` skills' mechanical invariants: the constraint exists, but the surface that *names* it as a generation constraint is not yet written.

**For the cycle-iteration audit trail:**

- #369 was Phase 2 of #366. The schemas Phase 3 will read are now pinned. The four debt items most likely to bind Phase 3 are (in order): (1) `#ProtocolGapRef.source` enum scope (Phase 6 may want it shifted), (2) `boundary_decision.actor` as `string` (Phase 3's V is the right surface to add role-identity policy), (3) the `transmissibility` derivation duplication (CUE + README), (4) the `base_sha` vs `contract_sha` required/optional split. None of the four block Phase 3 from starting; all four are explicit forward-handoff surfaces in `self-coherence.md` §Debt.
- The disconnect class was docs-only; no VERSION bump, no tag. This mirrors #367's precedent (`docs/2026-05-15/367/`) and is consistent with the cycle's mode (docs + schema, no executable code). The merge commit `ff54f2a0` is the disconnect signal; release-scoped triadic cycle directory move from `.cdd/unreleased/369/` → `.cdd/releases/docs/2026-05-17/369/` is γ's responsibility post-closeout per `release/SKILL.md` §2.5a.
