Skip to content

feat: activate typed identity invariants in Ward and Threads replay - #969

Merged
BunsDev merged 10 commits into
mainfrom
fix/885-identity-predicates
Sep 12, 2026
Merged

feat: activate typed identity invariants in Ward and Threads replay#969
BunsDev merged 10 commits into
mainfrom
fix/885-identity-predicates

Conversation

@BunsDev

@BunsDev BunsDev commented Sep 9, 2026

Copy link
Copy Markdown
Member

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

  • Preserve supported migrated invariants as active [[identity_invariant]] declarations. Unsupported active declarations and backup-only protection fail closed.
  • Derive candidate facts from the authoritative roster, SOUL.md, and IDENTITY.md, including unchanged sources. Expected values, descriptors, and advisory probes are not evidence.
  • Apply the upstream typed predicate before ordinary writes and coherence staging, and during approval/deadline/recovery replay. Tier-0 proposal writes remain forbidden.
  • Bind canonical declarations and candidate source bytes into an identityEvidence digest carried by pending records, canonical proposal revisions, and recovery commitments. Changed bytes fail replay even when their extracted facts still satisfy the predicates.
  • Terminally reject unapplied scheduled identity failures with the correct typed window close. Preserve unverifiable interrupted-apply evidence without manufacturing a terminal decision.
  • Resolve identity source aliases with the existing Gate-2 materializer, preserve significant punctuation and explicit empty-field ambiguity, and refuse incomplete candidate target mappings.
  • Replace an unsafe recovery-context assertion with an explicit error, preserving claims and keeping the shared write lock usable.
  • Commit every authoritative familiar-roster field, including workspace, rather than a projection. Redirecting the workspace cannot reuse a pending identity decision.

The concurrent e65b1c8 cloud-agent work was retained through normal merge 64e36eb, including its migration assertions and workspace-declaration restart journey. Its permanent archive-parity restriction was explicitly superseded in 30dfeec8 to 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 aa527d2d in an isolated detached worktree. Two valid controls passed; four invalid intake/approval journeys failed because main returned HTTP 200 and actually wrote after. 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 on 93568a8e and is green after full-roster binding.

Real-daemon journey Unchanged main This PR
Invalid purpose before Tier-2 intake HTTP 200; target written; apply audit HTTP 403; no write or proposal
Purpose changed before coherence approval HTTP 200; target written; approval audit HTTP 409; no write or approval
IDENTITY source missing after restart HTTP 200; target written; approval audit HTTP 409; no write or approval
Source bytes changed after restart, predicates still hold HTTP 200; target written; approval audit HTTP 409 proposal-identity-evidence-diverged; no write

Run 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.

  • Final CLI unit suite: 3,204 passed, three existing ignored tests.
  • Final locked full workspace suite and strict workspace/all-target Clippy.
  • Final identity/roster/Ward/migration regressions: 199 passed.
  • Final clock-feature authority regressions: 171 passed.
  • Follow-up strict CLI all-target Clippy.
  • Existing real-daemon protected-intake and terminal-recovery targets: 18 and 13 passed.
  • Exact pinned Threads core canary: 249 unit/integration tests and existing doc-test behavior passed.
  • Formatting, secret scan, staged privacy guard, and documentation ownership.
  • Additional real-daemon identity intake and approval journeys: 24 passed, with unchanged-main red and valid controls.
  • Final-head native PR CI and merged-main CI.

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.

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>
@BunsDev

BunsDev commented Sep 12, 2026

Copy link
Copy Markdown
Member Author

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.

BunsDev and others added 3 commits September 12, 2026 00:42
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>
@BunsDev
BunsDev marked this pull request as ready for review September 12, 2026 06:14
Copilot AI lite review requested due to automatic review settings September 12, 2026 06:14
@BunsDev
BunsDev enabled auto-merge September 12, 2026 06:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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_invariants and therefore emits [[identity_invariant]] in the generated TOML, but the dry-run test still only asserts that the plural string invariants is 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.

Comment thread crates/coven-cli/src/ward_identity.rs Outdated
Comment thread crates/coven-cli/src/ward.rs
Co-authored-by: BunsDev <68980965+BunsDev@users.noreply.github.com>
auto-merge was automatically disabled September 12, 2026 06:38

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>
BunsDev and others added 2 commits September 12, 2026 01:47
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>
@BunsDev
BunsDev enabled auto-merge September 12, 2026 06:58
@BunsDev
BunsDev merged commit edf3500 into main Sep 12, 2026
20 checks passed
@BunsDev
BunsDev deleted the fix/885-identity-predicates branch September 12, 2026 07:34
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.

3 participants