Skip to content

cnos#656: repo lifecycle Phase 1 — state ledger + cn repo status#663

Open
usurobor wants to merge 10 commits into
mainfrom
cycle/656
Open

cnos#656: repo lifecycle Phase 1 — state ledger + cn repo status#663
usurobor wants to merge 10 commits into
mainfrom
cycle/656

Conversation

@usurobor

Copy link
Copy Markdown
Owner

Refs #656 (Phase 1 of the #655 cn repo lifecycle wave).

Summary

  • schemas/repo_state.cue (checked-in, closed CUE schema for cn.repo.state.v1) + fixtures + a new CI job (repo-state-schema-check) — timestamp-freeness and no-lock-duplication are enforced structurally via CUE closedness.
  • internal/repostate — pure types + deterministic Marshal().
  • cn repo install now writes/updates .cn/repo.state.json idempotently, including dispatch-workflow render-contract metadata (P2). Survives an orthogonal label-doctor failure when the render itself succeeded; does not write a stale/corrupted ledger when the render didn't happen this run.
  • internal/dispatchrender (extracted from repoinstall.runDispatchCds) — single renderer-invocation authority shared by install and the new status command's drift comparison.
  • cn repo status (+ --json, --check) — read-only report of packages/lock/vendor sync, dispatch-workflow drift (matches_ledger / user_edit / renderer_moved / removed / unclassified), canonical label drift, orphan vendored packages, locally-edited managed files, and best-effort update-available.
  • docs/development/design/cn-repo-status-MOCKS.md — mock-first design doc (A6), authored before implementation.

Review

Adversarial review (independent subagent, not primed with the implementation narrative) found two real bugs during this cycle, both fixed with regression tests before this PR was opened — see .cdd/unreleased/656/beta-review.md for full writeups:

  1. A stale dispatch-workflow file from a prior successful install could get its ledger metadata silently corrupted by a later failed, different-identity install attempt.
  2. A confirmed workflow-content drift could be silently reported as "no drift" if the re-render classification step itself failed.

Test plan

  • go build ./... && go vet ./... && go test ./... (src/go)
  • go build ./... && go vet ./... && go test ./... (label-doctor module)
  • ./scripts/ci/validate-repo-state.sh --self-test
  • Manual end-to-end smoke: real cn build → real local index → real cn repo install → real cn repo status (clean, drifted via hand-edit, --check exit codes, zero-write verification)
  • Real cn repo install output validated against schemas/repo_state.cue via cue vet (not just hand-written fixtures)

🤖 Generated with cds-dispatch (interactive session acting as the cds-dispatch wake)

sigma@cnos.cn-sigma.cnos added 10 commits July 10, 2026 02:14
…d-drift silently reported as unknown

Adversarial review of the P2/P3 diff surfaced two real bugs:

1. canWriteLedger used os.Stat(dispatchWorkflowPath) as a proxy for
   'did this run's render happen', but that file can be a leftover from
   a PRIOR successful run. A failed identity-gate rerun (different
   --agent, no --workflow-pat-secret) would then rewrite the ledger's
   workflow render-contract fields using the new run's opts, corrupting
   the record for a file nothing this run touched. Fixed by threading
   runDispatchCds's own rendered bool through instead of re-deriving it
   from file presence.

2. When the live workflow's sha256 was confirmed to differ from the
   ledger, but the fresh-render comparison that classifies user_edit vs
   renderer_moved itself failed, the code fell back to DriftUnknown --
   which is excluded from the top-level Drift bool, so a confirmed
   mismatch could be silently reported as no drift. Introduced
   DriftUnclassified (counts as drift) distinct from DriftUnknown
   (nothing to compare against at all).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant