Skip to content

feat(analysis): bind TDT/CHRONOS composition to an analysis-run profile - #364

Draft
seonghobae wants to merge 4 commits into
mainfrom
feat/event-intelligence-analysis-run-gap-007
Draft

seonghobae wants to merge 4 commits into
mainfrom
feat/event-intelligence-analysis-run-gap-007

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

GAP-007 remaining operator-visible slice: bind the already-merged event_core TDT/CHRONOS composition (compose_event_intelligence, #269 on protected main) to an analysis_engine analysis-run output profile so operators can request the composed workflow.

  • New profile tdt_chronos_workflow_v1 / schema tepp.tdt_chronos_workflow.v1 (ADR 0030; 0026–0029 remain on other live PRs).
  • Cutoff-filters mentions by available_time against the request knowledge_cutoff; drops links that cite an excluded mention; keeps first-story/track streams aligned.
  • Digest-bound terminal result. Envelope layer stays tdt_detection; CHRONOS hypotheses stay chronos_prediction. Inference status is composed_workflow_not_instance_or_transition.
  • Invokes refuse_composition_as_instance and refuse_composition_as_transition. Does not invent an extractor, persist rows, or promote an instance/transition.

This is not implemented-main. Exact-head Checks on this head only. Predecessor-head evidence does not transfer.

Does not duplicate:

Test plan

  • cargo test -p analysis_engine
  • cargo clippy -p analysis_engine --all-targets -- -D warnings
  • RUSTDOCFLAGS="-D warnings" cargo doc -p analysis_engine --no-deps
  • Exact-head Required Checks on this SHA
  • Two independent (non-author, non-bot) APPROVE reviews

Merge bar

Ruleset 18156473: two independent approvals + exact-head Checks. Do not self-approve. Do not --admin merge.


Devin Review

Operators can request the existing event_core workflow as
tdt_chronos_workflow_v1. Mentions unavailable at the request cutoff are
excluded; the digest-bound tepp.tdt_chronos_workflow.v1 artifact records
detection versus prediction layers and refuses instance/transition
promotion. Not a new extractor, not persistence, and not implemented-main.
@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

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.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

Devin Review found 8 potential issues.

Devin Review

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Exact-head coverage remains pending

Repository rules require 100% production line and branch coverage. The PR description leaves exact-head checks pending for the new validation and error paths.

Devin Review

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

Comment on lines +363 to +370
config: input.config,
segmentation: input.segmentation,
mentions,
links,
first_story_labels,
track_assignments,
schema_slot_assignments: input.schema_slot_assignments,
occurrence_forecasts: input.occurrence_forecasts,

@devin-ai-integration devin-ai-integration Bot Aug 31, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 Late workflow evidence survives cutoff

When a run uses an earlier cutoff, admit_mentions_at_cutoff filters mentions but retains segmentation, schema slots, and forecasts unchanged. Results can include future-derived evidence.

Devin Review

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

Comment on lines +357 to +361
let links: Vec<_> = input
.links
.into_iter()
.filter(|link| eligible_ids.contains(&link.left()) && eligible_ids.contains(&link.right()))
.collect();

@devin-ai-integration devin-ai-integration Bot Aug 31, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Foreign links are silently accepted

When a link references a mention absent from the input, filter drops it as cutoff-excluded. Malformed workflows can succeed with understated links.

Devin Review

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

run_id: accepted.run_id.clone(),
snapshot_id: snapshot_id.to_owned(),
knowledge_cutoff: knowledge_cutoff.to_rfc3339(),
workflow_version: composition.config_version(),

@devin-ai-integration devin-ai-integration Bot Aug 31, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Workflow configuration escapes the digest

Replaying one accepted run with changed thresholds makes from_composition record only version 1. Different decision configurations can produce indistinguishable artifacts and digests.

Devin Review

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

Comment on lines +179 to +184
pub fn to_json(&self) -> Result<String, AnalysisEngineError> {
self.validate()?;
let payload =
serde_json::to_string(self).map_err(|_| AnalysisEngineError::SerializationFailure)?;
Ok(payload)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔍 Output limit is one-sided

to_json omits the advertised 256 KiB check. Current bounded fields stay small, but future variable-sized schema fields can bypass the output contract.

Devin Review

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

Comment on lines +258 to +259
let _ = refuse_composition_as_instance(&composition);
let _ = refuse_composition_as_transition(&composition);

@devin-ai-integration devin-ai-integration Bot Aug 31, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: Refusal calls are declarative

Both refusal APIs always return fixed errors without side effects. Ignoring their results preserves the boundary, but the calls add no runtime validation.

Devin Review

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

Comment on lines +328 to +346
if input.first_story_labels.len() != input.mentions.len()
|| input.track_assignments.len() != input.mentions.len()
{
return Err(AnalysisEngineError::Event(EventError::InvalidWirePayload));
}
let mut mentions = Vec::new();
let mut first_story_labels = Vec::new();
let mut track_assignments = Vec::new();
let mut excluded_after_cutoff_count = 0_u64;
for ((mention, first_story), track) in input
.mentions
.into_iter()
.zip(input.first_story_labels)
.zip(input.track_assignments)
{
if mention.clocks().available_time().instant() <= knowledge_cutoff.instant() {
mentions.push(mention);
first_story_labels.push(first_story);
track_assignments.push(track);

@devin-ai-integration devin-ai-integration Bot Aug 31, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: Indexed streams remain aligned

admit_mentions_at_cutoff checks equal lengths before zipping. Each excluded mention removes its corresponding label and track, then composition verifies track identities.

Devin Review

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

Comment on lines +247 to +248
let admitted = admit_mentions_at_cutoff(input, knowledge_cutoff)?;
let composition = compose_event_intelligence(

@devin-ai-integration devin-ai-integration Bot Aug 31, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟨 Untrusted workflow inputs lack resource bounds

execute_event_intelligence_run accepts unlimited collections before quadratic composition checks. An oversized request can exhaust service CPU and memory.

Devin Review

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

This was referenced Aug 31, 2026

@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 4 new potential issues.

Devin Review

Comment on lines +279 to +285
let summary = AnalysisResultSummary::new(
"tdt_chronos_workflow",
artifact.mention_count,
statistic_count,
EVENT_INTELLIGENCE_INFERENCE_STATUS,
)
.expect("bounded event-intelligence summary constants are valid");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 Oversized runs panic during completion

Over one billion evidence items or combined outputs makes AnalysisResultSummary::new fail. expect then crashes the executor instead of rejecting the run.

Suggested change
let summary = AnalysisResultSummary::new(
"tdt_chronos_workflow",
artifact.mention_count,
statistic_count,
EVENT_INTELLIGENCE_INFERENCE_STATUS,
)
.expect("bounded event-intelligence summary constants are valid");
let summary = AnalysisResultSummary::new(
"tdt_chronos_workflow",
artifact.mention_count,
statistic_count,
EVENT_INTELLIGENCE_INFERENCE_STATUS,
)?;
Devin Review

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

let links: Vec<_> = input
.links
.into_iter()
.filter(|link| eligible_ids.contains(&link.left()) & eligible_ids.contains(&link.right()))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: Link filtering remains equivalent

Bitwise & evaluates both pure contains calls, but returns the same Boolean result as &&. No links change eligibility.

Devin Review

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

Comment on lines +270 to +271
)
.expect("validated composition produces a valid bounded artifact");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: Artifact assertion remains unreachable

Successful composition guarantees every validation invariant used by from_composition. Its length conversions also fit u64 on supported platforms.

Devin Review

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

Comment on lines +529 to +546
#[test]
fn execution_refuses_invalid_completion_time() {
let fixture = KnownTruthFixture::build();
let request = request();
let accepted = accepted(&request);
assert_eq!(
execute_event_intelligence_run(
&request,
&accepted,
"snapshot-event-intelligence",
cutoff(),
fixture.input(),
"invalid",
),
Err(AnalysisEngineError::Api(
tepp_api::ApiError::InvalidWirePayload
))
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📝 Info: Completion errors still propagate

An invalid completion timestamp reaches terminal-result validation and returns its contract error. The earlier assertions do not mask this failure.

Devin Review

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

seonghobae and others added 2 commits September 14, 2026 14:27
Resolve the CHANGELOG.md append conflict by keeping both entries.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…elligence_run

The repository docstring contract scans attribute lines only when they
start with '#[', so a multi-line #[expect(...)] between the '///' block
and 'pub fn' hid the documentation. Move the attribute above the doc
comment; attribute order has no semantic effect. #502 fixes the checker.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@seonghobae

Copy link
Copy Markdown
Contributor Author

Restack on protected main (a243f18) + docstring-contract repair

  • Non-force merge of origin/main (merge commit b4b0efb1); the only conflict was the CHANGELOG.md append, both entries kept. ADR 0030 already carries an admitted maturity value (active-PR).
  • scripts/check_docstrings.py failed on this branch before the restack (event_intelligence_artifact.rs:239: public item lacks /// rustdoc): the function is documented, but a multi-line #[expect(clippy::missing_panics_doc, …)] between the /// block and pub fn hides it from the checker. Moved the attribute above the doc comment (no semantic change). The checker itself is fixed in fix(quality): keep rustdoc attached across multi-line attributes #502.

Local evidence on the pushed head (toolchain 1.98.0): cargo test -p analysis_engine 40 passed / 0 failed, clippy -D warnings clean, cargo fmt --all --check clean, documentation/workspace/docstring contracts PASS, git diff --check clean.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant