feat: gapped integer positions for block inserts (#188) #189
No reviewers
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo_admin/pal-e-api!189
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "188-gapped-integer-positions-for-block-inserts"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Changes
src/pal_e_docs/blocks/parser.py: AddedPOSITION_GAP = 1000constant, changed position calculation fromlen(blocks)tolen(blocks) * POSITION_GAPsrc/pal_e_docs/blocks/__init__.py: ExportedPOSITION_GAPconstantsrc/pal_e_docs/routes/blocks.py: Refactored_reindex_positionsto produce gapped positions, replaced bulk-shift create logic with collision-only handling, removed reindex from delete, added rebalance endpointsrc/pal_e_docs/schemas.py: AddedRebalanceOutschematests/test_gapped_positions.py: 24 new tests covering gapped positions, collision handling, rebalance, backward compat, range queriestests/test_backfill.py,tests/test_block_parser.py,tests/test_blocks_api.py,tests/test_note_block_sync.py: Updated assertions for gapped positionsTest Plan
Review Checklist
Related
plan-2026-03-16-knowledge-architectureSelf-Review
Bug found and fixed: In the gap-exhaustion collision branch, when the collider lands at position 0 after rebalance, the original code shifted it to
POSITION_GAP(1000). This would collide with the second block at position 1000 after a fresh rebalance. Fixed to usePOSITION_GAP // 2(500), which is guaranteed free. Added edge-case testtest_collision_at_position_zero_with_gap_exhaustion.All clear on:
PR #189 Review
DOMAIN REVIEW
Tech stack: Python / FastAPI / SQLAlchemy / Pydantic (pal-e-docs API)
Architecture assessment: The gapped integer position strategy is a well-understood pattern (used by Figma, Notion, etc.) for reducing write amplification on ordered lists. The implementation is clean:
src/pal_e_docs/blocks/parser.py):POSITION_GAP = 1000constant, position calculation changed fromlen(blocks)tolen(blocks) * POSITION_GAP. Straightforward, correct.src/pal_e_docs/routes/blocks.py):create_blockcollision handling is the core logic. Three paths: (1) vacant position = O(1) insert, (2) collision with free adjacent = shift collider +1, (3) gap exhausted = rebalance then insert. All three paths are tested.POST /notes/{slug}/blocks/rebalance): clean, returnsblock_countandgap. Route ordering is safe --/{slug}/blocks/rebalanceis a different path depth from/{slug}/blocks.RebalanceOut): minimal, appropriate.Auth consistency: The new
rebalance_blocksendpoint does NOT useis_authenticateddependency. This is consistent with the existing write endpoints (create_block,update_block,delete_block) which also lack auth gating. Not a regression.SQLAlchemy patterns: Session management follows existing patterns (flush within transaction, commit at end). The
db.refresh(collider)after_reindex_positionsis necessary to get the updated position after rebalance -- correct.Collision edge case analysis: After rebalance + position-0 collision, the collider is shifted to
POSITION_GAP // 2(500). This is safe because rebalance guarantees the next block is atPOSITION_GAP(1000), so 500 is always vacant. Sound logic.BLOCKERS
None.
test_gapped_positions.pycovering parser, vacant insert, collision, gap exhaustion, delete preservation, rebalance endpoint, backward compat, and range queries. Plus 6 existing test files updated. Comprehensive.BlockCreate.positionalready hasposition_non_negativevalidator (pre-existing). No new unvalidated user input.NITS
Stale docstring in parser.py (line 33):
"position": int, # 0-based orderingshould read something like# gapped ordering (0, 1000, 2000, ...). Similarly, line 38's example"paragraph-3"should be"paragraph-1000". The implementation is correct but the docstring now misleads readers._seed_note_with_blocksstill uses sequential positions: The helper intests/test_blocks_api.pyseeds blocks at 0, 1, 2, 3 (legacy sequential). This is intentionally testing legacy compat, and the tests pass, but a comment in the helper saying "intentionally legacy sequential" would clarify intent for future readers.SOP COMPLIANCE
188-gapped-integer-positions-for-block-insertsplan-2026-03-16-knowledge-architecturePROCESS OBSERVATIONS
VERDICT: APPROVED