Skip to content

MCP: preserve EC2 runtime and publisher identity - #23

Open
huronat wants to merge 8 commits into
mainfrom
fix/ec2-mcp-runtime
Open

MCP: preserve EC2 runtime and publisher identity#23
huronat wants to merge 8 commits into
mainfrom
fix/ec2-mcp-runtime

Conversation

@huronat

@huronat huronat commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • persist the resolved init machine identity and reuse it in login-time tracker
    units
  • make synty_status report the explicit MCP server bucket when no workstation
    config exists
  • resolve explicitly captured local-only repositories without requiring a Git
    remote
  • keep installed config, cursors, corpus, upload ledger, and logs under one
    persistent $HOME/.synty/ state directory
  • stamp canonical repository metadata at the edge so remote Athena trace
    reconstruction preserves repo attribution
  • keep Athena reconstruction fixtures inside the production lookback window
    and matching physical partition day

Why

Live EC2 onboarding activated the requested machine marker but originally
rendered the watcher with machine local; bucket-backed MCP status also
reported local state. After correcting those, a real publisher test exposed two
more runtime gaps: a no-remote sie-harness checkout failed the upload
allowlist, and installed path resolution created nested state or moved the
corpus off the persistent volume. Finally, the uploaded trace was queryable by
machine but not by repository because the canonical edge attribution was not
carried in the immutable session metadata.

These changes make the machine marker, stream, upload policy, persisted state,
MCP status, and remote trace identity agree without rewriting existing S3
objects.

Validation

  • cargo test — 309 passed
  • cargo test --features s3,gcs,mcp-http,athena — 330 passed
  • CodeRabbit's machine round-trip and Athena partition-day findings are covered
    by scenario tests and marked addressed
  • Rust 1.97 S3-enabled release build installed on the EC2 workstation
  • active systemd unit verifies:
    • WorkingDirectory=/home/ec2-user
    • --out .synty/corpus/local
    • --machine sie-dev-cuda-rust
    • the exact S3 bucket
  • live publisher recovered and uploaded 70 EC2 Codex events as two immutable
    chunks (80,564 and 36,335 bytes), with exact day/object partition metadata
  • bounded read-only Athena MCP query returned two completed synty_status
    spans from edge-sie-dev-cuda-rust-codex
  • a follow-up immutable session carries repo: sie-harness; no existing raw S3
    object was rewritten

Summary by CodeRabbit

  • New Features
    • Persist machine identity during setup and reuse it for login-time tracking, activation/event stream naming, and installed autostart behavior.
    • Repository canonicalization now stamps SESSION_START with the resolved repo, enabling remote/edge attribution.
    • MCP status and UI status can reflect the configured bucket when no local config is present.
  • Documentation
    • Updated README and design docs with the new machine persistence and onboarding/local-to-bucket ramp details.
  • Bug Fixes
    • Prevented activation/event streams from silently falling back to local-only identity.
    • Upload gating and remote traces now correctly honor explicitly provided/allowlisted repos without requiring a Git remote.

huronat added 2 commits July 30, 2026 15:46
Persist the resolved machine id and reuse it when init renders login-time tracking, keeping activation and edge stream names identical. Report the explicit server bucket from synty_status even when a supervised MCP pod has no workstation config. The default 304-scenario suite and the 325-scenario cloud/HTTP/Athena matrix pass.
Generate the fake raw events relative to the scenario start so the seven-day production guard does not make the test expire with wall-clock time. The complete 325-scenario S3, GCS, HTTP MCP, and Athena matrix passes.
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Initialization now resolves and persists machine identities for autostart and stream alignment. Installed services keep state under $HOME/.synty/, local repository allowlisting handles remote-less repositories, MCP status uses the configured bucket, and Athena reconstruction tests use dynamic timestamps.

Changes

Runtime identity and state consistency

Layer / File(s) Summary
Persisted machine identity and autostart wiring
src/config.rs, src/init.rs, src/track.rs, README.md, docs/design.md
Resolved machine IDs are persisted in configuration, propagated to autostart, selected with explicit/configured/local precedence, and documented for stream and activation naming.
Installed service working directory
src/track.rs, src/main.rs, README.md
Installed tracking and home resolution use $HOME as the working directory while retaining state under $HOME/.synty/.
Repository stamping and remote trace attribution
src/track.rs, src/sync.rs, src/trace.rs, README.md
Session events record canonical repositories, upload allowlisting includes captured local repositories, and trace folding preserves edge-stamped repository metadata.
Bucket-aware status reporting
src/view.rs, src/mcp.rs
synty_status passes the server bucket to status_for_bucket, which falls back to configuration when no runtime bucket is supplied.
Dynamic Athena reconstruction timestamps
src/trace_athena.rs
The reconstruction test creates timestamps and partition-day values at runtime and uses the generated start timestamp for filtering.

Sequence Diagram(s)

sequenceDiagram
  participant InitRun
  participant Config
  participant Autostart
  participant Unit
  InitRun->>Config: persist resolved machine
  InitRun->>Autostart: enable with resolved machine
  Autostart->>Unit: write machine-scoped unit
Loading
sequenceDiagram
  participant MCPClient
  participant Server
  participant StatusView
  participant Config
  MCPClient->>Server: call synty_status
  Server->>StatusView: pass configured bucket
  StatusView->>Config: load fallback bucket
  StatusView-->>Server: return Status
  Server-->>MCPClient: return health output
Loading

Possibly related PRs

Suggested reviewers: svonava

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and matches the PR’s main themes of preserving MCP runtime identity and publisher/tracker identity.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ec2-mcp-runtime

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/config.rs`:
- Around line 37-40: Add a scenario-style unit test in the existing #[cfg(test)]
block covering config save/load round-tripping with machine set and confirming
the value is preserved, plus deserialization of a legacy config without machine
yielding None. Reuse the existing config construction and save/load helpers
rather than testing serialization in isolation.

In `@src/trace_athena.rs`:
- Around line 1140-1145: Update the fixture setup around the timestamp variables
so the `days` partition value is derived from the original `DateTime<Utc>`
`started` value, before it is converted to RFC3339. Replace the hard-coded
`2026-07-22` value near the fixture row with that matching date while preserving
the generated `started`, `called`, and `completed` timestamps.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 92904ab4-4c0a-4ffe-9747-b8eb72900adc

📥 Commits

Reviewing files that changed from the base of the PR and between 1299a78 and 6933a47.

📒 Files selected for processing (8)
  • README.md
  • docs/design.md
  • src/config.rs
  • src/init.rs
  • src/mcp.rs
  • src/trace_athena.rs
  • src/track.rs
  • src/view.rs

Comment thread src/config.rs
Comment thread src/trace_athena.rs
huronat added 4 commits July 30, 2026 16:06
Treat capture_repos as repository identity input as well as upload policy. This lets a local-only checkout such as sie-harness pass the fail-closed upload boundary from its cwd without requiring a Git remote, while unlisted local sessions remain denied.
Run installed launchd and systemd trackers from the user's home because every persistent path already includes .synty. This keeps config, cursors, corpus, uploads, and logs in one state directory instead of silently creating .synty/.synty.
Exercise the same path-backed save and load helpers used by runtime configuration. The scenario verifies that a resolved machine survives a round trip and that a pre-machine config still deserializes with no identity.
Keep the raw-row reconstruction scenario's physical day aligned with its runtime-generated timestamp. The fixture now remains partition-consistent across calendar boundaries instead of depending on a historical hard-coded date.
huronat added 2 commits July 30, 2026 16:26
Stamp the canonical repository into session starts while the edge checkout and capture policy are available, then consume that metadata during remote reconstruction. This keeps repo-filtered Athena traces usable for local-only repositories without weakening the unknown-session upload boundary.
Render relative tracker output below .synty when the managed service runs from the user's home, while preserving repository-local corpus paths in development checkouts. This keeps the installed corpus on the persistent state volume without reintroducing nested config paths.
@huronat huronat changed the title MCP: preserve runtime bucket and tracker identity MCP: preserve EC2 runtime and publisher identity Jul 30, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/trace.rs`:
- Around line 485-492: Update the repository assignment in fold_context so the
top-level ev.payload["repo"] value is accepted only when processing the trusted
session-start event; otherwise leave ctx.repo available for the cwd-based or
later session-start fallback. Add a scenario covering a non-session event
containing repo and verify it does not establish authoritative session context.

In `@src/track.rs`:
- Around line 647-653: Update unit_output_for to accept explicit installed-mode
state instead of inferring it from cwd == home, and use that state when deciding
whether to prepend .synty/. Update all callers, including the related flow
around the additional referenced lines, and add a scenario-style unit test
covering a development checkout rooted at $HOME where relative --out
corpus/local remains unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9a318d81-5982-41e7-8694-01654d94b9c4

📥 Commits

Reviewing files that changed from the base of the PR and between 60f5dee and de490ea.

📒 Files selected for processing (3)
  • README.md
  • src/trace.rs
  • src/track.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • README.md

Comment thread src/trace.rs
Comment on lines +485 to +492
if ctx.repo.is_empty() {
ctx.repo = ev.payload["repo"].as_str().unwrap_or("").to_string();
}
if let Some(cwd) = event_cwd(&ev.payload).filter(|cwd| !cwd.is_empty()) {
if ctx.cwd.is_empty() {
ctx.repo = crate::units::resolve_repo(&cwd, known);
if ctx.repo.is_empty() {
ctx.repo = crate::units::resolve_repo(&cwd, known);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Only accept repository stamps from the trusted session-start event.

fold_context runs for every event, so any event with a top-level repo field can become authoritative session context. In a bounded remote trace where session_start is absent or arrives later, this can misattribute the session and all downstream spans/units, while also preventing the cwd or later session-start fallback from correcting it. Gate this assignment on the trusted session-start event (and add a scenario covering a non-session event with repo).

Suggested fix
-        if ctx.repo.is_empty() {
+        if ev.kind == "session_start" && ctx.repo.is_empty() {
             ctx.repo = ev.payload["repo"].as_str().unwrap_or("").to_string();
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ctx.repo.is_empty() {
ctx.repo = ev.payload["repo"].as_str().unwrap_or("").to_string();
}
if let Some(cwd) = event_cwd(&ev.payload).filter(|cwd| !cwd.is_empty()) {
if ctx.cwd.is_empty() {
ctx.repo = crate::units::resolve_repo(&cwd, known);
if ctx.repo.is_empty() {
ctx.repo = crate::units::resolve_repo(&cwd, known);
}
if ctx.repo.is_empty() {
ctx.repo = ev.payload["repo"].as_str().unwrap_or("").to_string();
}
if let Some(cwd) = event_cwd(&ev.payload).filter(|cwd| !cwd.is_empty()) {
if ctx.cwd.is_empty() {
if ctx.repo.is_empty() {
ctx.repo = crate::units::resolve_repo(&cwd, known);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/trace.rs` around lines 485 - 492, Update the repository assignment in
fold_context so the top-level ev.payload["repo"] value is accepted only when
processing the trusted session-start event; otherwise leave ctx.repo available
for the cwd-based or later session-start fallback. Add a scenario covering a
non-session event containing repo and verify it does not establish authoritative
session context.

Comment thread src/track.rs
Comment on lines +647 to +653
fn unit_output_for(cwd: &Path, home: &Path, out: &str) -> String {
let path = Path::new(out);
if path.is_absolute() || out.starts_with(".synty/") || cwd != home {
out.to_string()
} else {
format!(".synty/{out}")
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not infer installed mode from cwd == $HOME.

A development checkout rooted at $HOME also satisfies this condition, so a relative --out corpus/local is rewritten to .synty/corpus/local instead of remaining repository-local. Pass explicit installed-mode state into this helper and add a $HOME-rooted checkout scenario.

As per coding guidelines, every behavioral change must include a scenario-style unit test written from user expectations.

Also applies to: 1089-1114

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/track.rs` around lines 647 - 653, Update unit_output_for to accept
explicit installed-mode state instead of inferring it from cwd == home, and use
that state when deciding whether to prepend .synty/. Update all callers,
including the related flow around the additional referenced lines, and add a
scenario-style unit test covering a development checkout rooted at $HOME where
relative --out corpus/local remains unchanged.

Source: Coding guidelines

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