Skip to content

feat(analysis): bind topic activity/dormancy/reactivation to an analysis-run profile - #407

Draft
seonghobae wants to merge 1 commit into
mainfrom
feat/topic-activity-analysis-run-gap-004
Draft

feat(analysis): bind topic activity/dormancy/reactivation to an analysis-run profile#407
seonghobae wants to merge 1 commit into
mainfrom
feat/topic-activity-analysis-run-gap-004

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

GAP-004 leftover / issue #167 / ADR 0051. Bind existing topic_lineage activity/dormancy/reactivation and remint refusal to a cutoff-safe analysis-run profile so an operator can request a digest-bound identity artifact.

  • Profile topic_activity_v1 / schema tepp.topic_activity.v1
  • Invokes TopicLineageRecord dormancy/reactivation, refuse_new_identity_on_reactivation, and identity_recovery_rate
  • Artifact inference status reactivation_is_not_new_topic_not_birth_split_merge
  • Reminted reactivation identities, illegal transitions, and snapshot/profile/cutoff mismatch fail closed

Not a Bayesian sampler. Not topic birth/split/merge. Not trsl_topic_lineage_v1 sequence edges. Not implemented-main.

Verification

  • cargo test -p analysis_engine
  • cargo clippy -p analysis_engine --all-targets -- -D warnings
  • python3 scripts/validate_documentation.py

Merge gate

Two independent current-head APPROVEs required. Author COMMENTED is not APPROVE. Do not self-approve.


Devin Review

…sis-run profile

Cutoff-safe topic_activity_v1 invokes topic_lineage dormancy/reactivation
and remint refusal. Reactivation is not a new topic; not birth/split/merge
and not a Bayesian sampler.

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Author note (COMMENTED, not APPROVE): this slice binds topic_lineage dormancy/reactivation and remint refusal into topic_activity_v1. Reactivation is not a new topic. Not a Bayesian sampler and not birth/split/merge. Independent non-author APPROVE still required.

@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 30 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a85a4853-db59-4d1a-a3b0-d0f8f99d2467

📥 Commits

Reviewing files that changed from the base of the PR and between 1bc02f5 and 755cceb.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • CHANGELOG.md
  • crates/analysis_engine/Cargo.toml
  • crates/analysis_engine/src/lib.rs
  • crates/analysis_engine/src/topic_activity_artifact.rs
  • crates/analysis_engine/tests/topic_activity_execution_contract.rs
  • docs/TRACEABILITY.md
  • docs/adr/0051-topic-activity-analysis-run.md
  • docs/adr/README.md
  • docs/doctoring/topic-activity-analysis-run.md

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Devin Review found 6 potential issues.

Devin Review

Comment on lines +36 to +42
pub struct TopicActivityInput {
identity: TopicIdentity,
transitions: Vec<TopicActivityTransition>,
proposed_reactivation_identity: TopicIdentity,
truth: Vec<TopicIdentity>,
decided: Vec<TopicIdentity>,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 Activity history bypasses cutoff binding

TopicActivityInput carries neither snapshot nor availability metadata. Callers can label arbitrary transitions with the requested snapshot and cutoff, producing a falsely historical artifact.

Prompt for agents
Redesign TopicActivityInput and execute_topic_activity_run so each activity observation is immutably bound to its source snapshot and availability time. Validate that the input snapshot matches the request and exclude or reject every transition unavailable at the requested KnowledgeCutoff before applying the state sequence. Keep the validated cutoff-derived state in the digest-bound artifact and add tests for future-available transitions and cross-snapshot input.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +215 to +218
if request.knowledge_cutoff != knowledge_cutoff.to_rfc3339()
|| request.model_contract_version != TOPIC_ACTIVITY_MODEL_CONTRACT_VERSION
|| request.output_profile != TOPIC_ACTIVITY_OUTPUT_PROFILE
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Equivalent cutoffs reject valid runs

execute_topic_activity_run compares timestamp text instead of instants. Valid equivalent offsets fail with InvalidEvidence, although the API accepts them.

Suggested change
if request.knowledge_cutoff != knowledge_cutoff.to_rfc3339()
|| request.model_contract_version != TOPIC_ACTIVITY_MODEL_CONTRACT_VERSION
|| request.output_profile != TOPIC_ACTIVITY_OUTPUT_PROFILE
{
if KnowledgeCutoff::parse_rfc3339(&request.knowledge_cutoff)
.map_err(|_| AnalysisEngineError::InvalidEvidence)?
!= knowledge_cutoff
|| request.model_contract_version != TOPIC_ACTIVITY_MODEL_CONTRACT_VERSION
|| request.output_profile != TOPIC_ACTIVITY_OUTPUT_PROFILE
{
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

TopicActivityTransition::Reactivate => record.reactivate()?,
};
}
refuse_new_identity_on_reactivation(record.identity(), input.proposed_reactivation_identity())?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Dormant runs require reactivation identity

execute_topic_activity_run enforces the proposed identity when no reactivation occurred. Active and dormant runs can fail over an irrelevant value.

Prompt for agents
Apply refuse_new_identity_on_reactivation only when the transition sequence contains Reactivate, or represent the proposed reactivation identity as optional and reject inconsistent presence. Add empty-sequence and dormant-only tests so both states can produce artifacts without supplying a fictional reactivation proposal.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +168 to +173
|| !matches!(self.activity.as_str(), "active" | "dormant" | "reactivated")
|| !self.identity_recovery_rate.is_finite()
|| self.identity_recovery_rate < 0.0
|| self.identity_recovery_rate > 1.0
|| !self.reactivation_identity_preserved
|| self.inference_status != TOPIC_ACTIVITY_INFERENCE_STATUS

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Contradictory activity artifacts pass validation

TopicActivityArtifact::from_json accepts unreachable state/count combinations. A reactivated topic with zero transitions passes validation and can receive a valid digest.

Prompt for agents
Extend TopicActivityArtifact::validate to enforce state/count consistency from the executor's fixed active initial state: active requires zero transitions, dormant requires an odd positive count, and reactivated requires an even positive count. Add tampering tests for each contradictory combination.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +47 to +53
pub fn new(
identity: TopicIdentity,
transitions: Vec<TopicActivityTransition>,
proposed_reactivation_identity: TopicIdentity,
truth: Vec<TopicIdentity>,
decided: Vec<TopicIdentity>,
) -> Self {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Activity input lacks resource bounds

TopicActivityInput::new accepts unlimited transitions and scoring identities. Add explicit count limits before exposing this profile through a service boundary.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +61 to +72
## Verification

The PR includes Rust unit and integration tests for dormancy-then-reactivation
identity preservation, remint refusal, illegal transitions, minted-replacement
recovery rates, snapshot/profile/cutoff mismatch, and artifact tampering. Run:

```text
cargo fmt --all -- --check
cargo test -p analysis_engine
cargo clippy -p analysis_engine --all-targets -- -D warnings
python3 scripts/validate_documentation.py
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Coverage gate evidence is missing

The verification list omits the mandatory 100% line-and-branch coverage gate. Confirm exact-head coverage for every new validation and execution outcome.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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