Skip to content

feat(rfc0017.2): derive_template_registry from the audit stream - #274

Merged
jensholdgaard merged 2 commits into
mainfrom
rfc0017-green-2
Jun 21, 2026
Merged

feat(rfc0017.2): derive_template_registry from the audit stream#274
jensholdgaard merged 2 commits into
mainfrom
rfc0017-green-2

Conversation

@jensholdgaard

@jensholdgaard jensholdgaard commented Jun 21, 2026

Copy link
Copy Markdown
Owner

RFC 0017 green .2derive_template_registry

Second green slice. The read-time template registry, derived from the tenant audit stream exactly like alias_store::derive_alias_map (same audit_scan walk, same (timestamp, path, row) total fold order).

Changes

  • ourios-miner — add tree::parse_template (the inverse of format_template): split the canonical space-joined lit … <*> string back into Vec<OwnedToken>. Moved format_template from cluster.rs into tree.rs (now pub) so the canonical encode/decode pair lives together next to OwnedToken, with a round-trip unit test. The 6 in-crate callers are unchanged (import).
  • ourios-querier — now depends on ourios-miner (for OwnedToken + the registry, and reconstruct::render in .3; no arrow/DataFusion type crosses). New template_registry module exposing derive_template_registry(bucket_root, tenant) -> Result<TemplateRegistry, QueryError> and TemplateRegistry = HashMap<(u64, u32), Vec<OwnedToken>>.

Behaviour

Fold per template event:

  • template_created → key (id, TEMPLATE_INITIAL_VERSION) (the variant omits the version);
  • template_widened / template_type_expanded → key (id, new_version);
  • template_widening_rejected_degenerate → nothing (no version bump, no token change).

Keying by (id, version) is what makes a later widening never clobber an earlier version's tokens — the prerequisite for version-correct rendering (.5, .3). Same tenant-row backstop as the alias derivation (RFC 0005 §3.9).

Tests

  • Fills the RFC0017.2 stub: writes created + widened + type_expanded + rejected events via the production ParquetAuditSink, derives, and asserts every (id, version) is present including v1, v2 doesn't clobber v1, and the rejection adds no entry. .5 stays #[ignore]d until .3 (it needs the render path).
  • Round-trip test for parse_template ∘ format_template.
  • Corrects the RFC §3.2 canonical-form prose (it's the space-joined form format_template writes, not a JSON array — follow the code).

All ourios-miner / ourios-querier tests green; fmt --check + clippy -D warnings clean.

Next: .3 (query-time rendering — LogBody three zones via reconstruct::render).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added audit-based template registry derivation to reconstruct per-tenant template versions at query time.
    • Introduced canonical template serialization/deserialization utilities (fixed tokens and wildcard support) for consistent rendering and parsing.
  • Tests
    • Expanded template utility tests, including deterministic round-trips and property-based verification.
    • Enabled RFC0017.2 with assertions covering created, widened/type-expanded, and degenerate rejection handling.
  • Documentation
    • Updated RFC 0017 to reference the shared parsing/rendering behavior and canonical encoding.

RFC 0017 section 3.2 — the read-time template registry, mirroring
alias_store::derive_alias_map: fold a tenant's template_created /
template_widened / template_type_expanded audit events (deterministic
timestamp, path, row order) into HashMap<(template_id, version),
Vec<OwnedToken>>. template_created keys at TEMPLATE_INITIAL_VERSION (the
variant omits the version); widened/type_expanded at new_version;
rejections contribute nothing. Keying by (id, version) means a later
widening never clobbers an earlier version's tokens (section 3.5).

- ourios-miner: add tree::parse_template (inverse of format_template),
  co-locating the canonical encode/decode pair; format_template moved
  from cluster.rs to tree.rs (pub) so both live next to OwnedToken.
  Round-trip unit test.
- ourios-querier: depend on ourios-miner (for OwnedToken + the registry,
  and reconstruct::render in .3); new template_registry module exposing
  derive_template_registry + TemplateRegistry.
- Fills the RFC0017.2 stub (realistic space-joined templates via the
  production ParquetAuditSink write path). .5 stays ignored until .3.

Also corrects the RFC section 3.2 canonical-form prose: it is the
space-joined form format_template writes, not a JSON-array encoding
(follow the code).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8144a948-7a79-473f-b8af-4f9b24222a36

📥 Commits

Reviewing files that changed from the base of the PR and between e21857a and 5e6b27f.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • crates/ourios-miner/Cargo.toml
  • crates/ourios-miner/src/tree.rs
  • crates/ourios-querier/src/template_registry.rs
  • crates/ourios-querier/tests/rfc0017_registry.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • crates/ourios-miner/src/tree.rs
  • crates/ourios-querier/src/template_registry.rs
  • crates/ourios-querier/tests/rfc0017_registry.rs

📝 Walkthrough

Walkthrough

format_template is promoted from a private helper in cluster.rs to a public utility in tree.rs, and its inverse parse_template is added alongside it. ourios-querier gains a new template_registry module that defines TemplateRegistry and derive_template_registry, which folds tenant audit events into a versioned token map. The RFC0017 integration test scenario .2 is fully implemented and the RFC doc is updated.

Changes

RFC0017 Template Registry Derivation

Layer / File(s) Summary
format_template / parse_template public utilities
crates/ourios-miner/src/tree.rs, crates/ourios-miner/src/cluster.rs, crates/ourios-miner/Cargo.toml
format_template moves from cluster.rs to tree.rs as a public function; parse_template (its inverse) is added alongside it; both are covered by new round-trip unit tests including property-based testing; cluster.rs updates its import and drops the local definition; proptest is added as a dev-dependency.
derive_template_registry implementation and wiring
crates/ourios-querier/Cargo.toml, crates/ourios-querier/src/lib.rs, crates/ourios-querier/src/template_registry.rs
ourios-miner is added as a dependency; template_registry is declared as a module with TemplateRegistry and derive_template_registry publicly re-exported; TemplateRegistry is defined as a HashMap keyed by (template_id, version) storing token vectors; derive_template_registry walks tenant Parquet audit files, validates tenant ownership, sorts events by timestamp, and folds Created/Widened/TypeExpanded into per-version token vectors via parse_template; unit tests validate versioning behavior, type expansion, degenerate rejection handling, and deterministic ordering.
RFC0017 .2 integration test and RFC doc update
crates/ourios-querier/tests/rfc0017_registry.rs, docs/rfcs/0017-template-registry-query-rendering.md
The previously ignored rfc0017_2_registry_derives_completely_including_v1 stub is replaced with a full test emitting parquet audit events for two templates across two versions plus a degenerate rejection, asserting exact token vectors for all four (id, version) pairs; test helpers construct deterministic timestamps, template audit events, and token values; RFC0017 status doc is updated to mark scenario .2 green and clarifies the tenant backstop is not reachable via supported write path; RFC doc is updated to reference parse_template and the canonical space-joined encoding.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • jensholdgaard/ourios#272: Previously introduced or modified the RFC0017 test file where scenario .2 was a stub that this PR now activates.
  • jensholdgaard/ourios#273: Introduced TemplateChange::Created and the Parquet audit plumbing that persists the initial template string for version-1 creation, which derive_template_registry now reads and folds.

Poem

🐇 Hop, hop — the template hops from cluster to tree,
A format_template free for all to see!
parse_template unravels each <*> in line,
The registry folds every version just fine.
Four entries, four tokens, the audit rings true —
A rabbit rejoices: the .2 test came through! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: implementing RFC0017.2 by deriving the template registry from the audit stream.
Description check ✅ Passed The description comprehensively covers all required sections: detailed summary of changes across both crates, behavior documentation with fold semantics, testing methodology, and explicit note that fmt and clippy checks pass.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rfc0017-green-2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements RFC 0017 slice .2 by adding a querier-side, read-time template registry derived from the tenant audit stream, plus the miner-side canonical encode/decode pair needed to round-trip templates between audit storage and in-memory tokens.

Changes:

  • Add ourios_querier::derive_template_registry and TemplateRegistry = HashMap<(u64, u32), Vec<OwnedToken>>, folded from template audit events in RFC-defined total order.
  • Add ourios_miner::tree::parse_template and move/expose tree::format_template alongside OwnedToken, with round-trip unit tests.
  • Fill the RFC0017.2 test stub using ParquetAuditSink, keeping RFC0017.5 ignored until the rendering slice lands.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
docs/rfcs/0017-template-registry-query-rendering.md Updates §3.2 prose to match the actual canonical space-joined template encoding and parsing path.
crates/ourios-querier/tests/rfc0017_registry.rs Implements the RFC0017.2 green test using production audit persistence + derivation; keeps RFC0017.5 ignored.
crates/ourios-querier/src/template_registry.rs New module deriving (template_id, version) -> tokens from the audit stream using the shared audit_scan walk.
crates/ourios-querier/src/lib.rs Wires the new module and re-exports derive_template_registry / TemplateRegistry.
crates/ourios-querier/Cargo.toml Adds ourios-miner dependency to reuse OwnedToken and template parsing/formatting.
crates/ourios-miner/src/tree.rs Adds parse_template, makes format_template public, and adds round-trip tests.
crates/ourios-miner/src/cluster.rs Switches to importing format_template from tree.rs (removes local helper).
Cargo.lock Records the new ourios-querier -> ourios-miner dependency.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
crates/ourios-querier/tests/rfc0017_registry.rs (1)

62-112: ⚡ Quick win

Build fixture templates with format_template to lock canonical parity.

The fixture currently hardcodes canonical strings while claiming they match miner output. Constructing them with ourios_miner::tree::format_template makes that contract self-enforcing and prevents drift if canonical formatting changes.

Proposed refactor
-use ourios_miner::tree::OwnedToken;
+use ourios_miner::tree::{OwnedToken, format_template};
@@
             TemplateChange::Created {
-                new_template: "user <*>".to_owned(),
+                new_template: format_template(&[fixed("user"), OwnedToken::Wildcard]),
             },
@@
                 old_version: 1,
                 new_version: 2,
-                old_template: "user <*>".to_owned(),
-                new_template: "user <*> <*>".to_owned(),
+                old_template: format_template(&[fixed("user"), OwnedToken::Wildcard]),
+                new_template: format_template(&[
+                    fixed("user"),
+                    OwnedToken::Wildcard,
+                    OwnedToken::Wildcard,
+                ]),
                 positions_widened: vec![2],
             },
@@
             TemplateChange::Created {
-                new_template: "GET <*>".to_owned(),
+                new_template: format_template(&[fixed("GET"), OwnedToken::Wildcard]),
             },
@@
                 old_version: 1,
                 new_version: 2,
-                old_template: "GET <*>".to_owned(),
-                new_template: "GET <*>".to_owned(),
+                old_template: format_template(&[fixed("GET"), OwnedToken::Wildcard]),
+                new_template: format_template(&[fixed("GET"), OwnedToken::Wildcard]),
                 slots_expanded: Vec::new(),
             },
@@
             TemplateChange::RejectedDegenerate {
                 version: 2,
-                current_template: "user <*> <*>".to_owned(),
-                would_be_template: "<*> <*> <*>".to_owned(),
+                current_template: format_template(&[
+                    fixed("user"),
+                    OwnedToken::Wildcard,
+                    OwnedToken::Wildcard,
+                ]),
+                would_be_template: format_template(&[
+                    OwnedToken::Wildcard,
+                    OwnedToken::Wildcard,
+                    OwnedToken::Wildcard,
+                ]),
                 would_be_positions: vec![0],
             },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/ourios-querier/tests/rfc0017_registry.rs` around lines 62 - 112, The
fixture currently hardcodes template strings like "user <*>", "user <*> <*>",
"GET <*>", and "<*> <*> <*>" in the TemplateChange enum variants (Created,
Widened, TypeExpanded, RejectedDegenerate), which can drift if canonical
formatting changes. Instead of hardcoding these strings, construct them using
the ourios_miner::tree::format_template function to ensure the test fixtures
match the actual miner output and maintain canonical parity automatically.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/ourios-miner/src/tree.rs`:
- Around line 359-389: The parse_template and format_template round-trip
invariant needs property-based testing to cover broader token combinations
beyond the manual test cases. Add a new property test using proptest that
generates arbitrary OwnedToken combinations and verifies that parsing the result
of format_template always returns the original token sequence. This should be
implemented alongside the existing parse_template_inverts_format_template and
parse_template_empty_string_is_empty_template tests to ensure the invariant
holds across edge cases and various token shapes.

In `@crates/ourios-querier/src/template_registry.rs`:
- Around line 50-118: The function derive_template_registry lacks module-local
unit tests despite being non-trivial according to coding guidelines. Add focused
in-file tests in the template_registry.rs module that verify key behaviors: (1)
the tie-break ordering of audit events by timestamp and file/row order, and (2)
the row-vs-path tenant mismatch failure that correctly returns a
QueryError::Storage when an audit event claims a different tenant than expected.
Ensure tests exercise both the happy path (successful fold of template history)
and the error condition (tenant validation).
- Around line 81-83: The `derive_template_registry` function lacks unit test
coverage despite being a complex function (lines 50-118) that handles folding
audit events with error handling and version logic. Add comprehensive unit tests
for the `derive_template_registry` function in a tests module adjacent to the
function definition. The tests should cover key scenarios including successful
audit event processing, error handling paths, and version logic to ensure the
function behaves correctly across different inputs and edge cases.

---

Nitpick comments:
In `@crates/ourios-querier/tests/rfc0017_registry.rs`:
- Around line 62-112: The fixture currently hardcodes template strings like
"user <*>", "user <*> <*>", "GET <*>", and "<*> <*> <*>" in the TemplateChange
enum variants (Created, Widened, TypeExpanded, RejectedDegenerate), which can
drift if canonical formatting changes. Instead of hardcoding these strings,
construct them using the ourios_miner::tree::format_template function to ensure
the test fixtures match the actual miner output and maintain canonical parity
automatically.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2af30f2d-d730-44dd-979c-82c031e21a23

📥 Commits

Reviewing files that changed from the base of the PR and between 443066c and e21857a.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • crates/ourios-miner/src/cluster.rs
  • crates/ourios-miner/src/tree.rs
  • crates/ourios-querier/Cargo.toml
  • crates/ourios-querier/src/lib.rs
  • crates/ourios-querier/src/template_registry.rs
  • crates/ourios-querier/tests/rfc0017_registry.rs
  • docs/rfcs/0017-template-registry-query-rendering.md

Comment thread crates/ourios-miner/src/tree.rs
Comment thread crates/ourios-querier/src/template_registry.rs
Comment thread crates/ourios-querier/src/template_registry.rs
CodeRabbit (testing guidelines):
- ourios-miner: add a proptest round-trip for the template encode/decode
  invariant (parse_template . format_template == id) over arbitrary token
  sequences, alongside the example-based tests (CLAUDE.md §6.2
  "reconstruction is always a property test"). Adds proptest dev-dep.
- ourios-querier: factor the pure fold out of derive_template_registry
  into fold_registry, and add module-local unit tests for it (version
  keying: created→v1, widened/type_expanded→new_version; rejection skip;
  later version doesn't clobber; same-(id,version) last-wins by timestamp).

The row-vs-path tenant backstop is defense-in-depth: AuditWriter rejects
a tenant/partition mismatch at write time, so a foreign-tenant row is
unreachable through the supported write path (documented note; mirrors
the untested-at-unit-level backstop in alias_store::derive_alias_map).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 9 changed files in this pull request and generated no new comments.

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