Skip to content

V18 Continuum slices 6-10#94

Merged
flyingrobots merged 32 commits into
mainfrom
v18-continuum-slices-6-10
May 22, 2026
Merged

V18 Continuum slices 6-10#94
flyingrobots merged 32 commits into
mainfrom
v18-continuum-slices-6-10

Conversation

@flyingrobots
Copy link
Copy Markdown
Member

@flyingrobots flyingrobots commented May 22, 2026

Summary

  • Plan and document v18 Continuum slices 6-10 in BEARING and per-slice design docs.
  • Add explicit git-warp Continuum evidence posture and translated-evidence claim modeling.
  • Harden patch commits with writer-ref visibility verification and atomic CAS writer-ref advancement.
  • Project generated Continuum receipt-family facts into git-warp receipt/witness/delivery observations.
  • Add a warp-ttd smoke test proving receipt-family facts can feed the sibling warp-ttd adapter.

Verification

  • npm run test:local
  • npm run typecheck
  • npm run lint
  • node --experimental-strip-types test/smoke/warpTtdReceiptFamilyProjectionSmoke.ts
  • npx markdownlint-cli2 docs/BEARING.md docs/design/0154-v18-evidence-posture/v18-evidence-posture.md docs/design/0155-v18-patch-commit-visibility-contract/v18-patch-commit-visibility-contract.md docs/design/0156-v18-same-writer-concurrent-race-witness/v18-same-writer-concurrent-race-witness.md docs/design/0157-v18-receipt-family-projection/v18-receipt-family-projection.md docs/design/0158-v18-warp-ttd-receipt-smoke/v18-warp-ttd-receipt-smoke.md
  • git push pre-push IRONCLAD M9 gates

ADR checks

  • This PR does not implement ADR 2 without satisfying ADR 3
  • If this PR touches persisted op formats, I linked the ADR 3 readiness issue (not applicable; no persisted op format changes)
  • If this PR touches wire compatibility, I confirmed canonical-only ops are still rejected on the wire pre-cutover (not applicable; no wire-format cutover)
  • If this PR touches schema constants, I confirmed patch and checkpoint namespaces remain distinct (not applicable; no schema constants changed)

Summary by CodeRabbit

  • New Features

    • Evidence posture system and Continuum evidence/claim types added
    • Receipt-family projection and GitWarp receipt source facts introduced
    • Atomic same-writer commit semantics and stricter patch-commit visibility enforced
    • Warp-TTD receipt smoke harness added
  • Documentation

    • Comprehensive v18 design docs (evidence posture, patch visibility, same-writer witness, receipt projection) and updated operational/release notes
  • Tests

    • Extensive unit/smoke/benchmark tests and CAS-aware mock persistence added/updated

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

Warning

Rate limit exceeded

@flyingrobots has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 21 minutes and 4 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 47d64dc6-22b4-46cf-828e-d94302c67d20

📥 Commits

Reviewing files that changed from the base of the PR and between 1d99817 and ece36ef.

📒 Files selected for processing (19)
  • src/domain/continuum/ContinuumEvidenceClaim.ts
  • src/domain/continuum/ContinuumEvidencePosture.ts
  • src/domain/continuum/ContinuumReceiptFamilyProjection.ts
  • src/domain/continuum/GitWarpReceiptSourceFacts.ts
  • src/domain/services/PatchCommitter.ts
  • test/unit/domain/PatchOperationAssertions.ts
  • test/unit/domain/WarpGraph.backfill.test.ts
  • test/unit/domain/WarpGraph.checkpoint.test.ts
  • test/unit/domain/WarpGraph.strands.compare.test.ts
  • test/unit/domain/WarpGraph.strands.intents.test.ts
  • test/unit/domain/WarpGraph.strands.test.ts
  • test/unit/domain/WarpGraph.test.ts
  • test/unit/domain/WarpGraph.versionVector.test.ts
  • test/unit/domain/services/PatchBuilder.commit.test.ts
  • test/unit/domain/services/PatchBuilder.contentPersistence.test.ts
  • test/unit/domain/services/PatchBuilder.provenance.test.ts
  • test/unit/domain/services/PatchBuilderTestHarness.ts
  • test/unit/domain/services/PatchCommitter.visibility.test.ts
  • test/unit/domain/warp/PatchSession.operations.test.ts
📝 Walkthrough

Walkthrough

Adds Continuum evidence posture and claim types, receipt-family projection and source-facts, replaces non-atomic writer-ref updates with compare-and-swap plus immediate visibility checks in commitPatch, updates test fixtures/mocks to support CAS, and adds related unit and smoke tests and design/BEARING docs.

Changes

V18 Evidence Posture, Receipt Projection, CAS Visibility, and Test Updates

Layer / File(s) Summary
Design docs and BEARING updates
docs/design/*, docs/BEARING.md, CHANGELOG.md
Adds v18 design documents (evidence posture, commit visibility, same-writer race witness, receipt-family projection, warp-ttd smoke) and updates BEARING.md/CHANGELOG with task status and running task list.
Evidence posture and claim (+exports/tests)
src/domain/continuum/ContinuumEvidencePosture.ts, src/domain/continuum/ContinuumEvidenceClaim.ts, test/unit/domain/continuum/ContinuumEvidencePosture.test.ts, test/unit/domain/index.exports.test.ts, index.ts
Adds canonical posture literals, ContinuumEvidencePosture validation/predicates, ContinuumEvidenceClaim (descriptor+posture+optional native proof) with runtime guards, and adds exports and unit tests verifying classification and construction guards.
Receipt-family projection and source facts (+tests/smoke)
src/domain/continuum/GitWarpReceiptSourceFacts.ts, src/domain/continuum/ContinuumReceiptFamilyProjection.ts, test/unit/domain/continuum/ContinuumReceiptFamilyProjection.test.ts, test/smoke/warpTtdReceiptFamilyProjectionSmoke.ts
Implements GitWarpReceiptSourceFacts carrier and ContinuumReceiptFamilyProjection that projects TickReceipt + deliveryObservations into frozen receipts, witnesses, and deliveryObservations while preserving translated evidence posture; adds unit tests and a smoke test that exercises external adapter materialization.
PatchCommitter: CAS + visibility enforcement
src/domain/services/PatchCommitter.ts, src/domain/errors/WriterError.ts, test/unit/domain/services/PatchCommitter.visibility.test.ts
Replaces non-atomic updateRef with compareAndSwapRef for atomic writer-ref advancement, centralizes CAS-conflict creation, re-reads ref on CAS failure, and asserts immediate post-CAS visibility via readRef, throwing PersistenceError.E_REF_IO when not visible; WriterError gains expectedSha/actualSha. A visibility unit test asserts contract behavior.
Test infra: stateful compareAndSwapRef implementations
test/helpers/WarpGraphMockPersistence.ts, test/helpers/mockPorts.ts, test/benchmark/*, various test/unit/*
Test helpers and many unit tests now implement stateful compareAndSwapRef semantics (Map/#refs-backed), update readRef sequencing, and change assertions from updateRef to compareAndSwapRef where applicable.
PatchBuilder, content, provenance, and commit tests
test/unit/domain/services/PatchBuilder.*.test.ts, test/unit/domain/services/PatchBuilder.commit.test.ts, test/unit/domain/services/PatchBuilder.contentPersistence.test.ts, test/unit/domain/services/PatchBuilder.provenance.test.ts
Extensive test coverage for commit lifecycle, compare-and-swap behavior, content persistence and deduplication, provenance reads/writes tracking, and failure/retry scenarios updated to use CAS semantics.
Same-writer concurrent patch race witness test
test/unit/domain/warp/Writer.sameWriterRace.test.ts, test/unit/domain/warp/Writer.test.ts
Adds controlled same-writer race test using gated readRef to synchronize two commit attempts; asserts one winner, one loser with WRITER_REF_ADVANCED/CAS conflict behavior, and validates persisted winner head and materialized node presence.
Warp-TTD receipt-family projection smoke
test/smoke/warpTtdReceiptFamilyProjectionSmoke.ts
Smoke test dynamically loads adapter, feeds generated-family ContinuumReceiptFamilyProjection, and asserts receipt-summary fields; rejects handwritten/local receipt DTO shapes.

Sequence Diagram(s)

sequenceDiagram
  participant CommitPatch
  participant Persistence
  participant Reader
  CommitPatch->>Persistence: create commit object (write tree/blob)
  CommitPatch->>Persistence: compareAndSwapRef(writerRef, newCommitSha, expectedParentSha)
  alt CAS success
    Persistence->>Reader: readRef(writerRef) to verify visibility
    alt ref == newCommitSha
      Reader-->>CommitPatch: visible -> success path (onCommitSuccess)
    else ref != newCommitSha
      Reader-->>CommitPatch: PersistenceError.E_REF_IO (invisibility)
    end
  else CAS failure
    Persistence->>Persistence: re-read current ref
    Persistence-->>CommitPatch: WriterError (expectedSha / actualSha) -> CAS conflict
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I hopped through docs and tests at night,
Stamped evidence posture clear and bright,
Refs now leap with CAS in place,
Two writers raced — one kept the pace,
A smoke breathed proof, the tests delight!

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v18-continuum-slices-6-10

@github-actions
Copy link
Copy Markdown

Release Preflight

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

If you tag this commit as v17.0.1, release workflow will publish.

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

Caution

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

⚠️ Outside diff range comments (3)
test/unit/domain/services/PatchBuilder.test.ts (1)

1-1360: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

This test file should be split to satisfy the LOC limit.

At 1360 LOC, it substantially exceeds the repository test-file maximum and is now beyond the anti-sludge threshold.

As per coding guidelines, Maximum file size: 500 LOC (source), 800 LOC (test), 300 LOC (scripts).

🤖 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/services/PatchBuilder.test.ts` around lines 1 - 1360, The
test file is too large; split the monolithic PatchBuilder.test.ts into multiple
smaller test files grouped by responsibility to respect the LOC limits. Create
separate test files (e.g. PatchBuilder.NodeEdgeProps.test.ts for "building patch
with node/edge/property" and "reads/writes provenance" groups,
PatchBuilder.Versioning.test.ts for "multiple operations increment the
VersionVector" and "patch context includes version vector",
PatchBuilder.Commit.test.ts for all "commit()" tests including use-after-commit
and blob/commit-message assertions, and PatchBuilder.StateErrors.test.ts for
"empty state / removeNode/removeEdge" cases), and move the helper factories
createMockState, createMockPersistence, createPatchJournal plus imports
(PatchBuilder, VersionVector, ORSet, Dot, encodeEdgeKey, decodePatchMessage,
decode, CborPatchJournalAdapter, CborCodec, PatchError) into a shared
test-helpers file that each split test file imports; ensure each new file keeps
the original describe/it blocks intact and only changes imports to reference the
shared helpers so test semantics and referenced symbols (e.g., PatchBuilder,
builder.addNode/removeNode/addEdge/removeEdge/setProperty/commit, and helper
functions) are preserved.
test/unit/domain/services/PatchBuilder.content.test.ts (1)

1-820: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Split this test file; it exceeds the repository LOC ceiling.

This file is now 820 LOC, above the test-file limit, and should be split into focused suites.

As per coding guidelines, Maximum file size: 500 LOC (source), 800 LOC (test), 300 LOC (scripts).

🤖 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/services/PatchBuilder.content.test.ts` around lines 1 - 820,
The test file is too large and should be split into smaller focused suites:
extract the attachContent-related tests (describe('attachContent()' and the
"with streaming input" and "with blobStorage" groups) into a new test file,
extract edge-specific tests (describe('attachEdgeContent()',
describe('clearEdgeContent()')) into another, and extract
commit/commit-with-content tests (the "commit() with content blobs" describe)
into a third; factor out shared helpers (createMockBlobStorage,
createMockPersistence, createMockState, createPatchJournal) into a common
test-utils module and update the new test files to import them and PatchBuilder,
VersionVector, ORSet, Dot, encodeEdgeKey, CborPatchJournalAdapter, CborCodec as
needed, ensuring each new file only contains the relevant describe blocks and
aligned imports so no duplicated helpers remain.
test/unit/domain/warp/Writer.test.ts (1)

1-823: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

File length is over the test-file cap and should be trimmed/split.

This file is 823 LOC and exceeds the configured 800 LOC maximum for tests.

As per coding guidelines, Maximum file size: 500 LOC (source), 800 LOC (test), 300 LOC (scripts).

🤖 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/warp/Writer.test.ts` around lines 1 - 823, The test file
exceeds the 800 LOC cap; split it into smaller files and extract shared helpers:
move the entire "Writer (WARP schema:2)" describe block (all tests that
reference Writer, beginPatch, commit, commitPatch, WriterError) into a new test
file (e.g., Writer.test.ts) and move the "PatchSession operations" describe
block into a separate test file (e.g., PatchSession.test.ts); extract the helper
functions createMockPersistence, createPatchJournal, createPatchMessage and any
shared imports (VersionVector, ORSet, Dot, encodeEdgeKey, encodePatchMessage,
CborPatchJournalAdapter, CborCodec) into a test helper module and import them
from both new test files; update imports in the new files to reference the
helper module and ensure each test file now stays below the 800 LOC limit.
🧹 Nitpick comments (3)
test/unit/domain/services/PatchBuilder.test.ts (1)

40-42: ⚡ Quick win

Make the CAS mock enforce expected-old SHA.

Line 40 currently accepts all CAS writes; it should fail when current ref differs from expectedOid to keep commit-path tests meaningful.

🤖 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/services/PatchBuilder.test.ts` around lines 40 - 42, The CAS
mock currently accepts any swap; update the mock for
persistence.compareAndSwapRef to read the current ref (via persistence.readRef)
and enforce that the provided expected SHA (the first argument, e.g.,
expectedOid) matches the current ref before applying the newOid: if they match,
set persistence.readRef to resolve to newOid and return success; if they differ,
simulate a failed CAS by throwing or returning a failure value so tests
exercising commit-path behavior fail when the expected-old SHA is wrong.
test/unit/domain/warp/Writer.test.ts (1)

35-37: ⚡ Quick win

Align the mock with real CAS semantics.

Line 35 updates the ref regardless of expected-old value. Add expected-value checking so race/conflict behavior is exercised rather than assumed.

🤖 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/warp/Writer.test.ts` around lines 35 - 37, The
compareAndSwapRef mock currently always updates the ref; update the
mockImplementation for persistence.compareAndSwapRef to accept the expectedOld
and newOid parameters and only set persistence.readRef to newOid (or resolve
true) when expectedOld matches the current stored value (simulate current value
either held in a local variable or read from persistence.readRef mock),
otherwise simulate a CAS failure (resolve false or throw error consistent with
real CAS behavior); reference persistence.compareAndSwapRef and
persistence.readRef so test logic exercises race/conflict behavior.
test/unit/domain/services/PatchBuilder.content.test.ts (1)

41-43: ⚡ Quick win

Model CAS mismatches in the mock, not only success paths.

Line 41 currently ignores the expected-old ref, so CAS contract regressions can still pass these tests. Make the mock validate expectedOid against current ref and reject on mismatch.

Suggested change
-  persistence.compareAndSwapRef.mockImplementation(async (_ref, newOid) => {
-    persistence.readRef.mockResolvedValue(newOid);
+  persistence.compareAndSwapRef.mockImplementation(async (ref, newOid, expectedOid) => {
+    const current = await persistence.readRef(ref);
+    if (current !== expectedOid) {
+      throw new Error(`CAS mismatch for ${ref}`);
+    }
+    persistence.readRef.mockResolvedValue(newOid);
   });
🤖 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/services/PatchBuilder.content.test.ts` around lines 41 - 43,
Update the test mock for persistence.compareAndSwapRef so it enforces the CAS
contract instead of always succeeding: in the mockImplementation for
compareAndSwapRef, first obtain the currentOid (e.g., by calling
persistence.readRef or using a captured current value), compare it to the passed
expectedOid, and only if they match resolve with the newOid and also set
persistence.readRef to return newOid; if they do not match reject (or throw) to
simulate a CAS failure. Ensure the mock checks the expectedOid parameter rather
than ignoring it so tests fail on CAS mismatches.
🤖 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/continuum/ContinuumEvidenceClaim.ts`:
- Around line 17-20: The ContinuumEvidenceClaim constructor dereferences fields
(fields.descriptor) before validating fields exists; update the constructor in
ContinuumEvidenceClaim to first guard that the incoming fields parameter is
non-null/undefined and throw a WarpError('E_VALIDATION') on invalid input, then
call requireDescriptor(fields.descriptor), normalizePosture(fields.posture) and
optionalNonEmptyString(fields.nativeWitnessProof, 'nativeWitnessProof') as
before so all downstream helpers receive validated input.

In `@src/domain/continuum/ContinuumReceiptFamilyProjection.ts`:
- Around line 65-68: The constructor of ContinuumReceiptFamilyProjection must
validate the incoming envelope object before accessing nested properties; add a
guard at the start of the constructor to check that the parameter fields is not
null/undefined (and optionally has expected shape) and throw a domain WarpError
(or use your existing validation helper) instead of letting a raw TypeError
surface; only call
requireEvidence(fields.evidence).requireTranslatedGitWarpEvidence(),
requireReceiptFamilyDescriptor(this.evidence.descriptor) and
requireSourceFacts(fields.sourceFacts) after the envelope has been validated so
the constructor enforces its invariants and fails with a domain error.

In `@src/domain/continuum/GitWarpReceiptSourceFacts.ts`:
- Around line 18-20: The constructor of GitWarpReceiptSourceFacts dereferences
fields.tickReceipt before validating fields, so update the
GitWarpReceiptSourceFacts constructor to first guard that the input object
fields is non-null/undefined and throw the appropriate WarpError('E_VALIDATION')
(or call the existing validation helper) if it's invalid; only after that, call
requireTickReceipt(this.tickReceipt = requireTickReceipt(fields.tickReceipt))
and then requireReceiptOutcomes(this.tickReceipt) to preserve the existing
invariants.

In `@test/helpers/mockPorts.ts`:
- Around line 55-57: The mock compareAndSwapRef (compareAndSwapRef) currently
unconditionally writes newOid; change it to validate the expectedOid against the
current value in the refs Map before updating: fetch current = refs.get(ref) (or
treat missing as null), compare with the provided _expectedOid, and only set
refs.set(ref, newOid) when they match; if they don't match, simulate CAS failure
by either throwing a descriptive error or returning a failure value consistent
with how real CAS is consumed in tests (ensure callers of compareAndSwapRef in
tests still get the same success/failure semantics).

In `@test/helpers/WarpGraphMockPersistence.ts`:
- Around line 59-62: The mock compareAndSwapRef currently overwrites refs
unconditionally; change its implementation (the vi.fn for compareAndSwapRef) to
read the current value from this.#refs, compare it against the provided
_expectedOid (treat missing key as null), and only set this.#refs.set(ref,
newOid) and update readRef's mockImplementation when they match; otherwise leave
refs unchanged and return a failure indicator (e.g., false). Ensure the function
returns a boolean or promise<boolean> indicating success so tests can detect CAS
conflicts, and keep references to compareAndSwapRef and readRef when making this
change.

In `@test/smoke/warpTtdReceiptFamilyProjectionSmoke.ts`:
- Line 9: The import of GitWarpAdapter in warpTtdReceiptFamilyProjectionSmoke.ts
cannot resolve the source path; update the import to reference the warp-ttd
package export (e.g., import { GitWarpAdapter } from 'warp-ttd' or from the
package's published entrypoint) or add the underlying src path to the active
tsconfig "paths"/"include" so TypeScript can find GitWarpAdapter; locate the
import statement in test/smoke/warpTtdReceiptFamilyProjectionSmoke.ts and
replace the '../../../../warp-ttd/src/adapters/gitWarpAdapter.ts' path with the
correct package entrypoint export (or adjust tsconfig) so the GitWarpAdapter
symbol resolves during typecheck.

In `@test/unit/domain/continuum/ContinuumEvidencePosture.test.ts`:
- Around line 26-95: Add two negative-path unit tests to
ContinuumEvidencePosture.test.ts that exercise ContinuumEvidenceClaim
validation: (1) construct a claim with a non-native posture (e.g.,
'translated-git-warp-evidence' or 'unproven-continuum-shape') while providing a
non-empty nativeWitnessProof and assert that the constructor/validation throws
WarpError; (2) construct a claim with posture 'native-continuum-evidence' but
pass an empty nativeWitnessProof (empty string or whitespace) and assert that it
throws WarpError. Use makeGeneratedReceiptDescriptor() to build the descriptor
and reference ContinuumEvidenceClaim, ContinuumEvidencePosture and WarpError in
the expectations so the tests cover those branches.

In `@test/unit/domain/services/PatchBuilder.cas.test.ts`:
- Around line 25-27: The current test mock for persistence.compareAndSwapRef in
PatchBuilder.cas.test.ts always "succeeds" and blindly sets persistence.readRef,
so CAS semantics aren't tested; change the mockImplementation for
persistence.compareAndSwapRef to accept (expectedOldOid, newOid), compare
expectedOldOid to the current value returned by persistence.readRef (or a local
variable capturing the simulated ref), only update the simulated ref (and
persistence.readRef mock) when they match, and otherwise return/throw a failure
(e.g., false or throw) so tests can assert true CAS success and CAS failure
paths correctly.

In `@test/unit/domain/WarpGraph.test.ts`:
- Around line 60-62: The shared CAS mock currently always succeeds by setting
persistence.readRef to newOid; change
persistence.compareAndSwapRef.mockImplementation so it enforces the
expected-head match: have the mock read the current head (via
persistence.readRef or an internal variable), compare it to the provided
expectedOid argument, and only update persistence.readRef to newOid and return
success when they match; if they don’t match return a failure (or throw)
consistent with the real compareAndSwapRef behavior. Ensure you reference the
same mock signature (compareAndSwapRef, expectedOid, newOid, and readRef) when
updating the implementation.

---

Outside diff comments:
In `@test/unit/domain/services/PatchBuilder.content.test.ts`:
- Around line 1-820: The test file is too large and should be split into smaller
focused suites: extract the attachContent-related tests
(describe('attachContent()' and the "with streaming input" and "with
blobStorage" groups) into a new test file, extract edge-specific tests
(describe('attachEdgeContent()', describe('clearEdgeContent()')) into another,
and extract commit/commit-with-content tests (the "commit() with content blobs"
describe) into a third; factor out shared helpers (createMockBlobStorage,
createMockPersistence, createMockState, createPatchJournal) into a common
test-utils module and update the new test files to import them and PatchBuilder,
VersionVector, ORSet, Dot, encodeEdgeKey, CborPatchJournalAdapter, CborCodec as
needed, ensuring each new file only contains the relevant describe blocks and
aligned imports so no duplicated helpers remain.

In `@test/unit/domain/services/PatchBuilder.test.ts`:
- Around line 1-1360: The test file is too large; split the monolithic
PatchBuilder.test.ts into multiple smaller test files grouped by responsibility
to respect the LOC limits. Create separate test files (e.g.
PatchBuilder.NodeEdgeProps.test.ts for "building patch with node/edge/property"
and "reads/writes provenance" groups, PatchBuilder.Versioning.test.ts for
"multiple operations increment the VersionVector" and "patch context includes
version vector", PatchBuilder.Commit.test.ts for all "commit()" tests including
use-after-commit and blob/commit-message assertions, and
PatchBuilder.StateErrors.test.ts for "empty state / removeNode/removeEdge"
cases), and move the helper factories createMockState, createMockPersistence,
createPatchJournal plus imports (PatchBuilder, VersionVector, ORSet, Dot,
encodeEdgeKey, decodePatchMessage, decode, CborPatchJournalAdapter, CborCodec,
PatchError) into a shared test-helpers file that each split test file imports;
ensure each new file keeps the original describe/it blocks intact and only
changes imports to reference the shared helpers so test semantics and referenced
symbols (e.g., PatchBuilder,
builder.addNode/removeNode/addEdge/removeEdge/setProperty/commit, and helper
functions) are preserved.

In `@test/unit/domain/warp/Writer.test.ts`:
- Around line 1-823: The test file exceeds the 800 LOC cap; split it into
smaller files and extract shared helpers: move the entire "Writer (WARP
schema:2)" describe block (all tests that reference Writer, beginPatch, commit,
commitPatch, WriterError) into a new test file (e.g., Writer.test.ts) and move
the "PatchSession operations" describe block into a separate test file (e.g.,
PatchSession.test.ts); extract the helper functions createMockPersistence,
createPatchJournal, createPatchMessage and any shared imports (VersionVector,
ORSet, Dot, encodeEdgeKey, encodePatchMessage, CborPatchJournalAdapter,
CborCodec) into a test helper module and import them from both new test files;
update imports in the new files to reference the helper module and ensure each
test file now stays below the 800 LOC limit.

---

Nitpick comments:
In `@test/unit/domain/services/PatchBuilder.content.test.ts`:
- Around line 41-43: Update the test mock for persistence.compareAndSwapRef so
it enforces the CAS contract instead of always succeeding: in the
mockImplementation for compareAndSwapRef, first obtain the currentOid (e.g., by
calling persistence.readRef or using a captured current value), compare it to
the passed expectedOid, and only if they match resolve with the newOid and also
set persistence.readRef to return newOid; if they do not match reject (or throw)
to simulate a CAS failure. Ensure the mock checks the expectedOid parameter
rather than ignoring it so tests fail on CAS mismatches.

In `@test/unit/domain/services/PatchBuilder.test.ts`:
- Around line 40-42: The CAS mock currently accepts any swap; update the mock
for persistence.compareAndSwapRef to read the current ref (via
persistence.readRef) and enforce that the provided expected SHA (the first
argument, e.g., expectedOid) matches the current ref before applying the newOid:
if they match, set persistence.readRef to resolve to newOid and return success;
if they differ, simulate a failed CAS by throwing or returning a failure value
so tests exercising commit-path behavior fail when the expected-old SHA is
wrong.

In `@test/unit/domain/warp/Writer.test.ts`:
- Around line 35-37: The compareAndSwapRef mock currently always updates the
ref; update the mockImplementation for persistence.compareAndSwapRef to accept
the expectedOld and newOid parameters and only set persistence.readRef to newOid
(or resolve true) when expectedOld matches the current stored value (simulate
current value either held in a local variable or read from persistence.readRef
mock), otherwise simulate a CAS failure (resolve false or throw error consistent
with real CAS behavior); reference persistence.compareAndSwapRef and
persistence.readRef so test logic exercises race/conflict 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6e34bd16-dada-449e-8ceb-fca24951d9d5

📥 Commits

Reviewing files that changed from the base of the PR and between 42f1581 and 4fb31db.

📒 Files selected for processing (35)
  • docs/BEARING.md
  • docs/design/0154-v18-evidence-posture/v18-evidence-posture.md
  • docs/design/0155-v18-patch-commit-visibility-contract/v18-patch-commit-visibility-contract.md
  • docs/design/0156-v18-same-writer-concurrent-race-witness/v18-same-writer-concurrent-race-witness.md
  • docs/design/0157-v18-receipt-family-projection/v18-receipt-family-projection.md
  • docs/design/0158-v18-warp-ttd-receipt-smoke/v18-warp-ttd-receipt-smoke.md
  • index.ts
  • src/domain/continuum/ContinuumEvidenceClaim.ts
  • src/domain/continuum/ContinuumEvidencePosture.ts
  • src/domain/continuum/ContinuumReceiptFamilyProjection.ts
  • src/domain/continuum/GitWarpReceiptSourceFacts.ts
  • src/domain/errors/WriterError.ts
  • src/domain/services/PatchCommitter.ts
  • test/benchmark/detachedReadBenchmark.fixture.ts
  • test/helpers/WarpGraphMockPersistence.ts
  • test/helpers/mockPorts.ts
  • test/smoke/warpTtdReceiptFamilyProjectionSmoke.ts
  • test/unit/domain/WarpCore.snapshotHashStability.test.ts
  • test/unit/domain/WarpGraph.conflicts.test.ts
  • test/unit/domain/WarpGraph.invalidation.test.ts
  • test/unit/domain/WarpGraph.observerBoundary.test.ts
  • test/unit/domain/WarpGraph.receipts.test.ts
  • test/unit/domain/WarpGraph.strands.test.ts
  • test/unit/domain/WarpGraph.test.ts
  • test/unit/domain/WarpGraph.worldline.test.ts
  • test/unit/domain/WarpGraph.writerInvalidation.test.ts
  • test/unit/domain/continuum/ContinuumEvidencePosture.test.ts
  • test/unit/domain/continuum/ContinuumReceiptFamilyProjection.test.ts
  • test/unit/domain/index.exports.test.ts
  • test/unit/domain/services/PatchBuilder.cas.test.ts
  • test/unit/domain/services/PatchBuilder.content.test.ts
  • test/unit/domain/services/PatchBuilder.test.ts
  • test/unit/domain/services/PatchCommitter.visibility.test.ts
  • test/unit/domain/warp/Writer.sameWriterRace.test.ts
  • test/unit/domain/warp/Writer.test.ts

Comment thread src/domain/continuum/ContinuumEvidenceClaim.ts Outdated
Comment thread src/domain/continuum/ContinuumReceiptFamilyProjection.ts Outdated
Comment thread src/domain/continuum/GitWarpReceiptSourceFacts.ts
Comment thread test/helpers/mockPorts.ts Outdated
Comment thread test/helpers/WarpGraphMockPersistence.ts Outdated
Comment thread test/smoke/warpTtdReceiptFamilyProjectionSmoke.ts Outdated
Comment thread test/unit/domain/continuum/ContinuumEvidencePosture.test.ts Outdated
Comment thread test/unit/domain/services/PatchBuilder.cas.test.ts Outdated
Comment thread test/unit/domain/WarpGraph.test.ts Outdated
@flyingrobots
Copy link
Copy Markdown
Member Author

@codex self-audit findings before fixes:

ID Severity Source File Lines Issue Mitigation
SELF-1 P5 Self src/domain/continuum/ContinuumEvidenceClaim.ts; src/domain/continuum/ContinuumEvidencePosture.ts; test/unit/domain/continuum/ContinuumEvidencePosture.test.ts EOF git diff --check origin/main...HEAD reports extra blank lines at EOF. Remove trailing blank EOF lines and rerun git diff --check origin/main...HEAD.
SELF-2 P3 Self src/domain/continuum/GitWarpReceiptSourceFacts.ts 21 fields.deliveryObservations ?? [] accepts null from JavaScript callers as an empty observation list, weakening runtime boundary validation. Add an explicit optional array validator that defaults only undefined, rejects null/non-arrays with WarpError('E_VALIDATION'), and add a regression test.

@flyingrobots
Copy link
Copy Markdown
Member Author

Activity Summary

Issue Severity File / Area Commit Outcome
Validate evidence-claim constructor envelope P2 src/domain/continuum/ContinuumEvidenceClaim.ts 7c6ab30 Constructor now throws WarpError before field dereference.
Validate receipt projection constructor envelope P1 src/domain/continuum/ContinuumReceiptFamilyProjection.ts c5208a3 Projection envelope guard added with regression coverage.
Validate receipt source-facts constructor envelope P1 src/domain/continuum/GitWarpReceiptSourceFacts.ts 81f189c Source facts now guard fields before tickReceipt access.
Reject null delivery observations P3 src/domain/continuum/GitWarpReceiptSourceFacts.ts 493a3ae Null is no longer treated as omitted; JavaScript callers get WarpError.
Dynamic warp-ttd smoke adapter loading P0 test/smoke/warpTtdReceiptFamilyProjectionSmoke.ts a7cac70 Static sibling import removed; smoke test loads sibling adapter at runtime.
Evidence proof negative-path coverage P2 test/unit/domain/continuum/ContinuumEvidencePosture.test.ts 8f09a8a Non-native proof and blank native-proof branches are covered.
mockPorts CAS fixture semantics P1 test/helpers/mockPorts.ts 4e969b2 Shared mock now rejects expected-head mismatches.
WarpGraphMockPersistence CAS semantics P1 test/helpers/WarpGraphMockPersistence.ts d93c616 Shared graph mock now rejects expected-head mismatches.
PatchBuilder.cas fixture semantics P2 test/unit/domain/services/PatchBuilder.cas.test.ts 92d39de CAS fixture now has mismatch regression coverage.
WarpGraph fixture CAS semantics P2 test/unit/domain/WarpGraph.test.ts c4d12a0 Shared fixture now enforces expected-head matching.
PatchBuilder fixture CAS semantics P3 test/unit/domain/services/PatchBuilder.test.ts 26db4c4 Local mock no longer accepts stale CAS writes.
PatchBuilder content fixture CAS semantics P3 test/unit/domain/services/PatchBuilder.content.test.ts ab42b2f Content fixture mock now rejects stale CAS writes.
Writer fixture CAS semantics P3 test/unit/domain/warp/Writer.test.ts d02d235 Writer fixture mock now exercises stale-head behavior.
Oversized PatchBuilder test file P4 test/unit/domain/services/PatchBuilder*.test.ts 5e01fb0 Split into core, commit, and provenance files under 800 LOC.
Oversized PatchBuilder content test file P4 test/unit/domain/services/PatchBuilder.content*.test.ts c2f52ee Split content mutation and persistence tests under 800 LOC.
Oversized Writer test file P4 test/unit/domain/warp/Writer*.test.ts 783463d Split PatchSession operation tests into a separate file.
Source docstring coverage warning P4 src/domain/continuum/*, src/domain/services/PatchCommitter.ts df81a32 Added missing source declaration comments.
PR ADR checklist warning P4 PR body metadata ADR checklist completed in the PR description.
Changelog/review documentation P4 CHANGELOG.md ca6a4b3 Review fixes recorded under Unreleased.
Patch-count fixture exposed by full suite P2 test/unit/domain/WarpGraph.patchCount.test.ts 1d99817 Seeded the writer ref so strict CAS sees the materialized tip.

Verification completed after the fixes:

  • git diff --check origin/main...HEAD
  • npm run test:local: 457 files, 6855 tests passed
  • npm run typecheck
  • npm run lint
  • node --experimental-strip-types test/smoke/warpTtdReceiptFamilyProjectionSmoke.ts
  • npx markdownlint-cli2 on CHANGELOG and touched docs
  • git push pre-push IRONCLAD M9 gate: passed

@github-actions
Copy link
Copy Markdown

Release Preflight

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

If you tag this commit as v17.0.1, release workflow will publish.

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: 4

Caution

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

⚠️ Outside diff range comments (1)
src/domain/services/PatchCommitter.ts (1)

181-189: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle ambiguous CAS errors when ref already equals newCommitSha.

If compareAndSwapRef writes successfully but throws afterward, the current logic turns that into a false CAS conflict. Treating actualSha === newCommitSha as success avoids incorrect conflict signaling.

Suggested fix
 async function compareAndSwapWriterRef(
   persistence: PersistencePorts,
   writerRef: string,
   newCommitSha: string,
   expectedSha: string | null,
 ): Promise<void> {
   try {
     await persistence.compareAndSwapRef(writerRef, newCommitSha, expectedSha);
   } catch (err) {
     const actualSha = await persistence.readRef(writerRef);
+    if (actualSha === newCommitSha) {
+      return;
+    }
     if (actualSha !== expectedSha) {
       throw buildWriterCasConflict(expectedSha, actualSha);
     }
     throw err;
   }
 }
🤖 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/services/PatchCommitter.ts` around lines 181 - 189, The catch
block for compareAndSwapRef currently treats any error as a CAS conflict;
instead, after calling const actualSha = await persistence.readRef(writerRef),
first check if actualSha === newCommitSha and if so treat the operation as
successful (return/exit without throwing), otherwise if actualSha !==
expectedSha throw buildWriterCasConflict(expectedSha, actualSha), and only
rethrow the original err in the remaining case; reference compareAndSwapRef,
readRef, writerRef, newCommitSha, expectedSha, and buildWriterCasConflict to
locate and apply this logic.
🤖 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 `@test/unit/domain/services/PatchBuilder.commit.test.ts`:
- Around line 15-16: Tests in PatchBuilder.commit.test.ts use many occurrences
of `any`/`as any`; replace them with explicit test types: declare
interfaces/types for the mock state and ORSet shapes (e.g. MockState,
NodeAliveORSet, EdgeAliveORSet) and update variables like the harness,
mockState, and helpers (the values currently cast with `as any`) to use those
types instead of `any`; ensure functions/methods referenced in tests (e.g.
PatchBuilder.commit, any makeNode/makeEdge helpers, createHarness/getMockState)
return typed values or accept typed params and import or define those types in
the test file so all `as any` casts are removed.

In `@test/unit/domain/services/PatchBuilder.contentPersistence.test.ts`:
- Around line 13-14: This test file uses blanket any and as any in its mocks and
fixtures; replace those with precise test types by (1) creating minimal typed
test doubles or using Partial<T> / jest.Mocked<T> for mocked services (e.g., the
ContentPersistence mock and any PatchBuilder inputs), (2) avoid as any casts by
typing helper factories to return the exact shape the test needs (create a
TestContentPersistence interface or use jest.Mocked<ContentPersistence>), and
(3) when unknown values are needed first assert to unknown then narrow/cast to
the real type rather than as any; update references to the mock used in tests
(the ContentPersistence mock, PatchBuilder inputs and any helper functions) to
use these concrete types everywhere you previously used any or as any.

In `@test/unit/domain/services/PatchBuilder.provenance.test.ts`:
- Around line 13-16: The tests use `any` and `as any` in the mock V5 state and
PatchBuilder fixtures—replace the JSDoc `@returns {any}` on the mock function
(e.g., createMockV5State) with the concrete type (import the correct V5
state/interface from the domain types), type the builder inputs instead of
casting (the variables passed into the PatchBuilder tests / `builder`), and give
the decoded values proper types (replace `decodedPatch as any` and `decodedOps
as any` with their real types by importing the Patch/Op types and constructing
fixtures that conform to those interfaces); remove all `as any` casts and update
assertions to use the typed values so the tests compile against the repo TS
typings.

In `@test/unit/domain/WarpGraph.test.ts`:
- Around line 117-126: The test file WarpGraph.test.ts is too large and must be
split into focused spec files: extract related groups of tests (e.g.,
persistence/compareAndSwapRef behavior, graph-construction specs, writer/ref
tests) into separate files (for example WarpGraph.persistence.test.ts,
WarpGraph.construction.test.ts) and move shared helpers/fixtures like
createMockPersistence and any common mock setup into a shared test helper module
(e.g., test/utils or test/__fixtures__) that each new spec imports; update the
affected tests (including the "test fixture compareAndSwapRef rejects
expected-head mismatches" case) to import createMockPersistence from the new
helper and ensure any beforeEach/afterEach setup is preserved in the new files
so the tests run unchanged.

---

Outside diff comments:
In `@src/domain/services/PatchCommitter.ts`:
- Around line 181-189: The catch block for compareAndSwapRef currently treats
any error as a CAS conflict; instead, after calling const actualSha = await
persistence.readRef(writerRef), first check if actualSha === newCommitSha and if
so treat the operation as successful (return/exit without throwing), otherwise
if actualSha !== expectedSha throw buildWriterCasConflict(expectedSha,
actualSha), and only rethrow the original err in the remaining case; reference
compareAndSwapRef, readRef, writerRef, newCommitSha, expectedSha, and
buildWriterCasConflict to locate and apply this logic.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7d3ead7f-fb5b-4804-b3d0-cded7c457208

📥 Commits

Reviewing files that changed from the base of the PR and between 4fb31db and 1d99817.

📒 Files selected for processing (25)
  • CHANGELOG.md
  • docs/BEARING.md
  • docs/design/0158-v18-warp-ttd-receipt-smoke/v18-warp-ttd-receipt-smoke.md
  • src/domain/continuum/ContinuumEvidenceClaim.ts
  • src/domain/continuum/ContinuumEvidencePosture.ts
  • src/domain/continuum/ContinuumReceiptFamilyProjection.ts
  • src/domain/continuum/GitWarpReceiptSourceFacts.ts
  • src/domain/services/PatchCommitter.ts
  • test/helpers/WarpGraphMockPersistence.ts
  • test/helpers/mockPorts.ts
  • test/smoke/warpTtdReceiptFamilyProjectionSmoke.ts
  • test/unit/domain/WarpGraph.patchCount.test.ts
  • test/unit/domain/WarpGraph.test.ts
  • test/unit/domain/continuum/ContinuumEvidencePosture.test.ts
  • test/unit/domain/continuum/ContinuumReceiptFamilyProjection.test.ts
  • test/unit/domain/services/PatchBuilder.cas.test.ts
  • test/unit/domain/services/PatchBuilder.commit.test.ts
  • test/unit/domain/services/PatchBuilder.content.test.ts
  • test/unit/domain/services/PatchBuilder.contentPersistence.test.ts
  • test/unit/domain/services/PatchBuilder.provenance.test.ts
  • test/unit/domain/services/PatchBuilder.test.ts
  • test/unit/domain/warp/PatchSession.operations.test.ts
  • test/unit/domain/warp/Writer.test.ts
  • test/unit/helpers/WarpGraphMockPersistence.test.ts
  • test/unit/helpers/mockPorts.test.ts
✅ Files skipped from review due to trivial changes (4)
  • CHANGELOG.md
  • test/unit/domain/warp/PatchSession.operations.test.ts
  • docs/design/0158-v18-warp-ttd-receipt-smoke/v18-warp-ttd-receipt-smoke.md
  • docs/BEARING.md

Comment thread test/unit/domain/services/PatchBuilder.commit.test.ts Outdated
Comment thread test/unit/domain/services/PatchBuilder.contentPersistence.test.ts Outdated
Comment thread test/unit/domain/services/PatchBuilder.provenance.test.ts Outdated
Comment thread test/unit/domain/WarpGraph.test.ts
@flyingrobots
Copy link
Copy Markdown
Member Author

@codex self-audit findings before the next fixes:

ID Severity Source File Evidence Issue Mitigation
SELF-3 P2 Self test/unit/domain/warp/PatchSession.operations.test.ts Added lines in git diff -U0 origin/main...HEAD contain as any casts around patch.build() and mock state construction. The new split test file introduces blanket casts in touched TypeScript, violating the anti-sludge policy. Replace casts with runtime-backed Patch/operation narrowing and WarpState.empty()-based fixture construction; add no production behavior changes.
SELF-4 P3 Self test/unit/domain/WarpGraph.strands.test.ts wc -l reports 1439 lines on a touched test file. The file exceeds the 800-line test cap while this PR touches it. Split focused strand scenarios into smaller spec files and keep shared fixture code named and reusable.

These are queued with the unresolved CodeRabbit threads and will be resolved with separate commits and verification.

@flyingrobots
Copy link
Copy Markdown
Member Author

Activity Summary

Issue Severity File / Area Commit Outcome
Ambiguous CAS transport error after visible write P1 src/domain/services/PatchCommitter.ts d037143 compare-and-swap now treats an already-visible target SHA as success, preserving idempotent transport semantics.
PatchBuilder commit split introduced any casts P1 test/unit/domain/services/PatchBuilder.commit.test.ts e88946b Replaced local cast-heavy fixtures with typed harness, hydrator-based patch decoding, and op assertions.
PatchBuilder content persistence split introduced any casts P1 test/unit/domain/services/PatchBuilder.contentPersistence.test.ts e88946b Replaced broad blob-storage/persistence casts with typed mock ports.
PatchBuilder provenance split introduced any casts P1 test/unit/domain/services/PatchBuilder.provenance.test.ts e88946b Replaced cast-heavy builder construction and op inspection with typed helpers.
Self-audit: PatchSession operation split introduced any casts P2 test/unit/domain/warp/PatchSession.operations.test.ts e88946b Replaced build-result casts with typed patch operation assertions and runtime-backed state fixture.
Oversized WarpGraph.test.ts P2 test/unit/domain/WarpGraph*.test.ts 3baedee, 39e8ae2 Split into focused specs under the 800-line cap and tightened moved fixtures.
Self-audit: oversized WarpGraph.strands.test.ts P3 test/unit/domain/WarpGraph.strands*.test.ts 3baedee, 39e8ae2 Split strand foundation, comparison, and intent scenarios under the 800-line cap.
Source docstring coverage warning P4 src/domain/continuum/* ece36ef Added concise JSDoc to exported Continuum shapes.

Verification after these fixes:

  • git diff --check origin/main...HEAD
  • added-line sludge scan for any/as any/Record<string, unknown>/JSON.parse class patterns: clean
  • touched-file line-cap audit: clean
  • npm run test:local: 462 files, 6856 tests passed
  • npm run typecheck
  • npm run lint
  • node --experimental-strip-types test/smoke/warpTtdReceiptFamilyProjectionSmoke.ts
  • npx markdownlint-cli2 CHANGELOG.md docs/BEARING.md docs/design/**/*.md
  • git push pre-push IRONCLAD M9 gate: passed

@github-actions
Copy link
Copy Markdown

Release Preflight

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

If you tag this commit as v17.0.1, release workflow will publish.

@flyingrobots flyingrobots merged commit a4c5467 into main May 22, 2026
9 checks passed
@flyingrobots flyingrobots deleted the v18-continuum-slices-6-10 branch May 22, 2026 20:18
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