feat: activate typed identity invariants in Ward and Threads replay - #969
Conversation
Retain migrated declarations in active Ward configuration, derive complete candidate identity evidence, and bind those facts to direct validation and recovery commitments. Keep authority in the existing Threads predicates. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: BunsDev <68980965+BunsDev@users.noreply.github.com>
|
Kitty is adopting this existing checkpoint for the next branch-to-merge pass. issue-885 was unclaimed; the task worktree now holds the shared claim. I will integrate current main including #933 protected intake, #968 explicit clock, and #932 typed terminal recovery; preserve the Rust predicate boundary; and attach honest daemon evidence without claiming supported scheduled publication or human freeze acceptance prematurely. |
Integrate current main without restoring protected proposal authority. Enforce typed predicates before ordinary apply and coherence staging, bind exact identity evidence into proposal revisions and recovery, and preserve typed terminal closure for delayed rejection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>
Use the existing Gate-2 materializer for authoritative identity source paths, including case-insensitive aliases. Treat unavailable recovery evidence as an explicit error without poisoning the shared Ward lock. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>
Cover public intake, coherence approval, source drift, restart replay, protected refusal, and no-invariant compatibility. The same journeys reproduce four real invalid writes on unchanged main while valid controls pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical, moderate, and nit findings remain in roster evidence binding, backup validation, and dry-run coverage.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
This pull request activates typed identity invariants across Ward intake, proposal handling, and Threads replay.
Changes:
- Adds identity extraction, predicate enforcement, and durable evidence binding.
- Updates migration, recovery handling, documentation, and regression coverage.
- Pins the Threads core dependency.
File summaries
| File | Summary / final finding |
|---|---|
docs/reference/cli-ward.md |
Documents active identity invariants and replay behavior. |
crates/coven-cli/tests/threads_identity_invariants.rs |
Adds daemon identity journeys. |
crates/coven-cli/src/ward.rs |
Loads and validates declarations. Moderate (2 votes): unsupported or additional backup declarations may be ignored when active invariants exist. |
crates/coven-cli/src/ward_migrate.rs |
Migrates legacy invariants. Nit (1 vote): dry-run coverage does not assert generated identity-invariant tables and values. |
crates/coven-cli/src/ward_identity.rs |
Builds identity facts and evidence. Critical (3 votes): roster evidence hashes a reduced projection, omitting authoritative fields such as workspace. |
crates/coven-cli/src/threads_gate.rs |
Enforces identity predicates at intake and staging. |
crates/coven-cli/src/main.rs |
Registers the identity module. |
crates/coven-cli/src/cockpit_sources.rs |
Exposes roster identity fields. |
crates/coven-cli/src/api.rs |
Carries evidence through approval and recovery. |
crates/coven-cli/Cargo.toml |
Updates the Threads core pin. |
Cargo.lock |
Records the pinned dependency revision. |
Review details
Suppressed comments (1)
crates/coven-cli/src/ward_migrate.rs:317
- The migration now populates
identity_invariantsand therefore emits[[identity_invariant]]in the generated TOML, but the dry-run test still only asserts that the plural stringinvariantsis absent. That assertion does not match the new singular field name and will not detect a regression where dry-run drops the active declarations; add a dry-run assertion for the generated identity-invariant tables and their values.
let compiled_identity_invariants = if legacy_invariants.is_empty() {
Vec::new()
} else {
IdentityInvariantSet::compile(&legacy_invariants)
.expect("rejection reasons were handled above")
.declarations()
.to_vec()
};
- Files reviewed: 10/11 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: BunsDev <68980965+BunsDev@users.noreply.github.com>
Head branch was pushed to by a user without write access
Commit all authoritative roster fields, including workspace, rather than a hand-maintained projection. A real-daemon regression reproduces redirected-workspace approval on the prior checkpoint and now refuses it without writing either workspace. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>
Preserve the concurrent cloud-agent commit and its migration assertions. Retain fail-closed full-roster serialization; clarify archived-versus-active policy authority in the follow-up before merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>
Follow the explicit issue-885 authority clarification: do not promote backup data to implicit authority. Detect lost activation when the active set is absent, preserve immutable archives, and invalidate pending bindings when the valid current declaration set changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <68980965+BunsDev@users.noreply.github.com>
Context
Enforce the existing Threads identity predicates across supported Ward intake and replay. Addresses #885; this checkpoint does not close the full cross-repository acceptance gate.
Final candidate:
30dfeec893e81854bd04856e59b3d1a62d02d69b. Normal merges preserve both the original checkpoint and concurrent cloud-agent repair history. Main integration preserves #933's protected-intake prohibition, #968's explicit clock, and #932's typed terminal recovery.Implementation
[[identity_invariant]]declarations. Unsupported active declarations and backup-only protection fail closed.SOUL.md, andIDENTITY.md, including unchanged sources. Expected values, descriptors, and advisory probes are not evidence.identityEvidencedigest carried by pending records, canonical proposal revisions, and recovery commitments. Changed bytes fail replay even when their extracted facts still satisfy the predicates.The concurrent
e65b1c8cloud-agent work was retained through normal merge64e36eb, including its migration assertions and workspace-declaration restart journey. Its permanent archive-parity restriction was explicitly superseded in30dfeec8to follow the #885 authority clarification: backups must not become implicit authority. A valid complete active set is the current policy; absent active policy still cannot silently discard archival declarations. Regressions cover both immutable-backup preservation and invalidation of pending evidence after an active-policy change.The only lockfile change relative to main is the Threads pin:
c3bd46bcadb6396db8436c47411a4d0eac17192b. No unrelated tempfile/getrandom downgrade remains.Reproductions and evidence
The integrated inherited checkpoint was reproduced accepting an invalid ordinary write and an invalid coherence approval. Additional reds demonstrated stale-but-still-valid identity evidence acceptance, an opened window left unterminated, lossy literal normalization, ignored empty duplicate fields, discarded unsupported backup declarations, and incomplete Gate-2 materialization accepted as evidence.
Independent review identified two further defects, both reproduced on native macOS before repair: a lowercase identity filename caused proposed bytes to be missed, and unavailable recovery materialization panicked. Focused follow-up review confirmed both fixes with no remaining blockers in that scope.
The same daemon test source was run against unchanged main
aa527d2din an isolated detached worktree. Two valid controls passed; four invalid intake/approval journeys failed because main returned HTTP 200 and actually wroteafter. The detached baseline was then removed. The production branch passes all 15 identity journeys plus the nine shared fixture tests. A further real-daemon regression reproduced HTTP 200 approval through a redirected workspace on93568a8eand is green after full-roster binding.proposal-identity-evidence-diverged; no writeRun the selectable native journeys with
cargo test --locked -p coven-cli --test threads_identity_invariants. Restart cases use durable public human-review proposals; they do not claim synthetic opened-window or interrupted-apply recovery evidence.Remaining scope and handoff
Production scheduled publication remains in #972, and the consolidated journey harness remains in #931. Historical scheduled-envelope tests demonstrate replay and typed closure, not a supported public publication path. The scheduled publisher must carry the daemon-computed identity binding; missing evidence with active invariants is intentionally refused.
#885 stays open for the complete publication/deadline/restart matrix and cross-repository compatibility/human acceptance. This does not advance the required compatibility freeze or claim Nova's independent acceptance or Val's freeze.
Two pre-existing local lifecycle timing/publication observations were recorded separately on #1001 (Unix socket permission publication, 100 ms synthetic cleanup-phase assumption). The final workspace snapshot passes; no lifecycle timeout, permission check, or test selection was weakened to obtain that result.
Risk and rollback
R4 authority and migration change. Existing configurations without invariants retain their behavior. There is no new credential issuer, protected-write authority, audit store, or audit schema.
Preserve Ward backups and pending/recovery evidence. Rollback requires an explicit configuration compatibility review and must disable any affected mutation path fail-closed. Do not remove declarations or restore an unvalidated permit/apply route to make an older binary appear compatible.