Skip to content

Commit 3f7ff45

Browse files
authored
docs(stack-encrypt): the rustdoc entries that still admitted an untyped indexed field
Four public entries said, or left standing, what the previous commit made false for a Rust caller building a plan by hand: the FieldPlan doc described a field with no declared type as dispatched on each value's own type, and linked a module heading that no longer exists; Plan::new_with's Errors list did not include the rule it enforces; the Error::Plan list named the refusal as one of its causes; and encrypt's doc said Error::Term comes back for a value no term is defined for, where the kind check now comes first and returns Error::Source. Each now names Error::UntypedIndex where the rule applies, and the module docs in record, kind and the crate's dynamic root point at the variant rather than at record::plan. Addresses PR #1096 review comment 4194355775. Claude-Session: https://claude.ai/code/session_01V3WFXwax4J3uecpFEJ6yHc
1 parent 865f378 commit 3f7ff45

3 files changed

Lines changed: 29 additions & 17 deletions

File tree

‎packages/stack-encrypt/src/dynamic/kind.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
//!
3636
//! Every field with a term output declares its kind; a plan whose indexed
3737
//! field has none is refused when it is built
38-
//! ([`record::plan`](super::record::plan())). A field that only seals, or
38+
//! ([`Error::UntypedIndex`], naming the field). A field that only seals, or
3939
//! only carries its value through, may leave it out: no term derives from it.
4040
use vitaminc_aead_value::{FfiValue, ValueKind};
4141

‎packages/stack-encrypt/src/dynamic/mod.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
//! ([`admits`]) and to a query value ([`read`]); it decides nothing about
6262
//! the bytes ([`record`]). Every field with a term output declares one;
6363
//! a plan whose indexed field has none is refused when it is built
64-
//! ([`record::plan`]).
64+
//! ([`Error::UntypedIndex`], naming the field).
6565
//!
6666
//! For the same reason the enums that spell them — [`Output`],
6767
//! [`IndexSpec`] and [`ValueKind`] — are *not* `#[non_exhaustive]`, against this workspace's

‎packages/stack-encrypt/src/dynamic/record.rs‎

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@
6767
//! seals and which it opens to (checked by kind, both ways), and nothing
6868
//! about the bytes: declaring a type on a field written without one changes
6969
//! no leaf. A field with any index declares its type, and a plan whose
70-
//! indexed field has none is refused when it is built: the term then derives
70+
//! indexed field has none is refused when it is built
71+
//! ([`Error::UntypedIndex`], naming the field): the term then derives
7172
//! from the one declared kind, every value checked against it, never from
7273
//! whatever tag each value arrived with (`34` sent once as a float and once
7374
//! as an integer would otherwise store two terms under one field). A field
@@ -207,12 +208,15 @@ enum Verb {
207208
/// One field of a record plan: what to call it, what label to seal it
208209
/// under, what to produce for it, and, optionally, what type its values are.
209210
///
210-
/// A field with a declared type (a [`ValueKind`]) admits only the indexes
211-
/// that kind is defined for ([`admits`], checked when the plan is built),
212-
/// seals only values of that kind and opens only to one (checked per value),
213-
/// so the engine verifies what a binding hands it rather than trusting the
214-
/// binding's tagging. A field with no declared type is dispatched on each
215-
/// value's own type; see the [module docs](self#what-a-fields-type-decides).
211+
/// A field may declare the type of its values (a [`ValueKind`]), and must
212+
/// when it has a term output: [`Plan::new_with`] refuses the plan otherwise
213+
/// ([`Error::UntypedIndex`]). A typed field admits only the indexes that
214+
/// kind is defined for ([`admits`], checked when the plan is built), seals
215+
/// only values of that kind and opens only to one (checked per value), so
216+
/// the engine verifies what a binding hands it rather than trusting the
217+
/// binding's tagging. A field that only seals, or only carries its value
218+
/// through, may leave the type out; see the
219+
/// [module docs](self#what-a-fields-type-decides-and-what-it-does-not).
216220
#[derive(Clone, Debug)]
217221
pub struct FieldPlan {
218222
name: String,
@@ -512,7 +516,10 @@ impl Plan {
512516
/// fields whose labels sit under different contexts or carry different
513517
/// extensions, or does not build as a fields plan: two sealed or indexed
514518
/// fields keyed under one identity, for instance, whose terms would be
515-
/// interchangeable. [`Error::Target`] if a target field names a type the
519+
/// interchangeable. [`Error::UntypedIndex`], naming the field, if a field
520+
/// with a term output declares no type: this is where that rule is
521+
/// enforced, for a parsed and a hand-built plan alike.
522+
/// [`Error::Target`] if a target field names a type the
516523
/// resolver does not know or cannot produce, declares a `"type"` other
517524
/// than the kind that type is produced from, or sits in an extended plan.
518525
pub fn new_with(
@@ -741,7 +748,8 @@ pub fn plan(value: FfiValue) -> Result<Plan, Error> {
741748
/// binding is never trusted to have tagged each value alike (a `34` sent once
742749
/// as a `Float64` and once as an `Int64` would store two terms under one
743750
/// field). A field with term outputs and no `"type"` is refused when the plan
744-
/// is built. It is optional on a field whose only output is `"c"` or
751+
/// is built ([`Error::UntypedIndex`], naming the field). It is optional on a
752+
/// field whose only output is `"c"` or
745753
/// `"passthrough"`, and on a target field, whose kind is the EQL type's own.
746754
/// Declared, it is checked against the field's outputs here ([`admits`]) and
747755
/// decides nothing about the bytes (see the
@@ -800,10 +808,11 @@ pub fn plan(value: FfiValue) -> Result<Plan, Error> {
800808
/// is empty, names an output key twice or names `"passthrough"` beside
801809
/// another output, a `"target"` that is not a non-empty string, a `"type"`
802810
/// that is not a string naming a [`ValueKind`], a type that does not admit
803-
/// one of the field's index outputs, a field with a term output and no
804-
/// `"type"`, a context that is not a label of at
811+
/// one of the field's index outputs, a context that is not a label of at
805812
/// least two segments (optionally extended), fields under different
806813
/// contexts or extensions, or a plan the builder refuses ([`Plan::new`]).
814+
/// [`Error::UntypedIndex`], naming the field, for a field with a term
815+
/// output and no `"type"`.
807816
/// [`Error::Context`] for a `"context"` that is present but is not a
808817
/// context at all, or renders empty. [`Error::Target`] for a target the
809818
/// resolver refuses ([`Plan::new_with`]).
@@ -884,8 +893,8 @@ pub fn plan_with(
884893
/// index nothing.
885894
///
886895
/// The source is checked and converted here, with no cipher: that is
887-
/// [`check_source`], and it is where [`Error::Source`] and [`Error::Term`]
888-
/// come from. What comes back is the plan's [`Pending`], with every term
896+
/// [`check_source`], and it is where [`Error::Source`] comes from. What
897+
/// comes back is the plan's [`Pending`], with every term
889898
/// derived and every key request queued and nothing sent: one batched
890899
/// `generate_keys` for every ciphertext leaf of every row when it is
891900
/// awaited, however many rows and fields there are. Its failure is the
@@ -947,8 +956,11 @@ pub fn plan_with(
947956
///
948957
/// # Errors
949958
///
950-
/// [`Error::Source`] if the source does not fit the plan; [`Error::Term`]
951-
/// if a value has no term the plan asks for. Both are decided here, before
959+
/// [`Error::Source`] if the source does not fit the plan — a row that is
960+
/// not an object, a field the plan does not name or one it names that the
961+
/// row lacks, or a value of another kind than its field declares, which is
962+
/// how a value no term is defined for is refused: every indexed field
963+
/// declares its kind and the kind check comes first. Decided here, before
952964
/// the pending exists. A failure of the pending itself is the engine's.
953965
///
954966
/// A plan with a target field needs the resolver that built it:

0 commit comments

Comments
 (0)