Skip to content

Implement v18 property projection cutover#101

Merged
flyingrobots merged 11 commits into
mainfrom
v18-continuum-slices-31-35
May 24, 2026
Merged

Implement v18 property projection cutover#101
flyingrobots merged 11 commits into
mainfrom
v18-continuum-slices-31-35

Conversation

@flyingrobots
Copy link
Copy Markdown
Member

@flyingrobots flyingrobots commented May 23, 2026

Summary

  • Routes remaining public/state-reader property views through typed projection records, including StateQueryReadModel and property-count accounting.
  • Adds runtime-backed node/edge property write intent nouns and lowers PatchBuilder property writes through those intents while preserving the existing wire shape and reserved-byte validation behavior.
  • Cuts graph-op algebra projection over to typed content/property operation nouns, then closes the legacy-property projection backlog with BEARING, design, changelog, and source-audit evidence.

Verification

  • npm run typecheck
  • npm run lint
  • npm run lint:sludge
  • npm run lint:quarantine-graduate
  • npm run test:local (488 files, 6956 tests)
  • npx markdownlint-cli2 CHANGELOG.md docs/BEARING.md docs/method/backlog/v18.0.0/PROTO_legacy-props-as-projection.md docs/design/0183-v18-property-projection-closeout/v18-property-projection-closeout.md
  • git diff --check
  • pre-push IRONCLAD M9 gate passed, including static gates and full unit tests

Notes

A follow-up commit preserves the consumer type surface after widening createStateReader to accept immutable SnapshotWarpState sources in addition to live WarpState sources.

Summary by CodeRabbit

  • Chores
    • CI workflow reworked to run heavy static gates in parallel behind an aggregate status check.
  • New Features
    • Property projection now emits typed property and content-attachment operations and explicit write-intent records.
  • Bug Fixes
    • Projection closeout prevents malformed legacy keys from leaking into public property views; property counts now reflect projected properties.
    • Snapshot hydration rejects cyclic values and prototype-polluting keys.
  • Tests
    • Expanded unit/integration coverage for projection routing, patch lowering, and graph-op validation.
  • Documentation
    • Design docs and changelog updated to mark several v18 slices complete.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 23, 2026

Warning

Review limit reached

@flyingrobots, we couldn't start this review because you've used your available PR reviews for now.

Your plan currently allows 1 review/hour. Refill in 49 minutes and 2 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more review capacity refills, 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 trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c836dcb6-9f84-4bd1-92d2-aad09aff30a8

📥 Commits

Reviewing files that changed from the base of the PR and between c577419 and c6be78a.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/domain/services/state/StateReaderContext.ts
  • test/unit/domain/services/StateReaderPropertyProjection.test.ts
📝 Walkthrough

Walkthrough

This PR closes V18 property-projection slices 31–35: it adds runtime property write intents, extends graph-op algebra and projection emission to include content/property set ops, reworks StateReader snapshot hydration and projection helpers, updates PatchBuilder lowering and PropValue validation, expands public exports, updates tests, and parallelizes CI static gates under an aggregate type-firewall.

Changes

V18 Property Projection Closeout (Slices 31–35)

Layer / File(s) Summary
Property Write Intent Contracts
src/domain/graph/NodePropertyWriteIntent.ts, src/domain/graph/EdgePropertyWriteIntent.ts, test/unit/domain/graph/PropertyWriteIntent.test.ts
Introduces NodePropertyWriteIntent and EdgePropertyWriteIntent runtime classes with validation, factory methods, and immutable instances that wrap legacy node/edge property writes into type-safe intents; tests verify frozen instances and rejection of malformed carriers.
Graph Operation Types & Validation
src/domain/graph/GraphNodePropertySetOp.ts, src/domain/graph/GraphEdgePropertySetOp.ts, src/domain/graph/GraphContentAttachmentSetOp.ts, src/domain/graph/GraphOperation.ts, src/domain/graph/GraphOpAlgebra.ts, test/unit/domain/graph/GraphOpAlgebra.test.ts
Adds GraphNodePropertySetOp, GraphEdgePropertySetOp, and GraphContentAttachmentSetOp operation types with constructor validation; expands GraphOperation union from 3 to 6 operation variants; updates GraphOpAlgebra.requireOperation to recognize both record and projection operations via internal predicates.
PatchBuilder Property Intent Lowering
src/domain/services/PatchBuilder.ts, test/unit/domain/services/PatchBuilderPropertyIntent.test.ts
Refactors PatchBuilder.setProperty/setEdgeProperty to construct property write intents, validate and normalize values via requirePatchPropertyValue (recursive handling of scalars, arrays, objects), and lower intents into PropSet operations; tests verify intent lowering and schema correctness.
GraphOpAlgebra Projection with Property Operations
src/domain/services/GraphOpAlgebraProjection.ts, test/unit/domain/services/GraphOpAlgebraProjection.test.ts
Updates GraphOpAlgebraProjection.fromState to emit graph operations in order (node records, edge records, content attachments, then property operations) by delegating to helper functions; node/edge property operations filter out content-compatibility aliases; tests verify projection order and content/property op emission.
State Reader Snapshot & Projection Hydration Pipeline
src/domain/services/state/StateReaderContext.ts, test/unit/domain/services/StateReaderPropertyProjection.test.ts
Completely refactors StateReaderContext: introduces StateReaderSource union type (WarpState | SnapshotWarpState), snapshot-to-projection conversion (warpStateFromSnapshot with CRDT/property-map rebuild), and projection-backed property helpers (createProjectionProps, createNodePropertyRecords, createEdgePropertyRecords) replacing register-iteration; rebuilds content metadata indexing via ContentAttachmentProjection.
State Reader Public Interface & Context Wiring
src/domain/services/state/StateReader.ts, test/type-check/consumer.ts
Updates createStateReader to accept StateReaderSource instead of WarpState; introduces projection-state intermediate in buildReaderContext; wires new property-record creation and per-node/edge population helpers; updates type-check smoke tests to use snapshot readers.
Query & Read Model Property Projection Routing
src/domain/services/controllers/QueryReads.ts, src/domain/services/query/StateQueryReadModel.ts, test/unit/domain/services/QueryReadsPropertyProjection.test.ts, test/unit/domain/services/query/StateQueryReadModelPropertyProjection.test.ts
Updates getPropertyCountImpl to sum projection-derived property counts instead of returning raw state.prop.size; refactors StateQueryReadModel.nodeProps to iterate NodePropertyProjection.forNode records instead of decoding raw registers, replacing property-key derivation with projection records; tests verify projection routing and property visibility filtering.
Translation Cost & Supporting Service Routing
src/domain/services/TranslationCost.ts
Updates collectNodePropKeys to derive visible node properties via NodePropertyProjection.forNode instead of iterating and decoding raw state.prop entries, aligning cost computation with projection-based property visibility.
PropValue Cycle-safe Validation
src/domain/types/PropValue.ts
Reworks isPropValue to be generic and cycle-safe using a WeakSet, rejects prototype-polluting keys (__proto__, constructor, prototype), and validates arrays/objects recursively to prevent infinite recursion.
Public API Surface Expansion
src/domain/graph/publicGraphSubstrate.ts
Expands publicGraphSubstrate to re-export NodePropertyWriteIntent, EdgePropertyWriteIntent, GraphNodePropertySetOp, GraphEdgePropertySetOp, GraphContentAttachmentSetOp, operation constants, and corresponding field/type definitions (EdgePropertyWriteIntentFields, GraphContentAttachmentSetOpFields, etc.).
Documentation Status & CI Parallelization
.github/workflows/ci.yml, CHANGELOG.md, docs/BEARING.md, docs/design/0179-*.mddocs/design/0183-*.md, docs/method/backlog/v18.0.0/PROTO_legacy-props-as-projection.md
Marks V18 design tasks 0179–0183 as Complete; updates BEARING.md to document implemented slices 31–35 with routing/closeout/evidence status and remaining boundaries; adds CI workflow parallelization by splitting the consolidated firewall job into dedicated lint/semgrep/type/quarantine/surface/docs gates behind an aggregate status check; records changelog entries for added/fixed V18 items.
Tests & Type-check Updates
test/unit/..., test/type-check/consumer.ts
Adds and updates unit tests for projection routing, PatchBuilder intent lowering, PropValue validation, GraphOpAlgebraProjection, StateReader snapshot parity, and property-intent behavior; adjusts smoke type-check wiring and WarpGraph coverage test seeding to include live nodes for property visibility.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Caller
  participant Reader as createStateReader
  participant Hydration as createStateReaderProjectionState
  participant Snapshot as SnapshotWarpState
  participant Projection as NodePropertyProjection

  Client->>Reader: createStateReader(source: StateReaderSource)
  Reader->>Hydration: convert source to live WarpState
  Hydration->>Snapshot: check if SnapshotWarpState
  Snapshot->>Hydration: warpStateFromSnapshot (rebuild CRDT/frontier/props)
  Hydration-->>Reader: live WarpState (hydrated or original)
  Reader->>Projection: derive property records
  Projection-->>Reader: visible node/edge property records
  Reader-->>Client: VisibleStateReader with projection-backed props
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • git-stunts/git-warp#96: Adds projection-based graph-op types and projection routing that this PR extends.
  • git-stunts/git-warp#99: Overlaps StateReader/QueryReads projection routing and property projection helpers used here.
  • git-stunts/git-warp#41: Prior CI/type-firewall surface/typecheck gating changes related to the workflow gate rewiring in this PR.

Poem

"🐰 I wrapped old keys in intent-made coats,
Hydrated snapshots, counted projective votes,
Ops now speak typed nouns, projections sing,
Tests hop in circles — lint and semgrep bring,
A rabbit cheers: slices closed, here comes spring!"

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description covers the main changes (property view routing, write intent nouns, graph-op cutover, and backlog closure), includes a comprehensive verification section detailing tests run and gates passed, and provides relevant notes about follow-up work. However, it does not include all required ADR checks from the template (missing ADR 2, ADR 3, persisted op formats, and schema constants checkboxes). Complete the ADR checks section by explicitly checking or addressing each checkbox: ADR 2/3 applicability, persisted op formats, wire compatibility, and schema constants. If not applicable, explain why.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Implement v18 property projection cutover' clearly summarizes the main objective of the changeset—implementing the v18 property projection cutover—and is directly supported by the substantial property projection, write intent, and graph-op algebra changes throughout the PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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

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

🧹 Nitpick comments (1)
src/domain/services/state/StateReader.ts (1)

193-207: ⚡ Quick win

Cache node property records once during context build.

createProjectionProps(projectionState) and createNodePropertyRecords(projectionState) both end up walking NodePropertyProjection.fromState(...), so each reader build decodes/sorts the same node-property set twice. Materializing that array once here and deriving both projection.props and nodePropsById from it would avoid the duplicate pass.

🤖 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/state/StateReader.ts` around lines 193 - 207, Materialize
node property records once: call createNodePropertyRecords(projectionState) into
a local const (e.g., nodePropertyRecords) and reuse it for both building
projection.props and populating nodePropsById instead of calling
createNodePropertyRecords(...) twice; to do this, add or modify a helper so you
can derive projection.props from the precomputed records (e.g.,
createProjectionPropsFromRecords(nodePropertyRecords) or adjust
createProjectionProps to accept the records), then pass nodePropertyRecords into
populateVisibleNodeProps(nodePropertyRecords, nodePropsById) and remove the
duplicate createNodePropertyRecords(...) call.
🤖 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 @.github/workflows/ci.yml:
- Around line 36-38: Replace floating action tags by pinning the uses fields for
actions/checkout and actions/setup-node to their immutable commit SHAs (replace
uses: actions/checkout@v6 and uses: actions/setup-node@v6 with
actions/checkout@<commit-sha> and actions/setup-node@<commit-sha>, and update
every occurrence), add a top-level permissions: block with least-privilege
scopes required by the workflow, and set persist-credentials: false on each
actions/checkout step to avoid credential persistence (locate and modify the
checkout steps and the workflow header permissions in the CI yaml).
- Around line 33-48: The workflow grants excessive token scope and leaves
checkout credentials persisted; for the job type-firewall-lint (and all other
jobs using actions/checkout@v6) add a minimal job-level permissions block (e.g.,
permissions: contents: read and only the specific permissions needed) and update
each actions/checkout@v6 step to include with: persist-credentials: false so the
GITHUB_TOKEN is not left in the runner git config; apply the same changes to all
jobs named in the comment (type-firewall-types, type-firewall-lint,
type-firewall-semgrep, type-firewall-quarantine, type-firewall-surface,
type-firewall-docs, type-firewall-audit-advisory, typecheck-test-advisory,
test-node, test-bun, test-deno, coverage-threshold) to harden token scope and
disable credential persistence.

In `@src/domain/services/PatchBuilder.ts`:
- Around line 463-507: requirePatchPropertyValue currently can recurse forever
on cyclic inputs and can be polluted via prototype keys; fix by adding cycle
detection (pass a WeakSet seen through recursive calls and throw PatchError with
code 'E_PATCH_INVALID_PROPERTY_VALUE' if a non-scalar object/array is already in
seen) and by guarding against prototype-polluting keys when normalizing plain
objects (either reject keys like '__proto__' and 'constructor' with PatchError
or create records with Object.create(null) and still reject any key named
'__proto__' or 'constructor'); update requirePatchPropertyValue to accept an
internal seen: WeakSet<object> param, mark objects/arrays before recursing, and
keep isPlainPatchPropertyObject as-is for detection but ensure the object
key-check happens in requirePatchPropertyValue when building record/array to
deterministically fail on cycles and prototype-key pollution.

In `@test/unit/domain/services/PatchBuilderPropertyIntent.test.ts`:
- Around line 16-63: Add unit tests in PatchBuilderPropertyIntent.test.ts that
exercise the remaining property normalization branches: add a test that calls
createBuilder(...) and builder.setProperty('node:1','bin', new
Uint8Array([1,2,3])) then build() and assert the op value accepts Uint8Array and
patch.schema is correct; add tests that pass nested/recursive structures via
builder.setProperty (e.g., arrays and objects) to ensure they are normalized and
appended to ops by build(); and add a test that supplies a cyclic value to
builder.setProperty and asserts it throws PatchError (or the same cyclic
rejection path) and that builder.build().ops remains empty. Reference the
existing helpers and symbols used in the file (createBuilder,
builder.setProperty, setEdgeProperty, InvalidPropertyCarrier, PatchError,
requirePropSet, encodeLegacyEdgePropNode) so tests align with current test
patterns.

In `@test/unit/domain/services/StateReaderPropertyProjection.test.ts`:
- Around line 26-81: Add a parallel test that constructs a SnapshotWarpState via
warpStateFromSnapshot (or by calling StateReaderSource.snapshot path) containing
the same nodes/edges/prop entries as the existing WarpState test, then call
createStateReader with that SnapshotWarpState and assert the same results for
getNodeProps, getEdgeProps, getEdges, project().props and
getNodeContentMeta/getEdgeContentMeta as in the live-state cases; locate where
the existing tests create the live WarpState (functions addLiveNode,
addLiveEdge, encodePropKey, encodeEdgePropKey) and replicate those setup steps
but convert the final state into a SnapshotWarpState using warpStateFromSnapshot
(or the StateReaderSource API) before creating the reader so the snapshot code
path (SnapshotWarpState/StateReaderSource) is exercised and assertions remain
identical.

---

Nitpick comments:
In `@src/domain/services/state/StateReader.ts`:
- Around line 193-207: Materialize node property records once: call
createNodePropertyRecords(projectionState) into a local const (e.g.,
nodePropertyRecords) and reuse it for both building projection.props and
populating nodePropsById instead of calling createNodePropertyRecords(...)
twice; to do this, add or modify a helper so you can derive projection.props
from the precomputed records (e.g.,
createProjectionPropsFromRecords(nodePropertyRecords) or adjust
createProjectionProps to accept the records), then pass nodePropertyRecords into
populateVisibleNodeProps(nodePropertyRecords, nodePropsById) and remove the
duplicate createNodePropertyRecords(...) call.
🪄 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: 42937f48-5de7-4608-85e0-a36a20e15952

📥 Commits

Reviewing files that changed from the base of the PR and between 35e5a6a and 7004b0d.

📒 Files selected for processing (33)
  • .github/workflows/ci.yml
  • CHANGELOG.md
  • docs/BEARING.md
  • docs/design/0179-v18-state-reader-property-projection/v18-state-reader-property-projection.md
  • docs/design/0180-v18-property-write-intent-nouns/v18-property-write-intent-nouns.md
  • docs/design/0181-v18-patchbuilder-property-intent-lowering/v18-patchbuilder-property-intent-lowering.md
  • docs/design/0182-v18-graph-op-projection-property-cutover/v18-graph-op-projection-property-cutover.md
  • docs/design/0183-v18-property-projection-closeout/v18-property-projection-closeout.md
  • docs/method/backlog/v18.0.0/PROTO_legacy-props-as-projection.md
  • src/domain/graph/EdgePropertyWriteIntent.ts
  • src/domain/graph/GraphContentAttachmentSetOp.ts
  • src/domain/graph/GraphEdgePropertySetOp.ts
  • src/domain/graph/GraphNodePropertySetOp.ts
  • src/domain/graph/GraphOpAlgebra.ts
  • src/domain/graph/GraphOperation.ts
  • src/domain/graph/NodePropertyWriteIntent.ts
  • src/domain/graph/publicGraphSubstrate.ts
  • src/domain/services/GraphOpAlgebraProjection.ts
  • src/domain/services/PatchBuilder.ts
  • src/domain/services/TranslationCost.ts
  • src/domain/services/controllers/QueryReads.ts
  • src/domain/services/query/StateQueryReadModel.ts
  • src/domain/services/state/StateReader.ts
  • src/domain/services/state/StateReaderContext.ts
  • test/type-check/consumer.ts
  • test/unit/domain/WarpGraph.coverageGaps.test.ts
  • test/unit/domain/graph/GraphOpAlgebra.test.ts
  • test/unit/domain/graph/PropertyWriteIntent.test.ts
  • test/unit/domain/services/GraphOpAlgebraProjection.test.ts
  • test/unit/domain/services/PatchBuilderPropertyIntent.test.ts
  • test/unit/domain/services/QueryReadsPropertyProjection.test.ts
  • test/unit/domain/services/StateReaderPropertyProjection.test.ts
  • test/unit/domain/services/query/StateQueryReadModelPropertyProjection.test.ts

Comment thread .github/workflows/ci.yml
Comment thread .github/workflows/ci.yml Outdated
Comment thread src/domain/services/PatchBuilder.ts Outdated
Comment thread test/unit/domain/services/PatchBuilderPropertyIntent.test.ts
Comment thread test/unit/domain/services/StateReaderPropertyProjection.test.ts
@flyingrobots
Copy link
Copy Markdown
Member Author

@codex self-review findings for confirmation.

Severity File Lines Type Finding Mitigation prompt
P2 Major src/domain/services/PatchBuilder.ts 464, 488, 498-499 Anti-sludge policy The branch introduces new unknown signatures in domain code with nosemgrep comments that do not reference an owning ticket. This violates the repo's stated rejection rule for unknown outside adapters and the inline-suppression discipline used for 0025B boundary debt. "Remove the newly introduced helper-level unknown boundary in PatchBuilder, or convert it into a named validated boundary/parser shape that does not add fresh unknown suppressions. If a suppression is genuinely unavoidable, reference the owning ticket such as 0025B and document why the public PatchBuilder boundary cannot be moved yet."
P5 Nit src/domain/services/GraphOpAlgebraProjection.ts 16, 20-24 Documentation drift fromState() says it returns operations ordered as nodes, edges, then attachments, but the implementation now emits nodes, edges, content attachments, node-property ops, and edge-property ops. "Update the GraphOpAlgebraProjection.fromState() comment to name the actual operation ordering: node records, edge records, content attachments, node properties, then edge properties."
P5 Nit src/domain/graph/publicGraphSubstrate.ts 10-27 Export ordering The public graph substrate barrel is otherwise grouped lexically by concept family, but EdgePropertyWriteIntent appears before EdgeId, and NodePropertyWriteIntent appears before NodeRecord. This is tiny, but it makes the public surface harder to scan. "Restore concept-family ordering in publicGraphSubstrate.ts: keep EdgeId/EdgeRecord/EdgeTypeId together before edge property write intent, and keep NodeId/NodeRecord/NodeTypeId together before node property write intent, unless the repo has a documented alternate order."

@flyingrobots
Copy link
Copy Markdown
Member Author

Resolved the self-review findings in 731193e9.

Finding Severity Resolution Commit
New helper-level unknown suppressions in PatchBuilder property-value validation P2 Removed the new helper suppressions and reused the shared isPropValue guard with generic narrowing. 731193e9
Stale graph-op projection ordering comment P5 Updated the comment to match the emitted order: nodes, edges, content, node props, edge props. 731193e9
Public substrate export ordering drift P5 Restored concept-family ordering for edge/node records and property write intent exports/types. 731193e9

Local verification before push:

  • npm run typecheck
  • npm run lint
  • npm run lint:sludge
  • npm run lint:semgrep
  • npm run typecheck:policy
  • npm run typecheck:consumer
  • npm run typecheck:surface
  • GIT_WARP_QUARANTINE_BASE=origin/main npm run lint:quarantine-graduate
  • npx markdownlint-cli2 CHANGELOG.md
  • npx vitest run test/unit/domain/services/PatchBuilderPropertyIntent.test.ts test/unit/domain/graph/PropertyWriteIntent.test.ts test/unit/domain/services/GraphOpAlgebraProjection.test.ts
  • npm run test:local (488 files, 6956 tests)
  • pre-push IRONCLAD M9 gate (488 files, 6956 tests)

@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
Copy link
Copy Markdown
Member Author

Resolved the unresolved review threads in dfb1831a.

Thread Resolution Commit
CI token permissions and checkout credential persistence Added top-level permissions: contents: read and persist-credentials: false to every actions/checkout step. dfb1831a
Floating GitHub Action references Pinned actions/checkout@v6 to de0fac2e4500dabe0009e67214ff5f5447ce83dd and actions/setup-node@v6 to 48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e. dfb1831a
Cyclic/prototype-polluting property values Added cycle detection and forbidden object-key rejection to the shared property-value guard before write intent lowering. dfb1831a
PatchBuilder property normalization coverage Added coverage for bytes, nested recursive property-compatible values, cyclic rejection, and prototype-polluting key rejection. dfb1831a
SnapshotWarpState state-reader coverage Added live-vs-snapshot parity coverage for props, edges, projection rows, and content metadata. dfb1831a
StateReader duplicate node-property projection pass Materialized node/edge property records once during reader context construction and reused them for projection rows and indexes. dfb1831a

Local verification:

  • Workflow YAML parse
  • No remaining actions/checkout@v6 or actions/setup-node@v6 references in CI
  • npx eslint src/domain/types/PropValue.ts src/domain/services/PatchBuilder.ts src/domain/services/state/StateReader.ts src/domain/services/state/StateReaderContext.ts test/unit/domain/services/PatchBuilderPropertyIntent.test.ts test/unit/domain/services/StateReaderPropertyProjection.test.ts
  • npx vitest run test/unit/domain/services/PatchBuilderPropertyIntent.test.ts test/unit/domain/services/StateReaderPropertyProjection.test.ts
  • npm run typecheck
  • npm run lint
  • npm run lint:sludge
  • npm run lint:semgrep
  • npm run typecheck:policy
  • npm run typecheck:consumer
  • npm run typecheck:surface
  • GIT_WARP_QUARANTINE_BASE=origin/main npm run lint:quarantine-graduate
  • npx markdownlint-cli2 CHANGELOG.md
  • git diff --check
  • npm run test:local (488 files, 6960 tests)
  • pre-push IRONCLAD M9 (488 files, 6960 tests)

@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
Copy link
Copy Markdown
Member Author

@codex self-review findings for confirmation.

Severity File Lines Type Finding Mitigation prompt
P2 Major src/domain/services/state/StateReaderContext.ts 125-137 Boundary validation / prototype pollution / non-termination propValueFromSnapshot() recursively hydrates SnapshotPropValue arrays and objects without a seen-set and writes object entries into {} via assignment. This reopens the same class of cycle/prototype-key risk just closed for PatchBuilder: a cyclic snapshot value can recurse indefinitely, and enumerable __proto__ / constructor / prototype keys are not rejected before hydration. The currently added snapshot parity test only covers snapshots produced by createSnapshotWarpState(), so the public SnapshotWarpState reader boundary lacks hostile-value coverage. "Harden propValueFromSnapshot() in StateReaderContext: add a WeakSet<object> recursion guard, reject forbidden property keys (__proto__, constructor, prototype) with WarpError, and add tests that feed createStateReader() a SnapshotWarpState containing cyclic and prototype-key snapshot property values. Keep the fix local to snapshot hydration and preserve trusted createSnapshotWarpState() parity behavior."

@flyingrobots
Copy link
Copy Markdown
Member Author

Resolved the P2 self-review finding in c5774190.

Finding Severity Resolution Commit
Snapshot property hydration could recurse through cyclic values and did not reject prototype-polluting keys at the SnapshotWarpState reader boundary. P2 Major Added a WeakSet recursion guard, rejected __proto__, constructor, and prototype keys during snapshot hydration, added hostile SnapshotWarpState regression tests, and documented the fix in CHANGELOG.md. c5774190

Verification:

  • RED: npx vitest run test/unit/domain/services/StateReaderPropertyProjection.test.ts failed on cyclic and prototype-key snapshot values before the fix.
  • GREEN: npx vitest run test/unit/domain/services/StateReaderPropertyProjection.test.ts (5 tests)
  • npx eslint src/domain/services/state/StateReaderContext.ts test/unit/domain/services/StateReaderPropertyProjection.test.ts
  • npm run typecheck
  • npm run lint
  • npm run lint:semgrep
  • GIT_WARP_QUARANTINE_BASE=origin/main npm run lint:quarantine-graduate
  • npx markdownlint-cli2 CHANGELOG.md
  • git diff --check
  • npm run test:local (488 files, 6962 tests)
  • pre-push IRONCLAD M9 (488 files, 6962 tests)

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

🤖 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/services/state/StateReaderContext.ts`:
- Around line 168-179: The hydration currently treats any non-null object as a
snapshot property bag; update isSnapshotPropValueObject (and validate again at
the start of propValueObjectFromSnapshot) to only accept plain objects whose
prototype is Object.prototype or null, that are not arrays or ImmutableBytes,
and whose own property descriptors (Object.getOwnPropertyDescriptors) are all
data descriptors (no getters/setters); if the input fails these checks throw
E_STATE_READER_INVALID_SNAPSHOT_PROPERTY_VALUE. Keep the existing seen handling
in propValueObjectFromSnapshot and only proceed to
Object.entries/propValueFromSnapshotWithSeen after the plain-object +
data-descriptor validation passes.
🪄 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: 85bb31c8-bd84-4eef-bbca-95407d8653a2

📥 Commits

Reviewing files that changed from the base of the PR and between dfb1831 and c577419.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/domain/services/state/StateReaderContext.ts
  • test/unit/domain/services/StateReaderPropertyProjection.test.ts
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md

Comment thread src/domain/services/state/StateReaderContext.ts
@flyingrobots
Copy link
Copy Markdown
Member Author

Resolved the latest CodeRabbit actionable feedback in c6be78a2.

Feedback Severity Resolution Commit
StateReaderContext snapshot hydration accepted custom-prototype and accessor-backed objects before treating them as property bags. Major Added plain-object validation, data-descriptor-only validation before Object.entries, regression coverage for custom-prototype values, and regression coverage that proves getters are not invoked. c6be78a2

Verification:

  • RED: npx vitest run test/unit/domain/services/StateReaderPropertyProjection.test.ts failed before the fix on custom-prototype and accessor-backed snapshot property objects.
  • GREEN: npx vitest run test/unit/domain/services/StateReaderPropertyProjection.test.ts (7 tests)
  • npx eslint src/domain/services/state/StateReaderContext.ts test/unit/domain/services/StateReaderPropertyProjection.test.ts
  • npm run typecheck
  • npm run lint
  • npm run lint:semgrep
  • GIT_WARP_QUARANTINE_BASE=origin/main npm run lint:quarantine-graduate
  • npx markdownlint-cli2 CHANGELOG.md
  • git diff --check
  • npm run test:local (488 files, 6964 tests)
  • pre-push IRONCLAD M9 (488 files, 6964 tests)

@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 f9230f0 into main May 24, 2026
16 checks passed
@flyingrobots flyingrobots deleted the v18-continuum-slices-31-35 branch May 24, 2026 06:43
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