Skip to content

feat(digest): PR-39 workspace-primitives digest runtime (relayfile slice)#162

Closed
khaliqgant wants to merge 8 commits into
mainfrom
digest-tightening
Closed

feat(digest): PR-39 workspace-primitives digest runtime (relayfile slice)#162
khaliqgant wants to merge 8 commits into
mainfrom
digest-tightening

Conversation

@khaliqgant
Copy link
Copy Markdown
Member

@khaliqgant khaliqgant commented May 16, 2026

Summary

The relayfile-owned slice of docs/workspace-primitives-pr39-gap-spec.md. Implements the local/self-host digest runtime, CLI rebuild, mount exposure, and SDK taxonomy. Verified end-to-end locally (built CLI, exercised all 5 windows, full Go suite green).

Delivered (relayfile scope)

  • Work Item B — digest runtime: today, yesterday, YYYY-MM-DD, this-week, last-week window builders; workspace-timezone support (ResolveTZ, DST boundaries); immutable closing windows; exhaustive coverage (no 500-cap; cap retained only for back-compat); golden fixtures per window.
  • CLI rebuild: relayfile digest rebuild --window today|yesterday|this-week|last-week|YYYY-MM-DD [--workspace] [--json] — was a stub, now real; reports regenerated path + event count (spec acceptance check).
  • Work Item C: by-edited/<date>/ alias segment in mountfuse layout + mountsync.
  • Work Item D: relayfile writeback list --state pending|dead|succeeded|failed.
  • Work Item E / A: LAYOUT.md canonicalized across runtime/fixtures/skill contract (legacy .layout.md compat retained); digest runtime contract rule (.claude/rules/relayfile-integration-digests.md + CLAUDE.md).

Verification

  • go build ./... clean
  • go test ./... — all packages green (75+ digest tests: immutability, tz/DST, exhaustive/over-cap, header contract)
  • relayfile digest rebuild exercised for all 5 windows (path + event count reported)
  • pytest packages/sdk/python 9 passed · scripts/check-contract-surface.sh passed

Out of scope (NOT in this PR)

The spec is 3-repo. This PR is the relayfile slice only. cloud (hosted digest scheduler, adapter digest() invocation, hosted timezone, materialize /.skills/activity-summary.md) and relayfile-adapters (provider digest handler conformance, adapter-side by-edited) are not implemented here — tracked as follow-up runs scoped to those repos.

Note on branch contents

digest-tightening also carries two pre-existing, unrelated commits that were on the branch before this work: ba9c28c fix(mount): avoid false low-memory pending state and c93ea56 fix(mount): add low-memory sync diagnostics. Flagging for reviewer awareness — split out if you'd rather they land separately.

🤖 Generated with Claude Code

Merge conflict resolution

  • Merged origin/main into digest-tightening to resolve the dirty PR state.
  • Resolved internal/mountsync/syncer.go by keeping the digest close scheduler / rolling digest coalescer setup from this PR and the provider-layout observed alias handling, while retaining the current main polling and release changes.
  • Verified after the merge with go test ./internal/mountsync and go test ./... using Go 1.22.12.

Initiative Context

Proactive Runtime Bot and others added 5 commits May 14, 2026 13:08
Implements the digest/activity-summary gaps from
docs/workspace-primitives-pr39-gap-spec.md:

- internal/digest: date-stamped (YYYY-MM-DD), this-week, last-week,
  today, yesterday window builders with workspace-timezone support and
  golden fixtures.
- cmd/relayfile-cli: `relayfile digest rebuild --window ...` real
  implementation (was a stub) plus tests.
- internal/mountfuse: virtual LAYOUT.md / digest exposure in the FUSE
  layer.
- internal/mountsync: digest scheduler, digest-source event filtering
  (no recursion on /digests/* writes), digest writer + watcher tests.
- packages/sdk/python: expanded digest path taxonomy.
- .claude/rules/relayfile-integration-digests.md: digest runtime
  contract rule.
- docs/workspace-primitives-pr39-gap-spec.md: the gap spec this
  implements, with resolved decisions.

Generated by a Ricky master-executor run (12 child slices); only the
product source/tests/spec are committed here. Runtime digest output
(digests/*.md), ricky scratch (.workflow-artifacts/, workflows/generated/,
internal/digest/cmd/ demos, mount-verify/), and trail bookkeeping are
intentionally excluded.

Verified: go build ./... clean; go test ./internal/digest
./internal/mountfuse ./internal/mountsync ./cmd/relayfile-cli all pass;
pytest packages/sdk/python 9 passed; scripts/check-contract-surface.sh
passed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
trail compact --discard-sources for the workspace-primitives PR-39
master run: the two completed source trajectories are removed and
index.json updated to the compacted record. No source trajectory is
still referenced by the index.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 48f17d2c-fee8-4237-aa48-13367f73ed53

📥 Commits

Reviewing files that changed from the base of the PR and between b5f6fe3 and 7daf412.

📒 Files selected for processing (2)
  • cmd/relayfile-cli/main.go
  • internal/mountsync/syncer.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/mountsync/syncer.go

📝 Walkthrough

Walkthrough

Adds complete digest runtime: timezone-aware windows (today/yesterday/this-week/last-week/date-stamped), idempotent/atomic writers and markers, anti-recursion path filtering, rolling coalescer and close scheduler, CLI rebuilder wiring, provider-layout and SDK updates, extensive tests and fixtures, and documentation/spec additions.

Changes

Digest & Scheduling

Layer / File(s) Summary
Core digest types, timezone, and helpers
internal/digest/types.go, internal/digest/digest.go, internal/digest/timezone.go
Adds Window.Closing, RunClosing, timezone resolution (ResolveTZ, WorkspaceTZConfig, ErrInvalidTimezone) and compatibility constants for warnings/caps.
Today (rolling) digest
internal/digest/today.go, internal/digest/today_test.go
Implements timezone-aware today window, event filtering, MaxEvents truncation/warnings, Render/WriteToday atomic writes and comprehensive DST/boundary tests.
Yesterday (closed-day) digest
internal/digest/yesterday.go, internal/digest/yesterday_test.go
Implements closing-window yesterday writer with .relay/digests/yesterday.lock marker, idempotent/atomic writes, CloseLocalDay/CloseLocalDayFor, and extensive immutability/rotation tests.
Date-stamped closed-day digests
internal/digest/date_stamped.go, internal/digest/digest_test.go
Adds immutable digests/YYYY-MM-DD.md rendering/writing with O_EXCL semantics, MaybeCloseDateStampedWindow, and tests for immutability, rotation, and body equivalence.
This-week & Last-week digests
internal/digest/this_week.go, internal/digest/last_week.go, internal/digest/this_week_test.go, internal/digest/last_week_test.go
Implements rolling this-week and closing last-week windows, filtering, atomic writes, closing-day gating, and golden/unit tests.
Scheduler & coalescer
internal/mountsync/scheduler.go, internal/mountsync/scheduler_test.go
Adds tick-based CloseScheduler to catch up missed local days and RollingDigestCoalescer to debounce rolling digest regeneration, plus tests for timing, MaxDelay, and catch-up behavior.

Mountsync / Syncer Integration

Layer / File(s) Summary
Syncer integration and job wiring
internal/mountsync/syncer.go, internal/mountsync/syncer_test.go
Adds digest config fields to SyncerOptions, initializes CloseScheduler and RollingDigestCoalescer, runs closing/rolling digest jobs during reconcile, and adds low-memory public state handling and tests.
Watcher and writer tests (no recursion)
internal/mountsync/watcher_test.go, internal/mountsync/digest_writer_test.go, internal/mountsync/digest_filter_test.go
Tests asserting digest paths emit normal FS events but are excluded from regeneration sources, writers do not expose internal temp files, and yesterday/date-stamped writes produce watcher-visible events without recursion.

CLI: rebuilder and workspace timezone

Layer / File(s) Summary
CLI rebuilder & local implementation
cmd/relayfile-cli/digest.go, cmd/relayfile-cli/digest_test.go, cmd/relayfile-cli/main.go
Extends relayfile digest rebuild with this-week/last-week/YYYY-MM-DD windows, --json output, deterministic Now injection, real localDigestRebuilder, workspace Timezone persistence, and timezone-aware tests.

Provider layout and FUSE

Layer / File(s) Summary
Provider layout canonicalization and aliasing
internal/mountfuse/layout.go, internal/mountfuse/fs.go, internal/mountfuse/layout_test.go, internal/mountfuse/fuse_test.go
Canonical LAYOUT.md with legacy .layout.md compatibility, adds by-edited alias, derives manifests from remote trees, adjusts virtual layout serving and related tests/fixtures.
FUSE listing/metadata wiring
internal/mountfuse/fs.go, internal/mountfuse/fuse_test.go
Switches to context-aware provider manifest generation and synthesizes legacy provider layout filename alongside canonical one; tests ensure parity and alias resolution.

Python SDK & docs

Layer / File(s) Summary
Python SDK digest helpers & tests
packages/sdk/python/src/relayfile/provider.py, packages/sdk/python/src/relayfile/__init__.py, packages/sdk/python/tests/test_provider.py, packages/sdk/python/README.md
Expands DIGEST_PATHS, adds DATE_STAMPED_DIGEST_PATH_PATTERN and is_digest_path() with validation logic, re-exports symbols, updates tests and README examples.
Agent & workspace spec docs
.claude/rules/relayfile-integration-digests.md, AGENTS.md, docs/workspace-primitives-pr39-gap-spec.md
Adds Digest Runtime Contract and cross-repo workspace primitives spec documenting required runtime behaviors, immutability, anti-recursion rules, and SDK/OpenAPI sync requirements.

Tests & Fixtures

Layer / File(s) Summary
Test fixtures and data
internal/digest/testdata/*, numerous *_test.go files across digest/mountsync/mountfuse
Adds or updates golden fixtures (today/this-week/last-week/date-stamped), JSONL event sets, and comprehensive unit/integration tests covering boundaries, determinism, immutability, and scheduler/coalescer behavior.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as relayfile CLI
  participant Rebuilder as localDigestRebuilder
  participant Digest as internal/digest
  participant FS as MountedFS (watcher)
  participant Syncer as mountsync Syncer
  CLI->>Rebuilder: Rebuild(window, tz, now)
  Rebuilder->>Digest: Render/Write for cover (today/yesterday/this-week/last-week/date-stamped)
  Digest->>FS: atomic rename/write digests/* (emit file events)
  FS->>Syncer: watcher emits file events
  Syncer->>Digest: runClosing/runRolling jobs (Tick/ObserveChange)
Loading

Estimated code review effort:
🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs:

"I nibbled at clocks and paths tonight,
stitched timezones by the moon's pale light.
Digests safe, no recursive fright—
a little rabbit cheered, files sleeping tight. 🐇✨"

✨ 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 digest-tightening

# Conflicts:
#	internal/mountsync/syncer.go
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 16, 2026

Relayfile Eval Review

Run: .relayfile/evals/runs/2026-05-18T19-43-11-538Z-HEAD-provider
Mode: provider
Git SHA: 4858c73

Passed: 4 | Needs human: 0 | Reviewable: 0 | Missing output: 0 | Failed: 0 | Skipped: 0

Human Review Cases

No reviewable human-review cases captured Relayfile output.

Copy link
Copy Markdown
Contributor

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

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 7 additional findings in Devin Review.

Open in Devin Review

Comment thread internal/mountsync/scheduler.go Outdated
Comment on lines +60 to +61
c.pending = true
c.dueAt = now.Add(interval)
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.

🔴 RollingDigestCoalescer starves under sustained changes — dueAt resets on every ObserveChange

Every call to ObserveChange unconditionally resets c.dueAt = now.Add(interval) (internal/mountsync/scheduler.go:61). If provider changes arrive more frequently than the 30-second interval, the deadline is perpetually pushed forward and Due() never returns true. This means runRollingDigestJobsLocked at internal/mountsync/syncer.go:1482 always sees !s.rollingCoalescer.Due() and skips the rolling digest write, so today.md and this-week.md are never regenerated under sustained load.

The spec (docs/workspace-primitives-pr39-gap-spec.md:93-94) says "Rolling windows rebuild on every relevant change, coalesced to at most once per 30 seconds", meaning at most 30 seconds of delay — not indefinite starvation. The fix should track the timestamp of the first un-flushed change and fire when that exceeds the interval, rather than resetting the deadline on every new change.

Starvation scenario under continuous 10-second changes
  • t=0s: change → dueAt=30s
  • t=10s: change → dueAt=40s
  • t=20s: change → dueAt=50s
  • t=30s: SyncOnce runs, Due() checks 30 >= 50 → false, skip
  • t=30s: change → dueAt=60s
  • … repeats indefinitely, digest never written
Prompt for agents
In RollingDigestCoalescer.ObserveChange (internal/mountsync/scheduler.go), the line `c.dueAt = now.Add(interval)` resets the deadline on every change, causing indefinite starvation under sustained load. The fix is to only set dueAt when transitioning from non-pending to pending (i.e. the first change after a flush). When already pending, a new change should NOT push dueAt forward.

Concretely: add a guard like `if !c.pending { c.dueAt = now.Add(interval) }` before `c.pending = true`. This way the deadline is anchored to the first un-flushed change, and Due() will fire interval seconds after that first change regardless of how many subsequent changes arrive. The existing test TestCoalescer_30s only tests a single change; add a test with rapid repeated ObserveChange calls to prove the coalescer fires after the interval even under sustained load.
Open in Devin Review

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (2)
.trajectories/index.json (1)

239-1357: 💤 Low value

Consider investigating the batch creation of abandoned trajectories.

Over 100 abandoned trajectories were created within a 70-second window on 2026-05-13 (19:30:20 to 19:31:22), each with a lifespan of 1-2 seconds. All follow the pattern "ricky-child-update-*-workflow". This suggests an automated process may have spawned many short-lived child trajectories that were quickly abandoned.

While this doesn't break functionality, it adds significant noise to the trajectory index and may indicate an issue with the trajectory creation logic or a batch operation that encountered repeated failures.

🤖 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 @.trajectories/index.json around lines 239 - 1357, Many short-lived
"ricky-child-update-*-workflow" trajectories were created and abandoned in a
tight batch, so locate the trajectory creation site(s) (look for
functions/methods named createTrajectory, spawnChildTrajectory,
TrajectoryManager.create or WorkflowRunner.spawnChild) and add protections:
rate-limit/debounce rapid successive calls, check for existing active
trajectories with the same title/tag before creating a new one (dedupe), and
implement retry/backoff plus clearer logging/error propagation so failures don't
trigger repeated immediate child creations and automatic abandonment.
docs/workspace-primitives-pr39-gap-spec.md (1)

315-318: 💤 Low value

Consider clarifying the adapter digest handler design decision.

Lines 100-104 note that adapters currently have digest handlers, line 109 identifies cloud invocation as a gap, and this section decides not to implement cloud invocation but instead remove the handler requirement. While internally consistent, the rationale for this design pivot could be more explicit.

Optional clarification

Consider adding a brief sentence explaining why generic cloud rendering is preferred over adapter-specific handlers, such as:

- Keep digest rendering generic over workspace events in `cloud`; do not
  require adapter `digest()` handlers to own provider-specific bullet
  rendering. Remove the unused adapter-handler expectation from the skill
  contracts and adapter docs accordingly.
+ Keep digest rendering generic over workspace events in `cloud` to avoid
  adapter-specific implementation overhead and maintain consistent digest
  output format across providers; do not require adapter `digest()` handlers
  to own provider-specific bullet rendering. Remove the unused adapter-handler
  expectation from the skill contracts and adapter docs accordingly.
🤖 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 `@docs/workspace-primitives-pr39-gap-spec.md` around lines 315 - 318, The docs
currently remove the adapter digest() handler requirement and avoid cloud
invocation but don't explain why; update the paragraph around the decision
(where you mention cloud and removing the adapter-handler expectation from skill
contracts and adapter docs) to add one concise sentence that states the
rationale: prefer a generic cloud-level rendering of workspace events to keep
provider-specific presentation out of adapter digest() handlers, maintain
separation of concerns, reduce duplication across adapters, and simplify
evolving cloud rendering logic. Ensure the added sentence references digest(),
cloud, and the removed adapter-handler expectation so readers can quickly map
the rationale to the changed contracts and adapter docs.
🤖 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 @.trajectories/index.json:
- Line 243: Update the "path" values in .trajectories/index.json so they use
relative paths instead of absolute ones: replace occurrences starting with
"/Users/khaliqgant/Projects/AgentWorkforce/relayfile/.trajectories/active/" with
".trajectories/active/" for each affected entry (the JSON "path" field),
ensuring all new entries match the existing relative format used elsewhere in
the file.

In `@cmd/relayfile-cli/digest.go`:
- Around line 173-176: The rebuild branches currently ignore errors from
os.Remove (used with localDir and paths built from digestpkg.YesterdayPath,
digestpkg.YesterdayMarkerPath and digestpkg.DateStampedPath(closedDay, tz)),
which can mask permission/IO failures and leave stale artifacts; update those
calls to capture the returned error, and on failure either return or propagate
an explicit error (e.g., wrap with fmt.Errorf or use processLogger/Errorf and
return) so the rebuild path fails fast instead of silently continuing — do this
for all similar removals (the blocks that call os.Remove for YesterdayPath,
YesterdayMarkerPath and DateStampedPath).

In `@internal/digest/date_stamped.go`:
- Around line 130-145: Replace the current direct O_EXCL create-then-write flow
with a temp-file-then-atomic-publish pattern: create a temp file in the same
directory (e.g. localPath+".tmp"+random), write the content to that temp file,
call f.Sync() and then f.Close(); then attempt to atomically publish the temp
file to the final path by creating a hard link (os.Link(tempPath, localPath))
which will fail if localPath already exists (treat that as Written:false), and
finally remove the temp file; on any error ensure temp is removed and return the
appropriate error. Update the code around the existing localPath, f.Write,
f.Close logic and return values (DateStampedWriteResult, Path, Report, Written)
accordingly so partial writes cannot leave a truncated immutable file.

In `@internal/digest/yesterday_test.go`:
- Around line 278-292: The test builds laterEvents but still calls
WriteYesterday with the original events; update the second WriteYesterday
invocation to pass the modified slice (use SliceSource{Items: laterEvents}) so
the immutability case actually exercises a later-day event being present; make
no other logic changes—keep root, w, and error/assert checks the same.

In `@internal/digest/yesterday.go`:
- Around line 151-157: The current early-return when
readYesterdayMarker(mountRoot) == localDateStr and os.ReadFile(localPath) fails
can hard-fail on a stale marker; change the logic in the w.Closing branch so
that after attempting existing, if os.ReadFile returns an error you check
errors.Is(readErr, os.ErrNotExist) and treat that as a stale marker (i.e., do
not return YesterdayWriteResult{} error but fall through to the normal
render/write flow), while still returning an error for any other readErr; locate
the block referencing w.Closing, readYesterdayMarker, localDateStr,
os.ReadFile(localPath) and YesterdayWriteResult and implement the conditional
handling.

In `@internal/mountfuse/layout.go`:
- Around line 282-343: The providerLayoutManifest path repeatedly rescans via
deriveProviderLayoutManifest; add a memoization cache on fsState (e.g.
map[string]cachedEntry plus sync.Mutex) to store derived manifests keyed by
provider with a TTL and timestamp, check the cache in providerLayoutManifest
before calling deriveProviderLayoutManifest, and update the cache inside
deriveProviderLayoutManifest (or immediately after a successful derive) so
subsequent calls return the cached LayoutManifest until TTL expiry; ensure
thread-safety around reads/writes to the cache and provide a simple invalidation
strategy (TTL or explicit clear) for when configuration or remoteRoot changes.
- Line 138: Update the filename guidance string in the b.WriteString call (in
internal/mountfuse/layout.go) to replace the misleading `<uuid>` token with a
generic `<id>` token so it reads `<identifier>__<id>.json`; keep the rest of the
sentence about recovering the provider id from the last `__`-separated segment
unchanged.
- Around line 177-179: The helper function legacyProviderLayoutRemotePath is
dead code and should be removed to satisfy static analysis; delete the
legacyProviderLayoutRemotePath function from internal/mountfuse/layout.go (it
currently calls joinRemotePath and references legacyProviderLayoutFilename), or
if it was intended to be used, replace its callers to use
legacyProviderLayoutRemotePath instead of duplicating joinRemotePath calls so
the symbol is referenced.

In `@internal/mountsync/syncer.go`:
- Around line 884-886: HandleLocalChange currently calls
s.rollingCoalescer.ObserveChange(relativePath) without holding s.mu while other
code (lines reading/resetting pending/dueAt) accesses that same coalescer state
under s.mu, causing a race; fix by acquiring the same sync lock (s.mu) around
the mutation: wrap the call to rollingCoalescer.ObserveChange in the critical
section (or otherwise ensure s.mu is held) and only access/modify
rollingCoalescer.pending and rollingCoalescer.dueAt while holding s.mu so all
reads and writes to the coalescer state are consistently protected.

---

Nitpick comments:
In @.trajectories/index.json:
- Around line 239-1357: Many short-lived "ricky-child-update-*-workflow"
trajectories were created and abandoned in a tight batch, so locate the
trajectory creation site(s) (look for functions/methods named createTrajectory,
spawnChildTrajectory, TrajectoryManager.create or WorkflowRunner.spawnChild) and
add protections: rate-limit/debounce rapid successive calls, check for existing
active trajectories with the same title/tag before creating a new one (dedupe),
and implement retry/backoff plus clearer logging/error propagation so failures
don't trigger repeated immediate child creations and automatic abandonment.

In `@docs/workspace-primitives-pr39-gap-spec.md`:
- Around line 315-318: The docs currently remove the adapter digest() handler
requirement and avoid cloud invocation but don't explain why; update the
paragraph around the decision (where you mention cloud and removing the
adapter-handler expectation from skill contracts and adapter docs) to add one
concise sentence that states the rationale: prefer a generic cloud-level
rendering of workspace events to keep provider-specific presentation out of
adapter digest() handlers, maintain separation of concerns, reduce duplication
across adapters, and simplify evolving cloud rendering logic. Ensure the added
sentence references digest(), cloud, and the removed adapter-handler expectation
so readers can quickly map the rationale to the changed contracts and adapter
docs.
🪄 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: b0b75613-1979-4afb-b88c-6f4947e85f9e

📥 Commits

Reviewing files that changed from the base of the PR and between 55126cb and 85d5878.

📒 Files selected for processing (49)
  • .claude/rules/relayfile-integration-digests.md
  • .trajectories/completed/2026-05/traj_nxbsptr6c5q0.json
  • .trajectories/completed/2026-05/traj_nxbsptr6c5q0.md
  • .trajectories/completed/2026-05/traj_nxbsptr6c5q0.trace.json
  • .trajectories/completed/2026-05/traj_qrt7hh3ht8nk.json
  • .trajectories/completed/2026-05/traj_qrt7hh3ht8nk.md
  • .trajectories/index.json
  • AGENTS.md
  • cmd/relayfile-cli/digest.go
  • cmd/relayfile-cli/digest_test.go
  • cmd/relayfile-cli/main.go
  • cmd/relayfile-mount/main.go
  • docs/workspace-primitives-pr39-gap-spec.md
  • internal/digest/date_stamped.go
  • internal/digest/digest.go
  • internal/digest/digest_test.go
  • internal/digest/last_week.go
  • internal/digest/last_week_test.go
  • internal/digest/testdata/date-stamped-fixture.md
  • internal/digest/testdata/last-week-events.jsonl
  • internal/digest/testdata/last-week-fixture.md
  • internal/digest/testdata/this-week-fixture.md
  • internal/digest/testdata/today-fixture.md
  • internal/digest/this_week.go
  • internal/digest/this_week_test.go
  • internal/digest/timezone.go
  • internal/digest/timezone_test.go
  • internal/digest/today.go
  • internal/digest/today_test.go
  • internal/digest/types.go
  • internal/digest/yesterday.go
  • internal/digest/yesterday_test.go
  • internal/mountfuse/fs.go
  • internal/mountfuse/fuse_test.go
  • internal/mountfuse/layout.go
  • internal/mountfuse/layout_test.go
  • internal/mountsync/digest_filter_test.go
  • internal/mountsync/digest_writer_test.go
  • internal/mountsync/scheduler.go
  • internal/mountsync/scheduler_test.go
  • internal/mountsync/syncer.go
  • internal/mountsync/syncer_test.go
  • internal/mountsync/watcher_test.go
  • packages/sdk/python/README.md
  • packages/sdk/python/src/relayfile/__init__.py
  • packages/sdk/python/src/relayfile/client.py
  • packages/sdk/python/src/relayfile/provider.py
  • packages/sdk/python/src/relayfile/types.py
  • packages/sdk/python/tests/test_provider.py
💤 Files with no reviewable changes (5)
  • .trajectories/completed/2026-05/traj_nxbsptr6c5q0.md
  • .trajectories/completed/2026-05/traj_qrt7hh3ht8nk.md
  • .trajectories/completed/2026-05/traj_nxbsptr6c5q0.json
  • .trajectories/completed/2026-05/traj_qrt7hh3ht8nk.json
  • .trajectories/completed/2026-05/traj_nxbsptr6c5q0.trace.json

Comment thread .trajectories/index.json Outdated
Comment thread cmd/relayfile-cli/digest.go Outdated
Comment on lines +130 to +145
f, err := os.OpenFile(localPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o644)
if errors.Is(err, os.ErrExist) {
return DateStampedWriteResult{Path: path, Report: rep, Written: false}, nil
}
if err != nil {
return DateStampedWriteResult{}, err
}
if _, err := f.Write(content); err != nil {
_ = f.Close()
_ = os.Remove(localPath)
return DateStampedWriteResult{}, err
}
if err := f.Close(); err != nil {
_ = os.Remove(localPath)
return DateStampedWriteResult{}, err
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify current write strategy in WriteDateStamped (direct final-path O_EXCL write).
rg -n -A35 -B10 'func WriteDateStamped|O_EXCL|CreateTemp|Rename|Link' internal/digest/date_stamped.go

Repository: AgentWorkforce/relayfile

Length of output: 3194


🏁 Script executed:

# Check for callers of WriteDateStamped and MaybeCloseDateStampedWindow
rg -n 'WriteDateStamped|MaybeCloseDateStampedWindow' --type go -B2 -A2 | grep -E '(func|WriteDateStamped|MaybeCloseDateStampedWindow)' | head -50

Repository: AgentWorkforce/relayfile

Length of output: 3753


🏁 Script executed:

# Verify if Sync() is called anywhere in the file
rg -n 'Sync|sync|fsync' internal/digest/date_stamped.go

Repository: AgentWorkforce/relayfile

Length of output: 145


🏁 Script executed:

# Check the full file structure to see if there's any surrounding context
wc -l internal/digest/date_stamped.go

Repository: AgentWorkforce/relayfile

Length of output: 104


Use atomic file creation (temp+rename) instead of direct write with O_EXCL.

Process crash between f.Write() (line 137) and f.Close() (line 142) leaves a truncated file on disk. Because the file then exists, the O_EXCL check at line 131 prevents repair—subsequent runs skip creation, leaving a corrupted digest permanent. This is especially risky given the scheduler calls this function in a clock-driven loop (scheduler.go:127).

Write to a temporary file, fsync it, then atomically move it to the final path only if the target does not exist. This ensures partial writes never become the immutable artifact.

🤖 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 `@internal/digest/date_stamped.go` around lines 130 - 145, Replace the current
direct O_EXCL create-then-write flow with a temp-file-then-atomic-publish
pattern: create a temp file in the same directory (e.g.
localPath+".tmp"+random), write the content to that temp file, call f.Sync() and
then f.Close(); then attempt to atomically publish the temp file to the final
path by creating a hard link (os.Link(tempPath, localPath)) which will fail if
localPath already exists (treat that as Written:false), and finally remove the
temp file; on any error ensure temp is removed and return the appropriate error.
Update the code around the existing localPath, f.Write, f.Close logic and return
values (DateStampedWriteResult, Path, Report, Written) accordingly so partial
writes cannot leave a truncated immutable file.

Comment thread internal/digest/yesterday_test.go
Comment thread internal/digest/yesterday.go
Comment thread internal/mountfuse/layout.go Outdated
Comment thread internal/mountfuse/layout.go Outdated
Comment on lines +282 to +343
func (s *fsState) providerLayoutManifest(ctx context.Context, provider string) LayoutManifest {
provider = strings.TrimSpace(provider)
if manifest, ok := s.configuredLayoutManifest(provider); ok {
return manifest
}
manifest, err := s.deriveProviderLayoutManifest(ctx, provider)
if err != nil {
s.logf("derive provider layout for %s: %v", provider, err)
return LayoutManifest{Provider: provider}
}
return manifest
}

func (s *fsState) deriveProviderLayoutManifest(ctx context.Context, provider string) (LayoutManifest, error) {
manifest := LayoutManifest{
Provider: strings.TrimSpace(provider),
LazyMaterialization: s.lazyRepos != nil && strings.TrimSpace(provider) == "github",
}
if manifest.Provider == "" || s.client == nil {
return manifest, nil
}

resources := map[string]struct{}{}
aliases := map[string]struct{}{}
providerRoot := joinRemotePath(s.remoteRoot, manifest.Provider)
cursor := ""
for {
resp, err := s.client.ListTree(ctx, s.workspaceID, providerRoot, providerLayoutDeriveDepth, cursor)
if err != nil {
return manifest, err
}
for _, entry := range resp.Entries {
rel, ok := relativeToRemoteRoot(providerRoot, entry.Path)
if !ok || rel == "" {
continue
}
segments := providerLayoutPathSegments(rel)
if len(segments) == 0 {
continue
}
if providerLayoutResourceSegment(segments[0]) != "" && (len(segments) > 1 || isTreeDirectory(entry.Type)) {
resources[segments[0]] = struct{}{}
}
for _, segment := range segments[1:] {
if isProviderLayoutAliasSegment(segment) {
aliases[segment] = struct{}{}
}
}
}
if resp.NextCursor == nil || strings.TrimSpace(*resp.NextCursor) == "" {
break
}
cursor = strings.TrimSpace(*resp.NextCursor)
}

for resource := range resources {
manifest.ResourceDirectories = append(manifest.ResourceDirectories, resource)
}
for alias := range aliases {
manifest.AliasSegments = append(manifest.AliasSegments, alias)
}
return normalizeLayoutManifest(manifest), nil
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Cache derived provider manifests instead of rescanning on every access.

For providers without injected manifests, this path re-runs ListTree derivation each time providerLayoutManifest is called. Since layout metadata/content lookups call into this repeatedly, /provider/LAYOUT.md reads can trigger repeated depth-4 tree scans and transiently inconsistent output under backend flakiness.

Please memoize derived manifests (with invalidation/TTL) so provider layout reads are cheap and stable.

🤖 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 `@internal/mountfuse/layout.go` around lines 282 - 343, The
providerLayoutManifest path repeatedly rescans via deriveProviderLayoutManifest;
add a memoization cache on fsState (e.g. map[string]cachedEntry plus sync.Mutex)
to store derived manifests keyed by provider with a TTL and timestamp, check the
cache in providerLayoutManifest before calling deriveProviderLayoutManifest, and
update the cache inside deriveProviderLayoutManifest (or immediately after a
successful derive) so subsequent calls return the cached LayoutManifest until
TTL expiry; ensure thread-safety around reads/writes to the cache and provide a
simple invalidation strategy (TTL or explicit clear) for when configuration or
remoteRoot changes.

Comment thread internal/mountsync/syncer.go
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

7 issues found across 49 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/mountsync/scheduler.go">

<violation number="1" location="internal/mountsync/scheduler.go:61">
P2: Debounce without a max-delay cap can starve rolling digest regeneration indefinitely. If filesystem events arrive faster than the 30s interval, `dueAt` is perpetually pushed forward and `Due()` never returns `true`. Consider tracking the time of the first un-flushed event and capping the maximum delay (e.g., 5 minutes) so digests remain current under sustained write pressure.</violation>
</file>

<file name="internal/digest/timezone.go">

<violation number="1" location="internal/digest/timezone.go:28">
P2: The original error from `time.LoadLocation` is discarded. Include it in the wrapped error so callers can distinguish between an unknown zone name and a missing tzdata file.</violation>
</file>

<file name=".trajectories/index.json">

<violation number="1" location=".trajectories/index.json:243">
P2: All new trajectory entries use absolute local paths (`/Users/khaliqgant/Projects/...`) instead of the relative paths (`.trajectories/...`) used by every existing entry. These machine-specific paths will break on any other developer's machine or in CI and violate the established convention in this file.</violation>
</file>

<file name="internal/digest/today.go">

<violation number="1" location="internal/digest/today.go:160">
P2: The temp file is renamed into place without setting file permissions. `os.CreateTemp` creates files with mode 0600. The codebase convention (see `writeFileAtomic` in mountsync) is to `Chmod(0o644)` before rename so digest artifacts are readable by other processes. Consider adding `tmp.Chmod(0o644)` before `tmp.Close()`.</violation>
</file>

<file name="internal/digest/yesterday_test.go">

<violation number="1" location="internal/digest/yesterday_test.go:162">
P2: `laterEvents` is constructed but never used. The second `WriteYesterday` call passes the original `events` instead of `laterEvents`, so this test doesn't actually verify immutability when later-day events are present in the source — it just re-tests the byte-equal idempotency path. If the intent is to test that the writer is resilient to a source containing events outside the closed day, pass `laterEvents` here.</violation>
</file>

<file name="internal/mountsync/syncer.go">

<violation number="1" location="internal/mountsync/syncer.go:884">
P1: Data race: `ObserveChange` is called without holding `s.mu`, while `Due()` and `MarkFlushed()` are called under `s.mu`. Since `RollingDigestCoalescer` has no internal synchronization, concurrent access to `c.pending` and `c.dueAt` is a data race. Move the `ObserveChange` call below the `s.mu.Lock()` to use the syncer's existing mutex as the synchronization point.</violation>
</file>

<file name="cmd/relayfile-cli/digest.go">

<violation number="1" location="cmd/relayfile-cli/digest.go:252">
P2: The `digests` directory is not skipped with `filepath.SkipDir` in the walk, unlike in `collectDigestProviders`. The walker descends into `digests/` and checks each file individually via `IsDigestPath`. Add `"digests"` to the directory skip switch to avoid traversing accumulated digest files unnecessarily.</violation>
</file>

Tip: instead of fixing issues one by one fix them all with cubic
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic

Comment thread internal/mountsync/syncer.go
Comment thread internal/mountsync/scheduler.go Outdated
Comment thread internal/digest/timezone.go Outdated
Comment thread .trajectories/index.json
Comment thread internal/digest/today.go
Comment thread internal/digest/yesterday_test.go
Comment thread cmd/relayfile-cli/digest.go Outdated
…obustness

- CRITICAL data race: RollingDigestCoalescer.ObserveChange ran before
  s.mu.Lock() while Due()/MarkFlushed() run under s.mu. Moved under the
  lock; documented the single-sync-point contract. `go test -race` clean.
- MAJOR coalescer starvation: debounce reset dueAt every change so it
  never fired under sustained sub-interval churn. Added MaxDelay cap
  (default 5*interval) anchored at firstPendingAt + regression test.
- MAJOR portability: 204 absolute .trajectories paths normalized to
  relative to match the existing convention.
- today.go/this_week.go: Chmod 0644 before rename (CreateTemp is 0600)
  so digests are readable by mount/agents.
- timezone.go: wrap original LoadLocation error.
- yesterday.go: stale-marker robustness — regenerate on ErrNotExist
  instead of wedging the close pipeline.
- yesterday_test.go: pass laterEvents so the test actually exercises
  marker-pinned immutability against a contaminated source.
- cmd digest rebuild: removeForRebuild surfaces non-ErrNotExist delete
  failures so a stale marker can't make a forced rebuild a silent no-op.
- digest.go Events walk: SkipDir on digests/.
- mountfuse/layout.go: `<id>` wording; removed dead helper.

go build/vet/test ./... green; -race clean; contract + pytest pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
Copy link
Copy Markdown
Member Author

Addressed the review in b5f6fe3. Verified: go build/vet/test ./... green, go test -race ./internal/mountsync clean, contract check + pytest pass.

Fixed

  • CRITICAL data race (CodeRabbit/cubic): RollingDigestCoalescer.ObserveChange moved under s.mu — it mutated pending/dueAt that Due()/MarkFlushed() read under the lock. Documented the single-sync-point contract.
  • MAJOR coalescer starvation (Devin/cubic): added MaxDelay cap (default 5×interval) anchored at firstPendingAt, so sustained sub-interval churn can't defer today.md/this-week.md regeneration forever. New regression test TestCoalescer_MaxDelayPreventsStarvation.
  • MAJOR trajectory portability (CodeRabbit/cubic): 204 absolute /Users/.../relayfile/.trajectories paths normalized to relative.
  • today.go + this_week.go perms (cubic): Chmod 0644 before rename — os.CreateTemp is 0600; this is exactly why the earlier today.md was 0600. (yesterday/last_week already did this; this_week had the same bug, fixed for consistency.)
  • timezone.go (cubic): wrap the original LoadLocation error.
  • yesterday.go stale-marker (CodeRabbit): regenerate on ErrNotExist instead of hard-failing and wedging the close pipeline; other read errors still surface.
  • yesterday_test.go (CodeRabbit/cubic): pass laterEvents so the test verifies marker-pinned immutability against a contaminated source, not just byte-idempotency.
  • digest rebuild delete errors (CodeRabbit): removeForRebuild surfaces non-ErrNotExist failures so a surviving marker can't make a forced rebuild a silent stale no-op.
  • digest.go Events walk (cubic): SkipDir on digests/, consistent with collectDigestProviders.
  • layout.go (CodeRabbit): <identifier>__<id> wording; removed dead legacyProviderLayoutRemotePath.

Deferred, with reasoning (per "skip with a brief reason, keep changes minimal")

  • Memoize derived provider manifests (layout.go:282-343, CodeRabbit "heavy lift"): pure perf optimization. A cache here introduces stale-layout correctness risk without careful TTL/invalidation tied to backend sync state — out of scope for this PR and riskier than the read cost it saves. Tracked as a follow-up.
  • date_stamped.go temp+rename atomicity (CodeRabbit "heavy lift"): the O_CREATE|O_EXCL direct write is intentional — it's what gives the closed-window immutability / no-op-on-repeat semantics the digest rule requires (a second close for the same date fails O_EXCL and is skipped). The only exposure is a crash mid-write of a single closed-window file; the next close is then a no-op on the partial file. Converting to temp+rename while preserving the exclusive-create immutability guarantee is a non-trivial redesign; flagging as a known, narrow tradeoff rather than rushing it under this PR.

Reconciles PR #162 (digest runtime) with the mount-root clobber
hardening that landed on main (#163 clawpatch findings, #164
defense-in-depth, #165 structural mount-root invariants).

Only conflict was internal/mountsync/syncer.go — disjoint struct
additions: union of #162's `closeScheduler`/`rollingCoalescer` (digest
scheduler + coalescer) and main's `circuit *CloudErrorCircuit`
(cloud-error breaker), plus the matching constructor initializers. No
behavioral overlap.

Verified: go build ./... clean; go test ./... all green;
go test -race ./internal/mountsync clean (the #162 ObserveChange data-
race fix holds with main's mount-root hardening present);
scripts/check-contract-surface.sh passed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@khaliqgant
Copy link
Copy Markdown
Member Author

Status update — all inline review comments were already addressed.

The CodeRabbit/cubic/Devin inline threads above were posted before commit b5f6fe3 ("fix(digest): address PR #162 review …", 2026-05-16T10:10Z) and were never marked resolved, so they re-surface as "unresolved." Every one is fixed in b5f6fe3 and verified still intact after merging latest main (7daf412):

  • ✅ Critical data race — ObserveChange now runs under s.mu (verified: lock precedes the call in HandleLocalChange).
  • ✅ Coalescer starvation — MaxDelay/firstPendingAt cap added; go test -race ./internal/mountsync clean.
  • ✅ Trajectory absolute paths normalized to relative (0 absolute remaining).
  • digest.go rebuild delete errors → removeForRebuild; digests/ SkipDir added.
  • yesterday.go stale-marker → regenerate on ErrNotExist.
  • yesterday_test.go now passes laterEvents.
  • timezone.go wraps the original LoadLocation error (both sites).
  • today.go/this_week.go Chmod(0o644) before rename.
  • layout.go <id> wording + dead legacyProviderLayoutRemotePath removed.

Two heavy-lift items remain intentionally deferred with rationale (documented earlier in this PR): date_stamped.go O_EXCL→temp+rename (the exclusive-create is the closed-window immutability mechanism) and layout.go manifest memoization (perf-only, stale-cache risk without careful invalidation).

Branch is now merged current with main (the #163/#164/#165 mount-root clobber hardening — single syncer.go struct-field union, no behavioral overlap). Full re-verification on the merged HEAD: go build ./... clean, go test ./... all green, -race clean, scripts/check-contract-surface.sh passed. Ready for human review.

khaliqgant pushed a commit that referenced this pull request May 19, 2026
…obustness

- CRITICAL data race: RollingDigestCoalescer.ObserveChange ran before
  s.mu.Lock() while Due()/MarkFlushed() run under s.mu. Moved under the
  lock; documented the single-sync-point contract. `go test -race` clean.
- MAJOR coalescer starvation: debounce reset dueAt every change so it
  never fired under sustained sub-interval churn. Added MaxDelay cap
  (default 5*interval) anchored at firstPendingAt + regression test.
- MAJOR portability: 204 absolute .trajectories paths normalized to
  relative to match the existing convention.
- today.go/this_week.go: Chmod 0644 before rename (CreateTemp is 0600)
  so digests are readable by mount/agents.
- timezone.go: wrap original LoadLocation error.
- yesterday.go: stale-marker robustness — regenerate on ErrNotExist
  instead of wedging the close pipeline.
- yesterday_test.go: pass laterEvents so the test actually exercises
  marker-pinned immutability against a contaminated source.
- cmd digest rebuild: removeForRebuild surfaces non-ErrNotExist delete
  failures so a stale marker can't make a forced rebuild a silent no-op.
- digest.go Events walk: SkipDir on digests/.
- mountfuse/layout.go: `<id>` wording; removed dead helper.

go build/vet/test ./... green; -race clean; contract + pytest pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

# Conflicts:
#	.trajectories/index.json
#	internal/mountsync/syncer.go
@khaliqgant
Copy link
Copy Markdown
Member Author

Superseded by #167. The digest runtime/rules/docs/SDK pieces from this PR have been reconciled into the updated #167 branch, now based on latest main and combined with the cleaned local primitive work.

khaliqgant added a commit that referenced this pull request May 19, 2026
…167)

* feat(workspace): apply cleaned PR-39 local primitives

* feat(digest): PR-39 workspace-primitives digest runtime

Implements the digest/activity-summary gaps from
docs/workspace-primitives-pr39-gap-spec.md:

- internal/digest: date-stamped (YYYY-MM-DD), this-week, last-week,
  today, yesterday window builders with workspace-timezone support and
  golden fixtures.
- cmd/relayfile-cli: `relayfile digest rebuild --window ...` real
  implementation (was a stub) plus tests.
- internal/mountfuse: virtual LAYOUT.md / digest exposure in the FUSE
  layer.
- internal/mountsync: digest scheduler, digest-source event filtering
  (no recursion on /digests/* writes), digest writer + watcher tests.
- packages/sdk/python: expanded digest path taxonomy.
- .claude/rules/relayfile-integration-digests.md: digest runtime
  contract rule.
- docs/workspace-primitives-pr39-gap-spec.md: the gap spec this
  implements, with resolved decisions.

Generated by a Ricky master-executor run (12 child slices); only the
product source/tests/spec are committed here. Runtime digest output
(digests/*.md), ricky scratch (.workflow-artifacts/, workflows/generated/,
internal/digest/cmd/ demos, mount-verify/), and trail bookkeeping are
intentionally excluded.

Verified: go build ./... clean; go test ./internal/digest
./internal/mountfuse ./internal/mountsync ./cmd/relayfile-cli all pass;
pytest packages/sdk/python 9 passed; scripts/check-contract-surface.sh
passed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

# Conflicts:
#	cmd/relayfile-cli/digest.go
#	cmd/relayfile-cli/digest_test.go
#	cmd/relayfile-cli/main.go
#	internal/mountsync/syncer.go

* fix(digest): address PR #162 review — data race, starvation, perms, robustness

- CRITICAL data race: RollingDigestCoalescer.ObserveChange ran before
  s.mu.Lock() while Due()/MarkFlushed() run under s.mu. Moved under the
  lock; documented the single-sync-point contract. `go test -race` clean.
- MAJOR coalescer starvation: debounce reset dueAt every change so it
  never fired under sustained sub-interval churn. Added MaxDelay cap
  (default 5*interval) anchored at firstPendingAt + regression test.
- MAJOR portability: 204 absolute .trajectories paths normalized to
  relative to match the existing convention.
- today.go/this_week.go: Chmod 0644 before rename (CreateTemp is 0600)
  so digests are readable by mount/agents.
- timezone.go: wrap original LoadLocation error.
- yesterday.go: stale-marker robustness — regenerate on ErrNotExist
  instead of wedging the close pipeline.
- yesterday_test.go: pass laterEvents so the test actually exercises
  marker-pinned immutability against a contaminated source.
- cmd digest rebuild: removeForRebuild surfaces non-ErrNotExist delete
  failures so a stale marker can't make a forced rebuild a silent no-op.
- digest.go Events walk: SkipDir on digests/.
- mountfuse/layout.go: `<id>` wording; removed dead helper.

go build/vet/test ./... green; -race clean; contract + pytest pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

# Conflicts:
#	.trajectories/index.json
#	internal/mountsync/syncer.go

---------

Co-authored-by: Proactive Runtime Bot <agent@agent-relay.com>
@khaliqgant
Copy link
Copy Markdown
Member Author

Closing as superseded by merged #167. The digest runtime/rules/docs/SDK pieces from this PR were reconciled into #167 before it merged.

@khaliqgant khaliqgant closed this May 19, 2026
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