Thanks to visit codestin.com
Credit goes to github.com

Skip to content

rebased for readability - #7

Merged
Novapixel1010 merged 2 commits into
pollsfrom
poll-patch
Sep 2, 2026
Merged

rebased for readability#7
Novapixel1010 merged 2 commits into
pollsfrom
poll-patch

Conversation

@Novapixel1010

Copy link
Copy Markdown
Owner

had to start over with some stuff but everything should work now.

No backward compatibility needed - this feature hasn't shipped. Replaces
JSON as the sole format for the ```poll fenced Markdown block on both
sides:

- Frontend: parsePollDefinition (types.ts) now parses with the `yaml`
  package instead of JSON.parse; CreatePollDialog serializes with
  YAML.stringify instead of JSON.stringify, producing exactly the target
  block shape (id/question/type/options as a plain mapping, options as a
  block sequence).
- Backend: poll_definition.go's rawPollDefinition struct tags switch from
  `json:"..."` to `yaml:"..."`, and findPollDefinitionInContent unmarshals
  with gopkg.in/yaml.v3 (already a direct dependency) instead of
  encoding/json.

Everything the task asked to keep intact is untouched: the nested voting
route (/api/v1/memos/{memoUid}/polls/{pollUid}/votes) and
EnsurePollBinding's memo-authorization flow, the strict pollUIDPattern
UUID regex, and deletePollDataByMemoIDsTx's user/memo-cascade cleanup
(store/db/{sqlite,postgres,mysql}/user_delete.go - this is the actual name
of the cleanup function the task referred to as
deletePollVotesByVoterTx; it deletes both poll and poll_vote rows by
memo_id, not by voter, and was not touched by this change).

While preserving pollDefinitionHash's canonical/injective requirement,
switching formats surfaced a real pre-existing bug worth fixing here:
the hash wrote a bare NUL byte as a separator between options with no
length prefix, which is not actually injective - an option string that
itself contains a NUL byte reproduces that exact separator byte sequence,
so e.g. options ["ab", "c"] and a single option "ab\x00c" hashed
identically. YAML permits arbitrary control characters in a quoted
scalar, so this was reachable from memo content, not just internal data,
and a collision here would let an edited option set silently keep votes
that should have been reset as stale. Replaced the separator with a
fixed-width big-endian length prefix per field (Type and each Option),
which is unambiguous regardless of content - this is what "canonical/
injective serialization" actually requires, and is why option identity in
this hash was still separator-based rather than delimiter-free lengths
even in the JSON version's design intent.

Added tests for both: server/router/api/v1/poll_definition_test.go covers
YAML parsing (block/flow style, defaulting to single-choice, UID
mismatch, malformed YAML, too few options) and the hash property directly
(formatting-invariance, the concatenation collision the length prefix
fixes, and the NUL-byte-smuggling case specifically) - the NUL-smuggling
test fails against the pre-fix hash implementation, confirming it
exercises the real bug. web/tests/poll-definition.test.ts covers the
same parsing surface from the frontend side.

Verified end to end against a live server: created a memo whose content
is exactly the target YAML block example, confirmed it round-trips
through save untouched, voted through the nested route, read back
matching tallies, and deleted the memo (exercising the poll/poll_vote
cascade cleanup) without error. Full go test ./... and the full frontend
vitest suite (1127 tests) both pass.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016UZX8r5o3xdW8uKDTQv6Mb
…leanup

Two gaps found while rebasing the YAML-format refactor onto commits pushed
directly to this branch in parallel:

1. store/migration/postgres/0.32/01__poll_definition.sql was deleted
   ("no need for this file."). That file is the actual fix for the
   "column memo_id does not exist" bug reported earlier on this branch: a
   Postgres database that already recorded schema version 0.32.1 from the
   original poll_vote-only migration has no path to the poll table or
   poll_vote.memo_id without it, since editing the already-applied 0.32/00
   file in place (what an earlier commit had done) has no effect on a
   database that already ran it - schema version tracking is a monotonic
   per-version marker, not a per-file-content hash. Deleting 0.32/01
   silently drops GetCurrentSchemaVersion's computed target for Postgres
   back to 0.32.1 too, so Migrate() sees current == target and skips
   migration entirely - such a database would stay stuck exactly at the
   bug's original broken state. Restored the file (byte-identical to what
   was verified end-to-end in this branch's earlier fix: built the pre-fix
   binary, created a poll_vote row under the old schema, then ran the
   fixed binary against that same data directory and confirmed both the
   migration and the previously-failing memo delete succeed).

2. deletePollVotesByVoterTx (added to store/db/postgres/user_delete.go in
   a parallel commit) was Postgres-only. It's a real, distinct gap from
   deletePollDataByMemoIDsTx: that function only cleans up poll data for
   memos the deleted user owns, so a vote the user cast on someone *else's*
   memo survives deletion as a poll_vote row whose voter_id no longer
   resolves to any user. Mirrored the same function (with an explanatory
   comment) to store/db/{sqlite,mysql}/user_delete.go, matching this
   codebase's established pattern of giving every driver equivalent
   treatment. Extended TestDeleteUserCleansRelatedData
   (store/test/user_delete_test.go) with exactly this scenario - the
   deleted user and a peer both vote on the peer's memo poll - and
   confirmed only the deleted user's vote is gone; verified the assertion
   actually exercises the fix by reverting the SQLite half of it locally,
   watching the test fail, then restoring it.

Full go test ./... and frontend tsc --noEmit pass.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_016UZX8r5o3xdW8uKDTQv6Mb
@Novapixel1010
Novapixel1010 merged commit a1f6883 into polls Sep 2, 2026
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