Skip to content

The typed index and a ranked hosted list (nxf 6j6v.xkr7) - #55

Closed
cabcookie wants to merge 2 commits into
mainfrom
feat/xkr7-typed-index
Closed

cabcookie wants to merge 2 commits into
mainfrom
feat/xkr7-typed-index

Conversation

@cabcookie

Copy link
Copy Markdown
Member

Stacked on #54 (1c5s). Please merge #54 first; until then this diff also shows #54's commit.

What

A hosted board answers list ranked by the plugin's [ranking.list], derived ranking keys included, the way a local replica does. A hosted next whose keys read a [ranking.list] rank (spec §12 point 1, refused in #54) now ranks too.

Table contract change (for app-foundations / the deploying stack)

  • New GSI typed: partition key nxf_typed (S), sort key sk (S), projection ALL.
  • Sparse rule: the fold sets nxf_typed = <stream>#<type> on every LIVE item row (items#<id>): not deleted, closed and archived included. It removes the attribute on a delete. Items without a type are not indexed. The type is escaped as key values are (% → %25, # → %23).
  • Rollout order: deploy the stack (add the GSI) first, then the read. A fold against a table without the index still writes the attribute harmlessly. Only records::list_board, and a next whose keys read a list rank, query the index.
  • ddb::create_table matches. Documented in the nxs-fold-ddb crate doc and E4 §5.1.

Index revision

The attribute ships in index revision 3, together with #54's self-describing .adj# entries. Both PRs are unreleased and go into one beta, so there is no revision 4. Every stream folded before revision 3 is NotCurrent until refolded (one refold covers both).

Facade (changed, additive)

  • New types: ListReads, ListItem, ListBoard.
  • New functions: read::list_reads(cfg, &ListQuery), read::list_board(store, &reads) (the parity oracle), read::list_board_page(cfg, &board, &q) -> NextPage, read::list_board_value ({"items","total"}).
  • New fields: RankingReads::list_types and RankingGraph::listed. Both structs are #[non_exhaustive].
  • next_ranking_reads no longer refuses a plugin whose next order reads a list-only type's rank.

fold-ddb: Table::query_typed is a new required trait method, and records::list_board(table, &reads) is new.

Paging

Paging is the same as for the hosted next. The store path's page cache is machine-local, and server paging is open (15ed). So limit cuts the list and discloses the total, while paginate or a token returns validation. The server cuts the list itself.

Adjacency

Nothing new was needed. A listed item's .adj# entries already give its current parent, its contributes_to targets, its parents for parent_closed_reason, and every edge a key reads.

Tests (all run locally, green)

  • New list_differential: SQL path = Board path = fold-ddb path for list (9 queries per board: types, none, container, label, status, sort, limit) and for next. It runs on 40 generated boards of 4 types with retypes, closed/archived/deleted items, every key kind and cross-section ranks in both directions. Records JSON is compared too. Also a cost guard (1 index Query + 4 requests per item) and a refusal of revision-2 streams.
  • fold_differential (typed index = SQL per type, incremental = reindex), robustness (moves on retype/archive/delete; a type that is too long is refused), derived_differential, records_differential, fold-ddb lib, chat_and_memory.
  • facade: derived_ranking (new seam tests), list_query, next_query. core: graph_differential.
  • dynamodb_local was extended (typed listings through the SDK). Locally only cargo check --features dynamodb --tests; the test itself runs in CI.

🤖 Generated with Claude Code

https://claude.ai/code/session_016q5uMUkZJQW4fckJoA3FME

cabcookie and others added 2 commits October 11, 2026 18:29
The store-free `next` (read::next_active) now ranks a plugin with
`related` / `count` / `sum` keys from a RankingGraph on ActiveBoard, by
the same evaluation the store path runs. Owner decision 2026-10-11: a
key reads every LIVE neighbour (closed and archived count, deleted do
not) on both paths.

- facade: ActiveBoard::ranking, RankingReads, RankingGraph, Neighbour,
  next_ranking_reads, with_ranking (the parity oracle); derived.rs split
  into plan / context fill (store or graph) / finish. A [ranking.next]
  order reading the rank of a type only [ranking.list] orders is refused
  on the store-free path until xkr7.
- fold-ddb: .adj# entries copy from_id/to_id/kind/lamport/site and a
  removed flag, kept on edge removes; INDEX_REVISION 2 -> 3 (old streams
  NotCurrent until refolded); records::with_ranking reads the graph.
  Table contract unchanged (no new GSI, no new key attribute).
- core: EdgeKind and graph::Edge derive Ord.
- tests: derived_differential (SQL = Board = fold-ddb on generated
  boards, determinism, request-count guard, revision-2 refold), facade
  seam tests for live neighbours and the list-rank refusal.
- spec §6/§10.5/§11/§12 amended.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016q5uMUkZJQW4fckJoA3FME
A hosted board answers `list` ranked by `[ranking.list]`, derived keys
included, as a replica does, and a hosted `next` whose keys read a
`[ranking.list]` rank no longer is refused (spec §6, decision §10.4).

- fold-ddb: third sparse GSI `typed` (nxf_typed = <stream>#<type>, the
  type escaped; sort key sk; projection ALL) on every live item row,
  closed and archived included, kept by refresh_item after the row.
  Table::query_typed (MemTable, DynamoDbTable, create_table). A type
  whose partition passes 2,048 bytes is refused at fold time. Ships in
  index revision 3 with the self-describing .adj# entries (#54,
  unreleased): no revision 4. records::list_board reads a ListBoard;
  the graph builder is shared with with_ranking and reads the live
  items of RankingReads::list_types off the index.
- facade: ListReads, ListItem, ListBoard, list_reads, list_board (store
  oracle), list_board_page, list_board_value; RankingReads::list_types,
  RankingGraph::listed (additive); next_ranking_reads no longer refuses
  a next order reading a list-only type's rank. Not paged, as the hosted
  next: limit cuts, paginate/token are validation.
- No new adjacency: the revision-3 .adj# entries carry everything.
- tests: list_differential (SQL = Board = fold-ddb for list and next on
  generated boards with retypes, cross-section ranks, JSON, cost guard,
  revision refusal), typed index in fold_differential, robustness and
  dynamodb_local, facade seam tests.
- docs: crate table contract, E4 §5.1, spec §6/§9/§11/§12; 1c5s
  fragment aligned (contract change and lifted refusal).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016q5uMUkZJQW4fckJoA3FME
cabcookie added a commit that referenced this pull request Oct 11, 2026
…SI and a ranked hosted list (nxf 6j6v.1c5s, xkr7) (#56)

Folds #54 (1c5s) and #55 (xkr7) plus the mitigation of their combined independent review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016q5uMUkZJQW4fckJoA3FME
@cabcookie

Copy link
Copy Markdown
Member Author

Contained in #56, which folds #54 and #55 plus the review mitigation and was merged in one squash.

@cabcookie cabcookie closed this Oct 11, 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.

1 participant