contract disclosure · 60-visibility.md · 61-disclosure.md · 62-accountability.md · guide · card
Source-faithful visibility
A workspace serving a whole organization answers each reader inside the audience the originating source drew. This file holds the mirrored permission state, its observation clock, the resolution of a subject to the resources it reaches, the age budget on that state, the fidelity a table claims, and the pack that lands a source.
Mirrored permission state, from the source’s permission endpoint to the reader’s view:
mirror
The three-way conjunction, the access tables as store data, and the binding that compiles a table’s semi-join.
unbound-tabletestOn an organization-wide face, a table with no visibility block raisesVisibilityUnboundTablefrom diagnose and from the serving guardrail at start, naming the table.Why
P5face-scopetest[project] face_scope = "organization"makes every face the project serves organization-wide; absent or"personal", its faces are personal, and another value does not load.Why
because a local store serves its owner first, so the organization-wide guardrails bind where a project declares an organization audienceincomplete-bindingtestA binding at a servable level lacking a declared sweep for its source or amax_acl_stalenessraisesVisibilityBindingIncomplete.Why
P5binding-keystestA table’svisibilityblock declaresRawBinding;on_staletakesrefuse, the default, orpublic_only.memory-bindingtestA memory[[table]]takes avisibilityblock under the keys ofbinding-keys, parsed as a pipeline table’s block, so an organization-wide face serves it bound.grants-tabletestA sweep lands a source’s access data as ordinary rows of_visibility/<source>/resources,grants,principals,group_members,identity_links,tombstonesandfreshness, through the land path and its write lock.unmirrorable-openingtestA resource whose access list the sweep could not mirror opens only through a grant row the store owner lands carryingexpires_at; the row confers nothing past that instant, and no manifest key opens a resource.
sweep
Observation of one source’s permission state: sweep kinds, the observation clock, the coverage watermark, tombstones and revocation.
coverage-watermarktestA sweep run that failed or skipped any governed resource of its source and advanceswatermark_atraisesVisibilityWatermarkUncovered, and the watermark stays where it stood.ungapped-streamtestAdvancingwatermark_atfrom an event stream the mapping has not declared gap-detectable raisesVisibilityUngappedStream.orphan-granttestA grant landing with no resource row, or on a resource of the unknown class, raisesVisibilityOrphanGrantat commit and joins no reachable set.Why
P5sweep-blocktestAn[[acl_sweep]]block declares one source’s sweep asRawBlock:enumeratenames the table whose rows are its governed resources, and each cadence is{ every = <budget> }.cadence-grammartestA sweep cadence’severytakes the grammar ofbudget-grammar.sweep-verbtestvisibility sweep --source <s> --kind full|incremental|webhook --grants <file> [--directory <file>]runs one sweep of a declared source from its files and commits as one run.grants-filetestA--grantsfile is the run’s read of every resourceenumeratenames: one JSON object per line, aGrantLineorresource_idwith"unread": true; an unmarked resource with no grant line holds none.bare-resourcetestA--grantsline carryingresource_idalone names a resource read holding no grant, so a webhook run naming it withdraws every grant that resource held.directory-filetestA--directoryfile is the identity provider’s directory read, one JSON object per line: aLinkLineor aMembership; a run without one keeps the current rows.full-runtestA full run replaces the source’s resource and grant rows with those it read, writes a tombstone per grant it no longer observes, and setslast_full_sweep_at.incremental-runtestAn incremental run replaces the grants of each resource it read, tombstoning those withdrawn, leaves every other resource’s grants standing, and setslast_incremental_at.webhook-runtestA webhook run applies one delivery of the source’seventsstream: it replaces the grants of each resource its file names, leaves every other resource standing, and moveswatermark_atto the instant it began reading.empty-deliverytestA webhook run whose file names no resource lands nothing, andwatermark_atstays where it stood.Why
because an empty delivery reads no resource, so it carries no evidence the source’s grants standsuperseded-runtestBefore it lands, a run collects every run of its source’sresources,grants,principals,group_membersandidentity_linksbut the current one, so each of those tables holds at most two runs.watermark-advancetestA run reading every governed resource sets the source’swatermark_atto the instant it began reading; lag is now minuswatermark_at.sweep-epochtestA committed run advances its source’s epoch by one.
unsettled: Does visibility sweep given no --grants file read the source’s permission endpoint under the block’s credential? owner: disclosure affects: disclosure.sweep
reach
Per-request resolution of a subject to the resources it reaches, the bounded group closure, and the reachable-set cache.
subject-principalstestA subjectuser://<p>reaches theuserprincipal spelled<p>and each principal anidentity_linksrow maps to it, then the groups those principals belong to.closure-walktestThe closure walks the group graph with a visited set, ending any cycle, to a depth ofmax_group_depth, default 8 hops, and a breadth of 10000 nodes.closure-overflowtestA closure reaching its depth or node bound raisesVisibilityClosureDepthwith the non-retryable HTTP status 422 and returns no set.cache-capacitytestThe reachable-set cache holds at most 100000 entries and evicts the least recently used.degraded-uncachedtestRetaining a reachable set or result produced past a budget, or under the narrowing posture, raisesVisibilityDegradedCached.semi-jointestThe semi-join openingrelation-orderadmits a row of a bound table when itsresource_keyvalue names a resource with a read-conferring, unexpired, untombstoned grant in the reader’s reachable set.read-leveltestA grant confers read when itslevel, mapped through theleveltable of the pack mapping its table, or taken verbatim where no pack maps that table, isread,writeoradmin.public-granttestA grant whoseprincipal_kind, mapped through theprincipal_kindtable of the pack mapping its table, or taken verbatim where that table names no such kind, ispublicjoins every subject’s reachable set.cache-epochstestThe reachable-set cache keys on the subject, the directory epoch and the epoch of each source the read touches, so a sweep invalidates only sets reading its source.
bound-staleness
The declared age budget on mirrored authorization, the refusal past it, and the one narrowing posture.
budget-grammartestmax_acl_stalenessis a positive integer with one suffix froms,m,h,d. A compound form, a bare number or another suffix raisesVisibilityBudgetMalformed, naming the table and the text read.access-staletestA read raisesVisibilityAccessStale(HTTP 503, carrying source, lag, budget and last observation) when a touched table’s source lag exceeds its budget, the source has no completed full run, or the public-status watermark is past budget.budget-below-cadencetestA budget tighter than the sweep cadence its source sustains raisesVisibilityBudgetUnreachableat diagnose, naming both figures.clock-offsettestCONTEXTFUL_NOW_OFFSET_SECS, a non-negative integer, moves the instant a staleness check reads as now that many seconds later, so it can refuse a read and never extends a budget.Why
because a test observes a budget elapse without waiting, and an offset that only ages state cannot admit a readoffset-malformedtestACONTEXTFUL_NOW_OFFSET_SECSvalue other than a non-negative integer stops the process before it serves, naming the variable.public-watermarktestA table’s public-status watermark is the oldestacl_observed_atamong its source’s resources holding a read-conferring, unexpiredpublicgrant; with no such resource it lags zero.Why
because an incremental run over the public resources refreshes each one’s observation, so public status stays current while the full watermark lagspublic-onlytestPast its budget, apublic_onlytable whose source has a completed full run and a public-status watermark within budget serves only rows whose resource holds a read-conferring, unexpiredpublicgrant.degraded-blocktestA read touching a table served underpublic-onlyanswers with acontextful.visibilityblock holdingdegradedtrue and the narrowed tables undernarrowed.
declare-fidelity
The fidelity level a table claims, the source family bounding the claim, and live federation under a reader’s delegated credential.
family-boundtestAperson-containertable at a servable level, or adirectorytable aboveexcluded, raisesVisibilityFamilyBound, and the manifest declaring it does not load.family-undeclaredtestA mapping landing a table without naming itsfamilyraisesVisibilityFamilyUndeclared.federated-registeredtestRegistering afederatedtable on a read face raisesVisibilityFederatedRegistered.
unsettled: Does a grants mapping refuse a roster read from content, a sharing engine’s inputs, or a federated result cached without its subject? owner: disclosure affects: disclosure.declare-fidelity
pack
The reviewed unit landing one source: a manifest fragment plus a connector pin, its access mapping, defaults and container allowlist.
mapping-absenttestA pack landing a table with neither an access mapping norexcludedraisesVisibilityMappingAbsentat diagnose, naming the pack and the table.asserts-accesstestAn access-shaped key the mapping schema does not define raisesVisibilityPackAssertsAccessby name. Fields outside the mapping are fetch inputs and reach no authorization decision.any-of-allowlisttestAn allowlist evaluated as any-of raisesVisibilityAllowlistAnyOfat load.Why
P1unsupported-coarsetestDeclaringcoarsewhere the source emits no container or workspace signal raisesVisibilityUnsupportedCoarse.pack-blocktestA[pack.<name>]block names thetablesit lands, itsexcludedtables, oneaccess.<table>mapping per mapped table, and an optional containerallowlistofcontainerswithevaluate = "all-of".mapping-keystestAn access mapping holdsRawMappingand no other key.
drive-sweep
Mapping Drive file permissions into the governed source’s visibility rows.
resource-setA Drive sweep enumerates each file row of its bound connection as one governed resource undersweep-block.permission-pagesFor each governed file, the sweep follows everypermissions.listpage under the connection credential before its grants replace prior grants.grant-mappingUser, group, domain and anyone permissions map to distinct principal kinds; the mapping retains Drive permission id and role beside the source resource id.inherited-accessA shared-drive permission records its inheritance source when Drive supplies one; a direct permission and an inherited permission remain distinct grants.unreadable-resourceA refused or incomplete permission read marks its resource unread and advances no coverage watermark undercoverage-watermark.identity-linkAn email or domain from Drive becomes a reachable subject only through a verified identity link undersubject-principals.
Scenarios
disclosure.drive-sweep.permission-pages: WHEN a file’s permission response has a next-page token, THEN the sweep reads that page before replacing its grants.disclosure.drive-sweep.unreadable-resource: WHEN one file’s permissions refuse, THEN no complete sweep watermark advances.
Shapes
The access tables, each at _visibility/<source>/<name>. Every instant is an engine UTC instant taken when the sweep read the source.
CREATE TABLE resources (
resource_id VARCHAR NOT NULL,
source VARCHAR NOT NULL,
resource_kind VARCHAR NOT NULL,
container_id VARCHAR,
visibility_class VARCHAR NOT NULL, -- mirrored | coarse | federated | unknown
acl_observed_at TIMESTAMP NOT NULL,
acl_sweep_kind VARCHAR NOT NULL, -- full | incremental | webhook
acl_sweep_id VARCHAR NOT NULL
);
CREATE TABLE grants (
resource_id VARCHAR NOT NULL,
principal VARCHAR NOT NULL,
principal_kind VARCHAR NOT NULL, -- user | group | team | channel | org | public
level VARCHAR NOT NULL, -- source spelling, projected by the mapping
expires_at TIMESTAMP, -- set on an operator-landed opening
acl_observed_at TIMESTAMP NOT NULL,
acl_sweep_kind VARCHAR NOT NULL,
acl_sweep_id VARCHAR NOT NULL
);
CREATE TABLE principals (
principal VARCHAR NOT NULL,
principal_kind VARCHAR NOT NULL,
source_label VARCHAR
);
CREATE TABLE group_members (
"group" VARCHAR NOT NULL,
member VARCHAR NOT NULL,
member_kind VARCHAR NOT NULL,
acl_observed_at TIMESTAMP NOT NULL
);
CREATE TABLE identity_links (
source_principal VARCHAR NOT NULL,
subject VARCHAR NOT NULL,
method VARCHAR NOT NULL, -- scim_email | oidc_sub | operator_asserted
confidence DOUBLE
);
CREATE TABLE tombstones (
scope VARCHAR NOT NULL, -- resource | grant | principal
resource_id VARCHAR,
principal VARCHAR,
level VARCHAR,
revoked_at TIMESTAMP NOT NULL
);
CREATE TABLE freshness (
source VARCHAR NOT NULL,
epoch BIGINT NOT NULL, -- one per committed run
sweep_id VARCHAR NOT NULL, -- the run whose resources and grants rows are current
sweep_kind VARCHAR NOT NULL,
watermark_at TIMESTAMP, -- null until a run reads every governed resource
last_full_sweep_at TIMESTAMP,
last_incremental_at TIMESTAMP,
lag_seconds BIGINT,
budget_seconds BIGINT
);
A bound content table, the sweep feeding it, and a pack’s mapping:
[pipeline.tables.pages.visibility]
source = "wiki"
resource_key = "page_id"
resource_kind = "page"
fidelity = "mirrored"
family = "item-exception"
max_acl_staleness = "15m"
on_stale = "refuse"
[[acl_sweep]]
source = "wiki"
credential = "secret://wiki/permission-reader"
enumerate = "pages"
full = { every = "1h" }
incremental = { every = "5m" }
events = { stream = "wiki.permissions", gap_detectable = true }
[pack.wiki]
tables = ["pages", "drafts"]
excluded = ["drafts"]
allowlist = { containers = ["eng", "ops"], evaluate = "all-of" }
[pack.wiki.access.pages]
resource_key = "page_id"
resource_kind = "page"
family = "item-exception"
principal_kind = { user = "user", group = "group", workspace = "org", anyone = "public" }
level = { viewer = "read", commenter = "read", editor = "write", owner = "admin" }
The levels each source family permits:
| Source family | mirrored | coarse | federated | excluded |
|---|---|---|---|---|
container-roster | yes | yes | yes | yes |
item-exception | yes | yes | yes | yes |
person-container | — | — | yes | yes |
directory | — | — | — | yes |
The envelope a bound read returns:
{
"rows": 42,
"visibility": {
"fidelity": "coarse",
"grain": "teamspace",
"acl_lag_seconds": 212,
"acl_budget_seconds": 900,
"degraded": false,
"group_closure_depth": 3,
"federated_legs": [{ "source": "drive", "outcome": "timeout", "citations": 0 }]
}
}