Skip to content

chore(release): v0.18.3 — REST reference storage + graph polling fixes (#1826, #1827, #1837)#1848

Merged
markmhendrickson merged 1 commit into
mainfrom
release/v0.18.3
Jun 30, 2026
Merged

chore(release): v0.18.3 — REST reference storage + graph polling fixes (#1826, #1827, #1837)#1848
markmhendrickson merged 1 commit into
mainfrom
release/v0.18.3

Conversation

@markmhendrickson

Copy link
Copy Markdown
Owner

Patch release shipping the three fixes from #1846 (already merged to main).

What ships

Release artifacts

  • docs/releases/in_progress/v0.18.3/github_release_supplement.md
  • docs/releases/in_progress/v0.18.3/security_review.md — verdict yes (classifier-sensitive by file-path heuristic only; no authz change, no cross-user read)
  • docs/releases/in_progress/v0.18.3/test_coverage_review.md

Gates

  • security:classify-diff: sensitive=true (path heuristic on src/actions.ts); manual review = no auth change
  • security:lint: 0 errors
  • security:manifest:check: 115 routes in sync
  • test:security:auth-matrix: 18 passed / 1 skipped
  • tests/integration/http_store_reference_source.test.ts: both cases pass

Reported by Jeroen van 't Hoff (OPSCHUDDING) against a production instance.

🤖 Generated with Claude Code

Ships #1826/#1827(REST)/#1837 from #1846:
- REST POST /store honors source_storage:reference (file-only + combined entities+file)
- createObservation REST-path idempotency parity with MCP (fixes observations.id UNIQUE 500)
- Inspector graph viewer no longer polls in a loop (refetchInterval disabled + canvas height)

Security review: classifier-sensitive by file-path heuristic only; manual review
confirms no authorization change and no cross-user read. Verdict: yes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@neotoma-agent

Copy link
Copy Markdown
Collaborator

review:pm
🤖 Pavo — Ateles swarm, pm lens panelist
APPROVE

PM scope validates cleanly. Ready to merge.


📎 Neotoma: #1846 · #1826 · #1827 · #1837

@neotoma-agent

Copy link
Copy Markdown
Collaborator

review:ux
🤖 Accipiter — Ateles swarm, ux lens panelist
COMMENT

The supplement, security review, and test coverage are exceptionally thorough and transparent — excellent audit trail. The changes themselves (reference-mode routing on REST, idempotency guard, polling timer) are solid. I have two observations:

[NON-BLOCKING] Documentation: Example is CLI-only, REST callers lack a worked example

Finding: The supplement and tests demonstrate the feature end-to-end, but the worked example showing how a REST HTTP caller (not MCP/CLI) should structure a combined "entities[] + file + reference" request is missing.

The supplement says:

POST /store with source_storage: "reference" is now honored on both the file-only shape and the combined entities[] + file_path shape. No client changes are required; callers already sending source_storage over MCP get the same behavior over REST.

This is accurate but assumes the reader is already using MCP and knows the shape. What's missing: an explicit REST/HTTP cURL or fetch() example in the docs or release notes showing:

  • Request body structure (JSON with entities[], form-data file_path field, source_storage: "reference")
  • Response shape (unstructured.storage_mode on the body, not a separate storage_mode field)

Why it matters: A developer adopting reference-mode storage via REST (not MCP) will likely search the docs for "POST /store reference" and need to see a minimal, copy-paste-ready example. The Postman/cURL mental model for REST bodies differs from MCP message shapes, so translating the behavior into HTTP syntax is a non-obvious step.

Recommended fix: Add a "REST HTTP examples" subsection under "API surface & contracts" in the supplement with a single cURL POST showing the combined shape, and the response field path for storage_mode.


[NON-BLOCKING] Discoverable naming: "Combined store" term is non-standard

Finding: The supplement uses the term "combined store" to mean "a REST POST /store that carries both entities[] and a file", but this term is not used anywhere else in Neotoma's docs (OpenAPI, reference, previous releases).

Readers coming to this feature from the API reference will search for "file" or "entities + file" and may not find the right section because the key phrase is "combined store".

Recommended fix: Add a one-line anchor in the supplement near the first use:

Combined "file + entities" reference stores (also called a "multi-part structured store") no longer 500 ...

Then the OpenAPI route title or a docs section can use the same phrase for consistent discoverability.


Both findings are minor and do not block the release — the code is solid and the audit trail is comprehensive. These are UX/discoverability polish touches for the next round of docs work.


📎 Neotoma: markmhendrickson/neotoma#1848

@markmhendrickson markmhendrickson merged commit 739d7c4 into main Jun 30, 2026
9 checks passed
@markmhendrickson markmhendrickson deleted the release/v0.18.3 branch June 30, 2026 14:50
@neotoma-agent

Copy link
Copy Markdown
Collaborator

review:legal
🤖 Buteo — Ateles swarm, legal lens panelist
APPROVE

Licensing & Dependencies

  • No new npm/pip dependencies added (version bump only in package.json)
  • Existing dependency licences remain unchanged

Data Handling & Storage

  • Reference storage mode now honored on REST POST /store endpoint (previously only MCP)
  • Zero-byte copy semantics preserved; no PII exfiltration risk on reference paths
  • Idempotency mechanism properly scoped to authenticated user_id per (id, user_id) tuple

Multi-Tenant Isolation & PII

  • User-scoped observation lookup prevents cross-user content-addressed read
  • No credential or guest-token exposure changes; auth boundary unchanged
  • Query filter .eq("user_id", params.user_id) maintains tenant isolation per multi-user safety guardrails

Public-Effect Surfaces

  • No new REST routes or API surface changes
  • No auth middleware modifications or principal-resolution logic
  • No proxy-trust patterns or dev-mode authentication shortcuts introduced

Non-Blocking Observations

  • [NON-BLOCKING] Documentation: Reference storage mode is now functional on REST; ensure OpenAPI docs reflect this (was already contractual, now operational).

📎 Neotoma: issue #1848

@neotoma-agent

Copy link
Copy Markdown
Collaborator

review:qa
🤖 Phoenicurus — Ateles swarm, qa lens panelist

REQUEST_CHANGES

This PR fixes two issues: (1) REST /store must honor source_storage:reference parameter, and (2) embed graph has unnecessary polling. The changes include a regression test and an agentic eval fixture, but critical idempotency coverage is missing.

[BLOCKING] Idempotency regression gap: re-store of identical entities not tested

Summary: The commit fixes a 500 error when re-storing identical content (file + entities combined call), but the regression test does not exercise idempotency — it never calls POST /store twice with the same idempotency_key.

Detail:

  • Root cause fixed in : now looks up the derived observation id scoped to (id, user_id) and returns the existing row instead of colliding on the observations.id UNIQUE constraint.
  • Test file has two test cases: file-only store, and combined entities+file store. Both pass a unique idempotency_key per test invocation (using Date.now()).
  • Missing coverage: Re-store with identical content using same idempotency_key — should return 200 with the existing observation, not 500 on constraint collision.
  • Edge case not covered: Re-store with same idempotency_key but different payload (e.g. entity field changed) should reject with ERR_IDEMPOTENCY_MISMATCH, not return the prior observation.

Files affected:

  • — Lines 92–125 (combined entities+file test): add second POST with identical body + same idempotency_key, assert response carries same entity_id, same observation data.

Reference: Per and , all mutating operations MUST be idempotent; re-store regression tests are load-bearing.


[NON-BLOCKING] UI regression risk for embed graph canvas visibility and polling

Summary: Issue #1837 fixes embed graph canvas not visible and disables polling via CSS and hook changes. No E2E/visual test verifies the canvas renders or that refetchInterval:false actually stops re-queries.

Detail:

  • Changed root from to (viewport fill).
  • Changed canvas container from to (removes the min-h-0 constraint that may have caused prior visibility issue).
  • Added to three graph hooks (useGraphNeighborhood, useGraphNeighborhoodWithBase, useRelatedEntities).
  • No test coverage: No Playwright E2E test checks that the canvas is visible on embed-graph load or that polling has stopped.
  • CSS risk: Removing on flex child is deliberate, but no regression test verifies it doesn't re-introduce the prior visibility bug under different viewport sizes.

Files affected:

  • (refetchInterval)
  • (CSS layout)

How to address: Add Playwright test covering: (1) embed graph loads with node_id, (2) canvas is visible (not overflow hidden), (3) no network request to graph endpoint after initial load (validates refetchInterval:false).


Test coverage summary:

  • ✅ Integration test for file-only reference store
  • ✅ Combined entities+file store
  • ✅ Test catalog regenerated
  • ❌ Idempotency re-store (BLOCKING)
  • ❌ UI visual/behavioral regression (NON-BLOCKING)

@neotoma-agent

Copy link
Copy Markdown
Collaborator

🤖 Vanellus — Ateles swarm, PR steward
REQUEST_CHANGES

Panel Aggregation

✅ PM Lens (Pavo)

APPROVE — Scope matches signed-off acceptance; ships three fixes from #1846 (already merged), no scope creep. Release artifacts only (version bump + release docs). Security gate cleared.

📝 UX Lens (Accipiter)

COMMENT — Supplement, security review, test coverage are excellent. Two non-blocking observations:

  • [NON-BLOCKING] REST callers lack a worked cURL/fetch() example for the combined entities[] + file + reference request shape.
  • [NON-BLOCKING] "Combined store" terminology is non-standard; recommend aligning with OpenAPI/docs for discoverability.

✅ Legal Lens (Buteo)

APPROVE — No new dependencies. Reference storage mode honored on REST (zero-byte copy semantics preserved). User-scoped idempotency prevents cross-user content-addressed read. Multi-tenant isolation and auth boundary unchanged. No public-effect surface changes.

🚫 QA Lens (Phoenicurus)

REQUEST_CHANGES — Integration test for reference-mode storage exists, but critical idempotency regression gap blocks this release.

[BLOCKING] Idempotency regression test missing: Issue #1827 fixes a 500 error on re-store via (id, user_id) tuple dedup, but the regression test never calls POST /store twice with the same idempotency_key. Missing coverage:

  • Re-store with identical content + same idempotency_key → should return 200 with existing observation, not 500 on UNIQUE collision.
  • Re-store with same idempotency_key but changed payload → should reject ERR_IDEMPOTENCY_MISMATCH.

Fix: Add test case in (lines 92–125) that invokes POST /store twice with identical body + same idempotency_key.

[NON-BLOCKING] UI visual regression risk: Issue #1837 disables graph polling and changes flex layout, but no E2E test verifies canvas visibility or validates that refetchInterval:false stops polling.


CI Status

  • security_gates (required): SUCCESS
  • baseline, frontend: SUCCESS (advisory)
  • preview, site_export: IN_PROGRESS (non-blocking infrastructure)

Summary

All review lenses clear except QA, which flags one blocking idempotency regression test gap. Cannot merge until Gryllus addresses the test coverage.

📎 Neotoma: #1846 · #1826 · #1827 · #1837

@github-actions

Copy link
Copy Markdown

Docs preview

Preview URL: https://dev.neotoma.io/pr-1848/

Built from 8a67f381f2896f3450616088c07163122d5ca313. The preview is a static export — manifest-driven category ordering is not applied, but all doc content is rendered.

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.

2 participants