fix(server): make feature-request reads idempotent (ARN-240) - #385
fix(server): make feature-request reads idempotent (ARN-240)#385nerdsane wants to merge 6 commits into
Conversation
|
Independent review of the published open-PR diff at head Blocking findings:
Other audited properties in the diff look sound: the GET write loop is removed; identity includes tenant and explicit generator version; description and evidence ordering are normalized; the actor dispatch uses the stable entity ID and idempotency key; actor-first/projection-second ordering is retryable after a projection failure; and PostgreSQL/Turso preserve human-owned fields consistently on conflict. Verdict: FAIL |
|
Fresh re-review of the current published open-PR diff at head One blocking finding remains:
The prior concurrency finding is fixed: the test now counts Verdict: FAIL |
|
Fresh re-review of the current published open-PR diff at head The canonical-note-byte finding is fixed. One new blocking finding from the whole-diff review:
Verdict: FAIL |
|
Fresh re-review of the current published open-PR diff at head No blocking findings. Verified:
Verdict: PASS |
|
@greptile review |
ARN-240 live local E2E (head
|
|
ARENA SHIPPABLE · GPT-5.6 · 2026-07-14T12:46:34Z Fresh GPT-5.6 whole-diff review PASS: #385 (comment) Live local HTTP + durable restart E2E evidence: #385 (comment) Greptile PASS and all required CI checks green on head af103e9. PR is ready for review. MERGE NOTHING. |
|
Fresh independent review of the complete published open-PR diff at head 40f6471. The latest Greptile remediation is correct: stable_platform_gap_category_key is exhaustive, preserves the established category strings, and removes Debug formatting from the durable identity preimage. One actionable finding remains:
I also rechecked GET purity, actor/projection retry ordering, exact-one concurrent creation, restart durability, legacy cleanup bounds, preservation of human disposition and canonical note bytes, cross-action separation, tenant-ambiguous fail-closed migration, backend symmetry, and DST-sensitive collection/time behavior; no additional blockers found. Verdict: FAIL |
|
Fresh independent review of the complete published open-PR diff at reviewed head No blocking findings. The premise of the prior FAIL comment is refuted by the complete generator path. In The Greptile durable-category remediation is correct. I also reviewed the full ten-file PR diff for GET purity, tenant filtering and tenant-salted identity, fail-closed legacy tenant attribution, cross-action reconciliation, preservation of disposition and canonical note bytes, actor-first retry recovery, concurrent and restart idempotency, stable evidence ordering, bounded legacy cleanup, Postgres/Turso symmetry, and deterministic-simulation-sensitive collection/time usage. The focused tests cover pure repeated/concurrent GETs, exact-one creation under concurrent Sentinel calls, explicit revisions, legacy reconciliation, ambiguous cross-tenant evidence, category tokens, and process restart. Current GitHub checks, including Tests, Compile & Lint, DST/platform suites, integrity, verification, and Greptile, are green at the reviewed head. Verdict: PASS |
|
ARENA SHIPPABLE · GPT-5.6 · 2026-07-14T21:09:11Z ARN-240 is shippable at Required PR-gate evidence, in order:
Current-head validation is green: local pre-push |
|
Closing this ARN-240 competition entry. Adjudicated in favor of Fable #402 (messy path (6 commits, 4 self-introduced defects) vs the clean winner). This branch is preserved for grafting its best parts into the winner; full scoring is on the ARN-165 arena board. (Rita-directed close, 2026-08-11.) |
Summary
GET /observe/evolution/feature-requestsa projection-only read with no durable writesRoot cause
The GET handler generated feature requests and wrote both projection rows and
FeatureRequestactor events on every read. Generated record IDs and actor IDs were fresh UUIDs, so repeated or concurrent reads created durable duplicates.Design and tradeoffs
Materialization now belongs to
POST /api/evolution/sentinel/check, the existing authorized command boundary. The stable revision identity is SHA-256 over the source tenant, an explicit generator version, category, canonical description, frequency, and sorted trajectory references. Changed evidence or a changed generator version intentionally creates a new revision; an exact retry reuses the same actor ID and durable idempotency key.Generated fields may refresh on an existing projection, but conflict updates deliberately retain human-owned disposition and developer notes. Legacy
FR-YYYY-<12 hex>projections are migrated to the stable revision without losing review state. Reconciliation is action-disambiguated and retry-safe after partial cleanup: the canonical note blob is preserved byte-for-byte, while genuinely missing legacy note components append deterministically.The canonical
FeatureRequestentity lives in thetemper-systemcontrol-plane tenant, while the source tenant is filtered before generation and salted into the identity. Because legacy rows did not store tenant IDs, they are migrated only if every referenced trajectory is present and all refs resolve exclusively to the active source tenant. Ambiguous, malformed, incomplete, or mixed-tenant legacy evidence is deliberately left untouched for human resolution instead of guessed or deleted.No ADR was added: this is a localized correctness/durability repair using the existing Sentinel command, actor dispatch, durable idempotency, and metadata-store abstractions rather than introducing a new architectural pattern.
RED evidence
RED-only commit:
5338da03Validation
CARGO_INCREMENTAL=0 cargo test -p temper-server --features observe feature_request -- --nocapture— 8 passed, 0 failedCARGO_INCREMENTAL=0 cargo clippy -p temper-server -p temper-store-turso -p temper-store-postgres --all-targets --all-features -- -D warnings— passed (full touched-crate gate); final server-only follow-ups rechecked with the same strict flagscargo fmt --all -- --check— passedgit diff --check— passedThe local workspace suite compiled successfully and passed all completed groups, but the untouched
temper-actor-runtimeintegration binary failed before test logic because Docker timed out creating all five Postgres testcontainers (CreateContainer(RequestTimeoutError)). A serialized retry reproduced the Docker startup failure. GitHub CI on clean runners is the authoritative full-suite gate.Scope
No changes to
crates/temper-actor-runtime.Linear: ARN-240
Greptile Summary
This PR moves feature-request materialization out of the GET handler and into the authorized sentinel command, so reads are now projection-only with no durable side effects. Stable, content-addressed IDs (SHA-256 over tenant, generator version, category, description, frequency, and sorted trajectory refs) replace the previously random UUIDs, and durable idempotency keys prevent duplicate actor events on retry or concurrent invocations.
gap_analysis.rs: Normalizes description to the lexicographically smallest error string in each group, and sorts trajectory timestamps before hashing, eliminating two sources of order-dependence in the stable ID.operations.rs+reconcile.rs: Addsmaterialize_feature_requests(called only from sentinel) that upserts stable projections, dispatches actor events with idempotency keys, and reconciles legacy projections — safely skipping ambiguous or mixed-tenant rows.storage/evolution.rs: Extracts theEvolutionStoretrait and addsdelete_feature_request; the upsert SQL is narrowed to preservedispositionanddeveloper_noteson conflict.Confidence Score: 4/5
Safe to merge once the two open issues from prior review rounds are resolved.
The core correctness fix is sound and well-tested with five focused integration tests. Two issues flagged in earlier rounds remain open: the description accumulator starts at empty string when the first entry has no error, so the normalization loop never fires and the stable ID varies by arrival order; and format!("{:?}", category) is still used for the stored category column in reconcile.rs.
gap_analysis.rs (description accumulator initialization) and reconcile.rs (category string via Debug format)
Important Files Changed
Reviews (3): Last reviewed commit: "fix(server): stabilize feature request c..." | Re-trigger Greptile