Skip to content

Add v19 timeline intents, readings, and drafts#729

Merged
flyingrobots merged 19 commits into
mainfrom
v19-api-receipts-drafts
Jul 10, 2026
Merged

Add v19 timeline intents, readings, and drafts#729
flyingrobots merged 19 commits into
mainfrom
v19-api-receipts-drafts

Conversation

@flyingrobots

Copy link
Copy Markdown
Member

Summary

This PR lands the v19 first-use timeline facade slices after the v19 openWarp closeout audit:

  • Adds root intent builders, runtime-backed Intent, Timeline.write(intent), and WriteReceipt.
  • Adds root reading builders, runtime-backed Reading, Timeline.read(reading), ReadReceipt, and ReadingResult.
  • Adds public boundary tests and compile-only consumer fixtures for root, storage, advanced, diagnostics, and legacy surfaces.
  • Updates README, v19 API rationale, migration docs, changelog, and the source-backed reference generator/output.
  • Adds DraftTimeline, Timeline.draft(name), Timeline.previewJoin(draft), and Timeline.join(draft) with join receipts. Draft writes are backed by strand overlays; joins replay the recorded public intents into the live timeline.

Issue Coverage

Closes #713.
Closes #723.
Closes #725.
Closes #724.
Closes #714.
Part of #712.

Validation

  • npm run lint
  • npm run typecheck
  • npm run typecheck:consumer
  • npm run lint:source-backed-reference
  • npm run lint:md
  • npx vitest run test/unit/domain/WarpFacade.test.ts
  • git diff --check
  • Pre-push IRONCLAD M9 firewall:
    • link check
    • static gates 1-8
    • npm run test:local stable unit shards

Notes

npm run test:local initially refused to start with 83 MiB free memory and a 512 MiB guard. The pre-push hook reran once memory recovered and completed all stable unit shards successfully.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added v19 first-use APIs for intent/reading, with timeline write/read receipts and ReceiptOutcome/reading result outcomes.
    • Introduced DraftTimeline flows (create, write intents, preview-join, join) with structured JoinReceipt/JoinResult.
    • Broadened public root exports and added explicit API subpaths for storage/advanced/diagnostics; deprecated the prior graph-first legacy path for new usage.
  • Bug Fixes
    • Tightened runtime validation and receipt outcome branching guidance across write/read/join/draft.
  • Documentation
    • Updated README, v19 first-use and migration docs, and regenerated the API reference export surfaces.
  • Tests / Chores
    • Expanded type-check/unit coverage and improved markdown link checking to include fragments.

Walkthrough

This PR introduces v19 first-use intent, reading, receipt, draft, and join APIs, wires them through Timeline and WarpWorldline, expands explicit export surfaces, updates documentation and generated references, and adds consumer, boundary, runtime, and link-check validation.

Changes

v19 First-Use API

Layer / File(s) Summary
Intent model and write lowering
src/domain/api/Intent.ts, src/domain/api/IntentBuilders.ts, src/domain/api/IntentRuntime.ts
Adds immutable intent builders and lowers supported intents into patch operations.
Reading model and resolution
src/domain/api/Reading.ts, src/domain/api/ReadingBuilders.ts, src/domain/api/ReadingResult.ts, src/domain/api/ReadingRuntime.ts, src/domain/api/ReadReceipt.ts
Adds bounded reading builders, validated results, and runtime reads for properties and node existence.
Receipt and result contracts
src/domain/api/WriteReceipt.ts, src/domain/api/JoinReceipt.ts, src/domain/api/JoinResult.ts
Adds validated immutable write, read, and join receipt/result types with separate outcome axes.
Timeline operations
src/domain/api/Timeline.ts, src/domain/api/TimelineRuntime.ts
Adds runtime-backed write, read, draft, preview, and deterministic join operations with input and port validation.
Draft timelines and joins
src/domain/api/DraftTimeline.ts, src/domain/api/DraftTimelineRuntime.ts, src/domain/WarpWorldline.ts
Adds draft creation, intent accumulation, preview materialization, sequential joining, partial-failure tracking, and worldline draft ports.
Public exports and reference surfaces
index.ts, docs/topics/reference.md, scripts/check-source-backed-reference.ts
Expands root exports and generates separate root, storage, advanced, diagnostics, and legacy inventories.
Documentation
CHANGELOG.md, README.md, docs/migrations/v19/README.md, docs/topics/api/README.md
Updates first-use examples, receipt handling, migration guidance, and public-versus-advanced API descriptions.
Validation
test/type-check/*, test/unit/domain/*
Adds consumer type fixtures and tests for export boundaries, writes, reads, drafts, joins, receipts, and failed joins.
Fragment-aware link checking
.github/workflows/*, .lychee.toml, package.json, scripts/hooks/pre-push, test/unit/scripts/pre-push-hook.test.ts
Passes Lychee fragment checking explicitly through CI, package scripts, and the pre-push hook.

Estimated code review effort: 4 (Complex) | ~75 minutes

Possibly related issues

Possibly related PRs

Poem

A rabbit writes intents with care,
Reads timelines through open air.
Receipts hop in, stamped and bright,
Drafts preview joins just right.
🐇 V19 bounds the legacy night.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.10% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main v19 intent, reading, and draft API additions.
Description check ✅ Passed The description covers summary, issue links, validation, and ADR notes, so it is mostly complete despite nonstandard headings.
Linked Issues check ✅ Passed The changes implement the requested v19 intents, readings, drafts, receipts, docs, tests, and boundary coverage for #713, #723, #724, #725, and #714.
Out of Scope Changes check ✅ Passed No clear unrelated feature work stands out; the workflow, link-check, and reference-generator edits support the docs and validation changes.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Release Preflight

  • package version: 18.2.1
  • prerelease: false
  • npm dist-tag on release: latest
  • npm pack dry-run: passed
  • jsr publish dry-run: passed

If this PR is from a release/* branch and merges to main, Main Push Release Branch Check will run final preflight and create v18.2.1. A maintainer who is a JSR @git-stunts scope member must then dispatch the Release workflow manually.

@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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/check-source-backed-reference.ts (1)

211-270: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider naming the per-surface SourceText instances for consistency.

Other sources (packageSource, jsrSource, registrySource, cliSource, errorSource) are assigned to named consts before use, but the five new export-surface sources are constructed inline inside exportSurface(...) calls. Purely stylistic, but slightly inconsistent within the same function.

🤖 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 `@scripts/check-source-backed-reference.ts` around lines 211 - 270, The
export-surface SourceText instances are created inline in generate(), unlike the
other named sources, which makes the style inconsistent. Introduce named consts
for each surface source used by exportSurface (for example the ones passed for
root, storage, advanced, diagnostics, and legacy) and then pass those variables
into exportSurface so the source declarations match the pattern used by
packageSource, jsrSource, registrySource, cliSource, and errorSource.
🤖 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/domain/api/IntentRuntime.ts`:
- Around line 26-72: The six lowerer functions in IntentRuntime all repeat the
same kind-mismatch guard and WarpError logic. Extract that shared check into a
single helper near
lowerNodeAdd/lowerNodeRemove/lowerEdgeAdd/lowerEdgeRemove/lowerPropertySet/lowerEdgePropertySet,
then have each lowerer call it before delegating to PatchBuilder. Keep the
existing E_INTENT_KIND error behavior unchanged while removing the duplicated if
blocks.

In `@src/domain/api/JoinReceipt.ts`:
- Line 7: The receipt outcome type in JoinReceipt is duplicating the literal
list from WriteReceipt and can drift over time. Update JoinReceipt to import and
reuse the shared RECEIPT_OUTCOMES definition from WriteReceipt rather than
redefining the outcome union, so both JoinReceiptOutcome and ReceiptOutcome stay
in sync automatically.

In `@src/domain/api/Timeline.ts`:
- Around line 105-123: `Timeline.read()` and `Timeline.write()` validate their
inputs inline, unlike `draft()`, `previewJoin()`, and `join()` which use shared
assertion helpers. Extract matching helpers such as `assertReadingInstance()`
and `assertIntentInstance()` in `Timeline` and have `read()`/`write()` call them
so validation follows the same consistent pattern as `assertDraftTimeline()`.
- Around line 150-166: The port-validation helpers in Timeline are duplicated
across assertJoinDraft, assertOpenDraft, assertReadReading, and
assertWriteIntent, all doing the same undefined-or-function check with only
message/code differences. Refactor these into a single generic validator helper
in the same module, then have each of those functions call it with their
specific error text and WarpError code so the existing behavior and symbols
remain unchanged.

In `@src/domain/api/WriteReceipt.ts`:
- Around line 5-27: Export RECEIPT_OUTCOMES from WriteReceipt so other modules
like JoinReceipt can reuse the same canonical outcome list instead of
duplicating it. Update the declaration of RECEIPT_OUTCOMES in WriteReceipt to be
exported, and keep its contents unchanged so both validators stay in sync.

In `@test/unit/domain/WarpFacade.test.ts`:
- Around line 45-58: The browser export fence in FORBIDDEN_BROWSER_V19_EXPORTS
is missing the new speculative-workflow exports, so update the list to include
DraftTimeline, JoinReceipt, and JoinResult. Keep the change in the
WarpFacade.test.ts fixture where the existing forbidden browser exports are
defined so the browser root is still validated against the full v19 facade
surface.

---

Outside diff comments:
In `@scripts/check-source-backed-reference.ts`:
- Around line 211-270: The export-surface SourceText instances are created
inline in generate(), unlike the other named sources, which makes the style
inconsistent. Introduce named consts for each surface source used by
exportSurface (for example the ones passed for root, storage, advanced,
diagnostics, and legacy) and then pass those variables into exportSurface so the
source declarations match the pattern used by packageSource, jsrSource,
registrySource, cliSource, and errorSource.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: e9a194e0-7ff1-4bdb-80c1-ba127dbd2206

📥 Commits

Reviewing files that changed from the base of the PR and between 65963d7 and ed6697f.

📒 Files selected for processing (28)
  • CHANGELOG.md
  • README.md
  • docs/migrations/v19/README.md
  • docs/topics/api/README.md
  • docs/topics/reference.md
  • index.ts
  • scripts/check-source-backed-reference.ts
  • src/domain/WarpWorldline.ts
  • src/domain/api/DraftTimeline.ts
  • src/domain/api/DraftTimelineRuntime.ts
  • src/domain/api/Intent.ts
  • src/domain/api/IntentBuilders.ts
  • src/domain/api/IntentRuntime.ts
  • src/domain/api/JoinReceipt.ts
  • src/domain/api/JoinResult.ts
  • src/domain/api/ReadReceipt.ts
  • src/domain/api/Reading.ts
  • src/domain/api/ReadingBuilders.ts
  • src/domain/api/ReadingResult.ts
  • src/domain/api/ReadingRuntime.ts
  • src/domain/api/Timeline.ts
  • src/domain/api/TimelineRuntime.ts
  • src/domain/api/WriteReceipt.ts
  • test/type-check/tsconfig.json
  • test/type-check/v19-consumer.ts
  • test/type-check/v19-first-use.ts
  • test/type-check/v19-subpaths.ts
  • test/unit/domain/WarpFacade.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: coverage-threshold
  • GitHub Check: test-node (22)
  • GitHub Check: preflight
⚠️ CI failures not shown inline (2)

GitHub Actions: Link Check / Check broken links: Add v19 timeline intents, readings, and drafts

Conclusion: failure

View job details

##[group]Run /home/runner/work/_actions/lycheeverse/lychee-action/v2/entrypoint.sh
 �[36;1m/home/runner/work/_actions/lycheeverse/lychee-action/v2/entrypoint.sh�[0m
 shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
 env:
   INPUT_***REDACTED***
   INPUT_ARGS: --config .lychee.toml '**/*.md'
   INPUT_DEBUG: false
   INPUT_FAIL: true
   INPUT_FAILIFEMPTY: true
   INPUT_FORMAT: markdown
   INPUT_JOBSUMMARY: true
   INPUT_CHECKBOX: true
   INPUT_OUTPUT: ./lychee-report.md
   SUMMARY_URL: https://github.com/git-stunts/git-warp/actions/runs/29029891504#summary-86159505233
 ##[endgroup]
  [ERROR] Error while loading config: Cannot load configuration file `.lychee.toml`: Failed to load config from .lychee.toml
 Caused by:
     0: Failed to parse configuration file
     1: TOML parse error at line 15, column 21
           |
        15 | include_fragments = true
           |                     ^^^^
        wanted string or table
 See: https://github.com/lycheeverse/lychee/blob/lychee-v0.24.2/lychee.example.toml
 ##[notice]Summary report available at: https://github.com/git-stunts/git-warp/actions/runs/29029891504#summary-86159505233
 ##[error]Process completed with exit code 3.

GitHub Actions: Link Check / 0_Check broken links.txt: Add v19 timeline intents, readings, and drafts

Conclusion: failure

View job details

##[group]Run /home/runner/work/_actions/lycheeverse/lychee-action/v2/entrypoint.sh
 �[36;1m/home/runner/work/_actions/lycheeverse/lychee-action/v2/entrypoint.sh�[0m
 shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
 env:
   INPUT_***REDACTED***
   INPUT_ARGS: --config .lychee.toml '**/*.md'
   INPUT_DEBUG: false
   INPUT_FAIL: true
   INPUT_FAILIFEMPTY: true
   INPUT_FORMAT: markdown
   INPUT_JOBSUMMARY: true
   INPUT_CHECKBOX: true
   INPUT_OUTPUT: ./lychee-report.md
   SUMMARY_URL: https://github.com/git-stunts/git-warp/actions/runs/29029891504#summary-86159505233
 ##[endgroup]
  [ERROR] Error while loading config: Cannot load configuration file `.lychee.toml`: Failed to load config from .lychee.toml
 Caused by:
     0: Failed to parse configuration file
     1: TOML parse error at line 15, column 21
           |
        15 | include_fragments = true
           |                     ^^^^
        wanted string or table
 See: https://github.com/lycheeverse/lychee/blob/lychee-v0.24.2/lychee.example.toml
 ##[notice]Summary report available at: https://github.com/git-stunts/git-warp/actions/runs/29029891504#summary-86159505233
 ##[error]Process completed with exit code 3.
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Do not use direct imports from src/infrastructure/** in src/domain/** or src/ports/**; depend on a port instead.
Do not use direct Node built-ins in src/domain/** or src/ports/**; use a port instead.

Files:

  • test/type-check/v19-first-use.ts
  • src/domain/api/JoinResult.ts
  • test/type-check/v19-subpaths.ts
  • src/domain/api/IntentBuilders.ts
  • src/domain/api/ReadReceipt.ts
  • src/domain/api/WriteReceipt.ts
  • test/type-check/v19-consumer.ts
  • src/domain/api/ReadingBuilders.ts
  • src/domain/api/JoinReceipt.ts
  • src/domain/api/ReadingRuntime.ts
  • src/domain/api/TimelineRuntime.ts
  • test/unit/domain/WarpFacade.test.ts
  • src/domain/api/Reading.ts
  • src/domain/api/IntentRuntime.ts
  • src/domain/api/Intent.ts
  • src/domain/api/DraftTimeline.ts
  • src/domain/api/DraftTimelineRuntime.ts
  • src/domain/api/ReadingResult.ts
  • index.ts
  • src/domain/api/Timeline.ts
  • scripts/check-source-backed-reference.ts
  • src/domain/WarpWorldline.ts
src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx,js,jsx}: Do not introduce any, as any, as unknown as, unknown (outside adapters), Record<string, unknown> (outside adapters), *Like placeholder types, JSON.parse/JSON.stringify (outside adapters), fetch (outside adapters), process.env (outside adapters), @ts-ignore, or z.any() in core code; use validated boundary models and ports instead.
Use constructor-injected ports for external capabilities; do not rely on ambient dependencies for I/O, clocks, persistence, or entropy.
Do not create utils.ts, helpers.ts, misc.ts, or common.ts; name files after the actual concept they model.
Prefer one file per class, type, or object; if a file accumulates peer concepts, split it.
Keep helper corridors, fake shape trust, transitional duplication, and compile-time theater out of the codebase; runtime-honest TypeScript must reflect actual behavior.
No enum usage; prefer runtime-backed domain forms and unions.
Do not use boolean trap parameters; prefer named option objects or separate methods.
Avoid magic strings or numbers when a named constant should exist.
Keep domain bytes as Uint8Array; Buffer belongs in infrastructure adapters.

Files:

  • src/domain/api/JoinResult.ts
  • src/domain/api/IntentBuilders.ts
  • src/domain/api/ReadReceipt.ts
  • src/domain/api/WriteReceipt.ts
  • src/domain/api/ReadingBuilders.ts
  • src/domain/api/JoinReceipt.ts
  • src/domain/api/ReadingRuntime.ts
  • src/domain/api/TimelineRuntime.ts
  • src/domain/api/Reading.ts
  • src/domain/api/IntentRuntime.ts
  • src/domain/api/Intent.ts
  • src/domain/api/DraftTimeline.ts
  • src/domain/api/DraftTimelineRuntime.ts
  • src/domain/api/ReadingResult.ts
  • src/domain/api/Timeline.ts
  • src/domain/WarpWorldline.ts
src/domain/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/domain/**/*.{ts,tsx,js,jsx}: In src/domain/**, do not use Date.now(), new Date(), Date(), performance.now(), Math.random(), crypto.randomUUID(), crypto.getRandomValues(), setTimeout, setInterval, raw new Error(...)/new TypeError(...), or direct imports from Node built-ins; time, entropy, and external capabilities must enter through ports or parameters, and domain errors should extend WarpError.
Construct domain objects only in core when doing so establishes validated runtime truth; do not build infrastructure adapters, host APIs, persistence implementations, wall clocks, or entropy sources inside core.
Prefer discriminated unions and explicit result types instead of boolean-flag bags, and model expected failures as return values rather than exceptions.
src/domain/ must not import host APIs or Node-specific globals; hexagonal architecture boundaries are mandatory.
Domain code must not use the wall clock directly; time must enter through a port or parameter.

Files:

  • src/domain/api/JoinResult.ts
  • src/domain/api/IntentBuilders.ts
  • src/domain/api/ReadReceipt.ts
  • src/domain/api/WriteReceipt.ts
  • src/domain/api/ReadingBuilders.ts
  • src/domain/api/JoinReceipt.ts
  • src/domain/api/ReadingRuntime.ts
  • src/domain/api/TimelineRuntime.ts
  • src/domain/api/Reading.ts
  • src/domain/api/IntentRuntime.ts
  • src/domain/api/Intent.ts
  • src/domain/api/DraftTimeline.ts
  • src/domain/api/DraftTimelineRuntime.ts
  • src/domain/api/ReadingResult.ts
  • src/domain/api/Timeline.ts
  • src/domain/WarpWorldline.ts
src/domain/**/!(*.test).{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use explicit domain concepts with validated constructors, Object.freeze, and instanceof dispatch; domain objects should be runtime-backed nouns, not ad hoc shape bags.

Files:

  • src/domain/api/JoinResult.ts
  • src/domain/api/IntentBuilders.ts
  • src/domain/api/ReadReceipt.ts
  • src/domain/api/WriteReceipt.ts
  • src/domain/api/ReadingBuilders.ts
  • src/domain/api/JoinReceipt.ts
  • src/domain/api/ReadingRuntime.ts
  • src/domain/api/TimelineRuntime.ts
  • src/domain/api/Reading.ts
  • src/domain/api/IntentRuntime.ts
  • src/domain/api/Intent.ts
  • src/domain/api/DraftTimeline.ts
  • src/domain/api/DraftTimelineRuntime.ts
  • src/domain/api/ReadingResult.ts
  • src/domain/api/Timeline.ts
  • src/domain/WarpWorldline.ts
🧠 Learnings (1)
📚 Learning: 2026-03-08T19:50:17.519Z
Learnt from: flyingrobots
Repo: git-stunts/git-warp PR: 65
File: CHANGELOG.md:88-88
Timestamp: 2026-03-08T19:50:17.519Z
Learning: Follow the Keep a Changelog convention for CHANGELOG.md. Allow duplicate subheadings across versions (e.g., '### Added', '### Fixed'). Configure markdownlint MD024 with {"siblings_only": true} to avoid cross-version false positives.

Applied to files:

  • CHANGELOG.md
🔇 Additional comments (34)
src/domain/api/DraftTimeline.ts (1)

1-76: LGTM!

src/domain/WarpWorldline.ts (1)

33-256: LGTM!

index.ts (1)

19-53: LGTM!

src/domain/api/DraftTimelineRuntime.ts (2)

60-75: 🎯 Functional Correctness

Check previewDraftJoin result handling previewJoin drops the runtime.previewDraftJoin(draft.name) result and hardcodes accepted; wire the runtime outcome through, or make this an explicit placeholder if conflicts and policy rejections are not meant to surface here.


77-125: 🗄️ Data Integrity & Integration

Join can replay already-applied intents after a mid-stream failure. commitDraftIntents persists each intent in its own runtime.commit(...) call, while state.joined is only set after the loop. If a later commit throws, retrying join will re-run the full intent list and can duplicate the earlier writes.

CHANGELOG.md (1)

10-36: LGTM!

README.md (1)

3-4: LGTM!

Also applies to: 55-58, 73-76, 87-89

docs/migrations/v19/README.md (1)

125-132: LGTM!

Also applies to: 252-252, 287-294, 308-309

docs/topics/reference.md (1)

29-38: LGTM!

Also applies to: 39-118, 119-157, 158-186, 187-266, 267-316, 317-495, 497-552

test/unit/domain/WarpFacade.test.ts (2)

6-43: LGTM!


269-393: LGTM!

docs/topics/api/README.md (1)

310-313: 🎯 Functional Correctness

Check the previewJoin signature here. If it only accepts draft, remove the options object.

scripts/check-source-backed-reference.ts (2)

12-17: LGTM!


131-157: 📐 Maintainability & Code Quality

Search for stale captureRootExports references
Check for any remaining script or test imports and rename them to captureExports.

test/type-check/tsconfig.json (1)

11-17: LGTM!

test/type-check/v19-consumer.ts (3)

8-26: LGTM!


43-73: LGTM! The write/read/draft/join round-trip and the three @ts-expect-error negatives (operation-name literals for both receipt outcome unions, and the dryRun boolean-trap rejection on previewJoin) correctly pin the intended public contract, and excess-property checking on the inline { dryRun: true } literal makes the third negative valid as long as JoinOptions doesn't declare dryRun.


86-93: LGTM!

test/type-check/v19-first-use.ts (1)

1-36: LGTM! Clean root-only fixture matching the first-use surface (intent, openWarp, reading plus the storage subpath adapter).

test/type-check/v19-subpaths.ts (1)

1-60: LGTM! Subpath-only imports (storage/advanced/diagnostics/legacy) correctly stay off the root surface, consistent with #714's requirement to keep Strand/Braid-adjacent and advanced terminology out of first-use.

src/domain/api/Intent.ts (1)

1-189: LGTM!

src/domain/api/IntentBuilders.ts (1)

1-41: LGTM!

src/domain/api/WriteReceipt.ts (1)

29-60: LGTM!

src/domain/api/ReadReceipt.ts (1)

1-62: LGTM!

src/domain/api/JoinResult.ts (1)

1-27: LGTM!

src/domain/api/Timeline.ts (1)

3-33: LGTM on the remaining port-wiring, join-normalization, and operation logic — the dry-run trap, deterministic policy default, and unavailable-runtime guards are all correctly implemented.

Also applies to: 42-104, 126-149, 168-196

src/domain/api/JoinReceipt.ts (1)

3-3: 🗄️ Data Integrity & Integration

Check for a circular import between JoinReceipt.ts and DraftTimeline.ts. JoinReceipt uses DraftTimeline in an instanceof check, so any back-reference from DraftTimeline or DraftTimelineRuntime to JoinReceipt/JoinResult would make module init order fragile.

src/domain/api/IntentRuntime.ts (1)

1-24: LGTM!

src/domain/api/Reading.ts (1)

1-95: LGTM!

src/domain/api/ReadingBuilders.ts (1)

1-21: LGTM!

src/domain/api/ReadingResult.ts (1)

1-136: LGTM!

src/domain/api/ReadingRuntime.ts (1)

1-62: LGTM!

src/domain/api/TimelineRuntime.ts (2)

3-22: LGTM!


23-34: 🎯 Functional Correctness

writeIntent still only emits accepted. If commit or applyIntentToPatch can produce obstructed, conflicted, underdetermined, or rejected, this path needs to map them to receipts instead of letting the promise reject.

Comment thread src/domain/api/IntentRuntime.ts
Comment thread src/domain/api/JoinReceipt.ts
Comment thread src/domain/api/Timeline.ts
Comment thread src/domain/api/Timeline.ts
Comment thread src/domain/api/WriteReceipt.ts
Comment thread test/unit/domain/WarpFacade.test.ts
@flyingrobots

Copy link
Copy Markdown
Member Author

@codex second opinion requested.

Code Lawyer self-audit findings

ID Source Severity File Lines Finding Mitigation
S1 Self P2 src/domain/api/DraftTimelineRuntime.ts 60-75 previewDraftJoin() awaits runtime.previewDraftJoin() but discards the returned patch list, so the receipt can drift from runtime materialization truth. Use the runtime-returned patch SHAs in the preview receipt.
S2 Self P1 src/domain/api/DraftTimelineRuntime.ts 77-125 joinDraftTimeline() commits draft intents one-by-one and marks joined only after the loop; a mid-loop failure allows a retry to replay already-committed intents. Track committed join patch SHAs in state and make retry return a rejected receipt instead of replaying.
S3 Self P2 .lychee.toml 15 CI lychee v0.24.2 rejects include_fragments = true; the option now expects a string/table. Change to include_fragments = "full" and verify link-check parsing.
S4 Self P5 src/domain/api/JoinReceipt.ts 50-66 validateJoinReceiptFields() body is over-indented, violating local TypeScript style. Normalize indentation while touching the receipt validator.
P1 PR P5 src/domain/api/IntentRuntime.ts 26-72 Repeated kind mismatch guard across six lowerers. Extract a shared descriptor-kind assertion.
P2 PR P5 src/domain/api/WriteReceipt.ts, src/domain/api/JoinReceipt.ts 20-27, 7-26 Join receipt duplicates the canonical receipt outcome set from write receipts. Export RECEIPT_OUTCOMES and reuse it.
P3 PR P5 src/domain/api/Timeline.ts 105-123 read() and write() inline validation instead of using assertion helpers. Add assertReadingInstance() and assertIntentInstance().
P4 PR P5 src/domain/api/Timeline.ts 150-166, 192-195 Optional port validators duplicate the same function check. Collapse them through one shared helper preserving error messages/codes.
P5 PR P3 test/unit/domain/WarpFacade.test.ts 45-58 Browser export fence omits DraftTimeline, JoinReceipt, and JoinResult. Add the new draft/join API names to the forbidden browser export fixture.
P6 PR P5 scripts/check-source-backed-reference.ts 211-270 Export-surface SourceText instances are constructed inline unlike other source inputs. Name rootSource, storageSource, advancedSource, diagnosticsSource, and legacySource.

Verified non-issues during audit:

File Comment Result
docs/topics/api/README.md Check whether previewJoin(draft, options) is valid. Valid: Timeline.previewJoin(draft, options?) is the current signature.
scripts/check-source-backed-reference.ts Check stale captureRootExports references. No stale references found with rg.
src/domain/api/JoinReceipt.ts Check circular import with DraftTimeline. No back-reference from DraftTimeline to JoinReceipt/JoinResult; no cycle found.

@flyingrobots

Copy link
Copy Markdown
Member Author

Activity Summary

@codex follow-up from the Code Lawyer cleanup pass.

ID Severity Source File(s) Commit Outcome
S2 P1 Self src/domain/api/DraftTimelineRuntime.ts, test/unit/domain/DraftTimelineRuntime.test.ts 9c9a13f9 Prevented replay after partial draft join failure; retry returns rejected receipt without re-committing.
S1 P2 Self src/domain/api/DraftTimelineRuntime.ts, test/unit/domain/DraftTimelineRuntime.test.ts d4b8ee2d Preview receipts now report runtime materialization patch SHAs.
S1a P3 Self test/unit/domain/WarpFacade.test.ts f251c55a Facade expectation aligned with runtime-sourced preview patch list.
S3 P2 Self/CI .lychee.toml 09bc8f41 Initial lychee v0.24.2 parser fix verified against pinned CI binary.
S3a P2 Self/CI .lychee.toml, package.json, scripts/hooks/pre-push, .github/workflows/*, test/unit/scripts/pre-push-hook.test.ts 12c6b134 Removed version-specific TOML fragment mode and moved fragment checking to stable CLI flag for local 0.21 + CI 0.24.2 compatibility.
P5 P3 PR test/unit/domain/WarpFacade.test.ts 2847f7d1 Browser root fence now covers DraftTimeline, JoinReceipt, and JoinResult.
P1 P5 PR src/domain/api/IntentRuntime.ts 7cb68235 Lowerers now share one descriptor-kind assertion with unchanged E_INTENT_KIND behavior.
P2 P5 PR src/domain/api/WriteReceipt.ts, src/domain/api/JoinReceipt.ts, test/unit/domain/ReceiptOutcome.test.ts eacaa92b RECEIPT_OUTCOMES is canonical/exported and reused by JoinReceipt; validator indentation normalized.
P3 P5 PR src/domain/api/Timeline.ts 3a0eca0a Timeline.read() and Timeline.write() now use named assertion helpers.
P4 P5 PR src/domain/api/Timeline.ts 7bc386c9 Optional Timeline port validation now uses one typed helper without introducing unknown.
P6 P5 PR scripts/check-source-backed-reference.ts 1b8c2946 Export-surface SourceText instances are named consistently.
P6a P5 Self scripts/check-source-backed-reference.ts c28fbe0f Kept the reference generator under the tooling source-size budget after naming sources.
S4 P5 Self src/domain/api/DraftTimelineRuntime.ts 006e8487 Extracted helpers to satisfy max-lines/max-params lint limits after functional draft runtime fixes.

Verified non-issues:

File Finding checked Result
docs/topics/api/README.md previewJoin(draft, options) signature Valid; Timeline.previewJoin(draft, options?) accepts options.
scripts/check-source-backed-reference.ts stale captureRootExports references No stale references found.
src/domain/api/JoinReceipt.ts circular import with DraftTimeline No back-reference from DraftTimeline to JoinReceipt/JoinResult; no cycle found.
src/domain/api/TimelineRuntime.ts write receipts only emit accepted No actionable change: this path has commit(): Promise<string> plus deterministic intent lowering; no alternate outcome object exists to map here.

Validation:

Gate Result
git diff --check origin/main...HEAD Passed
Changed-line sludge scan Passed; no new any, unknown, double-cast, @ts-ignore, z.any(), JSON boundary calls, fetch, or process.env additions.
npm run lint Passed
npm run typecheck Passed
npm run typecheck:consumer Passed
npm run lint:source-backed-reference Passed
npm run lint:md Passed
local lychee 0.21 config parse with --include-fragments Passed
lychee v0.24.2 config parse with --include-fragments Passed
npx vitest run test/unit/domain/WarpFacade.test.ts test/unit/domain/DraftTimelineRuntime.test.ts test/unit/domain/ReceiptOutcome.test.ts Passed; 3 files, 16 tests
npx vitest run test/unit/scripts/pre-push-hook.test.ts Passed; 12 tests
pre-push IRONCLAD M9 Passed
npm run test:local through pre-push Passed; 574 files, 7,357 tests

Pushed branch: v19-api-receipts-drafts at 12c6b134.

@github-actions

Copy link
Copy Markdown

Release Preflight

  • package version: 18.2.1
  • prerelease: false
  • npm dist-tag on release: latest
  • npm pack dry-run: passed
  • jsr publish dry-run: passed

If this PR is from a release/* branch and merges to main, Main Push Release Branch Check will run final preflight and create v18.2.1. A maintainer who is a JSR @git-stunts scope member must then dispatch the Release workflow manually.

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/domain/api/DraftTimelineRuntime.ts (1)

93-134: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Race window allows concurrent join() calls to double-commit the same intents.

rejectedJoinPrecondition is a synchronous check, but state.joined is only flipped to true after await commitDraftIntents(...) resolves (Line 110). Two concurrent joinDraftTimeline calls on the same draft both pass the precondition check before either sets joined/joinFailed, so both proceed to commitDraftIntents and each commits every intent in state.intents — resulting in duplicate commits to the live timeline. The sequential "no replay after failure" fix (joinFailed) only guards retries after a call has already resolved; it does not guard overlapping in-flight calls.

🔒 Proposed fix: synchronous in-flight guard
 type DraftTimelineState = {
   readonly runtime: WarpWorldline;
   readonly draftPatchShas: string[];
   readonly intents: Intent[];
   readonly joinPatchShas: string[];
   joinFailed: boolean;
   joined: boolean;
+  joining: boolean;
 };
 function rejectedJoinPrecondition(
   runtime: WarpWorldline,
   draft: DraftTimeline,
   state: DraftTimelineState,
 ): JoinResult | null {
   if (state.joined) {
     return rejectedJoin({ runtime, draft, reason: 'Draft has already joined' });
   }
+  if (state.joining) {
+    return rejectedJoin({ runtime, draft, reason: 'Draft join is already in progress' });
+  }
   if (state.joinFailed) {
   const rejected = rejectedJoinPrecondition(runtime, draft, state);
   if (rejected !== null) {
     return rejected;
   }
-
+  state.joining = true;
   const patchShas = await commitDraftIntents(runtime, state);
   const failed = rejectedIncompleteJoin({ runtime, draft, state, patchShas });
   if (failed !== null) {
+    state.joining = false;
     return failed;
   }
   state.joined = true;
+  state.joining = false;
   return acceptedJoin({ runtime, draft, state, patchShas });

Also applies to: 196-211

🤖 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/domain/api/DraftTimelineRuntime.ts` around lines 93 - 134, Add a
synchronous in-flight join guard in the draft state and enforce it within
joinDraftTimeline/rejectedJoinPrecondition before the first await, marking the
join as in progress before calling commitDraftIntents. Ensure concurrent calls
reject without committing, and clear or transition the guard appropriately on
success and failure while preserving the existing joinFailed behavior.
🤖 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 `@scripts/check-source-backed-reference.ts`:
- Around line 241-243: Split the multi-variable declarations in the
source-reference generation function so each const binding—rootSource,
storageSource, diagnosticsSource, and legacySource—appears on its own line,
matching the surrounding one-declaration-per-line style.

---

Outside diff comments:
In `@src/domain/api/DraftTimelineRuntime.ts`:
- Around line 93-134: Add a synchronous in-flight join guard in the draft state
and enforce it within joinDraftTimeline/rejectedJoinPrecondition before the
first await, marking the join as in progress before calling commitDraftIntents.
Ensure concurrent calls reject without committing, and clear or transition the
guard appropriately on success and failure while preserving the existing
joinFailed behavior.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 5d1aed7d-cc52-49aa-bed2-b92e63f52441

📥 Commits

Reviewing files that changed from the base of the PR and between ed6697f and 12c6b13.

📒 Files selected for processing (16)
  • .github/workflows/links.yml
  • .github/workflows/main-push-release-branch-check.yml
  • .github/workflows/release.yml
  • .lychee.toml
  • package.json
  • scripts/check-source-backed-reference.ts
  • scripts/hooks/pre-push
  • src/domain/api/DraftTimelineRuntime.ts
  • src/domain/api/IntentRuntime.ts
  • src/domain/api/JoinReceipt.ts
  • src/domain/api/Timeline.ts
  • src/domain/api/WriteReceipt.ts
  • test/unit/domain/DraftTimelineRuntime.test.ts
  • test/unit/domain/ReceiptOutcome.test.ts
  • test/unit/domain/WarpFacade.test.ts
  • test/unit/scripts/pre-push-hook.test.ts
💤 Files with no reviewable changes (1)
  • .lychee.toml
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: preflight
  • GitHub Check: test-node (22)
  • GitHub Check: coverage-threshold
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Do not use direct imports from src/infrastructure/** in src/domain/** or src/ports/**; depend on a port instead.
Do not use direct Node built-ins in src/domain/** or src/ports/**; use a port instead.

Files:

  • test/unit/scripts/pre-push-hook.test.ts
  • test/unit/domain/ReceiptOutcome.test.ts
  • test/unit/domain/DraftTimelineRuntime.test.ts
  • src/domain/api/WriteReceipt.ts
  • src/domain/api/JoinReceipt.ts
  • src/domain/api/IntentRuntime.ts
  • src/domain/api/Timeline.ts
  • test/unit/domain/WarpFacade.test.ts
  • scripts/check-source-backed-reference.ts
  • src/domain/api/DraftTimelineRuntime.ts
src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx,js,jsx}: Do not introduce any, as any, as unknown as, unknown (outside adapters), Record<string, unknown> (outside adapters), *Like placeholder types, JSON.parse/JSON.stringify (outside adapters), fetch (outside adapters), process.env (outside adapters), @ts-ignore, or z.any() in core code; use validated boundary models and ports instead.
Use constructor-injected ports for external capabilities; do not rely on ambient dependencies for I/O, clocks, persistence, or entropy.
Do not create utils.ts, helpers.ts, misc.ts, or common.ts; name files after the actual concept they model.
Prefer one file per class, type, or object; if a file accumulates peer concepts, split it.
Keep helper corridors, fake shape trust, transitional duplication, and compile-time theater out of the codebase; runtime-honest TypeScript must reflect actual behavior.
No enum usage; prefer runtime-backed domain forms and unions.
Do not use boolean trap parameters; prefer named option objects or separate methods.
Avoid magic strings or numbers when a named constant should exist.
Keep domain bytes as Uint8Array; Buffer belongs in infrastructure adapters.

Files:

  • src/domain/api/WriteReceipt.ts
  • src/domain/api/JoinReceipt.ts
  • src/domain/api/IntentRuntime.ts
  • src/domain/api/Timeline.ts
  • src/domain/api/DraftTimelineRuntime.ts
src/domain/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/domain/**/*.{ts,tsx,js,jsx}: In src/domain/**, do not use Date.now(), new Date(), Date(), performance.now(), Math.random(), crypto.randomUUID(), crypto.getRandomValues(), setTimeout, setInterval, raw new Error(...)/new TypeError(...), or direct imports from Node built-ins; time, entropy, and external capabilities must enter through ports or parameters, and domain errors should extend WarpError.
Construct domain objects only in core when doing so establishes validated runtime truth; do not build infrastructure adapters, host APIs, persistence implementations, wall clocks, or entropy sources inside core.
Prefer discriminated unions and explicit result types instead of boolean-flag bags, and model expected failures as return values rather than exceptions.
src/domain/ must not import host APIs or Node-specific globals; hexagonal architecture boundaries are mandatory.
Domain code must not use the wall clock directly; time must enter through a port or parameter.

Files:

  • src/domain/api/WriteReceipt.ts
  • src/domain/api/JoinReceipt.ts
  • src/domain/api/IntentRuntime.ts
  • src/domain/api/Timeline.ts
  • src/domain/api/DraftTimelineRuntime.ts
src/domain/**/!(*.test).{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use explicit domain concepts with validated constructors, Object.freeze, and instanceof dispatch; domain objects should be runtime-backed nouns, not ad hoc shape bags.

Files:

  • src/domain/api/WriteReceipt.ts
  • src/domain/api/JoinReceipt.ts
  • src/domain/api/IntentRuntime.ts
  • src/domain/api/Timeline.ts
  • src/domain/api/DraftTimelineRuntime.ts
🧠 Learnings (1)
📚 Learning: 2026-03-04T12:08:30.347Z
Learnt from: flyingrobots
Repo: git-stunts/git-warp PR: 63
File: package.json:126-126
Timestamp: 2026-03-04T12:08:30.347Z
Learning: Vitest 4 removes vite-node as a dependency and rewrites its pool system. Do not flag the absence of vite-node in package.json or lockfiles as an error for Vitest 4 projects. Use this as a general guideline: if a project uses Vitest 4, missing vite-node is expected and correct; only flag issues if there is evidence the project is not using Vitest 4 or if vite-node is explicitly required by the project.

Applied to files:

  • package.json
🔇 Additional comments (18)
scripts/check-source-backed-reference.ts (3)

3-14: LGTM!


235-240: LGTM!

Also applies to: 244-264, 274-287


265-273: LGTM!

.github/workflows/main-push-release-branch-check.yml (1)

89-92: LGTM!

.github/workflows/release.yml (1)

110-113: LGTM!

package.json (1)

84-84: LGTM!

scripts/hooks/pre-push (1)

57-57: LGTM!

test/unit/scripts/pre-push-hook.test.ts (1)

139-139: LGTM!

Also applies to: 171-171

.github/workflows/links.yml (1)

22-25: 🗄️ Data Integrity & Integration

No conflict with .lychee.toml. .lychee.toml doesn’t set include_fragments, so the new CLI flag is the only setting in play.

			> Likely an incorrect or invalid review comment.
src/domain/api/IntentRuntime.ts (1)

26-69: LGTM!

src/domain/api/WriteReceipt.ts (1)

21-27: LGTM!

src/domain/api/JoinReceipt.ts (1)

4-4: LGTM!

Also applies to: 20-20, 47-62

src/domain/api/Timeline.ts (1)

33-37: LGTM!

Also applies to: 110-124, 133-144, 163-227

src/domain/api/DraftTimelineRuntime.ts (1)

11-91: LGTM!

Also applies to: 136-158, 185-195, 213-243

test/unit/domain/DraftTimelineRuntime.test.ts (1)

1-81: LGTM!

test/unit/domain/ReceiptOutcome.test.ts (1)

1-28: LGTM!

test/unit/domain/WarpFacade.test.ts (2)

45-61: LGTM!

Also applies to: 388-388


272-308: LGTM!

Also applies to: 310-344, 346-395

Comment thread scripts/check-source-backed-reference.ts Outdated
@flyingrobots

Copy link
Copy Markdown
Member Author

Activity Summary Update

Follow-up CodeRabbit pass on 12c6b134 found one valid new blocker plus one style regression from the prior size-budget workaround.

ID Severity Source File(s) Commit Outcome
CR2-1 P1 PR src/domain/api/DraftTimelineRuntime.ts, test/unit/domain/DraftTimelineRuntime.test.ts a5019c14 Added synchronous joining guard before the first await in joinDraftTimeline; concurrent joins now reject without double-committing.
CR2-2 P5 PR scripts/check-source-backed-reference.ts a5019c14 Restored one SourceText const per line and kept the file under the tooling source-size budget by compacting the tiny SourceText constructor.

Additional validation on a5019c14:

Gate Result
npx vitest run test/unit/domain/DraftTimelineRuntime.test.ts Passed; 3 tests
npm run lint:source-size Passed; reference generator is 298 lines
npm run lint:source-backed-reference Passed
targeted npm run lint -- src/domain/api/DraftTimelineRuntime.ts scripts/check-source-backed-reference.ts Passed
pre-push IRONCLAD M9 Passed
npm run test:local through pre-push Passed; 574 files, 7,358 tests

Pushed branch head: a5019c14.

@github-actions

Copy link
Copy Markdown

Release Preflight

  • package version: 18.2.1
  • prerelease: false
  • npm dist-tag on release: latest
  • npm pack dry-run: passed
  • jsr publish dry-run: passed

If this PR is from a release/* branch and merges to main, Main Push Release Branch Check will run final preflight and create v18.2.1. A maintainer who is a JSR @git-stunts scope member must then dispatch the Release workflow manually.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
test/unit/domain/DraftTimelineRuntime.test.ts (1)

71-114: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

LGTM! Preview materialization and partial-failure/no-replay behavior are well covered. Consider adding a case where commitPatch (or the intent-application step) throws synchronously outside the "return partial snapshot" path, to lock in the state.joining reset guarantee raised in src/domain/api/DraftTimelineRuntime.ts.

🤖 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 `@test/unit/domain/DraftTimelineRuntime.test.ts` around lines 71 - 114, Add a
test covering a synchronous throw from commitPatch or intent application outside
the partial-snapshot path, then verify the draft can safely handle a subsequent
join attempt with state.joining reset. Place it alongside the existing
partial-failure test and use the createRuntime, createDraftTimeline, and
joinDraftTimeline helpers to assert the expected rejection and retry behavior.
src/domain/api/DraftTimelineRuntime.ts (1)

118-141: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Block writes while a join is in progress. writeDraftIntent still appends to state.intents during state.joining, and commitDraftIntents iterates that live array. A concurrent draft.write(...) can be pulled into the in-flight join or make the final length check fail nondeterministically.

🤖 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/domain/api/DraftTimelineRuntime.ts` around lines 118 - 141, Block or
reject writes while a join is in progress: update writeDraftIntent to check
state.joining before appending to state.intents, returning the appropriate
rejection/error result. Ensure commitDraftIntents uses a stable snapshot of
intents captured before the join begins and performs its final length validation
against that snapshot, preventing concurrent writes from affecting the in-flight
commit.
🤖 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.

Outside diff comments:
In `@src/domain/api/DraftTimelineRuntime.ts`:
- Around line 118-141: Block or reject writes while a join is in progress:
update writeDraftIntent to check state.joining before appending to
state.intents, returning the appropriate rejection/error result. Ensure
commitDraftIntents uses a stable snapshot of intents captured before the join
begins and performs its final length validation against that snapshot,
preventing concurrent writes from affecting the in-flight commit.

In `@test/unit/domain/DraftTimelineRuntime.test.ts`:
- Around line 71-114: Add a test covering a synchronous throw from commitPatch
or intent application outside the partial-snapshot path, then verify the draft
can safely handle a subsequent join attempt with state.joining reset. Place it
alongside the existing partial-failure test and use the createRuntime,
createDraftTimeline, and joinDraftTimeline helpers to assert the expected
rejection and retry behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0bc9f939-6f70-46dd-ba37-8758c45f7ae3

📥 Commits

Reviewing files that changed from the base of the PR and between 12c6b13 and a5019c1.

📒 Files selected for processing (3)
  • scripts/check-source-backed-reference.ts
  • src/domain/api/DraftTimelineRuntime.ts
  • test/unit/domain/DraftTimelineRuntime.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: coverage-threshold
  • GitHub Check: test-node (22)
  • GitHub Check: preflight
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Do not use direct imports from src/infrastructure/** in src/domain/** or src/ports/**; depend on a port instead.
Do not use direct Node built-ins in src/domain/** or src/ports/**; use a port instead.

Files:

  • test/unit/domain/DraftTimelineRuntime.test.ts
  • scripts/check-source-backed-reference.ts
  • src/domain/api/DraftTimelineRuntime.ts
src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx,js,jsx}: Do not introduce any, as any, as unknown as, unknown (outside adapters), Record<string, unknown> (outside adapters), *Like placeholder types, JSON.parse/JSON.stringify (outside adapters), fetch (outside adapters), process.env (outside adapters), @ts-ignore, or z.any() in core code; use validated boundary models and ports instead.
Use constructor-injected ports for external capabilities; do not rely on ambient dependencies for I/O, clocks, persistence, or entropy.
Do not create utils.ts, helpers.ts, misc.ts, or common.ts; name files after the actual concept they model.
Prefer one file per class, type, or object; if a file accumulates peer concepts, split it.
Keep helper corridors, fake shape trust, transitional duplication, and compile-time theater out of the codebase; runtime-honest TypeScript must reflect actual behavior.
No enum usage; prefer runtime-backed domain forms and unions.
Do not use boolean trap parameters; prefer named option objects or separate methods.
Avoid magic strings or numbers when a named constant should exist.
Keep domain bytes as Uint8Array; Buffer belongs in infrastructure adapters.

Files:

  • src/domain/api/DraftTimelineRuntime.ts
src/domain/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/domain/**/*.{ts,tsx,js,jsx}: In src/domain/**, do not use Date.now(), new Date(), Date(), performance.now(), Math.random(), crypto.randomUUID(), crypto.getRandomValues(), setTimeout, setInterval, raw new Error(...)/new TypeError(...), or direct imports from Node built-ins; time, entropy, and external capabilities must enter through ports or parameters, and domain errors should extend WarpError.
Construct domain objects only in core when doing so establishes validated runtime truth; do not build infrastructure adapters, host APIs, persistence implementations, wall clocks, or entropy sources inside core.
Prefer discriminated unions and explicit result types instead of boolean-flag bags, and model expected failures as return values rather than exceptions.
src/domain/ must not import host APIs or Node-specific globals; hexagonal architecture boundaries are mandatory.
Domain code must not use the wall clock directly; time must enter through a port or parameter.

Files:

  • src/domain/api/DraftTimelineRuntime.ts
src/domain/**/!(*.test).{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use explicit domain concepts with validated constructors, Object.freeze, and instanceof dispatch; domain objects should be runtime-backed nouns, not ad hoc shape bags.

Files:

  • src/domain/api/DraftTimelineRuntime.ts
🔇 Additional comments (14)
scripts/check-source-backed-reference.ts (11)

8-8: LGTM!


41-41: LGTM!


68-68: LGTM!


86-86: LGTM!


128-128: LGTM!


142-142: LGTM!


161-161: LGTM!


172-172: LGTM!


183-183: LGTM!


238-242: LGTM!


264-272: LGTM!

src/domain/api/DraftTimelineRuntime.ts (2)

11-19: LGTM!

Also applies to: 77-92, 166-176


94-116: 🩺 Stability & Availability

state.joining does not stay stuck on commit failure. commitDraftIntents() already catches commit errors and returns the partial patch list, so the joining flag only depends on the local completion/receipt path here.

			> Likely an incorrect or invalid review comment.
test/unit/domain/DraftTimelineRuntime.test.ts (1)

36-69: LGTM! Correctly gates commit interleaving to deterministically prove the guard prevents double-commits.

@flyingrobots

Copy link
Copy Markdown
Member Author

Code Lawyer Activity Summary

Final update after the latest push (a5019c14). @codex please confirm there is no remaining structural issue in the addressed set.

# Severity Source File Commit Outcome
1 P1 Self src/domain/api/DraftTimelineRuntime.ts 9c9a13f9 Added deterministic partial-failure regression; blocked replay after partial join failure.
2 P2 Self src/domain/api/DraftTimelineRuntime.ts d4b8ee2d Runtime preview now reports the actual draft-join patch list.
3 P3 CI/Self .lychee.toml, workflows, hook 12c6b134 Removed TOML version drift; fragment checking now comes from CLI flags compatible with local and CI lychee.
4 P2 PR test/unit/domain/WarpFacade.test.ts 2847f7d1 Browser export fence now covers draft/join surface; browser support remains intentionally out of scope.
5 P5 PR src/domain/api/IntentRuntime.ts 7cb68235 Deduplicated repeated lowerer guards without changing error behavior.
6 P5 PR src/domain/api/JoinReceipt.ts, WriteReceipt.ts eacaa92b Shared canonical receipt outcomes to prevent drift.
7 P5 PR src/domain/api/Timeline.ts 3a0eca0a, 7bc386c9 Named input assertions and deduplicated optional port validation.
8 P5 PR scripts/check-source-backed-reference.ts 1b8c2946, c28fbe0f, a5019c14 Named export sources, kept script under size limit, restored one-declaration-per-line style.
9 P2 PR/CodeRabbit src/domain/api/DraftTimelineRuntime.ts a5019c14 Added synchronous in-flight join guard and concurrent-join regression.

Validation:

Gate Result
Local lint/type gates Passed before push.
Local targeted regressions Passed before push.
Local full stable suite via pre-push Passed on final push: 574 files, 7,358 tests.
GitHub checks All green on a5019c142c8a5f06b255e80c21778833ce99d06b.
Review threads 0 unresolved.
Strict merge gate Locked: only 1 approval; requested threshold is >=2.

MERGE GATE: LOCKED 🔒

Blocking reasons:

  • Approval threshold is not met: 1 approval present; required >=2.

@flyingrobots flyingrobots merged commit 9bbf6c1 into main Jul 10, 2026
16 checks passed
@flyingrobots flyingrobots deleted the v19-api-receipts-drafts branch July 10, 2026 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant