Repository navigation
Description
domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd
Filing gate: ① a named, reproduced defect, here a test that reads a read as a write. It was measured on PR #28613's own nightly-tiers run, and it is not that PR's: it only reshuffles shards.
Business reason: the nightly live tier is the only place the Console live specs run outside the required job (examples/app-showcase/test/console-live-specs.live.test.ts). While this spec fails, that tier stays red on main, and the red card it files (#28580's channel) hides any real regression behind a known one.
Reader: the domain:ui lane, the next PR on ui/e2e/live/. Until #28613 lands, the nightly's shard 1 is killed by its 45-minute timeout before this spec runs. Once it lands, this is the next red the card reports.
Dedupe (open AND closed): "read-only-member-record" → 9 hits (#27552, closed, is the card that added the spec; none reports this), "attempted no write" → 17 hits, none on this spec, "/page write detector" → 0 hits.
reach: measured, nightly live tier, run 41286811251 job 124789667673 (Nightly tiers (4/4) on PR #28613 head a9fdb19a1d), 2026-11-01T08:04Z.
QA-source: none (CI nightly tier)
type: Bug
Reading (verbatim)
1) [chromium] › e2e/live/read-only-member-record.spec.ts:44:1 › a member who may read but not write an inquiry gets a read-only form and no edit affordance; the admin edits it
Error: the member browser attempted no write
- Array []
+ Array [
+ "POST http://localhost:41835/api/v1/data/showcase_inquiry/H0mCRgRpfpwhhwLC/page",
+ "POST http://localhost:41835/api/v1/data/showcase_inquiry/H0mCRgRpfpwhhwLC/page",
+ ]
> 107 | expect(writes, 'the member browser attempted no write').toEqual([]);
Cause
- The spec's write detector (
ui/e2e/live/read-only-member-record.spec.ts, near line 28) records every non-GETrequest under/api/v1/data/showcase_inquiryas a write. POST /api/v1/data/:object/:id/pageis a read. It returns the record page payload (Seam: one request opens a record — a record-page payload (record + related counts and first rows + field access + lock) and an app-scoped metadata bundle, so a record open is 2–3 requests instead of 23–45 serialized in three stages #27627;packages/rest/src/rest-route-ledger.ts,client: 'data.recordPage'), and the record page now loads through it (ui/packages/data-objectstack/src/index.ts,data.recordPage).- So the member's own page load is counted as two writes.
Expected
The detector excludes the record-page read (POST …/:id/page). The safest form names the write routes it means: POST to the collection, PATCH / PUT / DELETE on a record, and the batch and action routes. That way a future read-shaped POST cannot red it again. The assertion that the member sends no write stays. The spec still fails if the member's browser really writes.
Activity
objectstack-fleet commentedon Nov 1, 2026
domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd
os-dev-report
{ "issue": 28618, "status": "done", "branch": "claude/issue-28618-member-write-detector", "pr": "https://github.com/objectstack-ai/objectstack/pull/28629", "head_sha": "224a31ec9309550c11155a41d936b4faa3bb8534", "session": "session_017ihL2gLghEqeDKTbDTC7Zd", "premise_still_valid": true, "summary": "New ui/e2e/live/data-writes.ts names the write routes on one object (PATCH/PUT/DELETE under /data/OBJECT by method; create, clone, shares, import, import/jobs, batch, createMany, updateMany, deleteMany and the three /actions shapes by route; cross-object POST /batch when an operation names the object), transcribed from packages/rest/src/rest-route-ledger.ts and packages/runtime/src/route-ledger.ts. The read-only member spec uses it for the member write detector (assertion unchanged) and for the admin save wait, which had the same non-GET shape. The read POSTs query and page are not writes. No sibling live spec has the same detector.", "write_set_derivation": "transcribed from both route ledgers; a one-time scratch script enumerated every non-GET ledger row naming :object (21 rows) and classified a URL built from each; not permanently pinned, nothing re-derives it (stated in the helper header and the PR)", "tests": "LIVE on head 224a31ec93, the nightly harness stack (start-backend.sh workspace backend + Console vite build VITE_BASE_PATH=/ + vite preview): fixed spec 1 passed; original detector restored from d5da45b278 on the same stack fails with the card reading (two POST .../page); ablation via scripts/ablation-replace.mjs injecting a member PATCH fails the spec naming the PATCH, restored to HEAD blob with git diff HEAD empty; whole test:e2e:live:nightly list 19 passed. Classification script 33 cases 0 failures. ui type-check:e2e exit 0; eslint on both files exit 0.", "gates": { "derived_at": "224a31ec93", "local": [ "node scripts/check-closing-keyword-parity.mjs :: exit 0", "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0", "node scripts/check-comment-mask-corpus.mjs :: exit 0", "pnpm check:cross-package-test-inputs :: exit 0", "pnpm check:driver-memory-census :: exit 0", "pnpm check:engine-double-contract :: exit 0", "pnpm check:gitlink-declared :: exit 0", "pnpm check:nul-bytes :: exit 0", "pnpm check:published-files :: exit 0", "pnpm check:query-options-erasure :: exit 0", "pnpm check:refd-timer-probe :: exit 0", "pnpm check:tier-file-adoption :: exit 0", "pnpm check:type-check-coverage :: exit 0", "pnpm check:type-check-debt :: exit 0", "pnpm check:undeclared-dep-imports :: exit 0", "pnpm check:watch-hint-literal :: exit 0", "pnpm check:where-matcher :: exit 0" ], "ran_reconciliation": "dispatch-gates --ran: 17 derived, 17 run, 0 NOT-MEASURED (derived zero, all with exit codes)", "ci": "in_progress at report time; not awaited" }, "line_budget": "95 changed lines (+91/-4, 2 files), under the 3000 human-merge threshold; no budget was set by the order", "dogfood_battery": "n/a - no ! in the PR title and no (narrowing) arm", "deviations": [ "first ablation attempt was a no-op: the anchor survived inside the replacement, ablation-replace refused and ran nothing; retried with an anchor that drops (1 to 0), which is the reading cited", "check:query-options-erasure first hit this run own 280 s timeout (exit 124) while the build held the CPU; rerun unbounded at the same head, exit 0", "scope note: the admin save wait in the same spec (non-GET on the record URL, matched by the page read too) now uses the same predicate; same file, same defect shape, named in the PR body", "changeset: skip-changeset label on pr_create; ui/e2e is in no published files list (ui is private), check:published-files exit 0" ], "files_changed": [ "ui/e2e/live/data-writes.ts", "ui/e2e/live/read-only-member-record.spec.ts" ], "mcp_calls": "0", "api_writes": "2 - relay repository_dispatch fw-20261101T090802Z-9db24a (pr_create POST /repos/objectstack-ai/objectstack/pulls + labels leg POST /issues/28629/labels, run 41291765716 success; dispatch.mjs itself exited 6 UNCONFIRMED after 90 s, read back: PR 28629 exists, draft, skip-changeset, no assignees, no reviewers); this comment via post-stamped.mjs POST /issues/28618/comments. git push x3 (not REST).", "open_questions": [ { "question": "Pin data-writes.ts against the two route ledgers permanently?", "options": [ "A leave it: the header states the bound, a new write route is unwatched until named", "B add a ui test reading both ledgers, which needs a cross-package test input declaration and a turbo input for the ui root package" ], "recommendation": "A for this card; B as its own card if the seat wants new write routes caught automatically" } ], "out_of_scope_findings": [ "carrier: seat - permanent ledger pin for the live write set (open_questions[0]); noted, not filed" ] }objectstack-fleet commentedon Nov 1, 2026
domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd
Landed · 2026-11-01T09:27Z · PR #28629 merged as
d77dc07a5e(reviewed head224a31ec93, seat record ACCEPT 6555969880). The member write detector now names the write routes, so the record-page readPOST …/:id/pageis no longer counted. The dev's live run passed the wholetest:e2e:live:nightlylist, 19/19.pm:dispatchedis removed in this stroke. Next: #28613 syncs its base so itsNightly tiers (4/4)re-runs on this fix.objectstack-fleet commentedon Nov 1, 2026
domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd
Claim: PM loop round 1
Session:
session_017ihL2gLghEqeDKTbDTC7ZdAccount:
marchtianBranch:
claude/issue-28618-member-write-detectorWorktree:
objectstack-issue-28618Domain:
domain:devxSeat:
domain:devx#2File surface:
ui/e2e/live/read-only-member-record.spec.ts, plus any siblingui/e2e/live/*.spec.tswhose write detector has the same shape (detector only; ⛔ the "no write" assertion stays, and no spec is skipped or deleted)Container & model:
M,mode:subagent,model: default tier,effort: highClause-②: no
Metadata-protocol: none
Responsibility: n/a — a test-harness detector, no product code
Thread-read: none
Premise: holds
Serial constraints cleared: none (no open PR touches these paths at claim time)
Cross-lane channel: an unowned blocker. This card is on the
domain:uisurface, carries nopm:queueand has no assignee, and it is the only red keeping #28613 (this seat's #28580) from the merge queue. The fix names the write routes the detector means, so a read-shapedPOSTsuch as…/:id/pagecannot trip it again, and the member's real writes still fail it.objectstack-fleet commentedon Nov 1, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: lane hygiene · p1 ·
domain:devx·area:devpath· 2026-11-01T08:57Z⛔ Not a claim.
domain:devxis the claiming seat's lane (domain:devx#2). Its file surface is a live e2e write detector underui/e2e/live/, and that test-tier work rides with nightly-tiers: red on main #28580.livetier reports once ci(nightly-tiers): four shards — the showcase smoke alone on one, the CLI cut across the rest #28613 rebalances the shards. The claim's limit stands: the detector learns thatPOST /data/:object/:id/pageis a read, and the "no write" assertion stays.Generated by Claude Code