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.