Qualified record selection

Read grants and writer grants select group content for exchange and local interpretation. These are application conventions implemented by ordinary Lace source modules, not a Lace schema or a second policy evaluator.

Records and currentness

The application chooses one issuer and scope. reading::ReadingPolicy also chooses an author interest filter; that key is eligible only through a current writer grant from the same issuer/scope. The storing provider need not be a writer or reader.

The issuer signs two statement families. Every listed field is singleton:

Kind Fields besides Kind
read-grant Member, Scope, Revision, After, Decision
writer-grant Member, Scope, Revision, Decision

Member names a public key. Revision is a canonical unsigned integer counter; Decision is granted or withdrawn. A granted read statement’s After is a canonical unsigned Unix epoch-second bound. Native constructors accept u64; rules accept Lace’s unbounded canonical integer domain within record-field limits.

Within each family and issuer/scope, rank revisions per member before filtering decisions or bounds. Keep every statement at the greatest revision. Different current decisions—or read bounds—deny rather than choosing a hash winner. Equivalent assertions under different record hashes do not conflict. Withdrawn or unknown decisions grant nothing; a nonnumeric current read bound grants nothing. Records missing singleton statement fields or a canonical revision have no statement meaning, but remain relevant evidence when their issuer, Kind, and Scope match.

Group content is a Seal with singleton Kind: group-content, Scope, Timestamp, and Timezone. Its signer must be an accepted writer matching the consumer’s author interest. Writer acceptance covers retained history; withdrawal removes that author’s content from current selection and further exchange, not possession. Read permission, writer acceptance, and execution permission are independent.

Timestamp is canonical unsigned Unix epoch seconds. Timezone is separate IANA display metadata: the content adapter requires its singleton presence but does not interpret the zone or derive authority from it. Native/Python creators write UTC; the browser uses its declared display zone. Application clocks do not prove chronology or freshness. Generic Lace constructors add neither field.

A reader qualifies only for content whose timestamp is strictly greater than its unambiguous current read bound. For After: 100, timestamp 101 qualifies but 99 and 100 do not. These numbers denote seconds after the Unix epoch. Normal browser-host enrollment uses After: 0 to include shared history.

Source contracts

Each source is supplied explicitly to Lace compilation. References are opaque; qualification maps to the exact file qualified-content.interlang.

Source Inputs Exports
src/membership.interlang configuration(issuer,scope) evidence(Record), offered_evidence(Record), current(Record,member,revision,after,decision), grant(member,after)
src/writers.interlang configuration(issuer,scope) evidence(Record), offered_evidence(Record), current(Record,member,revision,decision), accepted(member), accepted_evidence(Record,member)
src/content.interlang configuration(author,scope) checked(Record,timestamp), offered(Record,timestamp)
src/qualified-content.interlang candidates(Record,timestamp), grants(member,after), readers(member) readable(Record)

Evidence discovery checks the exact issuer By and singleton Kind/Scope, not statement-body validity. accepted_evidence returns current granted records only for unambiguously accepted writers. Advertisement adapters are request-only claims, never checked grants. Content’s checked and offered adapters apply the same field and integer constraints. Qualification binds the reader’s bound before joining content; conflict checks count assertions, not evidence pairs.

ReadingPolicy::local_source(member) exports readable, read current, and current_writer for independent consumers. exchange_source() binds checked and advertised candidates separately. reading::LIBRARIES supplies all four exact sources; compile_sources fills compilation slots without source IO.

Imports activate no library effects. Consumers write their own facets, and hygienic binding keeps each issuer/scope application distinct. Alternative qualified relations union through separate rules; conjunction requires both qualifications for the same record:

selected(Record) :- first.readable(Record).
selected(Record) :- second.readable(Record).
selected(Record) :- first.readable(Record), second.readable(Record).

Keep each arm’s reader, issuer, scope, writer acceptance, and read bound intact. Matching scope labels do not equate authorities. tests/composition.rs covers both forms. The test-only tests/fixtures/bulletin.interlang instead joins each bulletin’s author to that author’s read grant; this demonstrates relation reuse, not publication authority.

Exchange and local interpretation

ReadingPolicy::exchange_source() offers content for PeerConfidential(reader) and requests it for Here(reader). Both operands constrain selection. Live peer proof requires a host-asserted confidential, integrity-protected, endpoint-confined channel; provider identity does not substitute for the content signer.

Both evidence histories are deliberately shareable with proved peers without a read or writer grant. An empty receiver acquires checked support before requesting qualified content in a later round. Hiding withdrawals can leave an old grant apparently current: this convention promises neither private evidence with independent verification nor omission detection or global freshness.

ReadingPolicy::acquisition() captures relevant issuer history and author/scope candidates together, independently of current grants. It is trusted local acquisition, not network disclosure policy. Require a complete list outcome, seed a private memory Lace, and keep it unchanged while selecting content and current evidence through imported relations. Broad request/exposure facets in a local reader are confined to that approved input set.

An independent reader can inspect current statements, including withdrawals and conflicts; parsing selected records is presentation, not another ACL. Never combine separate captures from changing sources into a claimed coherent result. A result is current over the supplied set, not globally current. Incomplete acquisition is an error, not a complete empty group. Refreshing may shrink the result; admissions, retained bytes, and current selection are different things.

The archive and thread readers consume retained records and exact sources. Replies add references without granting target access. qualified-reading --help lists record creation and policy-emission commands; tests/feature_cli.rs checks that command boundary. Validation lists the remaining integration checks.