Skip to main content

The acceptance inventory

This is the required behavior inventory. ACCEPTANCE_PREFIXES in validation_evidence.py maps 50 acceptance groups (A to X, SA, SL, GC, AL, SP, SM, DN, LA, EX, SG, PK, CF, AY, MQ, HV, AQ, AK, XW, SN, AR, MC, MI, RF, AV, FD and TB) to the test nodes that must pass. All mutation assertions inspect the provider operation journal and invocation evidence, not only the gateway's HTTP response. Concurrency tests use separate database transactions/workers against real PostgreSQL. Use a controllable clock and deterministic barriers for races.

The hosted service's own rows are kept in an inventory of its own, so a group here may skip the numbers that belong to them. A row that ends Evidence not published. rests on a test that is not in the public repository.

Original scenarios​

IDSetup/actionRequired result
APermitted workstation and correctly linked authoritative critical incidentALLOW; one provider mutation, one impact unit and durable evidence.
BTier-0/domain-controller isolation requestDENY; zero mutations.
CProduction targetNo dispatch before scoped human approval; one dispatch after valid retry.
DTen principal autonomous isolations, then target elevenEleven requires approval; simultaneous requests cannot exceed autonomous allowance.
ECaller claims low-tier workstation; resolver identifies Tier-0DENY; claims never replace trusted facts.
FUnknown operation, raw passthrough or unsupported consequential optionDENY; no protected mutation.
GChange any approved execution field, account, target or security versionOld approval invalid; reevaluate or reject, zero unauthorized mutation.
HRetry a confirmed executionPrior result; no extra mutation or impact.
IProvider mutates then times outINDETERMINATE with capacity held; no automatic conflicting retransmission.
JReplay a policy changeChanged simulated decision; zero provider calls or writes to live control state.
KAGENT calls approve/deny/config/reconcile routesEvery path rejected and audited.
LSeveral principals collectively reach tenant ceilingFinal over-ceiling request denied regardless of principal allowance or human approval.
MInterleave HTTP and MCP requestsSame idempotency claims, resource guards, tenant impact and policy results.
NErroring Cedar forbid with a broad permit; repeat with an approval-set errorDENY; also deny missing required trusted attributes and configured-set load failures.
OChange version between last gateway read and provider writeAtomic provider precondition rejects mutation; stale authorization recorded.
PReconcile timeout using exact provider operation evidenceCorrect terminal/uncertain state and exact impact preservation.

Review regressions and specification closure​

ID / patchSetup/actionRequired result
Q / P1Submit permitted primary resource plus Tier-0 target; reverse order; embed target in argumentsAll contradictory/multiple-target forms rejected before dispatch.
R / P3Permute broad permit, production approval, exceeded soft threshold and exceeded hard ceilingDENY always wins; valid approval cannot waive hard ceiling.
S / P1/P6Two tenants with colliding local IDs, aliases, accounts and idempotency keysNo foreign object disclosure, approval consumption, replay selection or provider mutation.
T / P2Unrelated critical incident, agent-editable severity, stale incident, claimed derivation inputNo independent authority established; deny or invalidate old approval as appropriate.
U / P4Change provider resource/bundle/context at dispatch barriersConditional provider failure or precommit reauthorization; no old-plan dispatch after a prior bundle change.
V / P4Simultaneous same-key requests, changed payload, new key/run/alias, crash at each dispatch boundaryOne execution claim; conflicts rejected; possible dispatch stays uncertain without automatic resend.
W / P5Timeout, out-of-band inverse mutation, reconcile; delayed arrival after negative lookup; another actor creates positive stateReal impact never refunded; absent/current-state observations remain uncertain; cancellation tombstone fences late operation.
X / P6Agent markup in approval fields; cross-site forms; expired/wrong-scope human sessionStrings inert; forged/browser-mediated approvals fail; direct agent restrictions remain enforced.

Additional required edges:

  • First-use budget-row races and multiple simultaneous scopes; no negative/double-released reservations.
  • Fresh runs, reauthentication and bundle/rule-version changes preserve principal/tenant history.
  • Outstanding reservations remain counted beyond rolling-window boundaries until resolved.
  • Same-intent pending requests with new keys reuse one approval; completed intentional new-key operations reevaluate and count again.
  • Context reattestation with unchanged versions does not mutate a frozen plan; changed/expired dependencies invalidate approval.
  • MRTR MAC tampering, unknown/retired keys, wrong tenant/principal/audience/hash, expiry and concurrent approval consumption.
  • Modern and one supported older client use identical policy/approval behavior; tool-list cache isolation never substitutes for tools/call authorization.
  • Both providers reject agent credentials; fixed connector destinations reject redirect/URL/header injection; secrets absent from responses/logs/errors.
  • Audit edit/deletion/reorder/concurrent append/truncation checks against a retained trusted head.
  • Replay with unknown approval, hypothetical new execution, uncaptured context and uncertain dependent counters reports UNRESOLVED.
  • Every Entra operation, including enable and revoke_sessions, has explicit scoped authorization and operation-specific evidence.

V1 is complete only when A–X and applicable edge cases pass, startup is reproducible, browser approval is verified, tested dependency/client versions are recorded, and the validation package states its mock/coverage limits.

Context contracts​

IDSetup/actionRequired result
CC1Construct catalogs that violate each construction rule in Context contractsConstruction fails for each
CC2Both v1 contracts through resolution and evaluationFrozen plans, hashes and decisions match the pre-change golden fixture byte for byte
CC3Synthetic contract serving endpoint.isolate with row-backed String, Long and Boolean facts, an equals derivation and incident mode noneALLOW performs one provider mutation; a forbidden value denies with zero mutations
CC4Mapping names a contract missing from the catalog, or one that does not serve its actionINVALID_OPERATION; zero mutations
CC5Bundle settings with shorter and longer max ages; above-ceiling, empty-writer and unused-contract settingsShorter denies a fact the default accepts; longer accepts an older fact; invalid settings fail validation
CC6Source writers outside the effective allowlist, including an agent-writable incident sourceDENY; scenario T unchanged
CC7Bundles whose Cedar schema omits, adds, mistypes or makes optional a contract attributeValidation fails; the existing packs still activate
CC8Two tenants with colliding account and resource IDs in resource_factsNo cross-tenant read; runtime cannot insert, update or delete; RLS forced
CC9Migration upgrade and downgrade round trip; downgrade with rows presentRound trip passes; downgrade refuses
CC10Replay with candidate bundles that shorten and lengthen max ageShorter can deny history; longer cannot extend frozen validity; existing replay scenarios unchanged
CC11Pending approval, then a resource_facts row version changesRe-attestation with the frozen bundle's settings returns STALE_AUTHORIZATION
CC12Approval page for endpoint, identity and synthetic contractsEach shows its contract's display fact as inert text

Tests live in tests/test_contracts.py, test_context_parity.py, test_resource_facts_schema.py, test_context_resolution.py, test_context_evaluation.py, test_context_bundle_validation.py, test_context_execution.py and test_replay_scenarios.py.

SOC action catalog​

IDSetup/actionRequired result
SA1Construct action catalogs that violate each construction rule of the action catalogConstruction fails for each
SA2All four existing actions through parse, resolution, evaluation, command and journalBoth endpoint fixtures, the context parity fixture and the new identity golden match byte for byte
SA3Arguments that are nested, listed, null, float, oversized, unknown, missing, extra, mistyped or out of domain, on HTTP and MCPRejected before any lookup or mutation; scenario F unchanged
SA4Contained endpoint, reason false_positive, incident CLOSEDALLOW; one lift_containment mutation; journal shows contained true to false and binds the arguments
SA5Same target, reason remediated on a non-production endpointREQUIRE_APPROVAL; the approval page shows reason: remediated as inert text; valid retry after approval dispatches once
SA6Standard identity, OPEN HIGH incident, require_change_at_next_sign_in trueALLOW; credential transition increments the generation and sets must_change_password; enabled state and session generation unchanged; no password in journal, response or logs
SA7require_change_at_next_sign_in false, then a privileged identityREQUIRE_APPROVAL, then DENY with zero mutations
SA8Same key with a changed argument; new key with the same arguments while pendingIDEMPOTENCY_CONFLICT; attaches to the pending execution
SA9Synthetic action with a bounded Long argument in and out of range; synthetic second binding for endpoint.isolate through a tenant mapping; a mapping naming an unknown bindingIn range resolves and reaches Cedar; out of range is INVALID_ARGUMENTS; the second binding resolves; the unknown binding is INVALID_OPERATION
SA10Bundles whose action context omits, adds, mistypes or makes optional an argument, or omit a mapped actionValidation fails; the existing packs and the SOC pack still validate and activate
SA11Provider command with arguments altered after freezing; journal with an inconsistent transitionProvider rejects with 400 and no journal; evidence fails verification and nothing settles
SA12Isolate then lift the same target; lift while the isolate is unresolvedTwo impact units, no refund; while the claim is held the second request is recorded as a DENIED transition with reason RESOURCE_BUSY
SA13Migration upgrade and downgrade round trip; downgrade with a new-action row in each guarded tableRound trip passes; downgrade refuses; runtime privileges unchanged
SA14seed-validation outputSOC bundle installed as VALIDATED and written to the output; the demo bundle, its bytes and the browser demonstration unchanged
SA15Replay with a candidate that forbids reason == "remediated"The recorded lift becomes a candidate DENY; the report row shows the argument; existing replay scenarios unchanged

Tests live in tests/test_action_catalog.py, test_domains.py, test_identity_compatibility.py, test_requests.py, test_resolution.py, test_policy_evaluation.py, test_context_bundle_validation.py, test_soc_pack.py, test_soc_provider.py, test_soc_execution.py, test_soc_schema.py, test_replay_scenarios.py, test_replay_verify.py, test_human_surface.py and test_validation_demo.py, with shared fixtures in tests/soc_fixtures.py.

Approval quorum​

IDSetup/actionRequired result
QA1Bundle requires two approvers on the production obligation; first approver approves; agent retriesApproval PENDING with one decision; retry 202 pending; no dispatch
QA2Second distinct approver approves; agent retriesAPPROVED, then CONSUMED; exactly one provider mutation
QA3The first approver decides again with the same or another credentialINVALID_STATE; one decision row; nothing counted twice
QA4One approval, then a denial by another approverDENIED; execution DENIED (HUMAN_DENIED); retry denied; zero mutations
QA5One approval, then the approval window endsEXPIRED; a later approval by the second approver is refused; nothing consumed
QA6Two approvals; before the retry, one approver's credential is revoked or scope removedSTALE_AUTHORIZATION with INVALID_APPROVAL; zero mutations
QA7Bundle re-activated between the two approvalsSecond decision refused as stale; approval INVALIDATED
QA8Two approvers decide concurrently on two connectionsOne completes the quorum; two rows; consumed once; one execution
QA9Quorum rules naming an unknown obligation, required of 1 or 6, or duplicate rulesBundle validation fails with field locations; existing packs still validate and activate
QA10Human pages with real ChromiumProgress text; no form for the approver who already decided; a replayed decide POST by that approver refused; markup inert
QA11Audit and replayEvery approver captured; forged one-approver consumption against a two-approver requirement reports INSUFFICIENT_QUORUM; the parity golden and endpoint fixtures unchanged; the preview shows the candidate's effective requirement
QA12Migration round trip and check_runtimeColumn, table, forced RLS and grants present; runtime cannot update or delete decisions; downgrade refuses while any decision row exists

Tests live in tests/test_approval_quorum.py.

Observe-only mode​

IDSetup/actionRequired result
OB1Tenant in OBSERVE; production target request over HTTP and MCP200 OBSERVED, observed.effect REQUIRE_APPROVAL; no approval, impact reservation, claim or ticket; zero provider invocations
OB2Development target (would be eligible)OBSERVED ELIGIBLE; an OBSERVED impact row; zero provider invocations
OB3Tier-0 target (would be denied)OBSERVED DENY with the reasons
OB4Retry with the same key; a new key for the same intentSame view; a new observed execution; nothing consumed
OB5Enforcing tenant with one observe_only mappingThat action observed; another action enforced with a real approval and one mutation
OB6Eleven observed autonomous isolationsThe eleventh observes REQUIRE_APPROVAL under the assumed-executed projection; an enforced evaluation in the same tenant ignores observed rows; replay reproduces the decisions
OB7Switch to ENFORCE with a reasontenant.mode_changed audited; the next request creates a real pending approval; observed rows unchanged; a pending approval admitted under enforcement keeps its view while the tenant observes
OB8Mode change by an agent or approver, without a reason, to the current mode or to an unknown mode; admission during an emergency stopINVALID_IDENTITY, INVALID_REASON, INVALID_STATE, INVALID_MODE; TENANT_STOPPED
OB9Human pages with real ChromiumObserved badge and effect on Activity, no forms, Approvals empty, mode notice shown
OB10Audit, replay and previewCaptures carry mode: OBSERVE; a candidate bundle re-evaluates observed decisions; a forged observed execution with a claim, or an OBSERVED transition without observation, is OBSERVED_WITH_EFFECT
OB11Migration round trip and check_runtimeColumn and states present; downgrade refuses while any tenant is in OBSERVE or any OBSERVED row exists
OB12CLI mode and report commandsMode set and shown; report counts match the audit chain; non-ADMIN refused

Tests live in tests/test_observe_mode.py.

Shared limit scopes​

IDSetup/actionRequired result
SL1Two agents in one group under a group ceiling of three with REQUIRE_APPROVAL; a third agent outside the groupThe group's fourth isolation by either member is PENDING_APPROVAL with limit:<rule>; every member row retains the group; the outsider reserves at once with an empty membership and the group count is unchanged
SL2Account rule over three identity actions and endpoint.isolate on the identity account with a DENY ceiling of three; an isolation on the endpoint account and a second rule scoped to that accountThe fourth disruptive action on the identity account is DENIED with HARD_LIMIT:<rule>; the endpoint account's isolation neither charges nor triggers it and counts only under its own account's rule; every row retains its account
SL3Selector environment = production with a total ceiling of two; development isolations in between and at the ceilingOnly production isolations count; development ones reserve without charging; the third production request is PENDING_APPROVAL with limit:<rule> beside the pack's production obligation
SL4Multi-action budget over endpoint.isolate and endpoint.lift_isolation in the SOC world beside a rule without actions, both at a ceiling of oneIsolate then lift the same target draw on one counter: the lift escalates on the pair rule alone and executes after approval with the endpoint released; the rule without actions counts the isolation only
SL5Six principals of one group on six connections at a group DENY ceiling of threeExactly three tickets and three DENIED with HARD_LIMIT:<rule>; three retained rows each with the group; after settlement three confirmed units and a seventh request still denied
SL6Two reservations by a member, then unassign it and assign a newcomerThe newcomer's snapshot reads the group's two units and its first isolation is the third; the leaver's next isolation retains no group and charges nothing to it; the leaver's earlier rows keep the group
SL7Rules with a missing or mismatched qualifier, an unknown action, group, account or fact, a selector value outside the domain, empty, oversized or duplicate actions, or actions without actionThe model or the store refuses each, the store with its field location (limits.<i>.action, .group_id, .account_id, .selector); a bundle with one valid rule of each scope validates and activates; existing packs validate with unchanged hashes; deleting the group fails the active bundle closed
SL8Approved candidates under group, account and selector scopes with an autonomous DENY rule at its ceiling and a total rule per scopeThe approved retry executes at the hard autonomous threshold of every scope, adds zero autonomous units and one total unit, and its row retains the group and the fact
SL9Replay and preview over captures with and without recorded membershipGroup, account and selector candidates reconstruct from captures alone and recorded decisions match; a candidate group rule over captures without groups reports UNKNOWN_GROUP_MEMBERSHIP and UNRESOLVED while the baseline still matches; a lower-bound denial stands; an unserved selector or unknown listed action is POLICY_ERROR; report.json is deterministic
SL10Migration round trip; downgrade with a group, a membership or a scoped draft bundle presentBackfilled account_id and facts match executions.frozen and group_ids is null on legacy rows; each downgrade refuses and leaves the revision, forced RLS and check_runtime intact; the runtime cannot insert, update or delete group rows
SL11Owner CLI and the record page with real ChromiumGroup commands are audited and refused for non-ADMIN actors, non-AGENT members and the runtime role; the record page labels every scope and action list as inert text with no link or form in the list
SL12Observe-only tenant under a group rule and a selector ruleObserved rows carry the attributes; the observe-mode projection triggers both rules; enforced evaluation ignores the observed rows and a member's isolation reserves after the switch to ENFORCE

A principal with more than 64 memberships fails admission closed, audited as INVALID_CONFIGURATION and answered EXECUTION_UNAVAILABLE (THREAT_MODEL.md T1.17), and the 65th assignment is refused at provisioning.

Tests live in tests/test_limit_scopes.py (SL1 to SL6, SL8, SL12 and the membership bound), test_limit_scopes_schema.py (SL10), test_policy_models.py, test_policy_evaluation.py, test_context_bundle_validation.py and test_policy_store.py (SL7), test_admin_cli.py (the SL11 commands and the preview), test_replay_history.py and test_replay_scenarios.py (SL9), test_human_surface.py and test_browser_surfaces.py (the SL11 pages), with shared group, rule and bundle helpers in tests/scope_fixtures.py.

External execution checkpoint​

On real PostgreSQL, with the protected mocks acting as an external executor and the mock's conditional write standing in for a vendor's. The guide is External execution checkpoint.

IDSetup/actionRequired result
GC1An eligible checkpoint on a mapping with external_executor, in a tenant whose account has no connectorA checkpoint object of exactly grant and act, with operation, expected version, precondition class, both deadlines, report secret and act grant; an UNRESOLVED impact row and a canonical claim exist; admission returns no dispatch ticket and the dispatch path refuses the execution
GC2Six principals requesting checkpoints for one target on six connections, and separately at a shared group ceilingExactly one grant and one claim for the target and the rest RESOURCE_BUSY; at the ceiling exactly the ceiling's grants succeed and the rest carry the hard limit; no negative or double-released counter
GC3A checkpoint and an agent dispatch against one ceiling, with a total and an autonomous ruleBoth charge the same counters in every scope and the total ceiling is reached once across the two paths; an approved candidate adds zero autonomous units on both paths
GC4A checkpoint that requires approval, at a quorum of one and at a quorum of twoNo grant; the existing approval with its window and quorum; the retried checkpoint after the decisions consumes it exactly once and issues one grant
GC5A denied checkpointNo grant, no impact row, no claim; the denial is captured and replays to the same decision
GC6An attested executed outcome, then the identical report again, then a second signed record restating itEXECUTED at tier ATTESTED, impact confirmed, claim released; a report restating the settled tier, outcome and reason is a no-op returning the same view, whatever record carries it and whatever the retained proof stays, and a report contradicting any of the three is refused
GC7An asserted executed outcomeEXECUTED at tier ASSERTED, impact confirmed, the claim still held; a run before the act window releases nothing, the run after it releases the claim, and the record and page show the tier
GC8An asserted non-execution, then an administrator settlement with attested evidence through the connector-free pathThe report leaves INDETERMINATE with impact charged and the claim held; only the settlement releases them; the executor cannot reach that path
GC9An outcome report presented against an ordinary dispatched execution, another principal's checkpoint, an already settled execution, an expired report window, and with a forged or replayed secretEach refused with no state change, audited without echoing the secret, and the dispatched execution keeps its own owner secret as the only way to settle it
GC10A grant unreported past its report window, then a recovery run, then a cancellation runSwept to INDETERMINATE with impact charged and the claim held, listed in the uncertain queue; the cancellation run refuses to settle it as a non-execution
GC11Two simultaneous outcome reports on one grant, on two connectionsExactly one settles; one confirmation, one release, one audit event
GC12The target version changed between grant and report, under each precondition classENFORCED_BY_PROVIDER returns a non-execution that releases impact and claim; ASSERTED_BY_EXECUTOR records an assertion that releases nothing; UNAVAILABLE carries no version and the grant's own capture records that the change was undetectable
GC13A plan that expires and an act window that closes between grant and report, and an idempotent retry of a granted checkpointThe report is still accepted within the report window and settles at its tier; the retry returns the same checkpoint and a re-signed act grant, mints no second secret and reserves nothing new
GC14Replay of a history containing an attested checkpoint, an asserted checkpoint, an unreported grant, a settled FAILED_EFFECT_UNKNOWN row and a corrected row of each directionEvery decision recomputes; the asserted settlement is never presented as gateway evidence; the unreported grant replays as retained uncertainty before and after the sweep; the tenant still exports, publishes and previews; reports are byte-deterministic. The history holds a settled FAILED_EFFECT_UNKNOWN row because without one the scenario could not detect a skipped settlement gate, the ledger's refusal of a second settlement or the terminal gate's before set — and a corrected row of one direction alone cannot detect the last of those, because the after set already catches CANCELLED_NOT_EXECUTED
GC15Bundle validation of external_executor beside observe_only, without a catalog binding and without a registered executor key; a request naming an executor; and a checkpoint request in a tenant switched to OBSERVEThe model refuses the placement pair and the store refuses the other two with their field locations; the request fields are refused as unknown; the observing tenant returns an OBSERVED view with no grant, reservation or claim; existing bundles validate and activate with unchanged hashes
GC16Emergency stop between grant and report, and a stop before a checkpoint; and an executor spamming invalid reportsThe outstanding grant is not recalled and its report still settles; a new checkpoint under the stop is refused; the stop period is visible in replay; the refusals are bounded and do not starve the tenant's writers
GC17Migration round trip with a settled checkpoint of each tier, an unreported grant, a settled FAILED_EFFECT_UNKNOWN row and a corrected row retainedDowngrade refuses while any exists; check_runtime passes before and after; tests/fixtures/endpoint-contract-v1.json, tests/fixtures/identity-contract-v1.json and the context parity golden stay byte-identical. Without a FAILED_EFFECT_UNKNOWN row the downgrade would succeed either way and the clause would never be exercised. The corrected row is the case a check of executions.state alone would pass, because only its retained events name the new state
GC18The synthetic workflow contract end to end with real Chromium for the pagesThe story handles grant, denial, approval wait, expiry and report failure; the record and approval pages label the execution externally executed and show class and tier as inert text, with no control that dispatches

For GC6, what a settled row is closed to is a change of tier, outcome or reason, and a second record that differs in some other way — a later reported time, a signature by a second registered key — but restates the settlement is verified, found to move nothing, and answered as the no-op the first half of the row describes. It retains nothing and appends nothing, so a tenant cannot afterwards see that two of its registered keys attested one settlement; no budget, claim or execution state moves, which is why that is a limit on what the history can answer rather than a reason to refuse the record. A neighbouring record is refused by a different guard: one whose reported time predates the grant is INVALID_RECORD at the verifier.

Tests live in tests/test_checkpoint.py (GC1 to GC16 and GC18's approval-page clause), test_checkpoint_schema.py (GC17), test_checkpoint_workflow.py (GC18's story contract) and test_browser_surfaces.py (GC18's Chromium half), with shared fixtures in tests/checkpoint_fixtures.py; the four prefixes are group GC in ACCEPTANCE_PREFIXES. Supporting evidence lives in test_checkpoint_evidence.py, test_admin_cli.py, test_recovery_run.py, test_replay_scenarios.py and test_replay_verify.py.

Provider-specific proof and the live half of the workflow contract are not covered by these rows: every capability here is fixture-verified against the protected mocks.

Tines Gate qualification​

On real PostgreSQL, with the protected mocks acting as an external executor and, for PROVIDER_VERIFIED, as the provider that signs the journal too. The guide is External execution checkpoint.

IDSetup/actionRequired result
TG1A grant under each precondition class, and a re-grant, including one after the deployment declares the binding otherwisebinding always, matching the execution. provider_command exactly when a version is present, equal to provider_command of the frozen dispatch command. The class the grant was issued under is recorded on the execution at the first answer, and a re-grant is described under it, never under a later declaration. The contract fixtures stay byte-identical
TG2A provider journal reporting each journal outcome, for a grant under a class that carries its provider_commandSettles at PROVIDER_VERIFIED with the attested tier's state, impact and claim effects, and one mutation at the mock
TG3Journal refusals, for a grant under ENFORCED_BY_PROVIDER so the journal alone decides: no configured key, wrong key id, bad HMAC, another execution's journal, each command field altered, dated before the grant, outcome or reason contradicting the body, beside another evidence field. A journal of the command ExecBound would have sent, for a grant issued UNAVAILABLE, which carries no provider_command; the same for such a grant issued before the class was recorded, and through the administrator's settlementEach refused with no state change and no tier, and a correct report settles the grant afterwards; the combinations are INVALID_REQUEST at the parser. The grant with no recorded class and the administrator's settlement still take the journal, at PROVIDER_VERIFIED
TG4The administrator exit with a journal on an unsettled, an INDETERMINATE and a swept grant. The correction by a provider non-execution. A provider EXECUTED on the correctable row. An asserted EXECUTED presented with a journalThe first four settle. The last two are INVALID_STATE, audited, with nothing moved
TG5Configuration with an account in both connectors (or graph_connectors) and checkpoint_providers, a duplicate entry and a malformed key. A dispatched execution offered a checkpoint journal on every pathRefused at load. Every dispatch path refuses checkpoint evidence
TG6ES256 registration from PEM and JWK. Off-curve, wrong-curve and private-key inputs. Duplicates and compromised materialValid keys stored compressed, the rest refused, list shows the algorithm
TG7An ES256 attestation of each terminal outcome, then a second distinct JWS restating itSettles ATTESTED like Ed25519. The restatement is a no-op
TG8JWS refusals: alg none, HS256 keyed with the public key, RS256, EdDSA. Unknown kid. kid naming an Ed25519 key. An Ed25519 envelope naming an ES256 key. Extra header fields. Missing, extra or wrong claims. Binding mismatch. Reported before the second the grant was issued in, while a report within that second settles, since the comparison is at one-second precision. Key registered after, retired before, or compromised. Malformed segments and oversize. An attestation in the flattened form a settlement stores, presented as a record or a journal, which the administrator's settlement still takesEach INVALID_RECORD, or INVALID_REQUEST at the parser, with nothing settled; the stored form is refused before any signature is checked
TG9Migration 0056 round tripExisting keys ED25519 with identical bytes. Downgrade refuses while any ES256 key or PROVIDER_VERIFIED row exists. check_runtime passes before and after
TG10Replay of a history with Ed25519 attested, ES256 attested, provider-verified and asserted settlements and an unreported grantEvery decision recomputes. Provenance is distinct per kind. Limitation lines appear. Bytes are deterministic. A mislabelled tier is refused
TG11The record page and the settlement control for each tierTier shown as inert text. The control accepts a record, an attestation or a journal
TG12The workflow contract with the real mock app as the vendorGrant, provider_command, mock journal, report, PROVIDER_VERIFIED. One mutation
TG13Lost vendor response: UNKNOWN, then a lookup, then the journalINDETERMINATE, then settled. The mock shows one mutation and no second dispatch
TG14Execution A's secret, journal or attestation presented on execution B. A re-grantINVALID_REPORT or INVALID_RECORD with nothing moved. A re-grant carries no secret
TG15The story fileParses. Credentials by name only. No origin, token or tenant id. Every request, report and vendor body validates against the gateway's and mock's parsers. The vendor body is grant.provider_command alone. The re-grant branch cannot reach the vendor action. No outcome field carries the secret or the signature. Each exit says what happened on its path: an accepted UNKNOWN report hands off to an administrator with VENDOR_OUTCOME_UNKNOWN, the act-window path never says the vendor was called, and a refused report names no tier

Tests live in tests/test_gate_evidence.py (TG1 to TG11, on real PostgreSQL), tests/test_gate_vendor_walk.py (TG12 to TG14, the same story's whole exchange against the real mock app as its vendor) and tests/test_tines_gate_story.py (TG15, the committed story file checked the way the Execute story is checked). The seed in src/execbound_harness/gate_demo.py, which seeded the synthetic Gate tenant of the 24 September 2026 live trial, is covered by tests/test_gate_demo.py rather than by a TG number of its own; the harness that held it behind a tunnel origin is not published. Unlike GC and AL, this group is not yet registered in ACCEPTANCE_PREFIXES in validation_evidence.py, so it does not appear in the validation manifest's per-group test-node mapping the way the other named groups do; wiring it in is unbuilt.

Tines Monitor instrumentation​

IDSetup/actionRequired result
TM1Regenerate the Monitor storyByte-identical to the committed integrations/tines/execbound-monitor.json
TM2The story fileCredentials and resources by name only: the monitoring source and origin, the lab vendor and its origin. No URL, UUID, token or webhook path or secret
TM3Every HTTP Request actionNo content_type; TO_JSON text with one explicit Content-Type: application/json; redirects disabled; failure events emitted; fail_on_status off. The action is never retried; the report is retried only on 429 and 5xx
TM4The result and heartbeat bodies, evaluated from the story's own formulas for vendor statuses 200, 204, 401, 503 and 0, then every report statusEach body passes the intake's parser with the story id as a string; outcome success, error or unknown by status; a re-run rebuilds identical text; a target the intake would refuse never reaches the action; the heartbeat is scheduled every five minutes and joins the report as one flow; only 200 and 202 reach Reported, and every other status reaches Reporting failed with auth_lost, conflict, unreachable or not_recorded; no exit carries a credential
TM5The result and heartbeat bodies Tines built in the live trial, posted as the story sends them to the intake-only origin on real PostgreSQL; then the result with the story id as a numberThe result recorded once, then 200 duplicate with the same observation; each heartbeat returns 202 with no observation and refreshes the source; the numeric story id refused with INVALID_EVENT

Tests live in tests/test_tines_monitor_story.py (TM1 to TM4) and tests/test_tines_monitor_captured.py (TM5). The live trial of 2026-09-26 is the platform evidence; its lab vendor stub and evidence snapshot are kept with that record.

Trusted context provisioning​

IDSetup/actionRequired result
CP1Inventory manifest with column-backed and row-backed facts and a provider_version for an existing resource, imported under an ADMIN actorRows carry the source, version and observation time; the resources row carries the stated provider version; resolution freezes exactly those values; context.imported is audited with the digest and counts and no value
CP2The same manifest imported again, and a later one with a new version label and identical content, while an approval is pendingNo content or version changes; observed_at advances only for the second; the pending approval still passes re-attestation
CP3A manifest that changes one row-backed factThat row's version changes and its siblings keep theirs; the pending approval fails re-attestation with STALE_AUTHORIZATION
CP4An observation earlier than the retained one, one 61 seconds in the future, and a reused version with different contentOBSERVATION_REGRESSION, FUTURE_OBSERVATION, VERSION_REUSED; nothing written; no audit event; 59 seconds ahead is accepted
CP5Unknown, derived and ambiguous fact names; out-of-domain, wrong-type and oversized values; an incident fact in an inventory manifestUNKNOWN_FACT, DERIVED_FACT, AMBIGUOUS_FACT, INVALID_VALUE; nothing written; a value must satisfy every contract that declares the fact
CP6Missing or wrong-kind source, writer outside allowed_writers, unknown account, --tenant differing from the manifest, a non-ADMIN or foreign actor, and a source that exists only in another tenantINVALID_SOURCE, INVALID_WRITER, INVALID_ACCOUNT, TENANT_MISMATCH, INVALID_ACTOR; no row and no audit event in either tenant
CP7An entry for a resource the registry does not holdSkipped and counted by default; the whole manifest refused with --strict (UNKNOWN_RESOURCE)
CP8Retracting a row-backed and a column-backed fact, then active: falseRow deleted, column nulled, resource deactivated; resolution fails with INVALID_CONTEXT for the missing facts and INVALID_TARGET for the inactive resource
CP9Incident manifest creating an OPEN CRITICAL incident for a development endpoint, then closing it, then relinking itendpoint.isolate executes once under the v1 bundle after the first import (the provider version untouched) and is denied after the second; INCIDENT_RELINKED refuses the relink; a retraction on an incident entry is INVALID_MANIFEST
CP10The harness asset and ticket exports through the adapter, plus unmapped state, priority and classBoth manifests import, decommission the second asset and gate the action on the derived incident identifier; the adapter refuses each unmapped export
CP11Source create and deactivate through the CLI; an import through a source whose labels the default allowlist permits and one whose extra label it does not; the runtime role against every table the importer writesSources audited with sorted labels; the first import resolves, the second fails resolution until a bundle admits the label; deactivation makes its facts fail resolution and a repeat is INVALID_SOURCE; refusals exit 2 without echoing values; check_runtime passes and the runtime role cannot INSERT, UPDATE or DELETE
CP12A manifest over 16 MiB, one with 10,001 entries, a duplicate entry, a name in both facts and retract, an empty entry, a naive timestamp, an unknown field and an incident entry in an inventory manifest; then a 10,000-entry manifestMANIFEST_TOO_LARGE or INVALID_MANIFEST before any database work; the large manifest imports in one transaction within the statement timeout

Tests live in tests/test_context_provisioning.py. CP12's 10,000-entry import takes the machine's timing lock and is marked timed, so a run that selects not timed leaves it out while CP12's bounds and its round trips still run: an import of a thousand entries must make exactly as many as an import of ten, which reads no clock. The full suite runs all three.

Credential administration pages​

IDSetup/actionRequired result
CA1ADMIN issues an agent credential for a new principal from the pagePrincipal and credential rows exist; the token is shown once under Cache-Control: no-store; a second GET of the list shows identifiers only; the token authenticates on /v1/me; principal.created and credential.issued carry the acting credential and no secret
CA2ADMIN revokes a credential; repeats it; tries an administrator credential and an unknown oneRevoked at once and the token no longer authenticates; the repeat, the administrator credential and the unknown one answer 409 with nothing changed; credential.revoked audited
CA3ADMIN issues an approver credential and assigns the approver to a target and action; the approver signs in with the new tokenAssignment listed; the pending approval appears on the approver's list; an agent principal, an unknown target and an unknown action are refused with 400
CA4ADMIN unassigns the approverThe pending approval disappears from the approver's list; a repeat answers 409; approval_scope.assigned and approval_scope.revoked audited
CA5Issue for an ADMIN principal, new:ADMIN, an unknown principal, a malformed principal, an out-of-range or zero lifetime, an extra field; the functions called directly with an ADMIN kind, an ADMIN principal, a 91-day lifetime or a stale clockEvery page attempt answers 400 with no secret; every function call raises its code; no principal or credential is written
CA6Approver session on the pages and their forms; anonymous; agent bearer403 for the approver and the bearer (the bearer refusal audited), 401 anonymous; nothing issued
CA7The functions with another tenant's setting, without a setting, with an approver or unknown actor, with another tenant's credential, an unknown target or an unknown actionINVALID_ACTOR, INVALID_TENANT, INVALID_CREDENTIAL, INVALID_TARGET, INVALID_ACTION; no row in either tenant; the other tenant's credential still authenticates
CA8Direct INSERT, UPDATE and DELETE by the runtime role on principals, credentials and approval_scopes; EXECUTE revoked on one function; INSERT granted on principalsPermission denied; check_runtime passes only with EXECUTE on every function and no table write privilege
CA9Migration round tripFunctions absent after downgrade and present after upgrade; the owner commands still create tenants and principals while downgraded
CA10Chromium at phone widthBoth pages pass the accessibility sweep; the secret field is read-only and the token is absent from the list afterwards; a declined confirmation keeps the credential, an accepted one revokes it; unassign asks first and lands when accepted

Tests live in tests/test_admin_pages.py (the definer functions and the grants), tests/test_console_api_access.py and tests/test_browser_console_directory.py.

People page​

The list and the person page for a tenant's humans, with deprovisioning. The console API's rows are held by tests/test_console_api_people.py, the pages by tests/test_browser_console_directory.py, and PP9 by tests/test_people_pages.py.

IDSetup/actionRequired result
PP1ADMIN opens the list, then the deactivated and the ADMIN filters, then a bad state and an unknown keyEvery human principal with counts; the deactivated filter empty; the kind filter hides the approver; 400 for the bad state and the unknown key; the page passes the secret check
PP2Add user with a blank name, then with a name and a sign-in addressThe blank name is refused naming the label field and nothing is made; then a new approver with the trimmed name, principal.labelled audited, and its page answers with that name and every section
PP3The person page for an approver, an ADMIN, an unknown id, an agent id and a malformed idEvery section for the approver; "owner tooling" and no deactivate or issue form for the ADMIN; 404 for the other three
PP4Set a label; set an 81-character oneThe label appears beside the prefix on the credentials and approvers pages and is audited; the long one is refused without being echoed
PP5Issue an approver a credential through the console API, then revoke it; issue one to an administrator; open the person's pageShown once under Cache-Control: no-store, authenticates as that person, absent from the page's data afterwards; revoked and refused, credential.revoked audited; the administrator is refused INVALID_PRINCIPAL; the person's page offers no Issue button, because people sign in with their own account
PP6End all sessions on an approver with two sessions; the same on the acting ADMINBoth sessions of the approver refused at their next request, the ADMIN's session intact, one human_session.revoked with reason ADMIN per row; the ADMIN's own request is 400
PP7Deactivate with a blank reason, then with one; repeat; reactivate400; then the credential no longer authenticates and the session is 401 in the same change, principal.deactivated carries the reason and the counts, the person leaves the default list and shows under the deactivated filter; the repeat is 409; reactivation restores active, clears deactivated_at, keeps the scopes and issues nothing
PP8The functions with an ADMIN target, the actor, an approver actor, a blank reason, an unknown principal, a long label, an active target for reactivation and another tenant's fence; an approver session on every routeINVALID_PRINCIPAL, INVALID_ACTOR, INVALID_REASON, INVALID_LABEL, INVALID_STATE, INVALID_TENANT or INVALID_ACTOR; 403 or 400 for the approver session
PP9Head, catalog and round trip0036_people; the three functions in FUNCTIONS; check_runtime passes; downgrade to 0035_session_label and back
PP10Chromium at phone widthBoth pages pass the audit and the contrast probe in both schemes; End all sessions and Deactivate decline when the dialog is dismissed and land when accepted; the deactivated person's page then offers Reactivate

Tests live in tests/test_people_pages.py (the migration and the catalog), tests/test_console_api_people.py, tests/test_browser_console_directory.py and test_route_authority.py.

People page: history​

The person page's history: a person's decisions, sign-ins and administrative events.

IDSetup/actionRequired result
PH1An approver approves one request and denies another, signs in, and has every scope unassigned; an ADMIN opens their pageDecisions newest first, the denial then the approval, each with its approval prefix and action, still shown after the scopes went; one sign-in with its device and "active"; no administrative events; the page passes the secret check
PH2An ADMIN labels the approver, ends their session, changes the mode and signs out their own other devices, then opens their own pageAdministrative events newest first in words: the mode change to OBSERVE, one "Ended a session of" with the approver's new label and prefix, the label change and the bundle's activation; no reason text, no entry for their own devices, no decisions; their sign-ins include one signed out
PH3A person with no history; then twenty-five sign-ins"No decision yet." and "No sign-in yet."; then exactly twenty rows, the last sign-in first and the first five absent
PH4An approver labelled with markup is deactivated with a reason containing markup; the ADMIN opens their own pageThe deactivation is listed with the label escaped as text; the reason appears nowhere; the map of kinds covers policy, credentials, scopes, principals, bindings, sessions and the tenant and nothing else
PH5Chromium at phone width: the approver's page with decisions and a sign-in, and the ADMIN's pageBoth pass the audit and the contrast probe in both schemes; the decisions, sign-ins and administrative events tables are found by their captions with their rows

Tests live in tests/test_people_history.py and tests/test_browser_console_directory.py.

Agents page​

The list and the agent page for a tenant's AGENT principals, the governed half of the Agents page (tests/test_console_api_agents.py).

IDSetup/actionRequired result
AG1ADMIN opens the list; the month filters before and after the agent's first request; the deactivated filter; bad filter values, an unknown key and malformed cursorsOnly AGENT principals and the month figure with its definition; the agent under "Made no request" until it makes one and under "Made a request" afterwards; the deactivated filter empty; 400 for each bad value; the page passes the secret check
AG2Fifty-five labelled agents beside the fixture's unlabelled oneFifty on the first page in label order, the rest on the next with no overlap and the unlabelled agent last, and no further link
AG3Add agent, choosing a host and then a name and Space, with a blank name, a name of 81 characters, then a nameThe blank and the long name are refused naming the label field; then an AGENT principal with the trimmed name, principal.labelled audited, and its page answers with its sections
AG4The agent page; an unknown, an approver's, an ADMIN's and a malformed id; a label; a well-formed label form posted to an approver's idEvery section; 404 for the four ids; the trimmed label shown and audited; 404 for the approver's id with the approver's label unchanged
AG5Issue a credential from the agent page; revoke another principal's credential through this agent's route; revoke the agent's ownShown once under Cache-Control: no-store with a link back to the agent, authenticates as the agent, absent from the page afterwards; 404; revoked, refused and audited
AG6The agent page before any request; after two executed isolations and one pending request, with one live and one expired run; then with the executions moved past the evidence windowThe governed action inferred from the active bundle; then verified with the evidence's expiry, two executed and one pending row in recent activity, three requests this month, the live run only and the link to Activity for the agent; then no verified row
AG7Three executed and one open isolation by one agent and two executed by another; then the confirmed rows moved twenty minutes backThe principal budget reads 4 of 10 and the tenant total 6 of 20 with the store's own usage agreeing, and the other agent 2 of 10; then 4 of 10 and 1 of 20, again as the store counts
AG8Requests at the first and last instants of the month and the first instant of the next; another agent's in the previous monthThis month counts two for the first agent and nothing for the other, the next month one, the previous month the other agent's one; the list reads 01 and the agent page 2; December rolls into January
AG9Deactivate with a blank reason, then with one; repeat; reactivate; post deactivation to the ADMIN's and the approver's ids; an approver session on every route400; then the issued credential no longer authenticates, principal.deactivated carries the reason, the revoked credentials and no session, and the agent leaves the default list for the deactivated one; 409 on repeat; reactivation restores it with no live credential; 404 for both ids; 403 or 400 for the approver
AG10Chromium at phone widthBoth pages pass the audit and the contrast probe in both schemes; Deactivate declines when the dialog is dismissed and lands when accepted; reactivation asks first and lands when accepted

Tests live in tests/test_console_api_agents.py, tests/test_browser_console_directory.py and test_route_authority.py.

Agents page: bindings​

The Agents page's discovered agents, bindings and Govern this agent (tests/test_agents_bindings.py).

IDSetup/actionRequired result
AB1The two functions with an ADMIN, an approver, an unknown and a deactivated principal, an unknown and a gone agent, an approver as actor, another tenant's fence, each side already bound, a blank reason and an unknown binding; the runtime role updating the link or inserting a bindingINVALID_PRINCIPAL, INVALID_AGENT, INVALID_ACTOR, INVALID_TENANT or INVALID_ACTOR, INVALID_STATE and INVALID_REASON as each case names; a bind sets the link and an unbind clears it with who and why; the pair binds again with the history kept; permission denied for the runtime role
AB2link-agent with an ADMIN, with an agent principal, again, and with another principal; unlink-agentPRINCIPAL_UNAVAILABLE; one binding by the acting ADMIN with agent.bound; nothing new; LINK_CONFLICT; the binding withdrawn with the reason "withdrawn with unlink-agent"
AB3One bound pair and two discovered-only agents under a detection profile; each population, source and state filter; bad filter valuesThe bound pair as one row under its principal and the others under their agent ids; each filter narrows to its rows; a gone agent leaves the default list and shows under gone; 400
AB4A discovered-only page; the id of a bound agent; the bound principal's page; an unknown idThe source's facts, Govern this agent and a bind form offering the unbound agent principals, and no governed section; the principal's page, at the principal's address; both halves with Unbind; 404
AB5Bind from the governed side and from the discovered side; bind a principal already bound; a malformed targetThe principal's detail and agent.bound for each pair; 409 with the notice; 400
AB6An executed isolation derived as verified reach; Unbind with a blank reason, then with one; unbind againThe verified row names the binding; 400; then the link cleared, the ExecBound row marked gone at once, agent.unbound with the reason, and the agent its own row again; 409
AB7Govern this agent on an agent whose display name is longer than a labelShown once under Cache-Control: no-store; an AGENT credential; the label is the name cut to 80 characters; the binding and the four events name the new principal; what to do next holds the install and MCP lines and never the secret; the agent's id answers with the new principal's page; a second attempt issues nothing
AB8The agent leaves its source between the page load and Govern this agent409 with the notice, and no principal, credential, binding or audit event added
AB9Deactivate a bound principal; open a discovered agent's bind form; an approver session on bind, govern and unbindThe binding stays and the source's facts say the governed principal is deactivated; the principal is not offered; 400 or 403
AB10Chromium at phone widthThe discovered and bound pages pass the audit and the contrast probe in both schemes; Govern this agent shows the key once in a dialog with what to do next, then lands on the new principal's page; Unbind declines when the dialog is dismissed and lands when accepted

Tests live in tests/test_agents_bindings.py, tests/test_console_api_agents.py, tests/test_browser_console_directory.py and test_route_authority.py.

Agents page: tenant line​

The Agents page's tenant line per source (tests/test_agents_tenant_line.py).

IDSetup/actionRequired result
AT1A tenant with no monitoring connectionThe line says no connection lists agents and links to Monitoring's connections page, with no zeros; the governed side counts the active agent principal and no binding; the page passes the secret check
AT2Three agents collected through the fake Graph API under a detection profile; then one boundOne source row listing three; the listed, consequential and not-established totals equal Monitoring's enumerated, with-reach and not-established figures; then "1 of 3" bound on the row and one bound principal on the governed side
AT3One agent leaves its source; then the only agent with grants has its claims pass their validityListed and not established fall by one and still equal Monitoring's; then consequential reach is none, as Monitoring counts it, and the row reads "0 of 2"
AT4Chromium at phone width with a sourceThe list with its tenant line passes the audit and the contrast probe in both schemes

Tests live in tests/test_agents_tenant_line.py and tests/test_browser_console_directory.py.

Tines discovery and collection​

IDSetup/actionRequired result
TD1Register a connection and probe with every capability listed by the fake APIFive capabilities classified with probe times; health COLLECTING; no inventory and no observation written by a probe
TD2Inventory sync across three pages each of stories, actions and credentialsAllowlisted metadata only; options, credential values, descriptions, emails and addresses absent from every table, snapshot and page; counts match the fixture; an unrecognized action type is outbound = null, never false
TD3Audit pull over four pages with the page budget at twoTwo pages accepted with their evaluations pending; the cursor on the last accepted record; BACKLOG; the next run continues from the overlap and accepts the remainder without duplicates
TD4The same records served again after the cursor is rewound; then one record reused with different contentNo duplicate observations; the reused identifier records source-event-integrity.v1, marks the conflict and leaves the first content in place
TD5A failure injected between writing a page and advancing the cursorNothing written and the cursor untouched; the next run stores each record exactly once
TD6429 with Retry-After, 401 and 403 on the audit endpoint; 404 on credentials; three consecutive rate-limited runs then a 403RATE_LIMITED with the retry value, AUTH_LOST, unsupported for credentials with the others unaffected; exactly one audit request per run; one collection-health.v1 finding per episode
TD6bA tenant whose plan excludes the audit feature (422 on that endpoint)The audit and AI capabilities classify unsupported, not unknown; stories and actions stay available; inventory still collects and the run completes; the vendor's message body is never retained
TD7A cursor older than the retention floorRETENTION_GAP with a health finding; the connection snapshot shows it
TD8Configuration changes on a registered story, on an unregistered story, a credential change, a tenant change and an unlisted operation nameMATCH with one monitored-path-change.v1 finding each for the registered story, its action and the credential; NO_MATCH for the unregistered story and the tenant change; INSUFFICIENT_EVIDENCE for the unlisted name
TD9A discovered story with outbound actions and no source; a source registered; the source revoked; the story's connection revoked beside an open gap; a story whose live source replaced an earlier one, revoked or expired, that was heard from more recently and sorts after it; a story holding two live sources, registered before a second unrevoked source was refusedGap finding, then none while it reports, then a new episode after revocation; the other stories classify as instrumented, no-outbound, disabled and coverage-unknown; the replacement covers the story before its first heartbeat and on every later pass, and no further gap finding is raised; of two live sources coverage reads the one heard from last, then the newest, so a story reporting through either is instrumented, not stale; Inventory names only an unrevoked source, so a revoked one's story shows its gap with none, and counts a story's actions once whatever sources it has had; it names one in a Space the reader sees before one elsewhere and, among those, one whose token can report before an expired one, and says which it named, so a source registered since the last inventory pass, beside a gap that pass has not yet closed, reads as able to report, and says whether the story's connection was revoked, which no pass reassesses again, so its gap stays open; a source elsewhere is its identifier alone, never said to have expired, and which of several it names does not follow their tokens
TD10Enhanced AI records with a mapped and an unmapped tool nameThe mapped tool run matches under the profile version; the unmapped one stays INSUFFICIENT_EVIDENCE; the model run keeps the model identifier and token counts and no prompt or completion text
TD11Two tenants collecting from fixtures with the same identifiers; then a response claiming another platform tenantNo cross-tenant rows; every foreign record quarantined with one health finding and nothing stored
TD12Migration round trip, check_runtime, and the pages in Chromium at phone widthBoth tables forced-RLS with no runtime DELETE or TRUNCATE; downgrade refuses while collected evidence is retained; the Inventory and Connections pages pass the accessibility sweep, show every coverage class and the collected evidence label, and carry no fixture secret

Tests live in tests/test_tines_collection.py, tests/test_console_api_monitoring.py and tests/test_browser_console_monitor.py.

Scout, first source: Entra Agent ID​

IDSetup/actionRequired result
SR1Register an entra_agent_id connection and probe every capabilityFive capabilities classified with the moment each was established; a Tines connection beside it is unaffected; a probe writes no agent and no grant
SR2Enumerate three pages of agent identities and classic service principalsAllowlisted metadata only; no mail address, human name, credential value, hint or token in any table, snapshot, log line or page; an agent listed in both collections is one agent and keeps the directory's own class
SR3An agent identity carrying properties the vendor has not publishedEvery undocumented property dropped and counted; nothing raw stored or logged; agentIdentity is an open type and the parser takes fields rather than removing them
SR4An agent holding a directory role the catalog maps to a consequential actionOne inferred reach row on the role path with mode unknown; one ungoverned-reach.v1 finding naming the agent
SR5Register an operation mapping, an executor and a principal link for that actionA second reach row on the ExecBound path, native; the grant row unchanged and still live; the finding stays open
SR6The grant is gone at the next collectionThe grant and its reach rows marked gone and kept, never deleted; the episode closes; the finding remains for a person to read
SR7An ADMIN records an acceptance insteadThe episode closes with the acceptance; the reach row stays live and renders as accepted with its reason; an expired acceptance opens a new episode
SR8A blueprint declaring allAllowed roles for a resource applicationInherited grant rows whose path is the blueprint, read once however many agents share it; the declaration resolves to no action, so it is counted as unexplained rather than inferred
SR9A classic service principal holding a blocked-for-agents permission and an agent-shaped tagClass service_principal; the tag recorded and shown as evidence and never a promotion; owners read where sponsors do not apply
SR10An agent with no sponsor, and one whose sponsor read is refusedsponsorless-agent.v1 for the first; INSUFFICIENT_EVIDENCE counted separately for the second, and the page never shows a refused read as nobody
SR11An observation of the agent acting, then a settled execution under its linked principal; three actions each observed and settled, derived a page of two at a timeobserved then verified, on their own paths and modes, beside the inferred rows; deriving twice changes nothing; evidence older than its currency is not revived; an unlinked agent gets no verified row however many executions settle; every action's verified and observed row derived, however many pages it takes
SR12Two tenants reading directories that serve the same object identifiers; a directory that disagrees with the registrationNo cross-tenant row; the mismatched directory refused with DIRECTORY_MISMATCH and nothing stored; a directory that will not answer leaves it unverified rather than assumed
SR13Token failure, 401, 403 on one path, 429 with Retry-After, an oversized body, and a continuation that leaves the pinned origin or the requested pathAUTH_LOST before any Graph request; forbidden for one capability with the others unaffected; the retry value recorded with no retry in the run; the body refused before parsing; four shapes of redirected continuation refused
SR14Migration round trip, check_runtime, and both pages in Chromium at desktop and phone widthFour tables forced-RLS with no runtime DELETE; both downgrades refuse while agent evidence or findings are retained; the pages pass the accessibility sweep, state the denominator in words, name the two coverage holes, render a lapsed claim as unknown with the moment it lapsed, escape a hostile display name and make no external request
SR15A directory's first complete collection, then later ones; a first collection that could not read the agent identities or the service principals, throttled or refused; a directory none of whose collections reads both; an episode that ends while it waits for the summary; a later collection that fails, gets no link it can trust or could not read both; a directory listing more principals than a run reads, or served in pages too short for the run to reach its end; connections that had synchronized before the upgrade, whatever their latest collection's outcome or probe, holding the service principals they read or never having read themThe baseline set once, by a collection that read both principal collections; one initial-inventory.v1 finding that names the connection alone, carries its counts exactly and queues the collection's only delivery, the ungoverned-reach.v1 and sponsorless-agent.v1 episodes it opens recorded without one each, and none of the three new-actor rules; a collection that read one collection takes no baseline, summary or link, asks for no link and records its outcome like any collection, what the connection's first run opens waits undelivered for the summary unless the registration is refused the collection outright, and waits no longer: a later collection that cannot send the summary delivers what waited and what it opens, once each, and the collection that sends it counts what waited and still holds and delivers what waited and ended, and the principals the collection that reads both stores are not new; a directory past the bound in either collection or both, whatever its page size, and one under the bound whose pages run out before it does, refused whole with AGENT_CAPACITY, with no principal, baseline or link written, while one whose last page the run reaches is read whole; a delta link taken before the read, on the pinned read, only by a collection that reads both and kept only when it completes, from an initial round where Graph refuses latest; a later collection that fails, gets no link it can trust or could not read both leaves the stored link and its moment as they were; the upgrade baselines at its own moment every connection that had synchronized and holds a classic service principal, gone or not, whether its latest collection completed, failed, was interrupted or could not read a principal collection, including as an owner without row-security bypass, leaves one that never read the service principals or never synchronized to its first collection that reads both, and raises nothing retroactively; the downgrade refuses while a finding of the four rules is retained, including for an owner without row-security bypass; the runtime updates the seven new columns, inserts none of the connection's and writes no part of the lease mark
SR16A principal with consequential reach and no governed path appears after the baseline, by a delta pass or a full collection; a new-agent.v1 finding retained from an earlier releaseOne new-actor.v1 naming it and queued for delivery, its ungoverned-reach.v1 episode recorded beside it without a delivery of its own, never on the first collection and never twice; its episode closes when the path goes and never reopens; a principal that gains reach after its first week is reported by ungoverned-reach.v1 alone; new-agent.v1 is no longer raised, and one retained from before survives the upgrade and the downgrade, is served over HTTP with its agent and is filed under its agent in the findings list
SR17A delta round removes a principal, restores one with only some of its properties, lists one beside principals it does not list, and lists new principals whose entries state their class, state it once of two entries, or do not state it, one listed again with only what changed and one removed and restored within the roundThe removed one marked gone with its grants and paths, its episodes closed and nothing deleted; the restored one keeps its class, blueprint, name and sponsors; the grants and paths of the principals the round did not list are untouched; a new principal stored with the class its entries state and read for sponsors when an agent identity, one whose entry states none left for the full collection, which stores it as the agent identity it is; a principal's entries laid one over the other, so the vendor application listed again keeps its name, state, owning organization and AI publisher, raises new-ai-consent.v1 and no sponsorless-agent.v1, and the restored one keeps the class and owning organization its first entry stated; a full collection keeps a stored class the directory contradicts and completes
SR18A delta link or next link off the origin, the path, the scheme or the port, or with no delta token, from Graph or in the database; a 400, a 410 or an expired token; a round past its bounds, or one that would carry the directory past the principal bound; a page of the round that is not JSON, whose value is not a list or that carries both continuation links or neither; any other failureA link from Graph never taken or followed and the connection's link dropped; the database refuses a stored link off the pinned read, over 4,096 characters or on a connection with no baseline, and one that passes it but not the collector's check is dropped and never sent; a resync drops the link and leaves the connection healthy until the next full collection takes a new one; a round past 20 pages or 1,000 changes, and one that would leave the directory past 1,000 principals, writes nothing and drops the link, each with its code, and the next full collection refuses that directory with AGENT_CAPACITY; the rules refuse a connection past the bound rather than evaluate part of it; any other refusal, of the round or of what its principals hold, a round page that cannot be read among them (MALFORMED), keeps the link and writes nothing, and the next pass reads the same round
SR19collect-due between full collections, with a run holding the connection, a waiting collection request, a failed last run and a full collection due; a delta pass and a full collection each stopped while holding the lease; a delta pass refused by Graph; a delta pass whose key file is not the registered key or not a key file, or whose collector holds no platform app or another oneA delta pass inside its own lease, counted delta, moving neither last_run_at, last_sync_at nor the next due time; no delta claim while a run holds the connection, a request waits, the last run failed or a full collection is due, the database's own claim refusing a waiting request and leaving it; the request answered by a full collection; a lost or missing lease refused; a stopped delta pass's lease taken back by the next delta pass or full collection with nothing recorded, a stopped full collection recorded INTERRUPTED by a delta claim that then takes nothing; a refused pass counted delta_failed with the connection's health unchanged; a pass whose credential is refused sends nothing and records nothing, not the outcome, last_run_at, the health or the link, and the next full collection records the refusal
SR20A principal from a catalogued AI publisher appears; actors observed taking consequential actions after the baseline, before it, while linked to a governed route for the action, after one appears and after leaving the directoryOne new-ai-consent.v1, closed when the consent is removed; the catalog names each entry's source and keeps only its key; one first-consequential-action.v1 per actor, however many actors sort before it, carrying the observation it was raised on, never for an actor that acted before the baseline, raised for a linked actor that holds a governed route for the action, left open when a governed path appears, closed only when no qualifying observation is current or the actor is gone, and never reopened; without a sensitive-action list, insufficient evidence
SR21Directory audit entries an application initiated, one for each mapped activity, one change logged twice under one correlation id, the same assertion under one correlation id logged twenty milliseconds apart either side of a whole ten seconds, ten seconds apart, ten seconds and a millisecond apart and a day apart, every field the parser reads holding a value of another type, an unhashable one, a moment UTC cannot hold, one too long or an identifier ending in a line break, and a read meeting two such entries or one whose target, actor or entry id ends in a line break, a refused attempt, its successful retry and another actor's entry under one correlation id, an entry served again under its own id asserting another result or another actor, application activities the map does not cover or cannot read, entries a person initiated or an application initiated for a signed-in person, one naming no service principal, a refused attempt, and fields naming people, addresses, reasons and the application; the activity map built with an action outside the catalog; migration round trip and the runtime's privilegesOne entra_audit observation per mapped entry naming the actor's service principal, the action, the target's object id, the entry id and its moment, and one for the twice-logged change; one for the pair within ten seconds and two, each at its own moment, for the pair further apart; every entry the parser cannot read classified and none raising, an entry it maps holding only what the columns' checks accept, the read counting them and its run recording its outcome; the attempt, the retry and the other actor's entry kept as three, with no integrity finding, and the retry raising the rule; the entry served again an observation of its own beside the first, with no integrity finding, its success raising the rule; unmapped and unreadable entries counted and never stored, a person's ignored and the unattributed one counted; the attempt kept with outcome error; no name, principal name, address, reason, detail or application id in any row, result, scheduled command's output or line any logger writes, as the jobs service reads and evaluates the log, its collect-due reporting the connection collected and storing both observations itself, and as an operator's run then reads copies of them; the map refusing an action the catalog does not hold, a key or source it cannot explain, or two entries for one activity it cannot tell apart; the migration admitting the kind only with an action, an outcome and a GUID target, refusing a target on any other collected kind, keeping the activity baseline to Entra connections, refusing its downgrade while an audit observation is retained, also for an owner without row-security bypass, and the runtime updating and never inserting the baseline
SR22The audit read on a first collection and a later one; a next link off the origin, the path, the scheme or the port, or whose port or host cannot be read; a log longer than a run's pages; a log busy past the end of every read; more entries inside one second than a run reads; a read repeated inside the overlap; entries out of time order; a registration refused the audit log; a read Graph throttles, with a Retry-After, or refuses; an entry stamped two days ahead of the read, read again a day and a minute ahead and then a day ahead; a read throttled at its second page after the first reached an entry inside the overlap, then an entry Graph published late; the host's clock set back; an earlier cursor handed to the store; a delta pass that reads the log; reads that stay behind or refused for a day, caught up, then behind again; a read refused before the probe recorded the refusal, then skipped as refused, then granted over a log longer than a read takes; a cursor older than thirty days, read twice refused and then caught up; collect-due meeting a refused read and one that has not caught upCore Directory entries asked for from the cursor, oldest first, in pages of 100, the first read looking back thirty days; the cursor left at the read's moment less thirty minutes, to the second, after a read that caught up, at the second of the last entry read after a backlog, and never moved back; the busy log caught up with each run, its activity baseline the moment of the first such read, and another actor's action read after it raising the rule; the read inside one second left at its last entry to the microsecond and reading on until it reaches the log's end; a next link off the pinned read never followed, the page it came with kept and the cursor stopped there; at most four pages a run, the next run continuing from the cursor, and no activity baseline until a read catches up; a repeated read recognised with no integrity finding; an out-of-order page refused whole; a refused registration shown forbidden, never read by a full collection or a delta pass, still collected and not reported complete; a read refused at its first page keeping the cursor, the run's outcome, health and schedule, a delta pass leaving the run's record, when it is next due and whether it is reported as they were and a full collection recording no last refusal and no Retry-After, reporting and due a whole interval later, as for a page out of order, a next link off the pinned read and a read refused for a day; the entry two days ahead counted as dropped and kept by no read until the one it is a day ahead of, at the moment Graph stamped, and flagged by the clock-skew rule; the read throttled part way, with a Retry-After, leaving the run's record and schedule as they were and the cursor at its moment less thirty minutes rather than at the entry it kept, and the late entry read next; the cursor kept when the clock goes back, the read never asking the store to move it back, and the store keeping an earlier cursor from it whatever it is handed; a delta pass's read moving none of them; a day behind or refused raising collection-health.v1 once an episode, delivered, with the run's outcome, the health state and the last refusal unchanged, and the next episode raising its own; the skipped read ending the refused read's episode and the first read after the grant beginning its own, with nothing raised; the old cursor raising the retention-gap finding once for the episode, through both refused reads and the one that catches up; the refusal counted audit_failed and the backlog audit_backlog, in the report and on the log line
SR23An audit observation after both baselines, then process; observations read long after they happened, and one ahead of its receipt; observations found by a connection's first complete audit read, then the same actor and another acting again; a first read still in backlog after the directory's baseline, then caught up, then another actor acting; an entry Graph publishes only after the read that sets the activity baseline, stamped before it, after a read that reached the log's end and after one that read past its overlap through a busy log, with and without a sensitive-action list; an entry stamped before a connection's first collection that Graph publishes late, then its actor and another acting; the host's clock set back after the activity baseline, and between a backlog read and the read that catches up; no sensitive-action list, with an actor found by the first read, a refused attempt, ExecBound's own execution and then an action; an observation matching the one settled Graph execution of its action on its target, inside its window and at either edge of its ten-minute allowance, and observations missing it by target, action, a second past either edge, provider or state, sharing it with a second observation, or matching a second execution too; an entry naming its target in upper case, the execution's frozen id in either case; executions settled in the first read's look-back, two days and a month back, or between the directory's baseline and a first read that waited, then their executor acting outside ExecBound two days later or within the hour; a connection revoked after its settled entry and its directory connected again, then the executor acting outside ExecBound; the entry one settled execution matches, then the same action on the same target under the same correlation id two hours later; Home's board over that entry, a refused attempt and another actor's action, alone and beside a second entry sharing the execution; a back-fill larger than an evaluation's budget, then a story's reported action; a refused attempt, then a success; an entry stamped two weeks before the calendar's end after the same actor's action on another target, then process, and an observation at that moment written by the store, then process; two actors' two actions each, derived a page of two at a timefirst-consequential-action.v1 raised once with the observation and observed reach derived; no finding of an observation's own and no clock skew for an entry behind its receipt, while one ahead of it still raises it; nothing raised for what the first complete read found or the same actor's later action, the other actor raised; nothing raised from the backlog or once it caught up, and the other actor raised; the late entry raising the rule, and counted as insufficient evidence without a list; the entry from before the directory's baseline the habit, its actor's next action raising nothing and the other actor raised; a later read's entry received after the baseline and raising the rule, and the baseline no earlier than what the backlog read stored, raising nothing; none counted as insufficient evidence until the action; the matched observation left out of the rule and still deriving observed reach, every other one reported, both of a pair sharing one execution reported, and the one two executions match reported; the upper-case entry stored by its object id in lower case and left out; nothing raised for the settled executions and the executor's action outside ExecBound raised, however old they are; the two connections' copies of the settled entry left out and not drawn on Home's board, and the executor's later action raised on the new connection; the later action under the reused correlation id an observation of its own, recognised when read again, raising the rule and keeping observed reach current; the board drawing the other actor's action and neither the entry the execution accounts for nor the refused attempt, and both entries that share the execution; the reported action evaluated, and raised, by the first pass, the back-fill evaluated beside it; the refused attempt deriving no reach and raising nothing, and the later success raising the rule; the distant entry counted as dropped and the pass raising the rule for the other action, and the stored observation's reach current for thirty days from the pass, the pass completing; all four actor and action pairs' observed reach derived
SR24A month passing over a directory's audit observations: an actor's habit found by the first read, a refused attempt, another actor's first action that a finding cites and its repeat, a current action, an unevaluated observation, another workspace's habit; a baseline actor and a new one acting a month later; an old observation and a current one that one execution accounts for, the execution settled a month after its dispatch, the current one read before the purge and after it; an old observation an unsettled execution could account for, the execution then settling and another actor acting on its target; a baseline actor whose earliest baseline observation an unsettled execution could account for, the execution then settling; two old observations an execution that settled more than a month ago accounts for, one a baseline actor's earliest; two such observations, a stranger's and a baseline actor's only baseline observation, with an execution not yet settled dispatched between them; a read that comes while a purge batch is between its choice and its delete; a revoked connection; more to remove than one pass may; a pass whose second connection's batch fails after the first's committed, by a statement timeout or the workspace deactivated; a full batch handed to the function; three Entra connections, two of them revoked, with one batch a pass, then with batches of one; a connection a collection holds while process runs; a purge that fails in an operator's process and in the scheduled pass with --deliver; in both, a delivery that fails, by its routing or a finding that cannot be rendered, and an evaluation that fails, at its first step or its last; the function called with current, unevaluated, cited, unknown, another kind's and another workspace's observations, a month and a minute old, another workspace's connection, a Tines connection, no list, 1,001 ids, no workspace and an inactive one, and all of it again under an owner that does not bypass row security; a database session whose time zone's clocks went forward within the thirty days, with observations 719 and a half and 720 and a half hours old and an older one that an execution settled 719 hours and 55 minutes ago could account for; the runtime's privileges; at the observation bound, one actor's repeats with another's first action and its own first action of another kind; ExecBound's executor's second execution, its action outside ExecBound and that action's repeat; another actor acting on an execution's target as it runs, before and after the executor's own entry, a repeat of the executor's action outside ExecBound; an execution's own entry, its actor's repeat, a principal's or an actor's not yet inventoried, or by an actor not yet inventoried past the inventory's limit, and another actor beside it read only by the next read; the same two entries for an execution not yet settled when the read comes, the execution then settling; the executor's entry for an execution that a second, not yet settled, could also account for, and its action outside ExecBound in the same read, the first execution settled or settling only after the read; the executor's entry for an execution not yet settled, alone or beside a second that never settles, kept by an earlier read at the bound or stored under the bound earlier in the same read, the executor a principal or an actor not yet inventoried, and its action outside ExecBound an hour later, the execution then settling; an actor's entry held beside another actor's, both of which a settled execution accounts for beside a second not yet settled that could account for the actor's alone, or which an execution not yet settled could account for, and the actor's repeat an hour later, the execution then settling; three entries one execution could account for, then a fourth; a refused attempt, one actor's four actions and an entry older than thirty days; a principal's repeats twelve, fifteen, sixteen and nineteen days after its newest current observation, and the same repeats when the newest is ExecBound's own execution's; a principal's daily habit over a month; a principal created since the last full collection acting at the bound before the next collection inventories it; actors not yet inventoried with room in the inventory's limit for one, across two reads, the other's earlier entry stored before the episode, and a repeat of the counted one nineteen days after its first; a first read past the bound, a read at it, a purge and reads under it and at it again; a connection each purge brings just under the bound and the next read fills again, then a tenth under it; collect-due meeting the bound; the migration up and downThe old uncited observations removed by process and nothing else: what a finding cites and every finding byte for byte, the current and unevaluated ones, each baseline principal's earliest baseline observation of each action and every other workspace's kept, and a second pass removing nothing; the baseline actor raising nothing and the new one raising first-consequential-action.v1, the habit news once its kept observations are removed by hand; both observations the execution accounts for kept and the current one still reported, either way, its episode closing once the old one is removed by hand; the old observation kept while the execution is unsettled and the other actor raised once it settles; the earliest baseline observation no unsettled execution could account for kept beside it, and the actor still the habit once the execution settles; both old observations kept and the baseline actor's next action raising nothing, the habit news once the other is removed by hand, in both cases; the read waiting on the batch's lock until it commits, and the action it brings beside the execution raised; the revoked connection purged; two a pass, the rest on the passes after, an operator's process purging too, each pass that removes anything writing one monitor.audit_purged line with the workspace and its count, and the pass that removes nothing writing none; the first connection's old repeats removed and the line written with that count as the pass fails, in either case; the full batch accepted and its one old observation removed; every connection's old repeats removed in one pass, then each connection's oldest and the batch left over the oldest connection's, the others' second left to the next pass; the held connection passed over without a wait, the other purged and the queued findings delivered, and the held one purged by the next pass; a finding sent before the purge is tried and fails, on both paths; the purge run once the delivery is tried and the pass failing with the delivery's code, the finding that cannot be rendered left unleased and unattempted; nothing purged after an evaluation that fails, and the pass failing with its code; the function removing only the evaluated, uncited, month-old entra_audit observation of the named Entra connection in the caller's workspace, nothing of another kind, refusing INVALID_STATE, INVALID_LIMIT or INVALID_TENANT, and doing the same under that owner, each refusal included; the thirty days 720 hours in that time zone too, the observation 719 and a half hours old kept by the store's choice and the function alike, the one the execution could account for kept by the store's choice, and the other removed; the runtime holding EXECUTE and no DELETE; the repeats dropped, both first actions kept, the read complete with no error and both actors raised; the second execution's entry kept as its own, the action outside ExecBound kept and raised and its repeat dropped; both entries kept and the other actor raised, in either order; the execution's own entry kept and the other actor's kept by the next read and raised, in every case; both entries kept and the other actor raised once the execution settles, in every case; both of the executor's entries kept and its action outside ExecBound raised, in either case; the action outside ExecBound kept and raised once the execution settles, and once the next collection inventories an actor not yet inventoried, in every case; the repeat dropped and both actors raised from the entries held, in either case; two of the execution's entries kept and the third and fourth dropped; one of the actor's actions kept and the rest dropped; only the sixteen-day repeat kept and observed reach current to thirty days after it, or none kept and reach current to thirty days after ExecBound's own; the first day and the seventeenth kept and nothing else; its first of each action kept, its repeat dropped and first-consequential-action.v1 raised from the first once it is inventoried; the counted actor's first actions kept in both reads, the other's dropped in both, the principal's first kept and the counted actor's repeat dropped; the cursor, the activity baseline and the episode set, the run's record unchanged, collection-health.v1 raised once under its new title for the episode, ended by the read after the purge, and raised again for the next; one episode and one finding while the connection hovers at the bound, ended only a tenth under it, and the next episode raising its own; audit_bounded and no audit_failed, in the report and on the log line; the function, the index and the column added and removed, the function a definer on a fixed search path for the runtime alone, the column the runtime's to update and an Entra connection's alone
SR25A principal whose application the AI publisher catalog names, an agent identity with a blueprint and a classic principal with neither; the first removed and restored; a consent first seen by a delta pass; migration 0098's round trip with driver rows or recorded egress retained, as a superuser and as an owner that does not bypass row security; the runtime's privileges on the table and every new columnOne declared row each for the first two, naming publisher:anthropic (with the catalog's version) and the blueprint's application id, and none for the third, which is unattributed; the rows gone with their principal and the publisher's back with it, never deleted; the delta pass's consent declared at once; the table under forced row security with no runtime DELETE or TRUNCATE, the downgrade refusing SCOUT_DRIVERS_RETAINED while a row or an address is retained, by either owner, and otherwise round-tripping with row security forced again
SR26Service principal sign-ins from Anthropic's, Make's and Workato's published egress, from an address nobody publishes, a private one, one n8n publishes but says changes, and a refused sign-in from a catalogued range; user agents naming Tines or a catalogued platform from an address nothing matches and from the other's address, and shaped like an address, a mailbox or a secret; the probe and the read's queries, a delta pass, a host clock set back; a read throttled after its first page, a next link off the pinned read in six ways and one in Graph's own casing; more sign-ins than four pages; seven reports requests in one run and the pacer's bound, and a run whose budget is spent before its first sign-in page; the capability refused while the audit log is available, refused with it, unknown with it, gone and unavailable; a scheduled pass whose read is refused and one whose read is sampled; a sign-in by a principal not yet inventoried, then inventoried, one by a principal never inventoried, and one stamped ahead of the read; every catalog entry's checks and both feed parsers; a refresh that changes the feeds; the refresh script, and the script refreshing one feed of a module that holds the otherOne network row for each of the three with its first and last moment and the catalog's version, and none for the rest; a hint that is a leading product token or nothing, and no row from a user agent, the address alone naming the platform; the read asking for service principal sign-ins from thirty days back with its $select and page size, the cursor thirty minutes behind each read and never moving back; what the throttled read matched kept and its cursor left; every hostile link refused with nothing sent there, Graph's casing followed; the newest four pages read and the rest counted as a sample; one wait of ten seconds, the eleventh request refused PACED, a paced read past its first page a sample, and one paced before it failed with its cursor left; unlicensed, forbidden, unknown, unsupported and unknown, the run COMPLETE and the connection reading as complete unless the audit log itself is refused; collect-due counting sign_ins_failed and sign_ins_sampled, in its output and its log line; the stranger counted and not kept, the cursor waiting at its sign-in, and the read after the collection that inventories it making its row; the cursor waiting for the one never inventoried no further back than the look-back; the early sign-in kept at the read's moment and the late one dropped; no address, name, user agent remainder or application id in any table, result, printed line or line any logger writes; a catalog that cannot explain itself and a feed that cannot be read whole refused, each set of feed networks a catalog version of its own, a refresh that overlaps another platform refused, and the script's module formatting cleanly and checking, keeping the feed the module held that it was not given
SR27A Tines tenant whose credentials allow Microsoft Graph, Microsoft sign-in with another host, no host and another host only, collected with their references; its egress recorded and a directory principal signing in from it; a credential referenced by more actions than Tines lists; a credential one team shares with another, referenced by both teams' stories and by a reference that names no team, for a connection scoped to each team and to none; no credential allowed to call Microsoft; the egress changed, recorded while a read runs, recorded after a run began and before it read, and corrected to an address a later sign-in comes from; the Tines credentials changed while the directory's sign-ins go unread, and the Tines connection revoked; the Tines connection in another Space; the actor's detail read by a session looking at another Space and by an administrator narrowed to one; addresses that are repeated, nine, private, loopback, link-local, documentation, multicast, unique-local, with a zone, a network, not an address and in Anthropic's range, and the first, second and last address of every block the store refuses; a directory connection, from the store and from the console route, and an administrator narrowed to another Space; the egress function called directly by an approver, an agent, the scheduler, an administrator no longer active, one narrowed to another Space and one seated in the connection's Space as an approver; the console route without a recent factor and with a personal access token; the command line; a driver row that does not fit its levelA network and a joined row whose stories are every one referencing a credential allowed to call Microsoft Graph or Microsoft sign-in and none other, with the network row's moments, the unrestricted credential counted on the agent detail, and no host, metadata or owner kept; the capped credential's fifty stories marked "at least"; each scoped connection's join naming its own team's stories alone, and the unscoped one's every story; no join; the old rows gone and thirty days re-read once, by the run already under way too, a stale read's Tines matches dropped and its cursor left, the corrected address's rows dated from its own sign-ins; the join gone with the credentials and back with them, and the network and joined rows gone the moment the Tines connection is revoked; no match across Spaces, and no Tines connection, label, story or credential count on the detail for a session that does not see its Space, which still reads the actor's catalogued network row; each address refused by the store's own rule before the database is asked, INVALID_EGRESS and the catalogued one EGRESS_CATALOGUED, and the repeated, the nine, the network and every blocked address refused INVALID_EGRESS again by the database, whose definition holds exactly the store's blocks; the zone and what is not an address refused INVALID_EGRESS by the store alone, as the database's address type cannot read either, and the catalogued address by the store alone, as the database holds no catalog; INVALID_STATE, 409 CONFLICT from the console, and INVALID_ADMIN, the narrowed administrator refused by the store before the database is asked; INVALID_ACTOR from the function for each actor called directly, and the administrator seated in the Space as one recording; MFA_REQUIRED and TOKEN_NOT_ALLOWED; record-egress recording and clearing, and refusing neither or both; one monitor.egress_recorded per change with the count alone, informational to replay; every misfit refused by a check, and another tenant reading, writing or ending none of the rows
SR28An agent identity, a principal registered here, a managed identity, another organization's application holding a delegated consent and another's holding none; the consent moving from one to the other; a delta entry that states no type; the directory once listing the agent identity as a classic principal; a new consented app with ungoverned consequential reach after the baseline; an application id that is not a GUID; a principal first seen by a delta pass, and one a delta pass restores; the runtime moving each class to each other oneEach class as the directory states it and the consent decides it, the consent's move moving both classes at the next collection, the stated type unchanged by an entry that states none, the agent identity never moving and keeping its blueprint, new-actor.v1 titled "New consented app reaches a consequential action through a path nothing governs" beside ungoverned-reach.v1, the application id kept only as a GUID, the column refusing anything else, and kept by the delta pass that inserts a principal or restores one that had none; CLASS_FIXED for every move into or out of an agent identity or a Tines story, and a move within the classic family allowed
SR29Actors with successful consequential observations in the last thirty days, one of them matching a settled ExecBound execution, a failure and one from before the baseline; actors with open paths; more actors than the page shows, the one that needs attention last by name; actors a Tines tenant in another Space drives, one of them also declared, read from that Space, from another and after the Tines connection is revoked; a connection at its observation bound, and its CAPACITY finding under the title it has now and the one it had before 0095, raised within the thirty days or before them, beside another health finding; no detection profileDid counting the successes and the baseline-era one and leaving out the settled match and the failure, "at least" at the bound and while a CAPACITY finding of the thirty days stands, under either title, and not for an older one or another health finding, the actor that did something first and the open ones next, the 200-row cut applied after ordering so the last-by-name actor with an open path is shown first, the tenant line's actors per source and unattributed count over every actor, a Tines row counting toward the figure and the Tines Gate pointer, strongest or not, only where its Space is seen, so the figure always equals the rows read as unattributed, and nothing done or open without a profile
SR30An acceptance with an expiry, its expiry passing, another administrator accepting it again; a withdrawal, a second withdrawal; the console's Accept with a reason outside the list, a period outside the four, no path, a repeated path, a path the actor does not hold, a lapsed path, a path to an action the profile does not name and a path accepted already; the functions called directly by an approver, an agent, the scheduler, an inactive administrator, one narrowed to another Space, one seated in the actor's Space as an approver and one seated there as an administrator, and for an actor that is gone; accept-reach and withdraw-reach by a narrowed administrator and by the workspace's; an observed path accept-reach accepted, withdrawn from the console; the runtime writing an acceptance or its history directly; another workspace's session; the routes without a recent factor and with a personal access token; the Agents page and an actor's page for a workspace administrator looking at another Space, for an administrator narrowed to another Space, for one who approves in the actor's Space and for one seated there as an administratorThe path open again at the expiry and closed again by the renewal, whose reason, expiry, author and moment replace the first and whose history keeps both, one monitor.reach_accepted for each; the withdrawal reopening the path and, at the next collection, a second ungoverned-reach.v1 episode, one monitor.reach_withdrawn naming no reason, the second withdrawal NOT_ACCEPTED (409 CONFLICT from the console); every malformed Accept and every path not open INVALID_INPUT (400 INVALID_BODY) and nothing recorded; INVALID_ACTOR from both functions for every caller but the seated administrator, INVALID_ADMIN from both commands, which say only that the command is unavailable and record nothing, and an acceptance and its withdrawal recorded by them with their events, INVALID_AGENT accepting for a gone actor and its withdrawal recorded, and no path of a gone actor read open or accepted from the console (AGENT_UNAVAILABLE); the observed path's acceptance withdrawn, a kind none is recorded for 400 INVALID_BODY; permission denied for every direct write; AGENT_UNAVAILABLE across workspaces; MFA_REQUIRED and TOKEN_NOT_ALLOWED; the console answering the actor as the server holds it; each row and each actor's page administered for the workspace administrator whichever Space it shows and for the seated administrator, who accepts and withdraws, and not for the narrowed administrator or the approver, whose Accept is refused AGENT_UNAVAILABLE and INVALID_ADMIN, and the console offering Accept and Withdraw only where it is
SR31The synthetic directory added by its function, by create-connection and by a direct insert; a second one; a workspace that ever connected Microsoft Entra, from the console too; a direct insert beside a directory, and of a second one in another Space; connecting Microsoft Entra beside it, by the command line, the console's consent and a direct insert, and after removing it; its collection with every socket refused, twice an hour apart, and by collect-due with no key file, which the jobs service schedules on every installation (MC7); added with no detection profile, then a profile set, and another workspace connecting a real directory after removing it; added by an approver, an agent, the scheduler, an inactive administrator and an administrator a membership narrows to their Spaces, then by a workspace administrator, and from the console by a narrowed one; a schedule outside a directory's, from the store and the console; Monitoring read from a Space other than its own, beside a directory connected or once connected in another Space, and by a reader narrowed to some Spaces; a findings destination; the console assistant's findings tool; linking, binding and governing its actor, and a governed agent's bind picker; removing it; the scheduled purge a month on; Home; its findings and a late collection on Home, the workspace settings, the Spaces page and in the weekly summary's counts; migration 0099's round trip with a synthetic directory or an acceptance's history retained, as a superuser and as an owner that does not bypass row securityCreated only by admin_add_synthetic_directory, by a workspace administrator alone (INVALID_ACTOR from the function for every other caller, INVALID_ADMIN from the store before it is asked), with no key, its fixed shape and its first collection asked for, and monitor.connection_created appended once with kind fixture, mode synthetic and its label, INVALID_INPUT and a refused insert otherwise, CONNECTION_EXISTS for a second, and the index refusing a second inserted in another Space; DIRECTORY_CONNECTED, active or revoked, from the store, the trigger and the console (409 DIRECTORY_CONNECTED), and 403 FORBIDDEN for the narrowed administrator; a schedule outside one to twenty-four hours, or with an activity interval, INVALID_SCHEDULE (400 INVALID_BODY) with nothing written; Monitoring saying it is present for the whole workspace in every Space, and whether one can be added for the whole workspace to a reader of every Space and never to a narrowed one; SYNTHETIC_DIRECTORY_PRESENT from the store, the consent start and the trigger, and connecting allowed once it is removed; the collection complete with no socket opened and no delta link, its baseline and inventory summary first, then the late principal's new-actor.v1 and ungoverned-reach.v1 and process's first-consequential-action.v1, with no profile set as with one, assessed then against the built-in sensitive actions with built_in saying so, until a profile decides, and the real directory not assessed without one; its actors' classes, drivers, observations and Did, labelled synthetic with source fixture in every answer, the assistant's findings among them; its findings' intents closed SYNTHETIC_DIRECTORY and a destination's delivery refused; SYNTHETIC_ACTOR for each, 409 SYNTHETIC_ACTOR from Agent connections, and none of its actors offered to bind; its actors, their driver rows, grants and grant paths gone, none of their paths read open, and its findings kept; its audit observations purged as a directory's, each actor's first action and what a finding cites kept; Home not watching it or drawing its observations, and no open finding or overdue connection of it counted on Home, the workspace settings, the Spaces page or in the weekly summary; no address, token or secret kept; the downgrade refusing SCOUT_AGENTS_PAGE_RETAINED, and otherwise round-tripping with the classes mapped back and row security forced again
SR32Each class from each sourceThe removal guidance: the admin center's enterprise applications for a service principal or a consented app, the Azure resource for a managed identity, the blueprint for an agent identity, and none for the synthetic directory or a Tines story; the link is the console's constant and the application id is text beside it

Tests live in tests/test_scout_schema.py, test_scout_grants.py, test_scout_collection.py, test_scout_run.py, test_scout_reach.py, test_scout_derived.py, test_scout_rules.py, tests/test_console_api_monitoring.py and tests/test_browser_console_monitor.py. SR15 to SR20 are held by the test_sr15_ to test_sr20_ nodes of tests/test_scout_delta.py and tests/test_scout_delta_migration.py, with the replaced new-agent.v1 test in test_scout_rules.py, the retained new-agent.v1 finding read over HTTP by the test_sr16_ node of tests/test_console_api_monitoring.py, and the console's components/monitor/FindingRow.test.tsx. SR21 to SR23 are held by the test_sr21_ to test_sr23_ nodes of tests/test_scout_audit.py and tests/test_scout_audit_migration.py, the exact collect-due report and log line in tests/test_monitor_collect_due.py and the console's components/monitor/Activity.test.tsx and components/monitor/MonitorSetup.test.tsx. SR24 is held by the test_sr24_ nodes of tests/test_scout_audit_retention.py and tests/test_scout_audit_retention_migration.py, the exact collect-due report and log line in tests/test_monitor_collect_due.py and the exact process --all-tenants report in tests/test_monitor_process_all.py. SR25 to SR27 are held by the test_sr25_ to test_sr27_ nodes of tests/test_scout_drivers.py and tests/test_scout_drivers_migration.py, the test_sr26_ nodes of tests/test_scout_egress_catalog.py, the egress route's test_sr27_ node in tests/test_console_api_monitoring_connect.py, the egress form's test_sr27_ node in Chromium in tests/test_browser_console_scout.py, the agent detail's drivers and catalog gaps in tests/test_console_api_monitoring.py, the exact collect-due report in tests/test_monitor_collect_due.py and the console's components/monitor/Connections.test.tsx. SR28 to SR32 are held by the test_sr28_ to test_sr32_ nodes of tests/test_scout_agents_page.py, tests/test_scout_agents_page_migration.py and tests/test_console_api_scout_agents_page.py, the test_sr30_ and test_sr31_ nodes in Chromium in tests/test_browser_console_scout.py, the agent identity's fixed class in tests/test_scout_schema.py, the acceptance events' replay in tests/test_replay_informational_kinds.py, a real connection's findings unlabelled in the assistant's tool in tests/test_monitoring_acknowledgement.py, and the console's components/monitor/Scout.test.tsx and, for an actor's page on Agent connections, components/directory/agents.test.tsx.

Rulesets​

tests/test_rulesets.py holds RS1 to RS4 and tests/test_pack_rulesets.py holds RS5 and RS6. RS7 to RS9 are held by tests/test_console_api_rules.py (the editor's routes, its refusals with their locations and the approver's 403), tests/test_rulesets.py (the sentences, the inert note and policy.ruleset_compiled), tests/test_console_api_policy.py (the rule behind each preview change) and tests/test_browser_console_policy.py (the editor and a bundle's rules in Chromium). RS11, about the hosted sandbox's welcome page, is kept with the hosted service's inventory. RS12 is held by tests/test_console_api_agents.py, tests/test_browser_console_directory.py and the console's components/directory/agents.test.tsx.

IDSetup/actionRequired result
RS1One ruleset compiled twice, and once with its rules in another orderIdentical bytes for all five components; validated by the real Cedar engine, never a stub
RS2A condition naming an unknown fact or argument, a value outside the declared domain, an ordered operator on text, a ninth condition, a quorum on a rule that is not REVIEW, an action no mapping servesRefused with the field's location; the model refuses what it cannot mean before the compiler is reached
RS3A bundle carrying a ruleset, with each of the five components edited on its own while staying well-formedValidation refuses RULESET_MISMATCH naming the component; a bundle without a ruleset serialises with no ruleset key and validates as before
RS4A REVIEW rule with a quorum beside one withoutThe quorum names the positional obligation the engine actually raises for that rule, asked of the engine rather than restated
RS5The endpoint, identity and SOC packs as rulesets, every combination of classification, environment, incident status and severity, criticality and argument valueEffect, reasons and whether review is owed agree with the hand-written pack on every input; every reachable effect is reached
RS6Each pack's ruleset builder, recompiled from its own rulesetEqual to the bundle it built, and the compiler's raw limits already in the stored order; the hand-written builders stay the default fixtures derive variants from
RS7An ADMIN writes three rules (allow a workstation with an open critical incident, deny a domain controller, review production with a quorum of two), a review of open incidents and a budget, in the console's rules editorEach rule reads as one sentence and the compiled Cedar is shown read only; the draft is created through the compiler and the store and its bundle page shows the rules, the note as text and the Cedar; validation succeeds; the preview names the rule behind each changed decision and marks a review candidate unresolved; activation succeeds; policy.ruleset_compiled is audited with counts
RS8A condition naming an unknown fact, a text value where a number is declared, and a note containing markupRefused at the form with the field's location; the note renders as text and appears in no compiled component
RS9An approver requests the rules editor403
RS10Every fixture host the seeder writes, read by project() over its facts; every input of every pack (tests/test_pack_rulesets.py); and every input of rules written with is_not, at_least and at_most at every value of every field an action's rules may name, a Long argument through the synthetic probe action, and the Defender scenario's committed rules with every value of compromise (tests/test_rule_reading_operators.py)The reading equals the pack's stated effect on every host and names a rule for every reading that is not the default denial; over the whole input space the reading equals the kernel's policy decision, a reading owing review names a review rule, and no reading is made with a fact missing; for the other operators the review rules the reading names are exactly the obligations Cedar raised, each operator in every effect and in conjunction reads as the kernel decides, and the Defender scenario reads as allowed without review only for a compromised host under an open incident that is not a domain controller; a host with no open incident yields the names of the facts it lacked
RS12The agent page with a ruleset bundle active, and with a hand-written oneA Rules column names the rules about each governed action in the compiler's order, labelled as the reading and not the decision; the hand-written bundle adds no column and no claim

Approval deadline​

tests/test_approval_deadline.py holds AD1 to AD6, AD8, AD10 and AD11, tests/test_client_package.py and tests/test_examples.py hold AD7.

IDSetup/actionRequired result
AD1A fresh tenantapproval_deadline_seconds is 120 and an approval expires at min(valid_until, created + 120 s); every earlier 120-second test passes unchanged
AD2Deadline 900, facts valid for an hour; decision at +500 s, retry at +800 sThe approval carries created + 900 s; the retry executes exactly once; a further retry returns the same execution
AD3Deadline offexpires_at equals the plan's valid_until; a decision after it is STALE_AUTHORIZATION with approval_state: EXPIRED and no mutation; a decision before it executes
AD4--set 119, 3601, -1, 0, a string, a float or a boolean; the current value; a HUMAN_APPROVER credential; a blank reasonINVALID_DEADLINE, INVALID_STATE, INVALID_IDENTITY, INVALID_REASON; nothing written; each success is audited as tenant.approval_deadline_changed with previous and new values, the reason, principal and credential ids
AD5Deadline changed while an approval is pendingThe pending approval keeps its expiry; the next approval uses the new value
AD6Export after a decision made at +600 s under 900Replay verifies complete with no issues and reproduces every recorded effect, the review decision included
AD7Deadline 900; the sync client, the async client and the MCP example wait through an expired continuationEach resends the same intent, keeps polling, and returns EXECUTED after the later decision with one mutation
AD8Console under 900 and under offThe approval page and listing say (approval deadline) or (context validity); a decision submitted four minutes after the page rendered succeeds and executes once
AD10SessionsA load at +8 minutes extends the session to twelve hours after that load and marks it renewed, at +5 it does not; renewal never passes the absolute cap or the credential's expiry; a revoked session is not renewed; the console re-issues both cookies with the new age and twelve quiet hours still end the session
AD11Migration and runtime catalogHead 0027_approval_deadline; the column is updatable and the sessions expiry is not; renew_human_session is the only new definer function; downgrade to 0026 and back returns every tenant to 120, passing through 0100_longer_sessions' downgrade (sessions longer than eight hours are revoked and cut back) and upgrade

Approval expiry​

An approval past its deadline that nothing touches again would stay PENDING, and its execution PENDING_APPROVAL, indefinitely; the recovery run expires it. tests/test_approval_lapse.py holds AX1 to AX10, and console/src/routes/-home.test.tsx and tests/test_browser_console.py hold the console clauses of AX9.

IDSetup/actionRequired result
AX1A pending approval thirty-six hours past a 600-second deadlineNo execution_impact row, no resource_claims row, both demo rules projecting zero, and no approval.transition event: the row reserves nothing and claims nothing, so nothing is lost to capacity and the defect is a lifecycle that never terminates
AX2One recovery run over itexpired is 1; the approval is EXPIRED from PENDING and the execution STALE_AUTHORIZATION from PENDING_APPROVAL, bound to the same approval id and plan hash; no impact row, no claim and no provider mutation appear
AX3Two further runsexpired is 0 each time, the chain is byte-identical to after the first run, the states are unchanged and the selection is empty
AX4An approval inside its deadline, then past it but inside the run's graceSelected by neither run; the approval stays PENDING and the execution PENDING_APPROVAL
AX5An approved-and-consumed execution and a denied one, both past the deadlineexpired is 0; EXECUTED/CONSUMED and DENIED/DENIED are untouched and the single mutation stands
AX6An approval a human approved and the agent never came back to consumeSwept on the same terms: EXPIRED from APPROVED, execution STALE_AUTHORIZATION, no mutation
AX7A decision, then an agent retry, in the window after the deadline and before any runBoth answer STALE_AUTHORIZATION with approval_state: EXPIRED and no mutation; a second decision is INVALID_STATE
AX8A decision and a recovery run racing on two threads past the deadlineExactly one approval.transition to EXPIRED and one execution.transition to STALE_AUTHORIZATION; the loser adds nothing and holds nothing
AX8bThe same race inside the deadlineThe sweep always refuses under the fence and the decision always lands: APPROVED, execution PENDING_APPROVAL, no EXPIRED transition
AX9The pending view, the lapsed view and the overview count, before and after a runBefore: out of pending, in lapsed, overview pending 0 and lapsed 1, because the overview classifies an approval past its deadline on the server's clock. After: still out of pending, still in lapsed, overview pending 0, lapsed 0 and one STALE_AUTHORIZATION; an approval that ran out of time never disappears from the one view that says so
AX10Export and replay after a runThe verified export replays complete with no issues

Teammate invitations (TI1 to TI45)​

Expiring, single-use links that add a workspace membership, migration 0059_workspace_invitations. The pages are /join, /join/accept and /join/confirm; /invite belongs to the customer-directory invitation code (T4.29) and is a different feature. Real PostgreSQL throughout; TI20, TI21 and the real-Chromium Origin check below run in tests/test_browser_invitations.py; TI4, TI9, TI13d, TI14b, TI14c and TI14d run in the hosted service's own tests, which are not published, and TI18w and TI45, which concern the hosted plugin, are kept with the hosted service's inventory; everything else is in tests/test_teammate_invitations.py. The Case column names the signup design's acceptance case each row evidences (CS04, CS05, CS09, CS11 or CS12); the design is not published.

IDScenarioExpectedCase
TI1Migration and runtime catalogHead 0059_workspace_invitations; both tables forced-RLS with the runtime holding no INSERT/DELETE and UPDATE only on the messages table's seven delivery columns; the seven functions granted EXECUTE only; the drain's owner_drain SELECT policy names only the migration's own role, never execbound_app; check_runtime green; under another tenant's fence the runtime reads zero rows of either table while workspace_invitation_due still lists the messageCS05
TI1aMalformed input, and a duplicate addressEach bad shape (unknown role, empty or oversized grant list, an administrator grant scoped to a Space, an unknown Space, a duplicate grant pair) is refused before a row exists; a second invitation for a still-pending address is INVITATION_PENDING; an address an active principal already holds is ALREADY_MEMBER; a principal of another workspace is FORBIDDENCS05
TI1bA new address acceptsOne membership, one managed HUMAN_APPROVER holding exactly the invitation's grants, and no personal workspace or Community allocation for the account the link createdCS05
TI1cA digest mismatch, five timesEach wrong guess commits its own failure count on both check and accept; the fifth locks even the real token out and nothing is created; a fresh rekey resets the count to zero and the superseded token stays deadCS05
TI1dA revoked invitationAcceptance is refused INVITATION_REVOKED; check reports state REVOKED; a second revoke is INVALID_STATE, an unknown invitation is NOT_FOUND, and a rekey of the revoked row is INVALID_STATE; no principal is createdCS05
TI1eThe inviter loses access.manageAcceptance, resend and revoke are all refused FORBIDDEN; nothing is created and the invitation stays PENDINGCS05
TI1fAn existing accountA password is refused ACCOUNT_EXISTS; a different signed-in account is ACCOUNT_MISMATCH; both proofs or neither is INVALID_REQUEST; the real acceptance keeps the home membership and adds a second, the new principal's email left NULL with its label the address; a retry is ALREADY; a second invitation to the address is ALREADY_MEMBERCS05
TI1gResend at the SQL layerThe first send still in flight refuses RESEND_LIMIT; past the two-minute spacing it succeeds, returns the message to PENDING with a fresh next_attempt_at and zeroed attempts, and bumps sends; a sixth send is refused; the runtime can write only the messages table's delivery columnsCS05
TI1hThe drain, and acceptance, as an owner that does not bypass row securityworkspace_invitation_due lists a message across tenants only because owner_drain admits that specific role; _check_drain_policy reads that same policy and passes under this restricted posture too; the runtime role's own fence sees nothing outside its tenant; downgrade with a populated table is refused "lossy downgrade refused"; a new address, an existing account whose address a principal elsewhere holds, and a removed-and-reinvited member all accept correctly under this restricted postureCS05
TI1iA removed member is invited backWhile the old principal is active a second invitation is ALREADY_MEMBER; once it is deactivated a new invitation and acceptance re-point the account's one membership at the new principal (active=true, version+1), leaving the old principal deactivated with its own grant history intactCS09
TI1jA grant's space_id is canonical or refusedEvery shape but absent, null, or an 8-4-4-4-12 UUID string in any case is INVALID_SPACE; two cased spellings of one Space in one request are INVALID_ROLES; a shouted-case id is stored and later reported lowercase, and the accepted grant carries exactly that idCS05
TI2create_invitation writes a row and a chain eventOne PENDING row and message; invitation.created names no address, only the domain; a non-administrator is FORBIDDEN; a second pending address is INVITATION_PENDING; an active member's address is ALREADY_MEMBER; a grant naming an archived Space is INVALID_SPACE; every refusal is logged by code aloneCS05
TI2bAn expired pending invitationcreate_invitation revokes the expired row (invitation.revoked, reason EXPIRED) and creates the new one in the same transaction; an unexpired pending row still refuses INVITATION_PENDINGCS04
TI2cPython-side grant validation matches SQL_validate_grants normalizes every UUID spelling to the canonical lowercase form before a database round trip and refuses the same bad shapes and Space ids SQL's own GRANT_CHECK refusesCS05
TI2dlist_invitations requires access.manageAn administrator's own list shows the address, state, sends and delivery outcome; a member with no access.manage is FORBIDDENCS05
TI3deliver_invitations sends one message; the email for a workspace and inviter named in a non-Latin script; names holding a web address, a dotted host-like word, a colon or a slash, an inviter named by an address, and names ending a word with a full stop or holding an underscore or hyphenThe link is <origin>/join#ebt1.<tenant>.<invitation>.<secret>; the stored digest matches and generation is 1; the subject and body name the workspace and inviter, or say "a workspace" and "An administrator" where nothing of a name survives or its label holds anything a mail client could link, never "unknown", so the invitation's own link is the only one; a name no mail client would link is kept; no address or token reaches a log lineCS04
TI3bdeliver_one, the fast first sendDelivers the just-created message and marks it DELIVERED; a message that is not due, or does not exist, is a quiet False, never a raiseCS04
TI4The drain reaches a Community-only tenantA workspace made only through community_provision, which no jobs token or slots file names, is drained exactly like any other tenant Evidence not published.CS04
TI5Resend is bounded by spacing and by fiveIn flight, or under two minutes since delivery, is RESEND_LIMIT; past the spacing it sends again with a new digest and one invitation.resent event; the sixth send is refusedCS04
TI6Revoke stops deliveryThe invitation and its pending message both settle at once (REVOKED / FAILED REVOKED); the drain sends nothing for it; a second revoke is INVALID_STATE and an unknown invitation is NOT_FOUNDCS04
TI7A transient failure stays pending; an invalid state settles failedA relay refusal leaves the message PENDING with the attempt counted and the real cause recorded; an invitation that moved out from under an already-leased message (accepted or revoked mid-flight) settles FAILED INVALID_STATE on its first attempt, not spent through retriesCS04
TI8A new address accepts with a password and signs in onceOne verified account with no allocation; one managed HUMAN_APPROVER holding exactly the invitation's grants; one membership; the chain holds principal.created, access.set_user_roles (inviter as actor) and invitation.accepted, with no address, token or digest in any payload; sign_in_invited_account yields a session in that tenant; a retry is ALREADY and mints nothingCS05
TI8bAcceptance writes every row without bypassThe same new-address path, inspect_invitation, and an ACCOUNT_EXISTS only SQL's own cross-tenant check can raise, all run and read back fenced as a NOBYPASSRLS ownerCS05
TI9A Community workspace owner joins a second workspaceSigns in normally and accepts; two active memberships, each with its own local roles (Administrator at home, Viewer here); the home workspace and its allocation are unchanged; the new principal's email is NULL and its label is the address Evidence not published.CS05
TI10The wrong account, a pending session, and a held addressA password for an address an account or an active legacy principal holds is ACCOUNT_EXISTS; a different signed-in account is ACCOUNT_MISMATCH; a session missing its own account cookie is ACCOUNT_MISMATCH; both proofs or neither is INVALID_REQUEST; a pending-MFA session is not signed in yet and is ACCOUNT_MISMATCH; a holder who appears between inspection and acceptance is still caught by SQL's own recheckCS05
TI11Revoked, expired, forged and superseded linksRevoked is INVITATION_REVOKED; expired (seven days from creation regardless of resends) is INVALID_TOKEN; a forged guess counts on both check and accept and five lock the real link out too; a malformed code never reaches the database; a resend's new link works and the superseded one is INVALID_TOKENCS05
TI12An inviter who lost authority admits nobodyDemoted to Viewer by another administrator, or the inviter's own principal deactivated: acceptance is FORBIDDEN either way, and the chain gains neither principal.created nor invitation.acceptedCS11
TI12bA Space archived after the invitationaccess_change rechecks every Space at acceptance, so a grant naming a now-archived Space is INVALID_SPACE on both the new-address and the existing-account path, and nothing is madeCS11
TI13aTwo acceptances of one link at onceOne ACCEPTED and one ALREADY; exactly one account and one membership resultCS05
TI13bOne account accepting twice at onceThe account lock orders them; one ACCEPTED and one ALREADY; exactly one membershipCS05
TI13cAcceptance against a concurrent revokeExactly one of {ACCEPTED, INVALID_STATE} or {INVITATION_REVOKED, REVOKED} results, and the invitation's own state matches whichever wonCS05
TI13dAcceptance against a concurrent verified signupThe same new address racing an invitation and a Community signup produces exactly one account; the loser gets ACCOUNT_EXISTS, and whichever lost leaves its own request untouched (the signup stays VERIFYING or the invitation stays PENDING) Evidence not published.CS05
TI14aThe inviting administrator cannot reach the member's accountThe workspace's own fenced reads see one membership row and zero rows of every account table; the runtime cannot write a password or factor table directly; the administrator's own password-reset and set-email doors both refuse ACCOUNT_OWNER_REQUIREDCS09
TI14bRemoval ends the invited workspace, leaves the member's ownDeactivating the member's principal ends its sessions and drops it from the switcher and from switching; their own workspace, and password sign-in to it, are untouched; an account whose only membership was removed cannot sign in at all Evidence not published.CS09
TI14cAccount-wide revocation ends both workspaces"Sign out other devices" reaches the invited workspace's session too; suspending the account ends both workspaces' sessions and every new sign-in Evidence not published.CS09
TI14dA removed member invited back rejoins under a new principalThe account's one membership here re-points at the new principal (version incremented); the old principal stays deactivated with its own grant history; the home workspace is untouched; the next switch and session land on the new principal with its new grants Evidence not published.CS09
TI15An administrator invitationaccess_change's promotion handling runs for the new principal; it holds access.manage and role administrator, and no credential exists to revoke, because this call just made the principalCS11
TI16A scanner, and a query stringRepeated GET /join changes nothing (state and failure count unchanged); a query-string token is refused (400) before the databaseCS04
TI17The new-address flow over HTTPSigns the person in once (303, a minted session cookie); reopening the same link afterward shows "You have joined." with no session cookie, and the invitation stays ACCEPTEDCS04
TI18The existing-account flow over HTTPJoins (200, "You have joined <workspace>. Choose it from the workspace menu."), and never says the deployment cannot switch between workspaces, because switching is core; a pending-MFA session is refused at /join/confirm and redirected to /mfa without provisioning anything; a different signed-in account gets mismatch (403)CS05
TI19Each result kind carries its own statusinvalid 403, revoked 403, ready 200, sign_in_first 200, mismatch 403, joined 200, retry 503, matching RESULT_STATUS exactlyCS04
TI20The fragment, over real ChromiumLeaves the address bar in one replaceState; the token reaches no URL and no Referer, appears in exactly one request body (the exchange POST), and touches no storageCS04
TI21The invite pages at 390 pixelsEach page's <h1> is visible and nothing overflows the viewportCS12
TI22The console API as an administratorCreate, list, resend and revoke all succeed and agree with the row underneath; a second revoke of an already-revoked invitation is a typed CONFLICT (409), not a 500; a Viewer with no access.manage is refused FORBIDDEN on every route and changes nothingCS05
TI23Create schedules exactly one best-effort sendThe console's create route runs deliver_one as a background task after commit, using the same production call shape invitations-run uses; the message is DELIVERED with one attempt by the time the response returnsCS04
TI24Every new console code has a browser sentenceINVITATION_PENDING, ALREADY_MEMBER and RESEND_LIMIT are declared in console_api/errors.py, every code teammate_invitations.REFUSALS can answer with is one of them, and each has its own sentence in the console's COPY tableCS12
TI25The console mutations require the same recent MFAWith the session's MFA assurance aged past thirty minutes, create, resend and revoke all refuse MFA_REQUIRED (401) and change nothing; a list read is unaffected; a fresh factor lets create succeed againCS11
TI26The list window is a pure thirty-day cutoffA resolved row just past thirty days is dropped, a pending row well inside it is kept, and a pending-but-expired row past the cutoff is dropped too: created_at alone decides, never stateCS05
TI27An address SQL accepts but is_address refusescreate_invitation refuses it INVALID_EMAIL before a row exists, for shapes SQL's own looser regex would have accepted; the normal address still normalizes (strip, lowercase) and is storedCS04
TI28A bad stored address never stalls another tenantA row create_invitation would now refuse, inserted directly outside it, settles FAILED INVALID_ADDRESS on its own first attempt instead of aborting the whole drain; a valid tenant's message in the same pass still deliversCS04
TI29deliver_one logs and returns False on an unexpected failureAn unrelated fault is caught, logged once as invitation.refused naming the tenant and code with no exception text, and answered False rather than raised or swallowed silentlyCS04
TI30A settle fault counts failed and does not end the runA guarded _settle (SQLAlchemyError, UnsafeDatabaseRole, ValueError, the same trio _lease and _send already catch) counts its message failed and leaves the row exactly as _lease set it, IN_FLIGHT with one attempt spent, while a second tenant's due message in the same pass still delivers; the CLI's own invitations-run exit-2 mapping answers a SQLAlchemyError with a fixed sentence rather than a tracebackCS04
TI31The exchange answers retry for our own faultPOST /join maps INVITATION_UNAVAILABLE to retry (503), the same recoverable page /join/accept and /join/confirm already show, rather than telling the person a still-good link is invalidCS04
TI32A fault signing in after acceptance still says joinedsign_in_invited_account is guarded inside the same except (SessionError, InvitationError, SQLAlchemyError) issue_session already is; a fault there, after the acceptance already committed, answers result("ready") ("You have joined. Sign in.") rather than a bare 500CS04
TI33Resend gets the same fast first send as createresend_invitation returns the message id read in the same transaction, and the resend route schedules deliver_one as a background task exactly as create's route does, only when runtime.mail is setCS04
TI34invitation.sent logs the state actually writtenA message that settles FAILED on a terminal race is logged state=FAILED, not derived from result.delivered alone (which would misreport it PENDING)CS04
TI35list_invitations filters and bounds in SQLThe thirty-day cutoff and a LIMIT are applied in the query list_invitations itself runs, not filtered afterward in the console route; a direct service call already excludes a backdated rowCS05
TI36The drain refuses the run when owner_drain is missing_check_drain_policy reads pg_policy for owner_drain on the messages table before the batch drain lists anything due, passes on the migrated database, and refuses the whole run with a fixed code, leaving the due row untouched, when the policy is goneCS05
TI37A re-invitation marks the principal it replacedMigration 0061_replaced_principals: a removed member's second acceptance sets replaced_by on the old principal to the new one; the new principal is active and replaces nobody, the old stays inactive, nobody else in the workspace is marked, and a first acceptance replaces nobodyCS09
TI38A replaced principal is never reactivatedThe old principal held Administrator; admin_reactivate_principal refuses it PRINCIPAL_REPLACED; the two principals, the membership and the grants are exactly as before; access_has_permission still answers false for it and the workspace's active managers are unchanged; deactivating the workspace's own administrator is still LAST_ADMINISTRATORCS11
TI39Every reactivation surface refuses and shows the replacementpeople_pages.reactivate (the function the console route wraps) raises PRINCIPAL_REPLACED and appends no principal.reactivated; POST /api/console/v1/people/{id}/reactivate answers 409 with that code and its sentence; the person and the list both carry replaced_by; errors.ts holds the same sentence and a bare 409 never reads as this codeCS12
TI40The check refuses every write that would revive oneEven the owner inside the fence cannot make a replaced principal active, name a principal as its own replacement, or mark an active principal replaced (principals_replaced_retired, 23514); a replacement in another workspace fails the foreign key (principals_replaced_by, 23503)CS11
TI41A reactivation racing the re-invitationThe People function and the member's acceptance, started together on real threads and connections inside their open transactions: exactly {ACCEPTED, PRINCIPAL_REPLACED} or {ALREADY_MEMBER, REACTIVATED}, never a raw constraint violation reported as unavailability, and the rows and the chain match whichever wonCS11
TI42The lock order, in both queue ordersThe two definer functions called directly while a third connection holds the tenant fence; whichever queued first commits and the other refuses with its own code (ALREADY_MEMBER or PRINCIPAL_REPLACED); taking only the row lock before the fence instead deadlocks when the reactivation queued firstCS11
TI43The migration walks both waysUpgrade patches exactly its three fragments and keeps each function's owner, grants and definer; a membership re-pointed at 0059 needs no backfill; the downgrade refuses "lossy downgrade refused" while any principal names its replacement and leaves the head at 0061; with none, it restores both function bodies byte for byte and drops the column, both constraints and the covering indexCS05
TI44The same walk without bypassAs a NOBYPASSRLS owner: the acceptance writes replaced_by through the tenant arm, reactivation refuses, the check binds this owner, and the downgrade sees a retained replacement although this owner sees no principal unfenced, with FORCE back on afterwardsCS05

Two further tests carry no TI number. test_ti_invitation_token_round_trips_and_refuses_a_bad_code is a pure unit test of the ebt1.<tenant>.<invitation>.<secret> format and its INVALID_TOKEN refusal, with no scenario of its own. test_the_accept_post_passes_the_strict_origin_check_in_real_chromium drives POST /join/accept end to end and asserts it is never refused with 403 under the site's Referrer-Policy: same-origin, the same evidence T4.31's real-Chromium regressions record for the signup pages (CS04, CS12). The console side of TI39 is console/src/components/directory/people.test.tsx: a replaced entry reads "Rejoined as a new entry" in the list and on its page, which links to the new entry and offers no Reactivate, whatever roles the old entry held.

Arcade logic extension​

On real PostgreSQL, with a fixture Arcade caller and the protected mocks standing in for the vendor. The guide is Arcade logic extension. Rows live in tests/test_arcade.py (AL1 to AL25 and AL29 to AL34), tests/test_arcade_schema.py (AL26), tests/test_arcade_workflow.py (AL27) and tests/test_browser_surfaces.py (AL28 and AL30's page clause), with shared fixtures in tests/arcade_fixtures.py; those four prefixes are group AL in ACCEPTANCE_PREFIXES. AL32's relation, the deadline the deployment file declares against the slowest grant measured, is tests/test_arcade_deadline.py: it takes the machine's timing lock and is marked timed, so a run that selects not timed leaves it out while AL32's grants still run. Supporting evidence lives in tests/test_checkpoint.py, tests/test_replay_scenarios.py, tests/test_replay_verify.py, tests/test_recovery_run.py, tests/test_route_authority.py and tests/test_surface_configuration.py.

IDSetup/actionRequired result
AL1A governed tool's pre hook on a mapping with external_executor, in a tenant with no connector for the account and an unrevoked executor key{"code": "OK"} and nothing else; one DISPATCH_COMMITTED execution, one UNRESOLVED impact row, one canonical claim, one correlation row holding the Arcade id and the secret; no dispatch ticket and no provider call
AL2The same pre hook delivered three times under one Arcade execution id, and once more after the frozen plan expiresOne execution, one reservation, one claim, one correlation row and one secret; the earlier repeats answer OK from the re-grant and charge nothing; the post-expiry repeat is CHECK_FAILED with the reservation and claim still standing
AL3Two Arcade execution ids for one intent, concurrently and then sequentially while the first is granted and unsettled; then the same intent again after the first settlesThe second is CHECK_FAILED and ExecBound holds one execution, one reservation and one claim; the post-settlement repeat is a fresh decision that resolves, evaluates and counts again, and is CHECK_FAILED on RESOURCE_BUSY until the run releases the claim
AL4A second Arcade execution id for an intent whose first pre hook was abandoned at the extension's deadline while admission committed, and again for one whose correlation row was written without a secretBoth are CHECK_FAILED because neither row holds the grant's secret; ExecBound holds one execution, one reservation and one claim; neither is answered OK from a re-grant, and the abandoned grant is visible in the uncertain queue
AL5A denial, a tenant emergency stop, a ninth outstanding grant, a claimed target and a tenant whose key ring cannot attestEach CHECK_FAILED carrying only a stable code and the execution id where one exists; no input value, vendor string, rule id or secret in error_message; nothing reserved by any of them
AL6The runtime capacity bound full and the surface rate limiter tripped; separately, a shared hard ceiling reachedThe first two answer RATE_LIMIT_EXCEEDED with no execution row; the ceiling answers CHECK_FAILED, and no rule identifier reaches the caller
AL7The application's own refusals reaching the boundary on each route: the capacity limiter exhausted, and a handler-level 503, on POST /pre and then on POST /postOn the pre path both are 200 with a body of exactly {"code": ...} — RATE_LIMIT_EXCEEDED for the 429 and CHECK_FAILED for the 503 — and neither carries detail; on the post path both are passed through with their original status and body; a 401 is passed through on both
AL8A tool outside the map; a governed tool at an undeclared version; a tool of an ungoverned toolkit; a tool whose reported behavior contradicts the map's expectDenied, denied, OK, denied; nothing reserved in any case. The ungoverned pass is asserted against the tenant's chain: the audit head's sequence and hash are read before and after and are unchanged, and no executions row exists for it
AL9inputs missing the declared target key, carrying it as a non-string, and carrying an undeclared key; then, against a declaration naming an incident key, inputs missing it, carrying an explicit null, carrying a string no UUID reading admits, and carrying a number, and a hook that omits it while the reported metadata names oneEach refused before any kernel call; nothing resolved, reserved or claimed, and the refusal names no key value. The incident refusals answer INVALID_INCIDENT rather than the kernel's opaque code, the tenant's audit head is unmoved across all of them, and the reported id fills nothing
AL10inputs carrying a second target-shaped key beside the declared one, and an identity tool targeted by hostnameThe first is OK on the declared key alone with the other ignored for selection and refused as undeclared where it is undeclared; the second reaches the kernel and the kernel refuses it, which is where that refusal belongs
AL11An approval-requiring tool: the first hook, a human decision, a retry under a new Arcade id inside the deadline; and a second walk where the deadline passes firstThe first is CHECK_FAILED carrying the approvals page and the execution id; the retry adopts the same execution, is answered the execution's first grant with its own secret, consumes one approval exactly once and answers OK; the expired walk reaches STALE_AUTHORIZATION and its next attempt is a new decision and a new approval
AL12Post hooks carrying success: true, and success: true beside an execution_errorBoth settle EXECUTED at tier ASSERTED with impact CONFIRMED, the claim still held until the run after the act window; the self-contradiction is retained on the correlation row, appends no audit event and changes no settlement; the settled rows' correlation secrets are null; both answer OK
AL13A post hook carrying success: false with and without execution_code, against a DISPATCH_COMMITTED row and against one already INDETERMINATEBoth settle FAILED_EFFECT_UNKNOWN at tier ASSERTED with impact CONFIRMED and confirmed_at stamped, the claim held; outstanding_grants falls by one; the adoption query returns nothing for that intent; the transition payload carries the whole AssertedOutcome with reason REPORTED_FAILURE and tier: ASSERTED beside it; the platform's codes are retained as inert text; both answer OK
AL14A post hook with no success at all; one whose body exceeds post_bytes; one whose body will not parseAll three answer OK, settle nothing and leave the row where they found it with impact charged and the claim held; the oversized one is recorded as an unreadable report and no part of output is retained or logged; none of the three is a 4xx
AL15A post hook with content-type: application/json; charset=utf-8, one with application/json, one with Application/JSON, one with two content-type headers and one with content-encodingThe first three are accepted and settle identically; the last two are refused, exactly as the monitoring intake refuses them
AL16A post hook delivered twice; a second UNKNOWN against an INDETERMINATE row; a post hook arriving before its own pre hook; a post hook whose correlation row is a denialThe first two append and retain nothing and answer OK; the early arrival is the orphan case, recorded bounded and answered OK, and its later pre hook still decides normally; the denial case appends exactly one execution.control_point_contradiction to the tenant's chain, a second delivery of it appends none, and both answer OK
AL17A post hook carrying inputs that differ from the frozen ones, and one carrying noneThe difference appends one execution.control_point_contradiction and is retained as inert text; the absent case appends nothing and claims nothing; neither changes the settlement; a tenant holding both kinds still exports and replays with no UNKNOWN_EVENT_SEMANTICS
AL18A correlation row's report secret read out of the table by a reader with no credential, then presented on the outcome route as EXECUTED; then a recovery run after the act windowThe row settles and the run releases the canonical claim, so the theft does free the target — asserted as the guide's stated bound, not as a refusal; the impact stays CONFIRMED and no scope is refunded; the genuine post hook afterwards is answered with the settled view and appends nothing
AL19A governed pre hook and an ordinary agent dispatch against one ceiling with a total and an autonomous rule; and a group ceiling reached across two Arcade projects of one tenantBoth paths charge the same counters in every scope and the ceiling is reached once across them; an approved candidate adds zero autonomous units on both; the project past the hard ceiling is CHECK_FAILED
AL20A grant that never receives a post hook, past its report window, then a recovery run, then the console settlement with an ADMIN-signed record; and eight silent uncertain rows followed by a ninth pre hook, followed by one reported failureSwept to INDETERMINATE with impact charged and the claim held and listed in the uncertain queue; only the signed settlement releases them; the ninth pre hook is CHECK_FAILED with TOO_MANY_GRANTS; the reported failure settles one row terminally and the next pre hook is then answered OK with a grant, which is what says the cap drains on settlement
AL21The extension's deadline expiring while admission is still in flightThe hook answers CHECK_FAILED within the configured budget; whatever admission commits is retained, visible in the uncertain queue and never refunded; no second request is sent
AL22A tenant in OBSERVE through both hooksOK with an OBSERVED row and no reservation, claim or grant; the post hook is recorded and settles nothing and answers OK
AL23An ADMIN and an approver bearer; unknown, expired and revoked bearers; another tenant's bearer; a credential expiring before the report windowThe ADMIN and approver bearers are refused as non-AGENT and audited; the unknown, expired and revoked bearers are refused as unauthenticated and counted; no hook decision is reached in any of those; the foreign bearer reaches only its own tenant's objects; the short credential shortens the report window to its own expiry and its post hook afterwards is refused on identity rather than on the deadline
AL24Configuration validation: an operation_ref outside ActionRequest.operation_ref's own constraint, a toolkit named as both governed and ungoverned, a target.input outside its own inputs list, an incident.input outside it, a duplicate tool declaration, a deployment with an arcade block and no connectors, and a key reload whose file changes the arcade blockEach invalid file is refused at load as the same opaque invalid-configuration answer every invalid file gets; the connector-free deployment loads; the reload is CONFIGURATION_CHANGED and leaves the running keys and the running tool map untouched
AL25The create_arcade boundary, GET /health, and the route inventory with and without an arcade blockEvery method and raw path but the three answers 404 and a websocket is closed; GET /health is served by the application's readiness route, answers 200 with the database up and 503 with it down, is unauthenticated and names no tenant; tests/test_route_authority.py asserts the exact served set in both constructions and the two new routes carry AGENT authority
AL26Migration round trip with correlation rows of each kind and an execution in each settled state retained, including a corrected row whose own state is FAILED_NOT_EXECUTED and whose events name the new state; check_runtime; the runtime role against arcade_hooks; a replayed history containing a settled FAILED_EFFECT_UNKNOWN and a corrected oneDowngrade refuses while any of the three constrained columns holds the new state anywhere — asserted with the corrected row as the only holder, which a check of executions.state alone would let through — and succeeds once none does; check_runtime passes before and after; the runtime cannot DELETE; the export recomputes every decision, reconstructs the impact as CONFIRMED for the asserted failure and NONEXECUTION for the corrected one and reports both as settled rather than unresolved; Ledger.correct is asserted as the narrow method it is; the frozen contract fixtures and the context parity golden stay byte-identical
AL27The fixture Arcade caller over the real HTTP surface, driving every branch and asserting its recorded shapes against execbound_harness.fake_arcade.HOOK_CONTRACTThe walk covers governed permit, denial, approval wait and retry, ungoverned pass, duplicate pre and post delivery, reported success, reported failure, absent success, an oversized body and a missing post hook; the contract dictionary is a module-level constant of the harness rather than a literal inside the test, so the guide, the driver and this walk assert one object and a change to any shape fails in one place
AL28The record and approval pages for an Arcade-carried execution, with real ChromiumTool identity, Arcade user id, reported codes and metadata render as inert text with no control that dispatches; the tier is shown with what it rests on; a settled assertion says what still holds its claim and what releases it; a settled FAILED_EFFECT_UNKNOWN row says the effect was never established and that the impact is charged
AL29The settlement vocabulary, both halves. Every (outcome, reason) spelling on the outcome route, signed and unsigned; TerminalEvidence, ExecutorRecord and JournalRecord asked for FAILED_EFFECT_UNKNOWN and REPORTED_FAILURE; a verifier double returning the new pair, through record_outcome against a dispatched row and through the report route against a grantExactly five pairings validate and exactly ten (tier, outcome, reason) combinations settle — four verified at ATTESTED, the same four at no tier on the dispatched path, and two asserted — enumerated in the test rather than sampled; every other spelling is INVALID_REQUEST from parse_report with no execution row read, no fence taken and no secret compared; the three evidence models raise for both new members; a report presenting a signed record beside REPORTED_FAILURE is refused by OutcomeReport's own clause, asserted as that refusal; the verifier double is refused by _proof in both call paths; test_the_terminal_aliases_are_the_evidence_literals passes unchanged
AL30A row settled FAILED_EFFECT_UNKNOWN at tier ASSERTED, then an ADMIN-signed CANCELLED_NOT_EXECUTED through reconcile; the same walk with an attested VERSION_MISMATCH; a third where the recovery run released the claim before the correction; and, on a corrected row, the correcting record replayed on the report routeEach settles at the verified evidence's own state — FAILED_NOT_EXECUTED, then STALE_AUTHORIZATION — at tier ATTESTED, with the impact rewritten to NONEXECUTION and confirmed_at null; the claim is released, and in the third walk released_at and the earlier execution.claim_released event are unchanged; the chain holds both transitions with both statements retained and the administrator's reason on the second; an ADMIN drives one correction of each direction from the record page's own control, in Chromium, and the page then shows the corrected row and the statement it corrected; a redelivery of the original post hook afterwards is INVALID_STATE in the kernel, answered OK to the platform and settles nothing, while the correcting record on the same route is the restatement it is. The export clause is parametrized over both correction directions: for each, the ledger recomputes with no INVALID_IMPACT_HISTORY and no INCOMPLETE_HISTORY, ReplayReport.complete is true, and the exported row's settlement_tier and terminal time are the correction's
AL31Everything the correction refuses: an ADMIN-signed EXECUTED against a correctable row; an ADMIN-signed non-execution against an EXECUTED row at tier ASSERTED and at tier ATTESTED; against an already-corrected row; against a row ExecBound dispatched; a second correction; a report carrying a record presented against an uncorrected correctable row; and a row whose retained state, tier or reason is not the correctable trio, each of the three varied on its ownEvery one is INVALID_STATE, audited by _rejection and leaving the row, its impact, its claim and its tier untouched; the promotion the checkpoint guide's note refused is still refused with the same code; the report route produces no correction, so a held report secret corrects nothing. Four refusals are asserted individually, because a mutation of any one alone fails nothing: _correctable's state fact and its tier fact, each varied while the other two hold, and each of the two direction guards removed by name
AL32The granting-path latency measurement: the eligible pre hook end to end against the fixture caller and the protected mocks, at one, four and sixteen concurrent callers of one tenant, with the reservation, the canonical claim, an approval consumption, the executor key ring load, the closing attestation check and the secret mint inside the timed regionMedians and a maximum reported beside scripts/admission_benchmark.py's denied-path figures for the same concurrencies; the arcade block's required deadline_seconds is defended against the measured maximum rather than against a default, and a deployment file omitting it is refused at load
AL33A tenant whose only executor key is revoked as compromised, holding a live grant issued before the revocation: an attested report, then a bare success: false, then a recovery run past the act window, then an attempted correction with a newly registered keyThe attested report is refused and settles nothing; the bare word settles FAILED_EFFECT_UNKNOWN at tier ASSERTED with the impact confirmed; the run releases the canonical claim; the correction is refused because no key is usable at that grant instant, and a key registered after it is refused too — asserted as the guide's stated bound, not as a refusal the guide claims to make
AL34A governed tool declaring an incident key and mapped to endpoint.isolate under the released endpoint-isolation.v1, driven end to end: a hook claiming the target's own open critical incident; then hooks claiming an id naming nothing, an incident of another resource of the same account, and an incident of another tenant; then one claiming a second incident of this tenant standing against the same targetThe first is {"code": "OK"} with one DISPATCH_COMMITTED row and one UNRESOLVED impact, and the frozen plan carries the claimed id with the contract's incident facts naming it as their source object and nothing set in the claim beside it; the three misdirected claims are each CHECK_FAILED with nothing resolved, reserved or claimed; the second incident of the same target is granted, which is the guide's stated bound — the kernel binds a claim to the target and not to relevance — asserted rather than implied
AL35A governed call the tool map refuses, delivered three ways: an undeclared tool with a usable Arcade execution id, an undeclared input with another, and an undeclared tool whose execution id falls outside the kernel's idempotency class; then a legitimate call reusing the first refusal's idEach of the first two leaves a correlation row carrying the toolkit, the tool and the version refused, with decision CHECK_FAILED, no execution and no report secret; the unkeyable one is answered and recorded nowhere; the tenant's audit head is unmoved across all three; and the reused id grants, so a refusal row is not a tombstone

GC7, GC8, GC10, GC12 and GC13 are re-run as part of this group's evidence, and what they establish is that the checkpoint's own behaviour still holds; GC14 and GC17 are extended above, because without a FAILED_EFFECT_UNKNOWN or corrected row neither could detect a defect in that state. Provider-specific proof, the live half of the hook contract and every claim about how a real Arcade deployment behaves are not covered by these rows; the 18 September 2026 trial records what a real Arcade deployment was seen to do.

Assistant​

The engine's rows are tests/test_assistant_client.py, tests/test_assistant_turns.py, tests/test_assistant_tools.py and tests/test_assistant_loop.py; CI never calls a model, a scripted transport replays every provider answer.

IDSetup/actionRequired result
AS1A private configuration without an assistant block; with one; with the key in the environment, in the block, in both, in neither; a tenant with the switch offWithout the block runtime.assistant is None and assistant_enabled is false; with it the caps and model load and the key appears in no repr; boot merges the key from EXECBOUND_ASSISTANT_API_KEY when the block carries none, refuses both and neither naming the variable and never the value, and scrubs it; a turn for a tenant whose switch is off is refused ASSISTANT_OFF; an ADMIN sets the switch with a reason and it is audited, a no-op and an approver are refused
AS2The runtime role against assistant_turns; a person's turns read by another person and by an agent principalINSERT, UPDATE and DELETE are refused; every write goes through a definer function that checks the actor owns the turn; another person reads nothing and cannot step the turn; an agent can own no turn
AS3An approver with one scoped pending request and one execution outside the scope; the administratorThe approver's list holds the scoped request only; its detail carries the frozen intent, the facts with sources, the approval with its deadline and the kernel's decision events; the other execution is found: false; the administrator lists both
AS4Every tool called with an unknown name, a missing or extra argument, a wrong type, a bad uuid or a value outside its boundsRefused as UNKNOWN_TOOL or INVALID_ARGUMENTS before any read; every tool's wire schema is strict with no additional properties
AS5An agent label carrying instructions; a scripted answer carrying a Markdown image, a link and an id no tool returnedThe label reaches the model inside the untrusted envelope only; the answer is stored as text and cites only the id a tool returned
AS6A credential-shaped string in a tenant label read by a toolThe turn fails REFUSED_SECRET, is audited, and the transport recorded nothing carrying the string
AS7An explanation of an approval whose scripted answer recommends a decision; one that explainsThe first is FAILED/RECOMMENDATION with no answer stored; the second completes citing the approval; an approval the person cannot read is refused before any model call
AS8A completed turn read back, retired at 29 days 23 hours and at 30 daysSteps, answer, cited ids, tools and token counts are whole; retirement nulls the text at thirty days, keeps the counts, and is an ADMIN's call; assistant.asked carries the turn id, tools, counts and model and no question or answer
AS9Nine tool calls; output past the token ceiling; a provider slower than the turn's limit; a rate limit then success; a bad request; a turn left running for ninety seconds; the hourly and daily capsTOOL_LIMIT, TOKEN_LIMIT, TIME_LIMIT each once with nothing retried past the bound; one retry for the rate limit and none for the bad request; ABANDONED persisted on the first read; PERSON_LIMIT and TENANT_LIMIT counted in the creating transaction
AS10A console with no assistant block; with one and the tenant switch off; with one and the switch onWithout the block every assistant address answers 404; with it and the switch off a turn is refused ASSISTANT_OFF and the list answers empty; with the switch on a turn is created and answered
AS11Every assistant route with a bearer credential, with no session, and with another person's turn id403 and audited for the credential; a typed 401 in JSON for no session, even to a browser; 404 for another person's turn on the read, the stream and the opened mark
AS12The four constructions of the application: plain, with an arcade block, with the console, with the console and an assistant blockEach serves exactly its inventory; the assistant block adds its seven routes and nothing else, and all seven are session routes
AS13A turn watched as it gains steps, one already finished, and one still running at the stream's deadlineOne step event per step, each once, then one done event carrying the ending; a finished turn is one done and no wait; the deadline closes the stream saying what the row says
AS14Every packaged help text against the document it summarisesEach phrase that carries a claim appears in the text and in that document; each text is one bounded paragraph and carries no advice about a decision
AS15The recover sweep over a tenants fileEach tenant's report carries assistant_turns_retired beside its settlements, because the administrator and tenants-file runs retire through retire_turns, while on the schedule retirement rides on recover_scheduled (SJ2)
AS16A draft written as rules, and a scripted proposal the compiler acceptsThe answer is the rule as the form takes it, its sentence, and its conditions in the words the editor parses, which parse back to the same conditions; no bundle is created or changed; the turn is the asker's own, completed, carrying the rule's sentence
AS17Proposals naming an unknown fact, a value outside its domain, an action the draft does not map, an id the draft already uses, an impossible effect or quorum, and answers that are not a rule at allEach is refused INVALID_PROPOSAL with the field that caused it, the turn reads failed, and nothing is written
AS18The route as an approver; for a bundle written as a document; for a validated bundle; for a bundle of another tenant; with a bad body403 for the approver; the store's own refusal for a bundle with no rules to add to and for one that is not there, neither reaching the model; 400 for a body the model of the request refuses

Spaces (SP1 to SP22)​

Separation of ownership and view inside one tenant. A space is not isolation: forced row-level security is a second line of defence for tenants and there is no second line for spaces, so SP1 is the whole of the mitigation for a forgotten predicate and takes its parameter list from the migration's own column list.

IDSetup/actionRequired result
SP1Two spaces with rows in every space-carrying table; a member of one reads every list, count, chart, search and detailParametrized over every table the migration touches: nothing of the other space is returned, on any surface, in either role
SP2"All spaces"A tenant administrator sees both; a member of two spaces sees the union of theirs and nothing else; a member of one is offered no "All spaces" entry
SP3Membership restrictsA tenant administrator given a membership is narrowed at once; the ADMIN space role is refused for a HUMAN_APPROVER principal; the last tenant administrator cannot be narrowed away
SP4The current space is a preferenceRemoving a member while their session holds the space refuses the next read; session_set_space refuses another tenant's, an archived-but-unseen and an unknown space alike
SP5SharingAn offered account and an offered bundle are usable by another space and editable, retirable and un-offerable only by the owner; an unoffered one is invisible and a mapping on it is refused at admission
SP6Per-space policy selectionTwo spaces select two bundles; each agent is admitted under its own; a bundle no space selects retires; a bundle a space selects cannot be retired; ACTIVE equals "named by a selection row" after every transition
SP7LimitsA tenant rule counts across spaces; a space rule counts only its own retained rows; an approved candidate is exempt from autonomous and charges total in a space scope as in every other; a missing or doubled qualifier fails validation with its field location
SP8The tenant-wide claimSpace A's unresolved claim refuses space B's execution on the same canonical target with today's conflict and nothing about A on the wire or the page
SP9The archive raceAn archive and a decision run concurrently on real PostgreSQL; exactly one commits; an archived space refuses new work with SPACE_ARCHIVED at the stop's check point; a DISPATCH_COMMITTED execution is not cancelled by an archive
SP10Migration round tripThe default space holds everything; every column is backfilled and every CHECK holds; approvers gain memberships and administrators do not; the selection moves off the control row; downgrade refuses with two spaces and otherwise restores the column, the grant and the index; check_runtime passes; the endpoint and identity contract goldens and every frozen fixture are byte-identical
SP11Console APIThe harness's two sweeps on every route; a member is 403 on every administration route; a cross-tenant or unknown space is 404; /session/space answers the fresh session view; the secret check over every fixture response
SP12The console in ChromiumThe switcher in both schemes at 1280 and 390 px, axe clean with zero CSP or Trusted Types violations; the popover reachable and dismissable by keyboard alone; a switch clearing the cache and re-reading every count; an approval link, typed or followed from the Activity drawer while another space is open, opening in the space that owns it; a space named with markup rendered as text
SP13ReplayA space candidate rule reconstructs from captures; captures with no recorded space report UNKNOWN_SPACE and stay UNRESOLVED while the baseline still matches; report.json stays deterministic
SP14AuditEvery administration act appends its event under the tenant's one chain and head; the chain is not split; a space switch appends nothing; an owner command and the console write the same event with the same payload, except that the console's also names the credential that acted (actor_credential_id, a browser session's own or a personal access token's backing credential) and an owner command, which acts over the owner connection with no credential, names none
SP15Keys of a space's agentsAn administrator seated as ADMIN in one space issues, revokes and deletes the keys of an agent of another space, also when seated there as an approver, through the pages' functions and the console API; then the same for an agent of their own space; a workspace administrator in both; a person seated only in the other space; the credentials page and GET /credentials read by each; migration 0071 applied and rolled back
SP16Another space's agents and scopesAn administrator seated as ADMIN in one space labels, deactivates, reactivates, binds and unbinds an agent of another space, also when seated there as an approver, through the definer functions and the console API; binds their own agent to a discovered agent of another space's connection; withdraws an approver scope of another space and assigns the same approver, target and action in their own; then each for their own space's agent and scope; a workspace administrator in both; migration 0072 applied and rolled back
SP17People outside their spacesThe same administrator issues and revokes a credential, labels, deactivates and reactivates, sets the sign-in address, mints a set-password code, invites, links and unlinks a directory account, revokes a directory invitation and ends the sessions of a person seated only in the other space, of one seated in both, of one seated nowhere, of one managed by the access model and of a member of an access group; revokes and deletes a workspace administrator's personal access token; the console's People routes for the first; then each for a person seated in their space alone, their own token and another of their space's administrators'; a workspace administrator on each refused person
SP18What a space administrator is shownThe People list, a person's page, the credentials page and the workspace's token list, read by the space administrator and by a workspace administrator looking at all spaces and at one
SP19Adding a personThe space administrator creates an approver with New approver and with the credentials page's new:HUMAN_APPROVER, then labels them, sets their address, mints a code, issues and revokes a credential, and deactivates and reactivates them; then, seated as ADMIN in two spaces and looking at both, creates another
SP20The tenant's own identity providerAn administrator seated as ADMIN in one space registers a provider, enables a verified one and disables an enabled one under which a person holds a directory session, through the store, the definer functions and the console API, and names a provider that does not exist; signs in through a draft and through a verified provider by the store and by the self-link route, and through a draft by directory_link_self itself, as do, through a draft by directory_link_self, an approver seated in a space and one seated nowhere; links their own account through the enabled provider; then a workspace administrator each; migration 0073 applied, rolled back and applied again
SP21The workspace-wide settingsAn administrator seated as ADMIN in one space changes the enforcement mode, the approval deadline and the emergency stop through the store functions, resumes a stop a workspace administrator activated, turns the assistant on and off, and sets the organization's MFA requirement through mfa.manage_security and through account_security_change and user_security_change themselves with a factor verified on that session; the same through the console API, the command line and Account security; then reads each setting; then a workspace administrator each; migration 0074 applied, rolled back and applied again
SP22The workspace's requests and reportsAn administrator seated as ADMIN in one space reads the data and closure requests queue, which holds a request each from an approver seated only in another space and one from a workspace administrator, and records a response to each of the three kinds, a workspace closure included, through the store, through account_change itself and through the console API, reading the queue by a session and by a personal access token; runs observe-report and rotation-readiness through the functions and the command line; files and reads their own requests; then a workspace administrator each; migration 0075 applied, rolled back and applied again

SP12 is tests/test_browser_console_spaces.py, in real Chromium, beside console/src/shell/switcher.test.tsx and console/src/components/spaces/spaces.test.tsx for the components' own behaviour.

Guided console setup​

IDScenarioRequired result
UX1Run all three safe examplesCedar evaluates synthetic facts; allow, deny and approval appear; no execution is created; ADMIN session, Origin and CSRF checks run before evaluation
UX2Connect and verify a named agentCredential appears once, public host configuration contains no secret, verification reads actual scoped request history, and Activity opens with the selected agent filter
UX3Empty Space and paginated discoverySetup uses registered agents in the current view, includes bound agents, and exposes continuation instead of inferring tenant-wide completion
UX4Set up a reviewerNamed account and normal sign-in setup precede explicit review permissions; legacy credentials remain inspectable but are not normal issuance choices; disabled directory providers do not imply usable sign-in
UX5Read stale or uncertain executionPolicy cause, execution evidence and next action remain separate; recorded specific causes survive generic codes; uncertain effects never advise blind retry
UX6Start and edit policyNamed starts preserve denials, mappings, context and limits; unsupported conversion is refused; creation requires selected-Space ADMIN access and available accounts/source bundles; drafts retain that Space; validation, preview and activation remain separate; activation leaves other Spaces' selections unchanged
UX7Connect a monitoring sourceTines and Entra connect from the console keep a provider key out of every place but the sealing request; the operator path keeps it outside the browser. Registration requires ADMIN access to the target Space; verification distinguishes awaiting sync, reporting, stale/error and revoked states from persisted scoped evidence
UX8Navigate and cancel setupBoth themes and phone layouts pass accessibility/CSP checks; phone navigation reaches setup pages; a form with no available choices can be closed; unavailable clipboard access gives manual-copy guidance
UX9Read setup progress for a SpaceAn administrator of that Space reads five milestones, each from a record with its identifier; another Space's records tick nothing; an approver, an agent credential and a reviewer-role administrator are refused; the read writes nothing
UX10Return to Getting startedIt opens on the first unfinished step; the step survives a reload and the browser's Back; done steps show a tick and a time; without the read it opens as before
UX11The sidebar card at 1280 by 800It says how many required steps are done and which is next, collapses to a row when all are done or when hidden in this browser, and Sign out stays in view without scrolling
UX12An empty Space with no connectionHome, Connect an agent and Policies say requests are refused until a connection and a policy exist, offer samples only in the default Space to a workspace-wide administrator, say elsewhere that samples go to the default Space, and otherwise give the operator's commands (self-hosted) or the service operator's address (hosted)
UX13Wait for an agent's first requestThe panel asks only while the tab is visible and stops ten minutes of wall-clock time after it started, offers Resume, names no cause, and on arrival shows the state, the reference and a link to the record
UX14Connect a Tines storyThe two downloads are the committed files byte for byte; the steps name the credentials and resources the stories reference; no key, origin or tenant id is in a file
UX15Pilot in Observe onlyThe card says a policy is still required, that the mode is workspace-wide and that samples need Enforcing; the change goes through the reasoned dialog; observed decisions are counted apart and linked
UX16Empty pagesAgents with no agents and Activity with no requests say so and name the next action; filtered views keep their filtered wording, and so does a Space whose own agents are all asleep, which the default State hides, while a Space with no agents still says so when another Space's agents sleep
UX17CaveatsEach caveat is one disclosure away; the stale and lapsed notices still show whenever their condition holds
UX18Start by watching/monitor?setup= opens setup only for the two providers; the watch-first line shows on Home and under Connect an agent in this edition, and the Discover card links Monitoring setup
UX19Which actions nobody can reviewWith access.manage, the review card lists each mapped action the decision coverage read reports with no eligible reviewer, by action and never by target; each fix opens the existing prefilled assignment dialog and sends nothing until confirmed; a custom policy's unknown coverage reads "Coverage unknown for this policy" with no fix; without access.manage, no call is made

Evidence lives in the focused console component tests, tests/test_console_learning.py, tests/test_console_api_agents.py, tests/test_console_policy_usability.py, tests/test_console_policy_spaces.py, tests/test_console_api_monitoring_setup.py, tests/test_monitoring_setup_commands.py, tests/test_browser_console_directory.py, tests/test_browser_console_policy.py, tests/test_browser_monitoring_setup.py and the hosted service's own tests of its welcome page. UX9 to UX18: tests/test_setup_progress.py and tests/test_console_api_setup.py for the setup read on real PostgreSQL, with their Space boundaries mutation-checked; tests/test_console_api_agents.py for the agents' newest request; tests/test_console_serving.py, tests/test_tines_story.py, tests/test_tines_gate_story.py and tests/test_wheel_licences.py for the Tines stories and their license; tests/test_browser_console_setup.py and tests/test_browser_console_samples.py in Chromium; and the Vitest cases in console/src/components/welcome/ (setup.test.ts, WelcomePage.test.tsx, NextStep.test.tsx, OperatorSteps.test.tsx, NoConnectionHint.test.tsx, AgentConnection.test.tsx, TinesStory.test.tsx, PilotCard.test.tsx, SampleChecks.test.tsx), console/src/shell/ (StartedCard.test.tsx, shell.test.tsx), console/src/routes/ (-welcome.test.tsx, -help.test.tsx, -activity.test.tsx), console/src/components/monitor/ (search.test.ts, MonitorPage.test.tsx, MonitorSetup.test.tsx), console/src/components/directory/agents.test.tsx and console/scripts/stories.test.ts. UX19: console/src/components/welcome/ReviewCoverage.test.tsx, over the decision coverage read's response model, with its Space, reviewer-count, permission and custom-policy predicates mutation-checked.

Console: residual acceptance​

Console requirements an audit on 23 September 2026 found only partly tested, each now held by a test. CR4 found one real failure, since fixed: the review-workspace page's "Stay in the current workspace" link sat under its button below the 24 px minimum target (WCAG 2.2, 2.5.8).

IDSetup/actionRequired result
CR1Every console API route in the route inventory, with an agent's bearer credential and with no sessionRefused 401 or 403 with FORBIDDEN or SESSION_REQUIRED and audited once as that agent; without a session, 401. One application walks all of them, so a route added later is held to the same answers
CR2Every console API GET, as an administrator and as an approver, with a held request in the tenantNo answer carries a secret or sets a cookie, and none is a server error; the board's stream is left to its own tests
CR3Another tenant's approver, holding the real continuation of a held requestThe queue and the decided list are empty, the detail is 404, the decision is refused as INVALID_CONTINUATION, the approval is still held and nothing reached the provider
CR4Every navigation entry at 390 px in both schemes; Ask, a turn and a monitored agent's page in dark and at 390 px; the workspace review route at 1280 px and in dark at 390 px; the phone's navigation sheet, the bell's panel and the keyboard list in both schemes at 1280 and 390 pxaxe-core finds no WCAG 2.2 AA violation, the browser reports no policy or Trusted Types violation, and nothing scrolls sideways
CR5An agent labelled with markup, on the Agents pageThe label is the characters it is, no element it describes exists, and nothing it names ran
CR6The command palette's arrow keysThe selection moves down and up over the entries a keyboard can land on, skipping disabled lines, and Enter opens the one it rests on
CR7The copy the reconcile dialog and the workspace switcher show for a refusalThe client's own sentence per code, a fixed line for an unknown code, never the server's detail, and a failure to reach the server for anything without a string code
CR8A page component that throws, on an approval route and elsewhereThe page's error boundary inside an intact shell; the basic approval page link only on an approval route; Retry renders the page once it no longer throws
CR9A response through the generated client carrying a newer release than the build'sThe banner appears in the shell, the page still has its data and the navigation still works; the same release shows nothing
CR10The countdown ring and the sparklineThe ring's arc is the fraction left, turns to the deny colour at a quarter and clamps at both ends over a token-coloured track; each sparkline point sits by its value between the line's own low and high

Tests live in tests/test_console_api_walk.py (CR1, CR2), test_console_api_approvals.py (CR3), test_browser_console.py, test_browser_console_monitor.py, test_browser_console_shell.py and the hosted service's own tests (CR4, CR5), and in the console's own CommandPalette.test.tsx (CR6), lib/errors.test.ts (CR7), RouteError.test.tsx (CR8), shell/release-in-shell.test.tsx (CR9) and charts/charts.test.tsx (CR10).

Sample targets (SM1 to SM11)​

One click in guided setup gives an empty workspace a real first governed action: a sample connection to the endpoint mock, three sample targets and the starter policy, so the person's own agent sees an allowed request execute, a denied one stop and one wait for their approval and then execute. The administrator's demo configuration for the samples lets execbound-demo run its boundary and approval beats on them from the administrator's own machine. Real PostgreSQL throughout; SM1 runs under an owner with the hosted owner's attributes, SM5 and SM11 against the endpoint mock as a process of its own and SM7 in real Chromium.

IDSetup/actionRequired result
SM1Install as a workspace's administrator, under an owner that is NOSUPERUSER and NOBYPASSRLS with forced row security; install againExactly one sample connector account with sample set, its sources, the endpoint.isolate mapping, three canonical targets with resources, identities, two aliases each, an open critical incident each and the installer's review scope, and the starter bundle created, validated and activated, with samples.installed and the bundle's lifecycle events naming the administrator; the second install changes no row, appends nothing and logs nothing; replay reads the history as complete
SM2Install for a workspace with a selected policy, with an active connector account, with someone else's endpoint.isolate mapping; as an approver; with a malformed target set; on a deployment without a sample key; for a workspace the gateway's configuration holds a connector for; by an administrator switched off while the call waits on the tenant fenceEach refused with its code (SAMPLES_NOT_OFFERED in the console, SAMPLES_UNAVAILABLE without a key or beside a configured connector, FORBIDDEN for anyone but an administrator) and no row written; a sample account in a tenant holding a configured connector gets no derived connection, so its request is refused at admission and nothing is sent; an approver still sees the samples, their requests and their badges
SM3Derive the dispatch token, the control token and the journal keyFixed known answers for a fixed key, tenant and account; a value derived for one tenant or account differs for any other; the three labels never give the same value; the tokens take the form a generated token takes; a sample key is 32 to 128 bytes of lower-case hex and anything else is refused
SM4The endpoint mock holding a sample keyA derived sample account executes and its journal verifies with the derived key under sample-v1; a mismatched tenant, account, key or role answers 401; a sample account's target is created on first sight at sample-resource-v1 and a configured account's never is; configured accounts behave exactly as before; an unusable key stops the mock at start
SM5A workspace made through the owner commands, its administrator signed in with a password, two agents over HTTP, the mock as a real processThe development workstation executes and the provider's signed journal verifies with the derived key, with no settlement tier; the domain controller is denied with nothing sent; the production workstation waits, is approved by the person and executes; the shared limits count the sample requests across agents; replay reproduces every decision and touches neither the mock nor its journal; a lost response settles from the mock's journal by reconciliation
SM6Remove with an executed and a denied request on record; with a request attempted, pending approval, reserved, dispatch committed or indeterminate; after the person activated a policy of their own; with no samplesEvery sample row deactivated and none deleted, the history kept, the unchanged starter bundle deselected and retired, samples.removed logged once, and install offered again; the status with nothing written and nothing logged without samples; SAMPLES_BUSY with nothing changed while a request is unresolved; a policy the person activated stays and install is not offered again
SM7In real Chromium at 1280 and 390 px: add samples from Home's guided setup, refresh them, have an agent make a request, open Verify protection and Activity, removeThe card lists what it adds, then the three targets with a Sample badge and the starter policy's reading; after the refresh the card shows the three targets again, read afresh, and a notice that each has a new incident; the request executes; Verify protection shows it as the first request and suggests the other two targets, the production workstation as the request to relay with its operation, hostname and incident and with the workspace's approval deadline, and the domain controller with what the agent is told of a denial; Activity shows it with a Sample badge; removal asks first and offers the samples again; axe finds no violation, the browser reports no policy violation, nothing scrolls sideways and no secret reaches the page
SM8Migration 0060_sample_targets up, down and up again; the runtime catalogconnector_accounts.sample and the two definer functions, EXECUTE only for the runtime role and no new table write; the downgrade refuses while any sample account exists; check_runtime passes
SM9Refresh as a second administrator with a denied request and another reviewer's scope on record; with a request attempted, pending approval, reserved, dispatch committed or indeterminate; with an approval that lapsed and was not yet ended, and after it is ended; while a person's copy of the starter exists, as a draft, validated and then active, and when the person creates one while the refresh waits on the tenant fence; while a second space selects the starter; after the person added a connection of their own; with no samples; without a sample key; as an approver, an administrator seated in a space and a personal access token; with a held request on the tenant fence, in either order; on stale factsOne transaction removes and installs: the same three hostnames with new canonical ids and incidents and facts recorded now, the old starter retired and a new one active, review returned to the refreshing administrator alone, the first request counted afresh and every request kept, the removal's three audit events and the install's five naming the refreshing administrator and their credential, samples.refreshed logged and replay complete; SAMPLES_BUSY with nothing changed while a request is unresolved, a lapsed approval included until it is ended, and a refresh once it is; POLICY_PRESENT (SAMPLES_NOT_OFFERED in the console) before anything is removed while a person's copy names the sample account, which stays usable, or while a second space selects the starter, which both spaces still select; ACCOUNT_PRESENT with the removal rolled back; the status with nothing written and nothing logged without samples; SAMPLES_UNAVAILABLE without a key; FORBIDDEN and TOKEN_NOT_ALLOWED with nothing changed, the seated administrator refused before the refresh reads for a person's policy; the route refuses a missing CSRF token, another origin and an unknown field; request first, it is held and the refresh refused SAMPLES_BUSY, refresh first, the request is refused EXECUTION_UNAVAILABLE, and neither leaves an unresolved request on a switched-off account; a request on stale facts is refused EXECUTION_UNAVAILABLE with no execution until a refresh, after which the new incident is admitted and the replaced one refused
SM10Guided setup and the connection card with samples installed: the request to relay, with and without the operation; a mapping the starter names that is not live; stale facts, including a page left open as they go stale; the approval deadline on and off, and an agent key that expires before the facts; a pending approval on the held target; a lapsed one before and after the recovery run ends it; a lapse followed by a second agent's newer pending request, and by a newer request that executed; the domain controller's denial; the need for a new reference; the Sample targets card before and at stale_at, with the browser's clock wrong either way, refreshing, a refresh that finds the samples removed, and a refused refreshGET /api/console/v1/connection names the operation_ref read from the live mapping row the starter bundle names for the samples, never assumed from the catalog action (for the samples both are endpoint.isolate), and null without samples or while that mapping is not live, and no module of guided setup spells the operation; each target's request reads "call execute with operation_ref …, target hostname … and claimed_context.incident_id …", and names the target and its incident alone until the operation has arrived; stale facts are said to refuse every request until refreshed, within half a minute of stale_at on a page left open, with the way past a policy made from the starter (retire it in Policies, activating the starter again first where it is the active policy); the deadline is the tenant's deadline.seconds, null when off where the session reads 120, and a request never waits past stale_at: with the deadline off an approval ends at stale_at, or at the agent key's expiry where that comes first; the newest pending approval on the held target made since the facts were recorded is linked at its own address with its closing time, else a lapsed one that nothing has ended yet, with when it lapsed, that the agent that made it ends it by sending the same request again, after which a new request with a new reference waits for a new approval while the facts are current, and that otherwise the recovery run ends it; an ended one is never named, nor a lapse once a newer approval is pending; the domain controller's line carries the bare-denial sentence; a line under the targets says each new request needs a new reference, a recorded one bringing back the request recorded under it whatever incident it names, with reference as code; the Sample targets card shows a Stale badge from the moment the server's clock reaches stale_at, and within half a minute on a page left open, offers Refresh sample facts with what a refresh re-creates said beside it, the new reference the refreshed targets need among it, holds both buttons while a sample request waits and until the samples have been read again after a change, shows the samples as read again rather than the refresh's own answer, says there was nothing to refresh where the samples were removed first, and words SAMPLES_BUSY and SAMPLES_NOT_OFFERED from a refresh as a refresh that changed nothing, the second with the way past a policy made from the starter
SM11The demo configuration for a workspace's samples: download it as their administrator before adding them, with the tab's session generation and another session's, with a query key it does not take and after removing them; as an administrator signed in to an account, with no generation, another session's and the session's own; as an approver, with an agent's key, with no session and with the administrator's personal access token; on a deployment that holds no sample key, and on one that holds a configured connector for the workspace; with the starter's isolation mapping switched off or renamed, with the denied or the allowed target's incident closed, with a policy a person activated selected in the starter's place and with the workspace observing; under the workspace's emergency stop and after its release; after the person's agent has had the domain controller denied, the production workstation held, then approved and executed, and the development workstation executed, and after a refresh; once the sample facts have gone stale, and after a refresh; on a deployment whose endpoint mock is published, beside a loopback and a public console origin; with a document the secret check refuses; and the configuration built from a status for each of those, for one with a request unresolved, for one with any named target changed at the provider, for one read with a request on the sample workstation left in each execution state and for one read just before and at the instant its facts go stale, and beside a public and a loopback console origin, for a public and a loopback endpoint mock. Then, the console served over real HTTP, download it signed in, add one agent's key file and the mock this machine reaches, and run execbound-demo all, then budget, then read the status and the download, then a second decide, then decide again after a refresh and a fresh download; run all on a samples file naming a mock, or a gateway, this machine cannot reach; run decide on a samples and on a fixture file whose first request is refused for unavailable context, for a key the gateway does not accept, under an emergency stop, for a space with no policy and as busy; and load a samples file naming another hostname, a target by another kind, an admin key file, no agent_a file or an unknown workspace, one naming agent_b beside agent_a, a fixture file naming agent_a alone, and a samples or fixture file naming a loopback mock, beside a loopback gateway and beside one published elsewhere, whether the file or EXECBOUND_URL names itGET /api/console/v1/samples/demo-configuration answers 404 NOT_FOUND without samples and after their removal, and with samples whenever the demo could not run on them: on either deployment, which also refuses their refresh SAMPLES_UNAVAILABLE, while the mapping is not live, while a named target has no open incident, while a person's policy is selected in the starter's place or the workspace observes, though the hosts still carry their open incidents and the starter's effects, and while the emergency stop is active, when admission refuses the workstation isolation TENANT_STOPPED, each with GET /samples answering demo_available false and demo_needs_refresh false, and once the stop is released the file is handed out again; after the agent's denial both stay as they were, while its production request waits both are false, and once that request and the workstation's have executed demo_available is false and demo_needs_refresh true until a refresh, after which the file is handed out again; from the instant the facts go stale, when admission refuses the workstation isolation EXECUTION_UNAVAILABLE, demo_available is false and demo_needs_refresh true until a refresh, after which the file is handed out again; a request on the sample workstation left EXECUTED, DISPATCH_COMMITTED, INDETERMINATE or FAILED_EFFECT_UNKNOWN counts that target as changed and one in any other state counts none, so a settled one of those four holds the file back with a refresh to offer, an unresolved one holds it back with none, and any other leaves it offered; otherwise, with demo_available true, an attachment named sandbox.json under Cache-Control: no-store holding no credential and no secret: "workspace": "samples", the console's origin, the tenant, the endpoint mock's origin unless it is a loopback address, whatever the console's origin, and never the console's, and the allowed, denied and held sample targets by hostname with their open incidents, with an empty pool; another session's generation answers 409 WORKSPACE_CHANGED, and so does an account session's download without its own, which with it gets the file, an unknown query key 400, an approver 403 FORBIDDEN, an agent's key 403 audited, no session 401, and the token the same document its owner gets; a document the secret check refuses answers 503 UNAVAILABLE with nothing of it in the answer, logged once as dependency.unavailable with the code PRIVATE_DATA and nothing of what it found. The demo loads that file as samples, never as synthetic fixtures, with agent A's key alone. all runs boundary and decide and says that budget was not run: the agent's key opens the agent routes and nothing else and the endpoint mock refuses it; the workstation executes once and its retry returns the same execution, the domain controller is denied, a claim of the domain controller's incident on the workstation is refused EXECUTION_UNAVAILABLE, the agent's own approval is refused, and the production isolation waits, is approved by the administrator who added the samples and executes; the mock records two calls, every intent the run puts on the wire, refused ones included, names a sample hostname and none carries synthetic_demo, and no key is printed or recorded. budget exits 2 with nothing written; the status then says demo_needs_refresh and the download answers 404, the second decide exits 2 saying the workstation isolation ended STALE_AUTHORIZATION because a sample target has been isolated since its facts were recorded, and to refresh the sample facts and download again, and after that it runs. A refused first decide request exits 2 on either kind of file, recorded with its status and code and naming them, and says to refresh the facts only for EXECUTION_UNAVAILABLE: a key the gateway does not accept says to issue a new one, the emergency stop that it refuses every new request until an administrator lifts it, a space with no policy that it has none, and on samples to use an agent in the default space, and any other code points at the agent API reference. A mock or a gateway this machine cannot reach fails boundary with exit 2 and no traceback, the beat recorded as failed with the unreachable request and naming what could not be reached, and all stops there. Each such file is refused before anything is sent, the samples file naming agent_b too loads and the fixture file naming agent_a alone is refused, a loopback mock loads beside a loopback gateway and is refused beside any other, and the recording driver, which needs an administrator's credential, refuses a samples file

Tests live in tests/test_samples.py (SM1, SM2, SM6, SM9, and SM11's configuration built from a status and the status read with a sample request in each state), tests/test_samples_schema.py (SM1, SM2, SM6, SM8), tests/test_sample_accounts.py (SM3), tests/test_sample_mock.py (SM4), tests/test_samples_end_to_end.py (SM5), tests/test_console_api_samples.py (SM2, SM6, SM9, SM10 and SM11 through core's console API with no plugin loaded, reading the status from GET /api/console/v1/samples), tests/test_console_api_connection.py (SM10), tests/test_demo_command.py (SM11, the demo run against a served gateway and the samples mock) and tests/test_browser_console_samples.py (SM7, against a gateway that loads no plugin), with tests/test_sample_runtime.py for the gateway's configuration and connection resolution, and the console's WelcomePage.test.tsx (SM10, and SM11's link on the Sample targets card, shown only with demo_available while the facts are current by the card's clock and naming the tab's session generation, and its refresh advice in the link's place with demo_needs_refresh or once the facts go stale, the page left open included), SampleChecks.test.tsx and RequestToRelay.test.tsx (SM10), RecordTable.test.tsx, policy.test.tsx and agents.test.tsx for the components.

SM9 is held by tests/test_samples.py::test_sm9_refresh_records_the_samples_again_in_one_transaction_with_both_audits, ::test_sm9b_refresh_is_refused_while_a_sample_request_is_unresolved, ::test_sm9c_a_refresh_is_refused_rather_than_break_a_persons_policy_or_connection, ::test_sm9d_a_lapsed_approval_holds_the_refresh_until_it_is_ended, ::test_sm9e_a_refresh_and_a_held_request_on_the_fence_never_strand_the_request, ::test_sm9f_stale_sample_facts_are_refused_before_any_plan_until_a_refresh, ::test_sm9g_refresh_refuses_whom_install_refuses_and_writes_nothing_without_samples, ::test_sm9h_a_starter_copy_created_while_a_refresh_waits_on_the_fence_holds_it_off and ::test_sm9i_a_refresh_is_refused_while_a_second_space_selects_the_starter; by tests/test_console_api_samples.py::test_sm9_api_an_administrator_refreshes_the_sample_facts, ::test_sm9_api_refresh_without_samples_or_a_sample_key_adds_nothing, ::test_sm9_api_refresh_is_refused_while_a_persons_copy_of_the_starter_names_the_samples, ::test_sm9_api_an_administrator_seated_in_a_space_may_not_refresh_the_samples, ::test_sm9_api_a_token_may_not_refresh_the_samples, ::test_sm9_api_refresh_waits_for_a_held_request_and_for_its_lapsed_approval_to_end, ::test_sm2_api_an_approver_sees_the_samples_but_cannot_add_or_remove_them and ::test_sm_api_the_routes_take_the_guards_every_mutation_takes. SM10 is held by tests/test_console_api_samples.py::test_sm10_api_guided_setup_finds_the_held_request_under_the_workspaces_deadline, ::test_sm10_api_with_the_deadline_off_the_held_request_ends_no_later_than_the_facts and ::test_sm10_api_a_short_lived_agent_key_ends_the_held_request_before_the_facts_go_stale; by tests/test_console_api_connection.py::test_the_operation_ref_leaves_with_the_samples, ::test_the_operation_ref_is_the_samples_mapping_row_never_the_catalog_action and ::test_the_operation_ref_is_null_while_the_starters_own_mapping_is_not_live, which the validation evidence collects under SM by their own prefix; and by the console's SampleChecks.test.tsx, RequestToRelay.test.tsx, WelcomePage.test.tsx and agents.test.tsx. SM11 is held by every tests/test_samples.py::test_sm11_, tests/test_console_api_samples.py::test_sm11_api_ and tests/test_demo_command.py::test_sm11_ test, and by tests/test_console_api_tokens.py::test_a_token_downloads_the_samples_demo_configuration_its_owner_downloads, which the validation evidence collects under SM by its own prefix.

People numbers (PN1 to PN16)​

A person reads "User 3" where the console printed "unlabelled" and the first characters of a UUID, the way migration 0058_api_key_numbers gave agents "Agent 3". Migration 0062_people_numbers numbers administrators and approvers from one in each workspace, in creation order, on a counter separate from agents'; the console names a person by the label, else the email, else "User N", and the numbers are display handles only. The group also covers the People page's pending invitations card, which leaves out accepted, revoked and expired invitations, and the workspace switcher, which no longer cuts the workspace name through. Real PostgreSQL throughout: PN3 runs on six real connections at once, PN7 under an owner with the hosted owner's attributes, and PN8 and PN16 in real Chromium.

IDSetup/actionRequired result
PN1An administrator, an agent, an approver, an agent and an approver inserted in that order into a fresh workspaceThe people read 1, 2 and 3 and the agents 1 and 2: each class counts from one in creation order on its own counter, and other workspaces' people change nothing
PN2An approver made an administrator and back, then made an agent; an agent made an approverThe number stays across the two person kinds; the person who becomes an agent takes the next agent number and the agent who becomes a person the next person number, and neither keeps the other class's number
PN3Six writers on six connections in one workspace, four people and two agents, released together and each holding its transaction openThe people get 2 to 5 and the agents 1 and 2, all distinct: the advisory lock keyed on the tenant and the class makes each insert wait for the one before it, and none stops at a unique index
PN4A removed member rejoins through a teammate invitationThe old entry, now replaced, keeps its number, and the new entry takes the next person number
PN5As an administrator: the People list and a person, access, the approvers' assignments and options, a space's members and the credentials list; then a new agentEach carries the person's number, and the People list, the approvers' assignments and the credentials list carry the email the console names a person by; the new agent takes the next agent number, whatever the people's numbers are
PN6A space's member list in a workspace where every person has an email, read by a tenant administrator, by the approver seated in the space, and by two teammates managed by access control with one grant at Workspace scope: a Viewer seated nowhere and an Approver seated in the spaceThe administrator reads the member's email and number; the approver and both teammates read every member's number and no member's email, their own included. The teammates open every space and People refuses them: workspace-wide read access is not administration, and the gate is the session identity's effective kind, the check People makes
PN7Migration 0062_people_numbers under an owner that is NOSUPERUSER and NOBYPASSRLS with forced row security, over two workspaces holding a person from before creation times were kept, people created out of their id order and at the same moment, and agents numbered by 0058; new rows after it; then the downgradePeople numbered per workspace by created_at, a row without one first, then by principal id, and the agents' numbers unchanged; new rows continue both counts inside the tenant fence; the column is NOT NULL and the functions are number_agent_key and number_principal; the downgrade clears people's numbers and restores 0058's function with its grants, its index, check and trigger exactly, and 0058's own count carries on from the agents' numbers
PN8In real Chromium at 1280 and 390 px, in light and dark: a workspace named "contoso" and one named "Northwind security operations, second shift"The switcher chip's accessible name is "Workspace" and the name; both lines sit inside the chip and the chip inside the 56 px top bar; the name is one whole line tall and not cut through, and the long name ends in an ellipsis on that line; axe finds no violation, the browser reports no policy violation and nothing scrolls sideways
PN9The People list with a person who has an email and no label, and one with neitherThe first is named by the email with "User 3" beside it and the second by "User 5" once, each a link to the person; no id prefix and no "unlabelled"; the button reads "Edit roles for" the email and opens that person's roles
PN10A person's page for someone with no labelThe heading is the email, and "User 3" stands where the id prefix was; no "unlabelled"
PN11The approvers list and its assign form, with approvers who have no labelEach is named by the email, else "User 3", as a link to the person; the form's option reads "dana@example.com · User 3"; no "unlabelled"
PN12A space's members with no label, one with an email and one without"dana@example.com User 2" and "User 1"; no id prefix and no "unlabelled"; each remove button names the member the same way
PN13A space's assign form offering an administrator with neither a label nor an emailThe option reads "User 1 · Space administrator"
PN14The invitations card given a sent, a failed, a sending, an expired, a revoked and an accepted invitationThe sent, failed and sending ones are listed, each with its delivery state and its Resend and Revoke, and the expired one as Expired with only Invite again (AR7); the accepted and revoked ones are not
PN15The invitations card given only an accepted invitationIt reads "No open invitations." and shows no address
PN16In real Chromium at 360, 390 and 430 px, in light and dark, for a deployment with Ask and one without: a tenant administrator of a workspace named "Northwind security operations, second shift" who belongs to a second one, so the chip is thereNo control in the top bar, nor the breadcrumb, paints over another or into either 16 px gutter, measured from each one's own box and every visible part of its content; the compact Space switcher shows its mark and chevron, whole from 390 px and at 360 px painting nothing outside its own box, and is still named "Space in ; change space", the mode shows its dot and is still named by its word, and the Ask button is left out while Menu still offers Ask; axe finds no violation, the browser reports no policy violation and nothing scrolls sideways

Tests live in tests/test_people_numbers.py (PN1 to PN7), tests/test_browser_workspaces.py (PN8, PN16), and the console's directory/people.test.tsx (PN9, PN10), directory/access.test.tsx (PN11), spaces/spaces.test.tsx (PN12, PN13) and directory/invitations.test.tsx (PN14, PN15). tests/test_api_key_numbers.py keeps 0058's own proofs under the new revision: a person's credential still has no number, and a principal whose kind changes takes the next number of its class.

Personal access tokens (PT1 to PT13)​

An administrator's own bearer token for the console API, ebp1.<tenant>.<token>.<secret>, migration 0063_personal_access_tokens. A token carries its owner's authority except for the named exceptions (approvals and settlement, loosening enforcement, people/access/sign-in, and tokens and the owner's own account), each answering 403 TOKEN_NOT_ALLOWED and audited. Real PostgreSQL throughout, in tests/test_personal_tokens.py (the schema, the store and the owner rules), tests/test_console_api_tokens.py (the routes and the exceptions through the application), tests/test_route_authority.py (the closed route classification) and tests/test_console_api_base.py (the published reference), named in full below since each is one file among several; the console cards are console/src/components/settings/PersonalTokens.tsx and console/src/components/tenant/WorkspaceTokens.tsx, held by their own component tests rather than a PT row.

IDSetup/actionRequired resultTest
PT1An administrator creates a token; a person who is not an administrator tries to create oneThe token is returned once, under Cache-Control: no-store, and never again from the list. If the administrator has enrolled a second factor, an assurance older than thirty minutes is refused MFA_REQUIRED and creates nothing, and a fresh one lets it succeed again (require_recent_factor is a no-op with none enrolled, so an administrator with no factor is not stepped up at all). A non-administrator is refused FORBIDDEN, leaving no token and no credentialtests/test_console_api_tokens.py::test_an_administrator_creates_lists_revokes_and_deletes_own_tokens, ::test_creating_a_token_needs_a_recently_verified_factor_only_when_one_is_enrolled, ::test_a_person_who_is_not_an_administrator_cannot_create_a_token
PT2A token calls an allowed read and an allowed write as its ownerBoth succeed as the owner, carry no workspace-generation header, and the write's audit event names the owner as actor_id and the token's backing credential as actor_credential_id, as every write a token may make does; the parametrized case list is checked against TOKEN_ALLOWED itself, so a route added later without evidence fails closedtests/test_console_api_tokens.py::test_a_token_reads_and_writes_as_its_owner, ::test_every_write_a_token_makes_names_its_backing_credential, ::test_every_token_allowed_post_route_has_attribution_evidence
PT3Every route in token_rules.TOKEN_REFUSED, and every hosted route in the plugin's own refused set, is called by a token, with its path parameters filled inEach answers 403 TOKEN_NOT_ALLOWED and is audited as a refusal; switching to enforcing is allowed but switching to observe-only is not, and issuing a credential is allowed only for an agenttests/test_console_api_tokens.py::test_every_refused_route_answers_token_not_allowed_through_the_application, ::test_a_token_may_switch_to_enforcing_and_not_to_observe_only, ::test_a_token_issues_a_key_only_for_an_agent; for the hosted plugin's own routes, the hosted service's own tests
PT4A token tries an approval decision and a reconcile directly, and every write TOKEN_REFUSED carries under /people, /access and /tenant/sign-inThe decision and reconcile routes are refused before a continuation is ever offered; every people, access and sign-in write is refused, closing approval by proxy through a person the token could otherwise create and sign in astests/test_console_api_tokens.py::test_a_token_is_never_offered_an_approval_continuation, ::test_a_token_is_never_offered_a_reconcile, tests/test_route_authority.py::test_token_allowed_writes_never_touch_people_access_or_sign_in
PT5The owner's administrator role is removed; the owner is deactivated, through people_pages.deactivate (which revokes the backing credential, the product's own removal path) or directly; the owner's workspace_memberships row is marked inactive, distinct from bothEach ends the token on its next request with SessionError, whether or not anyone revoked ittests/test_personal_tokens.py::test_an_owner_demoted_from_administrator_loses_the_token, ::test_an_owner_who_stops_being_an_administrator_loses_the_token, ::test_a_token_revoked_through_its_backing_credential_can_be_deleted (the people_pages.deactivate case asserts the refusal directly), ::test_removal_from_the_workspace_ends_the_token_distinct_from_deactivation_or_demotion
PT6The owner revokes their own token; a different administrator revokes it; a revoked or expired token is deleted, a live one is notRevocation by either takes effect on the token's next request; a revoked or expired token is deletable, an unrevoked live one answers CONFLICT; the chain keeps personal_token.issued, .revoked and .deleted, in order, after the row is gonetests/test_personal_tokens.py::test_a_revoked_wrong_or_garbled_token_is_refused, ::test_delete_succeeds_for_an_expired_but_unrevoked_token, ::test_delete_token_removes_it_from_listing_and_is_audited, tests/test_console_api_tokens.py::test_a_different_administrator_cannot_revoke_through_settings_but_can_through_tenant, ::test_an_unknown_token_id_is_not_found_and_a_live_one_cannot_be_deleted
PT7An eb1 credential (an agent key, the CLI's admin token, a jobs credential) is presented as a bearer on the console APIRefused exactly as today (INVALID_IDENTITY), on every route, never authenticated as a token; auditing is checked directly on one route rather than the whole swept settests/test_route_authority.py::test_a_session_route_refuses_an_agent_credential (every route, status code only), tests/test_console_api_tokens.py::test_an_eb1_credential_is_still_refused_as_a_bearer (one route, with the rejection counted)
PT8A request carries a session cookie and a bearer token togetherRefused rather than one being preferredtests/test_console_api_tokens.py::test_a_cookie_and_a_token_together_are_refused
PT9Every served /api/console/v1 route: core's CONSOLE, AUTHORITY and ASSISTANT collections, the sample plugin's PLUGINS and the hosted plugin's HOSTEDEach of core's routes appears in exactly one of TOKEN_ALLOWED or TOKEN_REFUSED, which name nothing else; each of a plugin's appears in exactly one of the two sets that plugin registers with token_routes, which refuses any method of a path whose shape core classifies; a token calls a route a plugin allows and is refused one it refuses or leaves out; an unclassified route is refusedtests/test_route_authority.py::test_every_console_api_route_says_whether_a_token_may_call_it, tests/test_plugins.py::test_token_routes_are_the_plugins_own_console_routes_and_methods, tests/test_plugins.py::test_a_plugin_cannot_allow_any_method_of_a_core_path, tests/test_plugin_surfaces.py::test_a_token_calls_the_route_a_plugin_allows_and_no_other; for the hosted plugin's HOSTED, the hosted service's own tests
PT10A token calls an allowed route past its own rate limit429 with Retry-After, counted separately from the credential and peer-address limitstests/test_console_api_tokens.py::test_a_token_has_its_own_rate_limit
PT11The published console API reference (console_api_document())Its description opens with the Authentication section; every operation carries x-execbound-token (allowed or refused) matching token_rules.token_allowed, with its own sentence, and the two body-ruled operations state their own limit instead of the generic onetests/test_console_api_base.py::test_the_console_reference_opens_with_authentication_and_marks_each_token_rule, ::test_the_two_body_ruled_operations_state_their_own_limit
PT12Migration 0063_personal_access_tokens, upgrade and downgrade, under a role without row-level-security bypassUpgrade passes check_runtime (proven by the revision catalog test, which runs it against the full migration chain, this migration included); downgrade refuses while a token row alone, a token-surface authentication failure alone, or both together are retained, and succeeds once neither is, restoring the prior authentication-failures constrainttests/test_samples_schema.py::test_sm8_revision_catalog_and_privileges (check_runtime over the migrated schema), tests/test_personal_tokens.py::test_the_migration_runs_without_row_level_security_bypass_and_downgrades (the downgrade cases)
PT13A workspace with an identity provider requiring sign-in: an existing token is used, and a new one is requestedBoth refused DIRECTORY_REQUIRED; a provider that stops requiring it restores the existing tokentests/test_personal_tokens.py::test_a_token_is_refused_while_any_identity_provider_requires_sign_in, tests/test_console_api_tokens.py::test_directory_sign_in_refuses_a_token_as_it_refuses_a_session, ::test_issuing_a_token_is_refused_where_directory_sign_in_is_required

Scheduled jobs for every workspace​

The scheduled recover and notify passes reach every workspace, one made by verified Community signup included, with no workspace credential: recover --all-tenants walks the directory of tenants (job_tenants, migration 0064_scheduled_jobs) and acts in each active workspace as that workspace's scheduler principal, and notify --all-tenants drains every workspace a configured destination names. The tests are in tests/test_scheduled_jobs_schema.py (the schema), tests/test_scheduled_actor.py (the actor, SJ8 at the application and the SJ9 pin), tests/test_scheduled_recovery.py (recovery), tests/test_scheduled_notify.py (notifications) and tests/test_scheduled_jobs_cli.py (the walk and the CLI), named in full below. Every test that touches a database runs on real PostgreSQL, and the restricted and stack fixtures build a database whose owner has the hosted owner's attributes, neither superuser nor BYPASSRLS. Where a row's tests cover less than its scenario, the row says how.

IDSetup/actionRequired resultTest
SJ1Migrate a database that already holds a tenant, then create tenants by a direct insert into tenants (as seeded does; sandbox seeding, seed-demo, monitoring init-demo, gate_demo and validation_demo insert the same way), by administration.create_tenant (the owner CLI's tenant-create and quickstart), by community_provision, and under an owner without bypass; then widen owner_list, narrow it to USING (false), or add a restrictive policyEvery tenant is in job_tenants exactly once: the migration's backfill lists the tenant made before it, and the tenants_enroll trigger each one made after, by whichever path. job_tenants_page lists them in id order, 1 to 500 a page, and answers nothing for 501. The runtime role's direct read of the table is refused for want of a privilege while check_runtime still passes. The walk, enlistment and retirement work under the owner without bypass. Each changed policy stops the pass with UNSAFE_JOB_POLICY before any workspace is visited, and once it is restored the pass visits every workspace againtests/test_scheduled_jobs_schema.py::test_sj1_every_tenant_is_in_the_directory_exactly_once, ::test_sj1_the_page_is_ordered_and_bounded, ::test_sj1_the_runtime_role_cannot_read_the_directory, ::test_sj1_the_backfill_and_the_list_work_for_an_owner_without_bypass, tests/test_scheduled_jobs_cli.py::test_a_changed_directory_policy_stops_the_pass, ::test_the_walk_and_the_scheduler_work_for_an_owner_without_bypass; for a tenant made by community_provision, the hosted service's own tests
SJ2A workspace made only by community_provision, with no jobs token, holding a lapsed untouched approval on its sample production workstation, a lost response on a sample account and a 31-day-old assistant turn. A checkpoint grant past its report window and a settled assertion's claim past the act window, on the Gate test world instead, because a workspace made by signup cannot hold a Gate grant. A workspace with nothing due. execbound recover --all-tenants over a private configurationWith the workspace's ScheduledActor and the sample runtime, recover expires the approval to STALE_AUTHORIZATION, its approval.transition naming the SYSTEM principal, after which the samples can be removed; it settles the lost response EXECUTED from the sample mock's journal with skipped_no_connector 0, its execution.reconciliation_requested naming the SYSTEM principal. recover_scheduled retires the turn and, writing no event, makes no scheduler principal. On the Gate world the grant is swept INDETERMINATE and the claim released, each event naming the SYSTEM principal. The workspace with nothing due gains no scheduler principal. The CLI gives each workspace's pass the runtime, which derives a sample account's connection, and the configuration's whole list of destinations. Under the owner without bypass these steps rest on the directory, enlistment, retirement and guard tests (SJ1, SJ8): recovery reads nothing across tenants and calls no new definer function beyond those. What this row asserts of the workspace made by community_provision (the approval's expiry to STALE_AUTHORIZATION and the samples' removal after it, the lost response's EXECUTED settlement from the sample mock's journal, and the turn's retirement) rests on the hosted service's own tests, which are not publishedtests/test_scheduled_recovery.py::test_sj2_grants_sweep_and_claims_release_under_the_scheduler, ::test_sj2_a_settled_assertion_s_claim_is_released_under_the_scheduler, ::test_a_workspace_with_nothing_due_gains_no_scheduler_principal, tests/test_scheduled_jobs_cli.py::test_the_scheduled_recovery_is_given_the_runtime_and_its_destinations; for the workspace made by community_provision, the hosted service's own tests
SJ3A workspace with a configured email destination and a pending approval, drained with no administrator; a workspace made by signup whose sample production workstation asks for approval, with an email destination for it; a queued row whose approval then closes, and one whose destination the pass's configuration no longer names; a row under a live lease; a deactivated workspace; execbound notify --all-tenantsnotify_scheduled delivers one message through the TLS relay fixture in both workspaces, the first row DELIVERED after one attempt. destination_tenants names only the workspaces an email, Slack, Teams or webhook destination whose classes include approvals names, so a workspace whose last destination is removed is no longer drained, and the CLI drains each named workspace as its ScheduledActor and reports its counts. The recovery pass settles the closed approval's row APPROVAL_CLOSED without sending, and a second pass settles nothing. A pending row is kept while the pass's configuration names its destination and, once it does not, until the row is older than ORPHAN_AFTER (one day), and is then settled DESTINATION_UNKNOWN. A row under a live lease is left to its drain until the lease runs out. Settling refuses a deactivated workspace with INVALID_IDENTITY and leaves the row. With no plugin loaded the scheduled drain's mail links to /approvals/{approval_id}; with the hosted plugin loaded, given the plugin's approval path as notify --all-tenants gives it, to /workspaces/{tenant}/approvals/{approval_id} and its /classic page. Under the owner without bypass: as SJ2; the drain calls no new definer functiontests/test_scheduled_notify.py::test_sj3_destination_tenants_are_the_approval_kinds_only, ::test_sj3_the_scheduled_drain_delivers_with_no_administrator, ::test_sj3_recovery_settles_a_closed_approval_s_row_no_drain_will_reach, ::test_sj3_recovery_settles_against_the_destinations_it_is_given, ::test_sj3_a_pending_row_whose_destination_is_gone_is_settled_unknown, ::test_sj3_a_row_under_a_live_lease_is_left_to_its_drain, ::test_sj3_settling_refuses_a_deactivated_workspace, tests/test_scheduled_jobs_cli.py::test_sj3_the_notify_command_drains_every_workspace_a_destination_names; for the workspace made by signup and the hosted plugin's approval links, the hosted service's own tests
SJ4A mapped workspace with a configured connector and a lost response (RC1's setup), reconciled by a ScheduledActor before and after enlistment, recovered by one, and recovered by execbound recover --all-tenants with that connector in the private configuration and no credentialBefore enlistment reconcile_operation and reconcile each refuse the actor with INVALID_IDENTITY, settle nothing and retain no refusal, because there is no principal to name. Enlisted, the actor settles the operation EXECUTED from the journal with one provider mutation in total, the request and the settlement naming the SYSTEM principal, and one scheduler principal exists. recover with a ScheduledActor settles it the same way (examined 1, executed 1, unresolved 0) and records principal.created. The CLI run reports it executed in that workspace, with no workspace failedtests/test_scheduled_recovery.py::test_sj4_a_scheduled_actor_settles_a_lost_response_from_the_journal, ::test_sj4_a_mapped_workspace_settles_under_the_scheduler, ::test_reconcile_refuses_a_scheduled_actor_with_nothing_to_attribute, tests/test_scheduled_jobs_cli.py::test_the_cli_recovers_every_workspace_with_no_credential
SJ5Two real workspaces with due work, walked by every_workspace: the first's connection lookup refuses and its assistant retirement fails. A step that refuses in one workspace. The token-map walk, for_each_tenant, with an AssistantError in one tenant (defect 1). A sweep that fails after recover expired an approval. UnsafeDatabaseRole from a sweepThe second workspace is still recovered (executed 1), and the first is failed with ASSISTANT_UNAVAILABLE, keeping its partial counts (examined 1, unresolved 1); every transaction either workspace's pass opens is fenced to that workspace. A refusing step is its own workspace's outcome on both walks, and the next workspace still runs. A failed sweep raises SweepFailed carrying the expiry and the retirement that still ran, and the walk reports them beside the failure code. UnsafeDatabaseRole is never one sweep's failure: it stops the run. That the next workspace is still notified rests on the notify walk being the same every_workspace; no test drains two workspaces where one failstests/test_scheduled_jobs_cli.py::test_sj5_one_workspace_s_failure_is_its_own_outcome, ::test_a_step_s_refusal_is_contained_to_its_own_workspace, ::test_defect_1_the_token_map_run_contains_an_assistant_failure, ::test_a_failed_sweep_reports_what_its_run_had_already_committed, tests/test_scheduled_recovery.py::test_a_failed_sweep_keeps_what_the_pass_had_already_done, ::test_an_unsafe_database_role_is_never_one_sweep_s_failure
SJ6A deactivated workspace in the walk; a workspace whose activity cannot be read; a scheduled run whose workspace is deactivated inside its first operation, and one deactivated between its first and second; an administrator's run whose credential is revoked between two operations, two expiries or two claim releases (defect 2)The deactivated workspace is counted inactive, neither visited nor logged; the unreadable one is visited and failed with DEPENDENCY_UNAVAILABLE; a stopped workspace reports what it did beside its code. Deactivated inside an operation, the scheduled run stops there with RecoveryStopped (INVALID_IDENTITY), that operation counted unresolved and no second lookup made; deactivated between operations, it stops at the next recheck and the first settlement stands. The revoked administrator's run stops at the next recheck with RecoveryStopped, which carries its counts; an operation in flight at the revocation costs that one operation, and the later rows are untouchedtests/test_scheduled_jobs_cli.py::test_an_inactive_workspace_is_counted_and_a_stopped_one_reports_what_it_did, ::test_a_workspace_whose_activity_cannot_be_read_is_visited_and_failed, tests/test_scheduled_recovery.py::test_sj6_a_workspace_deactivated_inside_an_operation_stops_the_run_there, ::test_sj6_a_workspace_deactivated_between_two_operations_stops_at_the_next, ::test_defect_2_an_admin_revoked_between_two_operations_stops_the_run, ::test_defect_2_an_admin_revoked_between_two_expiries_stops_the_run, ::test_defect_2_an_admin_revoked_between_two_claim_releases_stops_the_run
SJ7recover with a ScheduledActor and cancel_unattempted; reconcile_operation with an enlisted ScheduledActor and cancel_if_missing on a never-attempted operation; execbound recover --all-tenants --cancel-unattempted, and the other flag combinations the modes excluderecover refuses with INVALID_IDENTITY before any selection reads. reconcile_operation refuses with INVALID_IDENTITY before any journal lookup or cancellation: the operation stays DISPATCH_COMMITTED, no reconciliation request is recorded, and the refusal is retained as execution.rejected naming the SYSTEM principal and no credential. The CLI refuses the combination and, beside --all-tenants, every flag another mode reads, with exit 2 before anything runs. No tombstone is requestedtests/test_scheduled_recovery.py::test_sj7_a_scheduled_actor_never_asks_for_a_tombstone, ::test_sj7_the_scheduled_run_refuses_cancellation_before_reading_anything, tests/test_scheduled_jobs_cli.py::test_the_modes_are_exclusive_and_cancellation_needs_an_administrator
SJ8The scheduler principal: made by scheduler_actor and by enlistment, twice each; named through each guarded route; changed; granted the administrator role past its guard; present while every console list is readIt is made once, with the derived id, kind SYSTEM, label "ExecBound scheduler", number 1 and no space, and principal.created is recorded once. scheduler_actor and enlistment refuse an unfenced or inactive tenant and record nothing, enlistment mapping the function's own INVALID_TENANT to INVALID_IDENTITY. access_effective_kind answers SYSTEM and access_has_permission false, even with an administrator grant written past the guard. No change to it is accepted (deactivation, a relabel, a change of kind) and no principal becomes one; principals_system_id refuses a SYSTEM principal under another id and a person under the derived id. The guard refuses it in credentials (fenced by tenant), in user_passkeys written under an account fence with no tenant fence by an owner without bypass, and as a replaced_by, and migration 0064's downgrade refuses while one exists. admin_issue_credential, admin_label_principal, admin_deactivate_principal and admin_reactivate_principal refuse it with SYSTEM_PRINCIPAL; the owner CLI's issue_credential and the console's POST /credentials/issue refuse it with INVALID_PRINCIPAL and leave no credential and no file. Every console list core's published console API document names answers below 500 with it present and never shows its id or label, and so does every one the hosted areas' own document names, with the hosted plugin loaded; the four in each that refuse this client do so for reasons of their own, and each set is pinned. The scheduled check admits only the workspace's own active scheduler, only in a transaction fenced to that workspace, and nothing once the workspace is deactivated. Two concurrent passes making one is SJ13. What this row does not assert directly: admin_revoke_credential and the directory functions are not called one by one: the guard on credentials.principal_id and the identity-link columns (SJ9) means the scheduler principal never holds a credential to revoke or a link to use; the people, access and space pages would map the guard's SYSTEM_PRINCIPAL to their own *_UNAVAILABLE codes, and only the API Keys page maps it to INVALID_PRINCIPAL; the cap counts are not asserted separatelytests/test_scheduled_jobs_schema.py::test_sj8_the_scheduler_principal_is_made_once_and_is_nobody, ::test_sj8_the_scheduler_principal_refuses_an_unfenced_or_inactive_tenant, ::test_sj8_no_change_to_the_scheduler_principal_is_accepted, ::test_sj8_the_guard_refuses_the_scheduler_principal_in_a_credential_and_a_replacement, ::test_sj8_the_guard_needs_no_fence_for_an_owner_without_bypass, ::test_sj8_kind_system_and_the_derived_id_go_together, ::test_sj8_an_administrator_grant_gives_the_scheduler_principal_nothing, tests/test_scheduled_actor.py::test_sj8_the_owner_cli_and_the_console_refuse_the_scheduler_principal, ::test_sj8_each_administration_function_refuses_the_scheduler_principal, ::test_sj8_reactivation_never_reaches_the_scheduler_principal, ::test_sj8_every_console_list_answers_with_the_scheduler_present, ::test_the_scheduled_check_admits_an_active_workspace_and_only_its_own_scheduler, ::test_the_scheduled_check_is_bound_to_the_transactions_own_fence, ::test_enlistment_refuses_an_inactive_workspace, ::test_enlistment_maps_the_databases_own_refusal_of_an_inactive_workspace; for the hosted areas' document, the hosted service's own tests
SJ9The code and the catalogEvery function in src/ that names ScheduledActor, RecoveryActor, actor_check or scheduled_check is one the pin lists, and no import aliases one of those names; store.identity_check refuses a ScheduledActor with INVALID_IDENTITY, a lookalike whose kind is ADMIN included. The catalog test enumerates every foreign key to principals, every uuid column named for a principal and the listed columns whose names do not say so, and fails on a column execbound.principal_columns classifies as neither GUARDED nor UNGUARDED with a reason, or on a classified column that no longer exists. Every guarded column carries system_guard_<column> BEFORE INSERT OR UPDATE OF it, and migration 0064's copy of GUARDED, together with the GUARDED_ADDED of every later migration that guards a column of its own, equals the application's, no column guarded twice. The pin is a review tripwire that reads names; what refuses a scheduled actor anywhere else is store.identity_checktests/test_scheduled_actor.py::test_sj9_only_the_pinned_functions_accept_a_scheduled_actor, ::test_identity_check_refuses_a_scheduled_actor, tests/test_scheduled_jobs_schema.py::test_sj9_every_principal_column_is_classified, ::test_sj9_every_guarded_column_has_the_guard_and_the_migration_agrees
SJ10The ADMIN modes: recover and notify with --tenant and --credential-file, or --tenants-filetests/test_recovery_run.py (RC1 to RC20), tests/test_approval_lapse.py and tests/test_notification_email.py pass unchanged. Two behaviours change by design: an administrator's run stops at the next recheck when its credential is revoked mid-run (defect 2, SJ6), and the CLI gives an administrator's run, single or mapped, the runtime rather than its map of configured connectors, so it reaches sample accounts too. A failed retirement in --tenant exits 2 with its code rather than a tracebacktests/test_recovery_run.py, tests/test_approval_lapse.py, tests/test_notification_email.py, tests/test_scheduled_recovery.py::test_defect_2_an_admin_revoked_between_two_operations_stops_the_run, ::test_defect_2_an_admin_revoked_between_two_expiries_stops_the_run, ::test_defect_2_an_admin_revoked_between_two_claim_releases_stops_the_run, tests/test_scheduled_jobs_cli.py::test_an_administrator_s_recovery_is_given_the_runtime, ::test_an_administrator_s_failed_retirement_exits_non_zero_without_a_traceback
SJ11A schema revision mismatch, and a database error, in the check the pass makes before it visits anythingevery_workspace raises UnsafeDatabaseRole before visiting any workspace, and recover --all-tenants and notify --all-tenants exit 2 with the runtime check's refusal sentence (plugins.database_refusal, which names the fix for a dormant-grants mismatch); a database error there exits 2 with refused: database error and no traceback. A changed directory policy stops recover's pass before any workspace too (SJ1)tests/test_scheduled_jobs_cli.py::test_sj11_a_schema_mismatch_stops_the_pass_before_any_workspace, ::test_sj11_the_cli_exits_non_zero_on_a_schema_mismatch, ::test_a_database_error_exits_non_zero_without_a_traceback, ::test_a_changed_directory_policy_stops_the_pass
SJ12The Compose deploymentCompose's jobs service runs recover and notify as --all-tenants --limit 50 with no shell, and both wait until jobs.json, quickstart's mark, existstests/test_jobs_schedule.py::test_the_documented_command_is_what_runs, ::test_a_job_whose_credential_is_not_written_yet_waits
SJ13Two scheduled runs at once over the same workspace and one lost response, forced to overlap after both have selected, as RC7 forces itBoth examine the operation and both enlist; there is one settlement, one provider mutation, one scheduler principal and one principal.created. A notification sent once under two drains is AN9's lease, which the scheduled drain shares because it is deliver_pending with another actor; AN9 is not rerun with scheduled actorstests/test_scheduled_recovery.py::test_sj13_two_scheduled_runs_at_once_settle_once_and_make_one_scheduler, tests/test_approval_notifications.py::test_an9_concurrent_drains_deliver_each_notification_once
SJ15scheduler_actor and assistant_turn_retire_due, unfenced, fenced to an inactive tenant, and over turns completed 29 and 31 days ago by the database's clockNeither takes an argument; each refuses an unfenced or inactive tenant with INVALID_TENANT; retirement keeps the 29-day turn, retires the 31-day one, and retires nothing on a second calltests/test_scheduled_jobs_schema.py::test_sj15_retirement_due_takes_no_time_and_needs_an_active_fenced_tenant, ::test_sj15_retirement_due_keeps_29_days_and_retires_31, ::test_sj8_the_scheduler_principal_refuses_an_unfenced_or_inactive_tenant
SJ16Five workspaces walked from an injected start; the same walk with a budget spent after the first workspace; the next run from another start, cut short the same wayThe walk begins just after the start, wraps round to it and visits all five; cut short, it visits one and counts four not_reached; the next run reaches a workspace the first did nottests/test_scheduled_jobs_cli.py::test_sj16_the_walk_starts_where_it_is_told_wraps_and_counts_what_the_budget_left

Dormant catalog (DC1 to DC24)​

The tables and functions only a plugin uses hold no runtime grant on any install unless a loaded plugin claims them, and the plugin's own upgrade command grants its claims in the transaction that applies the migrations (migration 0065_dormant_grants; Data model). Real PostgreSQL for every test that reads a grant. The core tests run with no plugin's grants, as a core install does; the hosted service's own tests run with its plugin loaded and its claims granted, as its deployment does. ES13 and ES14 carry the emergency stop's numbering because they extend its file.

IDScenarioExpectedTest
DC1The dormant catalogDORMANT_TABLES and DORMANT_FUNCTIONS sit inside TABLES and FUNCTIONS, ten tables and twenty-seven functions each named once and pinned by name, 37 names in DORMANT; account_switch, the teammate invitation, sample target, people number, personal access token and scheduled jobs objects are not dormanttests/test_dormant_catalog.py::test_dc1_the_catalog_marks_the_dormant_objects_inside_the_core_catalog
DC2Registry.claim and the loader: a valid claim; claims outside the catalog or the grammar; a second claim by one plugin; two plugins claiming one object; a conflict beside an unknown plugin; a second load that adds, leaves one out, or differs; a load refused after a claim; honour_claims called directly with an invalid or a conflicting claimThe valid claim is on the loaded plugins and honoured, and NO_PLUGINS claims nothing. A core table or function (account_switch included), an unknown or non-string name, an empty, string, bytes, non-iterable or unhashable set, DELETE, TRUNCATE, REFERENCES, MAINTAIN, EXECUTE on a table, a lowercase privilege, an uppercase or injected column, a whole-table and a column claim for one privilege, SELECT on a function, and a str subclass that compares equal to anything or renders as another name are each INVALID_CLAIM; a refused name and a refused privilege are logged as plugins.refused with the code and the plugin and without the claimed text; a second claim by one plugin is INVALID_CLAIM. Two plugins claiming one object are PLUGIN_CONFLICT, an unknown plugin beside them refuses UNKNOWN_PLUGIN first, and neither honours anything. A later load adds to what is honoured, one that leaves a claim out takes nothing away, and one that differs is PLUGIN_CONFLICT and changes nothing. A load refused after a claim (a duplicate console path, an unknown second plugin, a register that raises) honours nothing. honour_claims raises ValueError for an invalid claim and ClaimConflict for a conflicting one, and records nothingtests/test_plugins.py::test_dc2_a_plugin_claims_dormant_objects_and_the_process_honours_them, ::test_dc2_a_claim_outside_the_catalog_or_its_grammar_is_refused, ::test_dc2_a_refused_claim_is_logged_by_code_and_plugin_and_never_echoed, ::test_dc2_a_plugin_claims_an_object_once, ::test_dc2_two_plugins_claiming_one_object_conflict_and_nothing_is_honoured, ::test_dc2_a_claim_conflict_is_found_after_every_plugin_resolves, ::test_dc2_a_later_load_adds_to_what_is_honoured_and_never_changes_it, ::test_dc2_a_refused_load_honours_nothing, ::test_dc2_honouring_an_invalid_or_conflicting_claim_changes_nothing
DC3A core test database with no plugin; then five grant states: nothing, what the runtime held before 0065, claims beside grants to PUBLIC, claims beside extra grants, and an overload of a dormant function's name granted to the runtimeWith no plugin the runtime holds nothing on any dormant object, check_runtime passes, and the owner's check_dormant with no claims passes. In every state check_runtime's own reading of the grants, from the rows of its functions query, equals dormant_grants'tests/test_dormant_catalog.py::test_dc3_with_no_plugin_the_runtime_holds_nothing_on_any_dormant_object, ::test_dc3_the_runtime_check_reads_the_grants_dormant_grants_reads
DC4With no claim honoured, one grant at a time: SELECT on each dormant table and EXECUTE on each dormant function to the runtime role; a SELECT and an EXECUTE to PUBLIC; and grants only the dormant reading refuses, TRIGGER, REFERENCES and MAINTAIN on a whole dormant table and INSERT and REFERENCES on one column (onboarding_invitations.note)check_runtime raises DormantGrantsRefused for every one, and so does check_dormant with no claimstests/test_dormant_catalog.py::test_dc4_a_dormant_object_nobody_claims_refuses_any_grant
DC5A claim of one table, whole and on one column, and one function: honoured and not granted; granted; then each of an unclaimed column, INSERT, another table's SELECT and PUBLIC's EXECUTE on an unclaimed function added; then a claimed column grant taken awayClaimed and not granted is refused; granted exactly, check_runtime and check_dormant pass; every extra grant, and the missing column, is refused with DormantGrantsRefusedtests/test_dormant_catalog.py::test_dc5_a_claimed_object_holds_exactly_its_claim
DC6A claimed dormant table also granted DELETE, or TRUNCATE, to the runtime rolecheck_runtime refuses it as unsafe table privileges, whatever the claimtests/test_dormant_catalog.py::test_dc6_no_claim_lets_the_runtime_delete_or_truncate_a_dormant_table
DC7grant_dormant over stray grants to the runtime role and to PUBLIC; grant_dormant given a claim no plugin could make; a claimed privilege also granted to PUBLIC or held with a grant option; an overload of a dormant function's name granted to the runtime rolegrant_dormant leaves exactly the claim, which check_dormant accepts, and with no claims leaves nothing; a core table, SELECT on a function, DELETE, a whole-table and a column claim for one privilege, and an injected column are refused with ValueError. Where the runtime's reach equals the claim but PUBLIC holds it too, a grant option is held, or the overload is granted, check_dormant still refuses, and grant_dormant converges the first two againtests/test_dormant_catalog.py::test_dc7_grant_dormant_sets_exactly_the_claim_whatever_the_database_held, ::test_dc7_grant_dormant_refuses_what_no_plugin_could_claim, ::test_dc7_check_dormant_reads_every_acl_entry_not_only_what_the_runtime_can_do, ::test_dc7_check_dormant_refuses_a_grant_on_another_function_of_a_dormant_name
DC8Down to 0064_scheduled_jobs, then up to 0065_dormant_grantsAfter 0065's downgrade to 0064 the runtime holds exactly what it held before 0065 (the hosted plugin's claims), and PUBLIC executes no dormant function, because the downgrade does not give back PUBLIC's EXECUTE on onboarding_invitation_revoke; at 0065 it holds nothing and check_dormant with no claims passestests/test_dormant_catalog.py::test_dc8_0065_takes_the_grants_away_and_its_downgrade_gives_back_the_runtimes
DC9A caller's owner connection, inside a transaction it began, passed to Alembic in config.attributes["connection"], upgraded from 0064 to the head and then rolled backThe upgrade reaches SCHEMA_REVISION inside the caller's transaction, and after the rollback the database is at 0064tests/test_dormant_catalog.py::test_dc9_a_callers_connection_owns_the_migrations_transaction
DC17python -m execbound.monitoring.commands with EXECBOUND_PLUGINS naming an unknown plugin, then a plugin that claims a dormant table; then a command refused DormantGrantsRefused with no claim honoured and with oneAn unknown plugin exits 2 with Plugin refused: UNKNOWN_PLUGIN.; the named plugin's claim is honoured before the command runs; the refusal exits 2 with the sentence naming EXECBOUND_PLUGINS with no claim and the one naming the plugin's upgrade command with one, and the database is closedtests/test_monitoring_commands.py::test_dc17_the_commands_load_the_plugins_the_environment_names, ::test_dc17_a_named_plugins_claims_are_honoured_before_any_command_runs, ::test_dc17_grants_present_or_missing_are_each_refused_with_their_own_sentence
DC18UPDATE_COLUMNSIt no longer names signup_messages: the outbox's seven columns are the hosted plugin's claimtests/test_dormant_catalog.py::test_dc18_the_outbox_columns_are_the_plugins_claim_now
DC19Every source under src but db.py and a plugin's own packageNone names a dormant object as execbound.<name>tests/test_dormant_catalog.py::test_dc19_no_core_source_reaches_a_dormant_object
DC21A stand-in for a Supabase platform role holding a dormant table's SELECT and a dormant function's EXECUTE; then granted a claimed function after the claims; and a role holding a grant option that grants a claimed function to PUBLICgrant_dormant takes the platform role's grants away; granted after the claims, the runtime's reach is still the claim and check_dormant refuses until grant_dormant runs again. The other grantor's grant survives grant_dormant, and check_dormant refuses it. Each is skipped where the test owner cannot create a roletests/test_dormant_catalog.py::test_dc21_grant_dormant_revokes_what_a_platform_role_holds, ::test_dc21_a_grant_by_another_grantor_survives_grant_dormant_and_is_refused
ES13execbound tenant-stop with no plugin loaded against a database holding a claimed object's grant; then with the claim honoured and the grant missing; then with the two matchingExit 2 with "Database refused: it holds grants for a plugin this process has not loaded. Set EXECBOUND_PLUGINS in the real environment to the plugins the deployment runs, and run the command again." and no stop; then exit 2 with "Database refused: its grants do not match what the plugins this process has loaded claim. Restore them with the upgrade command of the plugin that claims them, then run the command again." and no stop; never a traceback; then the tenant is stoppedtests/test_emergency_stop.py::test_es13_the_kill_switch_names_the_fix_for_either_grant_mismatch
ES14Every command on the runtime connection, in the same two mismatches: the emergency stop and its seven siblings, the six bundle-* commands, audit-export, recover and notify in all three modes, reconcile, notifications, the three export commands and invitations-runEach exits 2 with the sentence for the mismatch, prints nothing on standard output and no traceback, and changes nothing: no stop, no audited event, no exporttests/test_emergency_stop.py::test_es14_every_command_on_the_runtime_connection_names_the_fix

Tests with no DC number cover the rest of the refusals. A plugin command refused by the runtime check prints the same sentences as core's commands (tests/test_plugin_surfaces.py::test_a_plugin_command_that_fails_says_only_how), quickstart keeps its own refusal and never advises running it again (tests/test_quickstart.py::test_a_runtime_check_refusal_stops_quickstart_without_advice_to_run_it_again), and a run over a tenants file skips every tenant at another schema revision but stops at the first refused for its grants (tests/test_jobs.py::test_a_revision_mismatch_skips_every_tenant, ::test_a_refusal_for_the_dormant_grants_stops_the_run).

Agent capacity (AC1 to AC13)​

The agent limit is the workspace's own tenants.max_agents, null for uncapped, since migration 0066_max_agents (Data model). The core tests set the limit directly, as an operator would, with no plan involved; the hosted service proves the same cap through its plans in its own inventory, which also keeps AC11, its plan view. Real PostgreSQL throughout.

IDScenarioExpectedTest
AC1Six agents created in a workspace with no limitAll six succeedtests/test_agent_capacity.py::test_ac1_no_limit_is_uncapped
AC2Workspaces with limits of 0, 1, 3 and 5, filled to the limit and then asked for one moreEvery agent up to the limit succeeds and the next is refused PLAN_LIMITtests/test_agent_capacity.py::test_ac2_a_limit_refuses_exactly_the_agent_past_it
AC3A limit of three, filled; one agent put to sleep, then woken; one deactivated by hand, a replacement created and the first reactivated; a person created; then the limit lowered to oneA sleeping agent still counts and waking it is never refused; a hand deactivation frees its allowance, and reactivating it at the limit is refused PLAN_LIMIT; a person is never counted; lowering the limit leaves all three agents held and refuses the next creationtests/test_agent_capacity.py::test_ac3_what_the_limit_counts
AC4Two creations racing a limit of three's last allowance, both held at the fence and the tenant-row lock and released togetherExactly one succeeds and the other is refused PLAN_LIMIT; the workspace holds threetests/test_agent_capacity.py::test_ac4_two_creations_race_the_last_allowance_and_one_wins
AC5A limit of -1Refused by the check tenants_max_agentstests/test_agent_capacity.py::test_ac5_a_negative_limit_is_refused_by_the_schema
AC6At 0065_dormant_grants, one script of four creations, a hand deactivation, a creation, the hand reactivation, a sleep, a creation and the wake, run on a sandbox, a free and a team workspace; then the upgrade to 0066_max_agents and the same script on a second workspace of each planThe backfill gives free 3 and the others null, and every decision after the upgrade is the one the plan cap made before it: free refuses three times, sandbox and team nevertests/test_max_agents_migration.py::test_ac6_the_limit_reproduces_every_decision_the_plan_cap_made
AC7Up from 0065 and back, once with a team workspace's limit set to 7 by hand and once with it clearedThe patched functions keep their grants, the two core ones the runtime's EXECUTE and the three dormant ones none. The downgrade refuses "An agent limit differs from its plan's; downgrade refused" while the hand-set limit is there; once it is cleared, the downgrade restores the five function bodies byte for byte with the same grants and drops the columntests/test_max_agents_migration.py::test_ac7_the_downgrade_refuses_a_hand_set_limit_and_otherwise_restores_everything
AC8The upgrade and the downgrade as an owner without BYPASSRLS, over a sandbox, a free and a team tenant, with the team limit then set to 10 and clearedThe backfill sees every tenant (free 3, the others null) and puts FORCE back; the downgrade refuses the hand-set limit although this owner sees no tenant unfenced, and once it is cleared commits with the column gone and FORCE ontests/test_max_agents_migration.py::test_ac8_the_backfill_and_the_downgrade_see_every_tenant_as_the_hosted_owner
AC9The source of the modules a request passes through: execbound.requests, identity, runtime, the HTTP, MCP and human surfaces, the console's approval routes, and every module of execbound.execution, execbound.policy, execbound.resolution, execbound.arcade and execbound.providerNone names max_agents, agent_capacity or execbound.capacitytests/test_agent_capacity.py::test_ac9_nothing_on_the_request_path_reads_the_agent_limit
AC10execbound.capacity.agent_capacity on a workspace with a limit of two, after one creation, then after a hand deactivation and a sleepIt reads the limit and counts (2, 1, 0), then counts exactly what the cap counts, one held and one asleep; execbound.plans cannot be imported and execbound.administration has no plan_summarytests/test_agent_capacity.py::test_ac10_core_reads_the_limit_and_no_plan
AC12The runtime role and tenants.max_agentsUnder check_runtime the runtime reads the limit through the table-wide SELECT; it holds SELECT on the column and no INSERT, UPDATE or REFERENCES, tenants carries no column-level grant, and the runtime's UPDATE of the limit is refusedtests/test_agent_capacity.py::test_ac12_the_runtime_reads_the_limit_and_holds_nothing_that_writes_it
AC13A workspace with a limit of one and its scheduler principal, made by scheduler_actorThe scheduler principal is not counted: the capacity reads (1, 0, 0), one agent is still created, and the next is refused PLAN_LIMITtests/test_agent_capacity.py::test_ac13_the_scheduler_principal_is_never_counted
HF50The Agents page's line on a workspace with no limit, then after its max_agents is set to 3 with one of three agents asleepThe line carries no plan in either state; agent_limit reads null, then 3; agents_held 1, then 3, and agents_dormant 0, then 1: the sleeping agent still counts as heldtests/test_console_api_agents.py
HF51A workspace at its agent limit of three (max_agents 3) with one agent asleep, read through a real browser at 1280 and 390 px in both colour schemesThe line reads "Agents: 3 of 3.", then the limit sentence, "This workspace has reached its agent limit. Every agent you have keeps running." (the refusal toast's own words), then the dormancy sentence; the sleeping row carries an "Asleep" badge; every page is axe-cleantests/test_browser_console_directory.py
HF52A sleeping agent and a hand-deactivated agent, in the row list and in each one's detail pageThe row and the detail both carry a dormant field distinct from active, so asleep and deactivated read differently rather than both as merely inactivetests/test_console_api_agents.py

The Agents page's line is held by HF50 and HF51 above. The console's own tests hold the line's text (directory/agents.test.tsx: "Agents: 5." with no limit, "Agents: 1 of 3." under it, and the limit sentence at or over it). Core's Workspace settings ask for no plan and show no plan card (settings/WorkspaceService.test.tsx).

Denial notice (DN1 to DN10)​

An agent is told that a request was denied, the request's reference and one of three categories, and never the reason itself: a mistaken, prompt-injected or compromised agent gets no map of the policy from its denials, and a reviewer's words stay with people. DN1 to DN3 cover the notice itself, which discloses nothing new; DN4 to DN10 cover the busy and limit categories and the audit's specific causes for a refusal before any plan, with the readers those causes reach (threat row T1.16). Real PostgreSQL, the live endpoint provider, HTTP through the application and MCP over a real Streamable HTTP server.

IDSetup/actionRequired resultTest
DN1A domain controller's isolation over MCP, which the endpoint pack's deny rule refuses (NOT_AUTHORIZED); then one isolation under a principal budget of one that denies, and a second over HTTP (HARD_LIMIT:isolation-budget), each re-sent and read back on both surfaces; a third through the Python client's execbound_action; an administrator searching the console for each reference; a pending approval refused by a reviewer with a distinctive comment, then re-sent and read over HTTP and MCP; a DENIED view built without a referenceEach denial answers 200 DENIED with exactly the view's members, denial and notice: the deny rule's and the reviewer's withheld with "Denied. The reason is recorded for a person, who can find it by searching the console for EB-n. Re-sending this request returns this same answer.", the budget's limit with its own sentence (DN4), each naming its own reference; no member carries the recorded reason, the rule id, the fact or the words NOT_AUTHORIZED, HARD_LIMIT or HUMAN_DENIED; the MCP text content is the structured content and isError is false; re-sends and status reads answer the same bytes; the client's summary carries the same category and sentence and nothing of why; the console search for EB-n finds the denied execution and its record carries the reason; the refused request shows approval_state DENIED, the disclosure the view already made, while the comment, recorded in the audit chain, appears in no answer; the view without a reference gets the sentence without onetests/test_denial_notice.py::test_dn1_a_denied_answer_names_its_reference_and_nothing_of_why, ::test_dn1_a_reviewers_refusal_shows_as_the_approval_state_and_never_as_the_comment, ::test_dn1_a_denied_view_without_a_reference_still_says_nothing_of_why
DN2A pending approval over HTTP, read over MCP; the same request re-sent after its approval deadline; the target made autonomous and executed over MCP; an observing tenant's domain controller over HTTP; then every execution state through the presenter with no keys and no databasePENDING_APPROVAL, STALE_AUTHORIZATION, EXECUTED and OBSERVED carry no notice; the observed would-be denial keeps observed.reasons with NOT_AUTHORIZED, the deliberate exception; through the presenter, DENIED with no recorded category gains exactly denial withheld and the withheld notice, and every other state, with neither member, is answered exactly as the view serializestests/test_denial_notice.py::test_dn2_no_other_state_carries_a_notice, ::test_dn2_the_presenter_adds_a_notice_to_a_denial_and_to_no_other_state
DN3The execute tool's description, the agent guide and its OpenAPI schema, every agent instruction shipped (the OpenAI Agents recipe and both client tool examples, one of which the Claude Agent SDK recipe names), and every Python source under src/The description tells the model to call list_actions for the operation_ref values its space offers (LA8), that a denial's reason is kept for a person and to relay the request_ref rather than guess, in under 800 characters; the guide states the rule and its reason, shows the notice, promises only that re-sending the same request returns the same answer, states the approval_state disclosure, covers an observe-only mapping as well as a workspace, answers a busy target as a denial, lists exactly the reasons a denial records (with HUMAN_DENIED, without APPROVAL_REQUIRED or INVALID_APPROVAL, which never end a request as denied) and lists no RESOURCE_BUSY error; the schema describes notice for DENIED alone, with the withheld sentence among its examples; each instruction tells the agent to give the person the request_ref on a denial; no source raises RESOURCE_BUSY as an error or maps it to a status, and ERROR_STATUS has no entry for ittests/test_denial_notice.py::test_dn3_the_execute_tool_says_where_actions_come_from_and_to_relay_the_reference, ::test_dn3_the_guide_withholds_the_reason_and_answers_a_busy_target_as_a_denial, ::test_dn3_every_agent_instruction_shipped_tells_it_to_relay_the_reference, ::test_dn3_the_claude_agent_sdk_recipe_names_the_example_that_relays, ::test_dn3_nothing_in_the_gateway_raises_a_busy_target_as_an_error
DN4Each of four denials, first over HTTP and then first over MCP: the world's own target while another agent's admission holds its claim (RESOURCE_BUSY); a second target under a principal budget of one already spent (HARD_LIMIT:isolation-budget); a domain controller under that spent budget (HARD_LIMIT:isolation-budget and NOT_AUTHORIZED); a domain controller with no budget (NOT_AUTHORIZED). Each re-sent and read back on both surfaces; the busy one again after the holder executes and its claim is released, then a new request for the same target. Separately, a reviewer's refusal read over HTTP and re-sent over MCP, and a limit denial through the Python client's execbound_action; and, under a spent principal budget, one target the policy allows and one a deny rule forbidsThe recorded transition carries exactly those codes. The answers are busy, limit, limit and withheld (any recorded limit is limit, whatever sits beside it), each with exactly the view's members, denial and notice, and the notice is the category's: "Denied because another request holds this target. Re-sending this request returns this same answer; a new request after that one settles may be decided differently. A person can find it by searching the console for EB-n.", "Denied because a shared limit is spent. Re-sending this request returns this same answer; a new request after the limit resets is decided afresh. A person can find it by searching the console for EB-n." or the withheld sentence. No answer carries NOT_AUTHORIZED, HARD_LIMIT, RESOURCE_BUSY, the rule id, the fact, or the holding execution's id or reference. The first answer, the HTTP re-send and status read (byte for byte) and the MCP re-send and status read are one answer, and after the holder settles they still say busy; the new request is not denied. The reviewer's refusal is withheld with approval_state DENIED and no comment; the client's summary carries denial limit and its sentence and no rule id; the allowed and the forbidden target under the spent budget record HARD_LIMIT:isolation-budget and HARD_LIMIT:isolation-budget with NOT_AUTHORIZED, and answer alike but for their own identifiers, so the category is no per-target policy verdicttests/test_denial_categories.py::test_dn4_a_denial_names_its_category_and_nothing_more, ::test_dn4_a_reviewers_refusal_and_the_clients_summary_carry_the_category, ::test_dn4_under_a_spent_limit_an_allowed_and_a_forbidden_target_answer_alike
DN5Every execution state through the presenter with no keys and no database; a DENIED view with each category and with none; a view of any other state constructed with a categoryA denial gains exactly denial and the category's sentence, withheld when the view records none, and the category is not part of the view's own serialization; every other state carries neither member and is answered exactly as the view serializes; a category on any state but DENIED is refused at constructiontests/test_denial_categories.py::test_dn5_the_presenter_adds_a_category_to_a_denial_and_to_no_other_state
DN6store.denial_category over recorded payloads: RESOURCE_BUSY alone; one and two HARD_LIMIT codes; a limit beside NOT_AUTHORIZED, INVALID_CONTEXT or INVALID_USAGE, and beside NOT_AUTHORIZED and POLICY_ERROR; NOT_AUTHORIZED alone; RESOURCE_BUSY beside NOT_AUTHORIZED; HUMAN_DENIED; no codes; no keybusy only for the busy reason alone, limit whenever any code is a limit, withheld for everything else; each category's sentence, with and without a reference, names none of the codes or rule idstests/test_denial_categories.py::test_dn6_the_category_is_limit_for_any_recorded_limit_and_busy_only_alone
DN7The agent guide and its OpenAPI schemaThe guide names the three categories with each one's sentence, says a busy target means another request holds it and a limit means a shared limit is spent, says the category never names the rule, and says a limit is given whatever else denied the request, and its DENIED states row says that for busy or limit a new request after the other request settles or the limit resets is decided afresh, that re-sending returns the same answer and to tell a person the request_ref; the schema's denial is a string enumerating exactly the three categories, described as present only on a DENIED executiontests/test_denial_categories.py::test_dn7_the_guide_and_schema_document_the_three_categories
DN8Over HTTP and MCP: an unknown action, an unknown canonical target, an unknown hostname, a real target claimed under another target's incident, a run never issued, then the world's own request once its facts are stale; separately, resolve_snapshot failing with a database error, with a plain ValueError and with a resolution code outside the closed list; and a reviewer's approval whose reattestation after the decision refuses, with a listed code and with an unlisted one; then, through admit, a known target under another target's incident, an unknown canonical target, an unknown hostname, a hostname two live aliases name, a run never issued and a resolved target with no canonical identity row, each with every statement the database runs recordedEvery refusal answers 503 with exactly {"detail":"Execution unavailable","code":"EXECUTION_UNAVAILABLE"} over HTTP and the same refusal over MCP, whatever the cause; the audit records, once per surface, exactly {"operation": "admit", "reason": …} with INVALID_OPERATION, INVALID_TARGET, INVALID_TARGET, INVALID_CONTEXT, INVALID_RUN and INVALID_CONTEXT; the two dependency failures and the unlisted code are recorded as DEPENDENCY_OR_CONTEXT_UNAVAILABLE; the reviewer is refused EXECUTION_UNAVAILABLE as before and the audit records STALE_AUTHORIZATION for decide_approval, or the decision path's own DEPENDENCY_UNAVAILABLE for the unlisted code; through admit, the six refusals audit INVALID_CONTEXT, INVALID_TARGET, INVALID_TARGET, INVALID_TARGET, INVALID_RUN and INVALID_CONTEXT, and every one runs exactly the same statements in the same order, so no cause costs a round trip another does nottests/test_denial_categories.py::test_dn8_a_refusal_before_any_plan_audits_its_own_cause_and_answers_as_before, ::test_dn8_a_dependency_failure_or_an_unlisted_code_keeps_the_generic_reason, ::test_dn8_a_reviewers_decision_that_fails_reattestation_audits_its_cause, ::test_dn8_every_refusal_after_the_mapping_costs_the_same_statements
DN9Every ResolutionError raised under src/, and the literals the snapshot's refusal-path classification returnsEvery code is a literal in RESOLUTION_CODES, the closed list the audit records from, which does not contain the generic reason; the only non-literal argument is that classificationtests/test_denial_categories.py::test_dn9_every_resolution_code_the_kernel_raises_is_one_the_audit_records
DN10The live board's read after an unknown action and an unknown target are refused over HTTP, an unknown hostname over MCP, a reviewer's decision on an approval that does not exist, an administrator's change to a mode that does not exist and a malformed body at the surface; the board's read and the console's board route after a deny rule's denial with no limit beside it, then a denial under a spent principal budget of one and one under it beside the deny rule; the welcome page's progress over refusals audited as INVALID_OPERATION, INVALID_TARGET, INVALID_CONTEXT and, in another workspace, the historical DEPENDENCY_OR_CONTEXT_UNAVAILABLE; the Python client's summary of a denial carrying each category and an unknown one; the console's ticker over refusals, a reviewer's denial, a denial worded limit and a denial whose detail carries an approval obligation's limit: prefixEach of those refusals is recorded, and the board's refusal entries are exactly the three admission refused, with INVALID_OPERATION, INVALID_TARGET and INVALID_TARGET as their detail (the reader named a key the audit never wrote, so the detail was empty) and the window's "refused before a decision" figure three: no reviewer's, administrator's or surface refusal is drawn or counted, and the MCP refusal counts once; the two denials whose recorded codes include HARD_LIMIT:isolation-budget, which their agents are told are limit, are worded limit and the rule's alone denied, and the window counts two by a limit among three denied, in the read and in the route's answer (the reader looked for limit:, an approval obligation's prefix, under the singular reason a policy denial never writes, so neither the word nor the figure ever fired); "claim refused" is unset by the unknown action and target and set by INVALID_CONTEXT and by the historical code; the summary passes busy, limit and withheld and drops the unknown value; the ticker reads each refusal code as a sentence about a request refused before any plan ("The action named is not one this workspace offers.", "The target named could not be found.", and never "frozen arguments"), falls back to the phase's sentence for a code it has no words for, still reads a denial's recorded reason with the decision's words, says an impact limit blocked a denial worded limit, and does not say so for a limit: detailtests/test_denial_categories.py::test_dn10_the_board_reads_a_refusals_cause_where_the_audit_writes_it, ::test_dn10_getting_started_counts_a_claim_refused_under_either_code, ::test_dn10_the_client_summary_passes_only_a_known_category, ::test_dn10_the_board_words_and_counts_a_denial_by_a_limit_as_the_agent_is_told; console/src/components/board/board.test.tsx ("a request refused before a plan was frozen", and "the ticker"'s two limit cases)

The action listing, which applies the same rule to what an agent can discover, is the LA group below.

Action listing (LA1 to LA8)​

An agent lists the operations its own space offers, through GET /v1/actions and the MCP tool list_actions, and admission refuses every other operation exactly as it refuses an unknown one: the same 503, the same statements and no record, with the cause in the audit alone. It closes the two oracles threat row T1.16 records (threat row T1.17). A listed action is not permission, and a target is never listed. Real PostgreSQL, the live endpoint provider, HTTP through the application and MCP over a real Streamable HTTP server. The console's board words the two causes admission now audits for an operation outside the space, INVALID_CONFIGURATION and INVALID_BUNDLE, as refusals before any plan, in the console/src/components/board/board.test.tsx cases DN10 cites.

IDSetup/actionRequired resultTest
LA1bundle_operations over: the world's policy, which names one isolation mapping on the world's account; the SOC mappings seeded and not named; a policy naming the lift too; the isolation reference changed to another account, mapping version, schema version or contract version; the mapping, then its account, made inactive and active again; a reference the tenant does not map; an operation on a contract that requires no incident, under a catalog that holds the contract and under the production catalog; three references whose order differs by collation; the agent moved to a second space, then its account offered tenant-wideWhat the policy names on a current mapping, whose account is in the space or offered tenant-wide and whose tuple the catalog binds, is offered, in code point order of operation_ref whatever the database's collation, with its action, resource type and whether an incident is required; a mapping the policy does not name is not offered; a changed reference, or an inactive mapping or account, is stale and refused INVALID_BUNDLE; an unmapped reference is none of the three and refused INVALID_OPERATION; the operation needing no incident is offered as such under its catalog and refused INVALID_OPERATION under the production one; another space's account is named elsewhere and refused INVALID_CONFIGURATION until it is offered tenant-wide, when it is offeredtests/test_action_listing.py::test_la1_a_space_offers_what_its_bundle_maps_on_its_own_or_offered_accounts, ::test_la1_a_reference_the_tenants_mapping_no_longer_matches_is_stale, ::test_la1_an_action_that_needs_no_incident_says_so, ::test_la1_the_order_is_the_bundles_whatever_the_database_collation, ::test_la1_another_spaces_account_is_named_elsewhere_until_it_is_offered_tenant_wide
LA2Through admit, with the SOC mappings seeded: bad arguments for the offered isolation; the lift, which the tenant maps and the space's policy does not name, with bad and with good arguments; an operation nobody maps, with bad arguments; a request held for approval, then a changed request under its key naming the lift with bad arguments. Separately, the tenant's isolation mapping moved to a new account and mapping version while the policy names the old one, as a sample removal and reinstall leaves it; and the lift from an observing tenantThe offered operation's bad arguments are refused INVALID_REQUEST and audited INVALID_ARGUMENTS; every other request is refused EXECUTION_UNAVAILABLE whatever its arguments, audited INVALID_OPERATION, the changed request under a known key included, and the stale policy audited INVALID_BUNDLE; none records an execution, neither a DENIED row with INVALID_BUNDLE nor an OBSERVED one, so the held request's is the only rowtests/test_action_listing.py::test_la2_bad_arguments_answer_400_only_for_an_operation_the_space_offers, ::test_la2_a_stale_policy_is_refused_as_unknown_and_audited_as_itself, ::test_la2_an_observing_tenant_is_refused_the_same_way
LA3A request held for approval; then an unknown operation, the unnamed lift with bad arguments, the world's isolation after the agent moves to a second space and the same after its mapping is repointed (a stale policy), each as a new request and as a changed request under the held key, with every statement the database runs recordedThe four new requests run exactly the same statements in the same order, and so do the four changed requests under the known key, whose sequence differs from the new ones' because that branch reads the held row first; every one is refused EXECUTION_UNAVAILABLEtests/test_action_listing.py::test_la3_every_operation_outside_the_space_costs_the_same_statements
LA4Over HTTP with the live provider: a request held for approval; the agent moved to a second space that selects the same policy, its account left behind; then a new request, and the held one re-sent unchangedBoth answer 503 with exactly {"detail":"Execution unavailable","code":"EXECUTION_UNAVAILABLE"} and each is audited once as INVALID_CONFIGURATION: the new one by the offered check, the held one by _account_in_space, which it meets because an unchanged re-send skips the offered checktests/test_action_listing.py::test_la4_another_spaces_account_is_audited_as_itself_and_answered_as_unavailable
LA5The listing for the world's space; the listing for a policy naming the lift too; an identity action with a boolean argument; a catalog with an integer argument and a string argument whose set does not iterate in order; the world's mapping marked observe-only, then checkpoint; Runtime.list_actions with the structured log capturedEach listed action carries exactly operation_ref, action, label, arguments, target_kinds and incident_required: isolation with no arguments, the three target kinds and an incident required; the lift with reason and its two values; the identity action with its boolean argument, no values and no hostname kind; the integer argument with its minimum and maximum and the string one with its values in code point order. No listing contains the target, its canonical identity, the account, the provider, the provider operation, the mapping version, a hostname, a fact, observe, external_executor, a budget or a rule id; the observe-only and checkpoint listings equal the connected one and name no placement; actions.listed carries the principal and the count, and the log never names the operationtests/test_action_listing.py::test_la5_the_listing_names_operations_arguments_and_target_kinds_and_nothing_else, ::test_la5_an_identity_action_takes_no_hostname_and_each_domain_is_listed_as_it_is_checked, ::test_la5_an_observed_or_checkpoint_mapping_is_listed_as_a_connected_one_is, ::test_la5_the_runtime_logs_how_many_were_listed_and_never_which
LA6The agent moved to a second space, then its account offered tenant-wide; a stale policy; the policy selection removed; the agent's space archived; an emergency stop; a person's identityThe second space lists nothing until the account is offered to it, then isolation; a stale policy lists nothing; no active policy lists {"actions": []}; an archived space is refused SPACE_ARCHIVED; under the stop the listing is unchanged; a person is refused INVALID_IDENTITYtests/test_action_listing.py::test_la6_what_a_space_lists_follows_the_space_and_what_it_is_offered, ::test_la6_a_stale_policy_lists_nothing_it_can_no_longer_authorize, ::test_la6_no_active_policy_lists_nothing_and_an_archived_space_is_refused, ::test_la6_an_emergency_stop_does_not_stop_a_listing_and_only_an_agent_lists
LA7GET /v1/actions; the same with a query string and with a body; the same after the agent's space is archived; the published agent API document200 with the listing and Cache-Control: no-store; the query and the body each 400 INVALID_REQUEST, audited once each as the surface's refusal; the archived space 423 SPACE_ARCHIVED, audited once; the document's path answers ActionListing, whose ListedAction has exactly the six members and whose ListedArgument requires only name and type and has no nullable member; it documents 200, 400, 401, 403, 409, 423, 429 and 503 and nothing else, a 403 for a credential that is not an agent's, a Retry-After sent with RATE_LIMITED alone, and no TENANT_STOPPED, BUSY, IDEMPOTENCY_CONFLICT or TOO_MANY_GRANTStests/test_action_listing.py::test_la7_get_v1_actions_answers_the_listing_and_refuses_a_body_or_a_query, ::test_la7_an_archived_space_is_answered_423_and_audited_once, ::test_la7_the_published_document_describes_the_listing_and_only_what_it_can_answer
LA8Over MCP: list_actions with no arguments; tools/list; the tool with {"x": 1} and with {"request": {}}; a tools/call with no arguments member to each of the three tools over the raw transport, and list_actions through the SDK's own client; arguments sent as null, a list, a string and a number; the agent's space archived; the whole SOC pack active in the space, over HTTP and MCP; the execute tool's descriptionlist_actions answers exactly what GET /v1/actions answers; tools/list advertises exactly execute, execution_status and list_actions, the last with an input schema of no properties and no additional ones and a description saying a listed action is not permission and targets are never listed; any argument is a tool error INVALID_REQUEST; a call with no arguments lists the actions over the raw transport and through the SDK, while execute and execution_status refuse it INVALID_REQUEST; arguments that is not an object is refused 400 before any tool runs; the archived space is a tool error SPACE_ARCHIVED, audited twice as the surface's refusal, as a refused status tool is; the SOC pack lists its six operations in code point order alike over both surfaces, the lift with its values, the password reset with its boolean, the identity actions without a hostname kind and no member null; the description tells the model to call list_actions for the operation_ref values its space offers, no longer names the published catalog, and stays under 800 characterstests/test_action_listing.py::test_la8_the_mcp_tool_answers_what_the_route_answers_and_takes_no_arguments, ::test_la8_a_call_with_no_arguments_member_is_a_call_with_none, ::test_la8_an_archived_space_is_a_tool_error_audited_as_the_status_tool_is, ::test_la8_a_whole_soc_policy_is_listed_alike_over_both_surfaces, ::test_la8_the_execute_tool_sends_the_model_to_the_listing_for_action_names

Console editions (CE1 to CE15)​

The console is built as one of two editions from one source tree (Surfaces): the core edition, which the package and the self-hosted image carry and which never contains hosted code, and the hosted edition, which adds the hosted service's pages, cards and counts through the slots of one Edition (console/src/edition/context.ts). The server lists core's console pages only, and serves a plugin's where that plugin is loaded. The Python rows run on real PostgreSQL, the browser rows in real Chromium, and the console rows under Vitest, which resolves import() without chunking, so the hosted build's own manifest is the evidence that its cards load with their own chunks (CE11).

IDSetup/actionRequired resultTest
CE1The core build and core's lint over hosted code: a module under console/src/hosted/ among those the core build loaded, a ?raw one included, and an asset it emitted from one; src/hosted or the root reached through a link; a static, re-exported or lazy import of a hosted path, and @edition or @route-tree, in a core fileThe core build fails with "The core build reached hosted code:" and every hosted module it reached, and not src/hostedness.ts, which only looks alike; an asset emitted from a hosted file fails it too; src/hosted is named by its real path where it or the root is a link; the core build's configuration runs that refusal in its own bundle and in every worker's, resolves both aliases to core's files and writes into the package; core's stylesheets name no hosted file, and Tailwind's scan for core leaves the hosted sources out. ESLint refuses each such import, and either alias, in every core file under src/ and scripts/; it leaves alone a core import, a directory named alike (hostedness, ghosted, unhosted) and a lazy core chunk, lets src/main.tsx name the aliases while still refusing it hosted code, and leaves the hosted edition's own modules to import each otherconsole/scripts/editions.test.ts ("the core build's refusal of hosted code", "the core-only plugin", "the core build's configuration", "core's stylesheets"); console/scripts/bans.test.ts ("core's edition bans", "the project's edition bans")
CE2Core's edition, and core's pages rendered with no edition or with a stand-in oneEvery slot of the core edition renders nothing, its event asks the server nothing, and a component with no provider reads the core edition. Core's Workspace settings asks for no plan, product counts or sandbox, My account for no preference, Getting started starts from core's own reads, the shell asks nothing for a count and lists no Invitations entry, and the palette offers no edition link whatever features the session reports. A stand-in edition's content appears where its slot is placed, after core's own: an entry after core's in the sidebar, the tab bar, the breadcrumbs and the palette, and in the tab bar only where it asks; top bar items among the actions; panels after the workspace's requests and between the profile and the data requests; definitions after the active bundle; Getting started's part after its steps; a workstation where core names none, and none where core names its own, while core's answer is on its way or where it failed; and event at the shell's opening and when a decision completes an approvalconsole/src/edition/core.test.tsx; console/src/shell/shell.test.tsx ("shows an approver Home, Approvals, Activity, Live board and Settings", "the edition in the shell"); console/src/components/settings/WorkspaceService.test.tsx, console/src/components/tenant/TenantSettings.test.tsx, console/src/components/settings/PersonalSettings.test.tsx and console/src/components/welcome/WelcomePage.test.tsx (each "" case); console/src/approvals/approvals.test.tsx ("tells the edition when a decision completes the approval"); console/src/components/directory/agents.test.tsx ("names an edition's workstation where core names none", "where an edition's workstation stays out"); console/src/components/ui/CommandPalette.test.tsx ("an edition's links in the palette")
CE4The console addresses the server answers, with no plugin and with the hosted pluginWith no plugin the server's list is CONSOLE_ROUTES, core's 24 addresses, equal to core's generated route tree, and /invitations, /workspaces/{tenant_id}/approvals/{approval_id} and its /classic answer 404 under the pages' policy and are no console path. With the hosted plugin the list is core's, then the workspace-scoped approval address and /invitations, equal to the hosted route tree, and both serve the console document, carrying the running commit, under the console's policy. The hosted plugin's console page, /invitations, and the two workspace-scoped approval addresses, which are core's handlers mounted where a plugin registers approval links, are pinned as a session's and refuse an agent's credential, and core's own test holds the same refusal at the two addresses for a plugin that registers approval linkstests/test_console_serving.py::test_the_server_answers_exactly_the_addresses_the_application_has, ::test_without_a_plugin_its_console_addresses_are_not_served; tests/test_route_authority.py::test_a_plugin_route_refuses_an_agent_credential; for the hosted plugin's addresses, the hosted service's own tests
CE5Core's console API document and a plugin's, and the script that writes themThe committed console/openapi/console-v1.json equals core's document as the router builds it, schemas included, and names only the console API's own paths; a plugin's document holds only the routes its areas append, split where the same build's core areas end. The hosted service's own tests, which are not published, hold the rest: core's document carries none of the hosted plugin's paths or the models only they use, even when the hosted document was built first in the same process; the hosted plugin's committed document is current, holds exactly the hosted routes and none of core's paths, and is titled "ExecBound console API: hosted"; and scripts/console_openapi.py, given a plugin by name with --plugin, writes both documents, --check fails naming each missing or stale one and no other, and --output beside --plugin is refused before anything is writtentests/test_console_api_base.py::test_the_committed_openapi_document_is_current_and_names_only_the_console; tests/test_plugin_surfaces.py::test_a_plugins_console_document_holds_only_what_its_areas_add, ::test_a_plugins_console_document_splits_where_the_same_builds_core_areas_end; and the hosted service's own tests
CE6Core's GET /api/console/v1/samples as an approver, with an agent's credential, with no session, and with the administrator's personal access tokenThe approver is refused 403 FORBIDDEN; the agent's credential 403 and audited once; no session 401; the token reads exactly the status its owner readstests/test_console_api_samples.py::test_the_status_route_is_an_administrators, ::test_the_status_route_refuses_a_bearer_credential_and_a_missing_session; tests/test_console_api_tokens.py::test_a_token_reads_the_samples_status_its_owner_reads
CE7Each build's document and files, and readinessNeither the packaged core build nor the hosted build inlines a script or a style; each names its edition in its document's execbound-edition tag, the package's names core and its manifest lists no module under src/hosted/, and the hosted one names hosted; the server reads a well-formed name and none from a missing or malformed tag; /health/ready reports console, the edition the packaged build names, where the application has a human surface, and none where it has not; readiness in the key rotation test carries console as the packaged build names it and otherwise exactly its four fieldstests/test_console_serving.py::test_a_packaged_build_emits_no_inline_script_or_style, ::test_the_packaged_edition_is_read_from_the_document, ::test_readiness_reports_the_edition_the_packaged_build_names, ::test_the_packaged_build_is_the_core_edition; tests/test_key_rotation.py::test_kr5_kr6_private_configuration_reload_rotates_keys_and_refuses_other_changes; console/scripts/editions.test.ts ("the document's edition tag"); for the hosted build, the hosted service's own tests
CE9The approvals page, when the approval opened cannot be readIts "use the basic page" link opens the approval's own /approvals/{approval_id}/classic, whatever workspace the session is inconsole/src/approvals/page-empty.test.tsx ("links the basic page at the approval's own address when the record cannot be read")
CE10"Create a workspace": the hosted gate on real PostgreSQL, the session's features, and where the entry and its address appearWithout a plugin the session reports features [] and invitations false; with a plugin its features are listed by name; a session view with no features list, as an older server sends it, reads as naming none. The hosted service's own tests, which are not published, hold the rest. The hosted plugin registers create_workspace; it holds for an account's session with signups open or review and no consumed Community allocation, an unresolved allocation included, and not for a session that is not an account's, with no signups block or closed signups, or once the allocation is consumed; the entry shows exactly where the sign-in page links /signup; another account's consumed allocation of the same workspace never decides the gate; over HTTP the console session reads create_workspace in features until the allocation is consumed. The hosted edition's entry links /signup where the feature holds, is absent otherwise, sits among the top bar's actions, after the mode and the emergency stop and before Ask, in the hosted edition alone, and is in the palette too; given a session view with no features list, the hosted shell renders, its palette opens, and neither offers the entry. No script or document of the packaged core build names /signup, /invitations or any path of the hosted plugin's committed console API document, ten today, each matched only where it ends, with a parameter standing for any one segment, so core's /api/console/v1/welcome/example is not the hosted /api/console/v1/welcome; and the hosted build's scripts link /signup. Those two build checks pass without checking anything where their build is absent, the core one without pnpm build and the hosted one without pnpm build:hosted (console/dist/hosted); CI builds the core console before the suite, and in the development repository the hosted one as welltests/test_console_api_base.py::test_without_a_plugin_the_session_reports_no_feature; tests/test_plugin_surfaces.py::test_the_session_reports_a_plugins_invitations_feature_as_its_check_answers; console/src/lib/SessionProvider.test.ts ("reads no features from a view that names no list, as a rolled-back server's"); and the hosted service's own tests
CE11The hosted build inside core's budgetsA workspace approval link opened cold is charged to the approval budget, 160 KB, and a hosted route like any other route. The hosted service's own tests, which are not published, hold the rest: each hosted card (the three settings panels, Welcome, FixtureHint) and the counter is a dynamic entry of the hosted build that index.html's static imports never reach, and each lazy slot, once loaded, renders its card. The test that reads the hosted build's manifest passes without checking anything where console/dist/hosted is absent. In the development repository, CI builds the hosted edition before the suite, and CI's console job holds pnpm build:hosted to every budgetconsole/scripts/budget.test.ts ("charges a hosted edition's route like any other route", "holds a workspace approval link, opened cold, to the approval budget"); in the development repository, CI's console job (the budget itself); and the hosted service's own tests of the hosted build's manifest and of its slots
CE12A plugin's session feature check that raises, directly and through the console session; one refused by the databaseThe feature is withheld, the others still read, and plugins.feature_failed is logged at ERROR with the feature's name and none of the exception's text; the console session still answers 200, with the feature in neither invitations nor features; a check that raises DormantGrantsRefused propagates, and no feature failure is loggedtests/test_plugins.py::test_a_session_feature_whose_check_raises_is_withheld_and_logged_by_name, ::test_a_session_feature_check_refused_by_the_database_is_not_swallowed; tests/test_plugin_surfaces.py::test_a_session_feature_check_that_raises_withholds_the_feature_and_the_session_answers
CE13The hosted top bar in real Chromium, for an account's session with the workspace chip, at 320, 360, 390 and 500 px with Ask, 480 px without it, and at 900 and 1024 px; core's own at 900 and 1024 px; and both at 768 px, the narrowest width with the sidebar, with Ask and without itUp to 500 px the bar holds core's six controls and no seventh, none over another or in a gutter, in both schemes, nothing scrolls sideways and axe finds nothing; from 360 px the Space switcher keeps a usable width; Menu's navigation sheet offers "Create a workspace" among its actions, inside the sheet's own box, and it opens /signup. At 900 and 1024 px the entry and Ask show their icons alone, each keeping its name, and at 1280 px the entry shows its label; core's bar at 900 and 1024 px, with Ask where a deployment has it, has nothing over anything else and nothing in the gutter. At 768 px, beside this long a workspace name, the emergency stop's whole box is on screen with room for a 15 px classic scrollbar, with Ask and without it: in core's bar with its label shown and Ask, where there is one, after it, and in the hosted bar with the entry after ittests/test_browser_workspaces.py::test_no_top_bar_control_overlaps_another_on_a_tablet_or_small_laptop, ::test_the_emergency_stop_stays_on_screen_at_768_px; for the hosted top bar, the hosted service's own tests
CE15The hosted cards' reads failing, first and in the backgroundThe plan card asks again once on its own after any failure, a 404 included, and then shows the failure with Try again, which reads the plan again; the consent card shows a failure with Try again, a 404 included, which reads the setting again, keeping its heading and the focus while it does; the product counts show a failure with Try again, which reads them again; Getting started's hosted part shows a first read that failed as a failure with Try again, which reads it again; a card that has loaded, the plan, the counts, the fixture inventory with its disclosure open, and core's own data and closure requests, keeps what it read through a background read that failsthe hosted edition's own tests; console/src/components/settings/WorkspaceService.test.tsx ("keeps the requests it read through a background read that fails")

Tests live in tests/test_console_serving.py, tests/test_console_api_base.py, tests/test_plugin_surfaces.py, tests/test_plugins.py, tests/test_console_api_samples.py, tests/test_console_api_tokens.py, tests/test_route_authority.py, tests/test_browser_workspaces.py and tests/test_key_rotation.py; in the console's scripts/editions.test.ts, scripts/bans.test.ts and scripts/budget.test.ts, src/edition/core.test.tsx and the core pages' tests CE2 names; in the development repository's CI, which holds the hosted build to the budgets (CE11); and, for the hosted plugin and its edition, in the hosted service's own tests.

Console shell and navigation (NV1 to NV19)​

The console's shell around every page (Surfaces, The console's shell): page names and the document title, the bell, the keyboard, the phone's navigation sheet, the command palette's Recent, commands and all-spaces retry, focus, Help, a failed page's report, release navigation and the first paint. Like CR and CE, whose evidence is mostly the console's own Vitest suites, the group is not in the validation manifest's prefix list. The browser rows run in real Chromium against the real gateway on real PostgreSQL.

IDSetup/actionRequired resultTest
NV1A list route, a detail route (an approval, an agent with a markup label, a monitored agent with a hostile display name), in a space and in All spacesThe title reads the page's own words, its section, the space, the workspace and ExecBound, most specific first; no hostname, target, agent label or display name is in it; ExecBound is restored on unmountconsole/src/shell/title.test.tsx ("the document title"); console/src/shell/page-name.test.tsx; the hosted edition's own tests; tests/test_browser_console_shell.py::test_nv1_titles_name_the_page_and_never_a_server_string
NV2Two approvals assigned, then a third while the tab is hidden; the tab shown again"(2)" then "(3)" in the title; no request of any kind while hidden; the count corrected on returnconsole/src/shell/title.test.tsx ("counts the approvals waiting for this person", "reads 50+", "asks for nothing while the tab is hidden"); tests/test_browser_console_shell.py::test_nv2_the_title_counts_what_waits_and_asks_nothing_while_hidden
NV3The pending count rises by two within a second; then a switch to another space with approvals waitingOne polite announcement, "4 approvals waiting for you"; none on the first read, for an unchanged count, or as the new space's countconsole/src/shell/title.test.tsx ("the waiting count's announcement")
NV4The bell for an approver with assigned approvals, for an administrator with findings, approvals waiting on other approvers (more than fifty, then fewer) and uncertain dispatches, and for a person with nothingThe dot and the name count assigned approvals and, for an administrator, open findings; the others row counts only approvals the administrator is not assigned to, reads "50+" with a next page, links to /approvals?view=others and is not in the dot; no row names a period; the administrator's two reads are made only while the panel is open, and an approver's panel makes neither; links only, no decision control; "Nothing is waiting on you."; the security log belowconsole/src/shell/notifications.test.tsx
NV5g a, g p, g ?, g x, g then a 1.1 s pause, g a in a field, with a dialog open, and g p for an approverNavigates only to a visible entry; g ? goes to Help and does not open the keyboard list; nothing for an unknown key, after the timeout, while typing, over a dialog, or to an entry the role cannot seeconsole/src/lib/keys.test.tsx ("g then a letter"); console/src/shell/shell.test.tsx ("gives the pages their g keys, each once", "goes to a page on g then its letter"); console/src/components/ui/Shortcuts.test.tsx
NV6Single-key shortcuts turned off from My account's Appearance card and from the keyboard list; storage that throwsBoth switches show the same state; ?, g sequences, j and k do nothing and Ctrl K still opens search; the choice survives a reload; with storage throwing they stay on and nothing failsconsole/src/lib/keys.test.tsx ("the single-key preference"); console/src/components/settings/PersonalSettings.test.tsx ("the single-key switch in Appearance"); console/src/components/ui/Shortcuts.test.tsx; console/src/shell/shell.test.tsx ("opens nothing on ? while single keys are off")
NV7j on the Approvals page with no row focusedThe first queue row takes focus, as on Activityconsole/src/approvals/approvals.test.tsx ("focuses the first row on j from no focused row"); console/src/lib/keys.test.tsx ("j and k along a list")
NV8Menu at 390 px for an administrator and an approver, in both schemes; the hosted edition with "Create a workspace"The sheet opens with no field focused and the word not overflowing; every visible entry reachable in two taps; the same pills as the sidebar, the Monitoring pill included; the edition's action and Ask are in it; axe clean; nothing scrolls sidewaysconsole/src/shell/sheet.test.tsx; the hosted edition's own tests; tests/test_browser_console_shell.py::test_nv8_the_phone_menu_opens_the_navigation_sheet; tests/test_browser_console.py::test_every_entry_is_clean_at_phone_width
NV9A policy version's Rules page and an agent at 768, 1024 and 1280 px; /ask without an assistant; the hosted workspace-scoped approval route"Policies / Policy version … / Rules" with linked ancestors, never marked current; "Not found" on the missing page; the middle crumbs collapsed from 768 to 1099 px behind a "…" button that opens them as links by keyboard; axe clean at 1024 px with the list open and closed; the emergency stop's whole box on screen at 768 px; the hosted approval's title carries "Approvals"console/src/shell/shell.test.tsx ("the breadcrumb"); console/src/shell/page-names.test.tsx; tests/test_browser_console_shell.py::test_nv9_a_policy_versions_rules_name_their_ancestors
NV10Typing "people", "tenant", "approvers", "bundle" and "mfa" in the paletteUsers, Workspace settings, Approval rules, Policies and My account, each showing the word that matchedconsole/src/components/ui/CommandPalette.test.tsx ("finds a page by the words people use for it"); console/src/shell/shell.test.tsx ("gives every page the words people search for it by")
NV11Recents across two principals and two workspaces in one browser; an approval visited by an approver whose scope is then deactivated; an approval assigned to someone else, visited by an administrator; a tampered stored listEach person sees only their own; the approval is recorded as its execution; the revoked record is absent; the administrator's visit is shown; a tampered list shows nothing; storage holds no labelconsole/src/lib/recents.test.tsx; console/src/components/ui/palette-commands.test.tsx ("Recent"); tests/test_browser_console_shell.py::test_nv11_recents_are_per_person_and_drop_revoked_records
NV12Each palette command, as an administrator, as an approver, and as a session holding access.manage without the ADMIN roleShown only where its target page is visible and its dialog's control would be; each opens its dialog and performs nothing on Enter; the stop asks its reason and confirmation; Copy link copies the router-built address, and on an approval route the validated link; a person result from the search is listed under Records and opens /people/<id> for an administrator holding access.manageconsole/src/components/ui/palette-commands.test.tsx ("Commands", "the empty palette's hint, name and people"); console/src/lib/commands.test.tsx
NV13A record in another of the person's spaces, searched from a space"No record matches in ." and "Search all your spaces", which switches to All spaces through the session and finds it; no ?space= anywhereconsole/src/components/ui/palette-commands.test.tsx ("searching all your spaces"); tests/test_browser_console_shell.py::test_nv13_a_record_in_another_space_is_found_by_searching_all_spaces
NV14An Activity chip, a Home record, a drawer opened and closed by keyboard and from an address on Activity and on Home; a sidebar navigationFocus stays on the chip; closing returns focus to the row on both pages; a page change focuses the heading; the filtered count is announced onceconsole/src/shell/shell.test.tsx ("focus on a change of the query alone"); console/src/routes/-activity.test.tsx and console/src/routes/-home.test.tsx (each "NV14" case); tests/test_browser_console_shell.py::test_nv14_focus_stays_on_a_query_change_and_returns_to_the_row
NV15Help with and without help_url, a support address and a release; the palette with and without an assistantDocumentation only where named; Keyboard opens the list; the version with copy, or the no-version line; the console's words; "Search" or "Search or ask" accordinglyconsole/src/routes/-help.test.tsx ("Help's own cards"); console/src/components/ui/palette-commands.test.tsx ("is Search without an assistant", "is Search or ask where the deployment has an assistant")
NV16A page that throws, on an approval route and elsewhere; a typed FORBIDDEN, NOT_FOUND and UNAVAILABLE; four throws in one load; a throw where crypto.subtle is absentOne report each with the route pattern and bounded fields, never the path or message; the reference shown; the codes' own words with no report; no more than three reports; without crypto.subtle no report and no referenceconsole/src/lib/client-errors.test.ts; console/src/components/RouteError.test.tsx ("what a failed page says and reports"); tests/test_browser_console_shell.py::test_nv16_a_failed_page_reports_once_by_its_route_and_shows_a_reference
NV17A record's drawer on Activity and on Home, with and without an assistantNo disabled Explain anywhere; exactly one Explain below the record where an assistant existsconsole/src/routes/-activity.test.tsx and console/src/routes/-home.test.tsx (each "NV17" case)
NV18A newer release noted, then a page change, a filter change, a page change during a change in flight, Reload with a dialog open, and the board idle for 60 sA document navigation on the page change only; none during the change in flight; the banner's Reload disabled while it is sent; with a dialog open Reload asks once before reloading; the board reloads when idleconsole/src/shell/release-navigation.test.tsx; console/src/shell/release-in-shell.test.tsx; tests/test_browser_console_shell.py::test_nv18_a_newer_release_loads_on_the_next_change_of_page
NV19A cold load with the session read held and then failing; a root component that throws on render; hovering a row and focusing its button, then opening itThe frame stays until the session is known and the error renders in the frame's styling; after the throw the frame is gone and the error card visible; one read per row, and the drawer opens without a second request within five secondsconsole/src/lib/frame.test.tsx; console/src/components/RecordTable.test.tsx ("reading a record before it is opened")

Tests live in console/src/shell/*.test.tsx, console/src/lib/keys.test.tsx, console/src/lib/recents.test.tsx, console/src/lib/commands.test.tsx, console/src/lib/client-errors.test.ts, console/src/lib/frame.test.tsx, console/src/components/ui/palette-commands.test.tsx and tests/test_browser_console_shell.py.

Self-hosted export (EX1 to EX10)​

What leaves the development repository for the public self-hosted one, and what the public copy does without the hosted plugin. scripts/export_foss.py builds the public tree from one commit, checks it and publishes it; scripts/ci.py is the public repository's CI, run one stage at a time. EX1 to EX4, EX6 and EX7 test the development repository's own export tooling and are kept in its private inventory. EX5's stage list, EX8, EX9 and EX10's preflight and provenance are exported tests and are registered as group EX in ACCEPTANCE_PREFIXES; EX10's workflow tests are private, like EX5's. The builder's and publisher's tests use a fixture repository, a local bare target and a fake API, never the network; EX8's pages and EX9's token calls run on real PostgreSQL.

IDSetup/actionRequired resultTest
EX5scripts/ci.py --print for every stage and for chosen ones, with the defaults and with every setting from the environment, a setting it cannot use and an unknown stage; a failed stage; the script under the system Python; the public ci.yml and export-suiteThe stages are sync, lint, licences, console, tools, database, suite, package, validation, restore, monitoring, image, provenance, fresh-machine and cleanup, and all prints each in that order and runs nothing; ports, names and workers come from the environment, the worker count otherwise one per CPU the machine gives the run and at most four, and one that cannot be used is refused before anything runs; the restore commands never show the password; a failed stage skips the rest but not cleanup; the script needs nothing but the system Python; provenance describes the image image built, from an environment synced as the Dockerfile syncs the image's and installed apart from the project's own, records the run GitHub names, and cleanup removes that environment and nothing it published. The public workflow calls every stage once and in order, cleanup whatever failed before it, on GitHub-hosted ubuntu-latest alone, with every action pinned to a full commit and a token that reads the repository and nothing else; the export puts it in place of the development repository's workflow; export-suite runs every stage against a tree built from its own committests/test_ci_stages.py::test_the_stages_are_the_workflows_in_order, ::test_all_prints_every_stage_in_order_and_runs_nothing, ::test_every_setting_comes_from_the_environment, ::test_the_default_worker_count_follows_the_machine, ::test_an_explicit_worker_count_wins_over_the_machine, ::test_a_setting_that_cannot_be_used_is_refused_before_anything_runs, ::test_an_unknown_stage_is_a_usage_error, ::test_the_restore_commands_never_show_the_password, ::test_a_failed_stage_skips_the_rest_but_not_cleanup, ::test_the_script_runs_with_the_system_python_alone, ::test_provenance_describes_the_image_the_image_stage_built, ::test_the_sbom_environment_is_synced_as_the_dockerfile_syncs_the_image, ::test_a_real_provenance_run_records_the_run_and_installs_apart, ::test_cleanup_removes_the_environment_provenance_described, tests/internal/test_public_workflow.py::test_the_workflow_calls_every_stage_once_and_in_order, ::test_cleanup_runs_whatever_failed_before_it, ::test_the_workflow_runs_on_github_hosted_ubuntu_alone, ::test_every_action_is_pinned_to_a_full_commit, ::test_the_token_reads_the_repository_and_nothing_else, ::test_the_export_puts_it_in_place_of_this_repositorys_workflow, ::test_the_export_suite_runs_every_stage_against_a_tree_built_from_the_commit
EX8ServiceLinks with each kind of bad link and address, and the longest it admits; a runtime file with a service block, a bad one and one changed on reload; a gateway with no service links, with only core's default, with links from its configuration, from a plugin, and from both; a service block that leaves out source_url, names another or sets it to null; the sign-in page, the footers, the MFA pages and the console session; a plugin registering links twice, and two plugins registering themA link is https:// with a host and no user information, printable, at most 200 characters and free of quotes, angle brackets, backquotes and backslashes, while an @ after the host is admitted; an address is one @ between letters, digits and ._+- and a dotted domain of at most 190 characters, so nothing in it can add a header to a mailto: link; a bad block or an unknown field refuses the file, and a changed block is refused on reload; without links no page links to a service page; with neither a block nor a plugin's links every footer links only Source, to the public repository, a block keeps it unless it names another address or null, and a plugin's links replace it with theirs; with them each page links exactly the deployment's addresses and the session carries them in service; a plugin sets them once, and a second plugin's links, or a block beside a plugin's, is PLUGIN_CONFLICT and refuses starttests/test_service_links.py::test_no_service_links_is_every_link_absent, ::test_a_link_is_an_https_address_of_at_most_two_hundred_characters, ::test_a_link_carries_no_user_information, ::test_an_at_sign_after_the_host_is_admitted, ::test_a_support_address_is_one_at_sign_between_a_short_local_part_and_a_domain, ::test_the_longest_address_and_link_are_admitted, ::test_a_service_block_with_a_bad_link_or_an_unknown_field_refuses_the_file, ::test_a_reload_that_changes_the_service_block_is_refused, ::test_a_service_block_beside_a_plugins_links_refuses_start, ::test_without_service_links_no_page_links_to_a_service_page, ::test_the_sign_in_page_and_every_footer_link_the_deployments_pages, ::test_the_mfa_pages_offer_account_help_only_at_the_deployments_address, ::test_the_console_session_carries_the_deployments_service_links, ::test_core_names_its_public_source_where_nothing_else_names_links, ::test_a_service_block_keeps_the_source_link_unless_it_names_another_or_none, ::test_every_footer_links_the_public_source_where_nothing_names_other_links, tests/test_plugins.py::test_a_plugin_sets_its_service_links_once, ::test_service_links_are_exactly_a_service_links_whose_values_hold, ::test_a_second_plugin_registering_service_links_conflicts, ::test_the_service_links_come_from_the_configuration_or_a_plugin_never_both
EX9A plugin's token_routes with its own route; with any method of a path whose shape core classifies, a renamed parameter included; a pair in both of its sets, a path outside the console API, a method not in upper case, pairs that are not exact strings, and a second call; two plugins classifying one route; a token calling the sample plugin's routes; every console API route served; the welcome page's two old download addresses without the hosted pluginA plugin classifies only its own console routes: any method of a core path, compared by shape, and every malformed classification refuse the plugin with INVALID_TOKEN_ROUTES, and two plugins on one route are PLUGIN_CONFLICT, so no plugin can loosen or restate a route of core's; core's answer is decided before a plugin's is read, even for a plugin's set built by hand; a token calls the route a plugin allows and is refused, with TOKEN_NOT_ALLOWED, one it refuses or leaves out; every route is in exactly one set; without the plugin the two old addresses answer 404tests/test_plugins.py::test_a_plugin_classifies_its_own_console_route_for_tokens, ::test_a_route_a_plugin_refuses_or_leaves_out_is_refused_to_a_token, ::test_a_plugin_cannot_allow_any_method_of_a_core_path, ::test_a_plugin_classifies_its_token_routes_once, ::test_token_routes_are_the_plugins_own_console_routes_and_methods, ::test_two_plugins_classifying_one_route_conflict, tests/test_plugin_surfaces.py::test_a_token_calls_the_route_a_plugin_allows_and_no_other, tests/test_route_authority.py::test_every_console_api_route_says_whether_a_token_may_call_it, tests/test_console_serving.py::test_the_paths_that_moved_redirect_so_a_bookmark_still_arrives
EX10release_preflight.py check against a fixture repository and a fake API: a releasable tag; tags that are not release versions; a package version wrong in a project file or in the lock; a project file that names another package or cannot be read; missing and empty notes; a commit off main; a tag that points elsewhere; image names off ghcr.io, with a tag or a digest, in capitals or empty; CI runs each wrong in one field, and answers of the wrong shape; approved and record with an approval, a rejection, another environment's approval and none; bad values and a missing file; release_provenance.py --amend over a matched build, an unmatched one, a signed one and bad values; the public release.ymlcheck prints the version, the minor line, the image, the notes and the passing CI run, and otherwise names every reason and exits 1, reading no API when the repository itself is wrong; the API is asked for a successful push to main on exactly the commit, and every answer is checked anyway; the token goes to the GitHub API alone; approved and record refuse without an approval for release, and record then writes nothing; the record names the release, the image and its digest, the signature, the CI run, the run, the approval and each published file's digest, and the notes are the reviewed file and then the commands to pull and verify the image; --amend adds the registry digest and the signature only to a build whose SBOM matched its image, and changes nothing else; the workflow starts on a version tag alone on GitHub-hosted runners; build can only read and runs every third-party step; publish holds every write behind the release environment, checks the approval before it pushes, refuses a published version, signs the pushed digest with a checksum-pinned cosign and verifies it before the provenance, the record and the release; nothing is tagged latest, no secret is held and nothing is interpolated into a script; the export carries the workflow, its script and the notestests/test_release_preflight.py::test_a_releasable_tag_passes_with_the_values_the_workflow_reads, ::test_a_tag_that_is_not_a_release_version_is_refused, ::test_every_package_must_carry_the_tags_version_in_its_project_and_the_lock, ::test_a_project_file_that_names_another_package_or_cannot_be_read_is_refused, ::test_missing_or_empty_release_notes_are_refused, ::test_a_commit_that_is_not_on_main_is_refused, ::test_a_tag_that_points_at_another_commit_is_refused, ::test_an_image_off_ghcr_or_with_a_tag_a_digest_or_capitals_or_none_is_refused, ::test_ci_must_have_passed_on_exactly_this_commit_for_a_push_to_main, ::test_an_answer_that_is_not_a_list_of_runs_is_refused, ::test_problems_in_the_repository_refuse_before_the_api_is_read, ::test_the_token_is_sent_to_the_github_api_and_nowhere_else, ::test_the_record_names_the_release_its_checks_its_approval_and_each_files_digest, ::test_the_notes_are_the_reviewed_file_then_how_to_pull_and_verify_the_image, ::test_without_an_approval_for_the_release_environment_nothing_is_recorded, ::test_an_approvals_answer_that_is_not_a_list_is_refused, ::test_bad_values_and_missing_files_are_refused_before_the_approval_is_read, ::test_the_command_line_prints_the_values_for_github_output, ::test_the_command_line_prints_every_reason_and_exits_1, ::test_the_command_line_needs_a_token, ::test_the_script_runs_with_the_system_python_alone, ::test_the_publishing_job_starts_only_on_an_approved_run, ::test_an_approval_is_read_only_for_a_real_run_of_a_real_repository, tests/test_release_provenance.py::test_a_release_records_the_digest_and_the_signature_and_nothing_else_changes, ::test_a_value_that_cannot_be_a_release_is_refused, ::test_only_a_build_whose_sbom_matched_its_image_can_become_a_release, ::test_a_document_that_is_signed_already_or_of_another_format_is_refused, ::test_the_runner_is_the_one_github_names_or_local, ::test_the_command_line_amends_the_document_in_place, ::test_the_command_line_refuses_a_document_it_cannot_amend, ::test_the_command_line_takes_a_build_or_a_complete_release, tests/internal/test_public_workflow.py::test_a_release_starts_on_a_version_tag_and_nothing_else, ::test_the_release_runs_on_github_hosted_ubuntu_alone, ::test_only_the_approved_publishing_job_can_write_anything, ::test_third_party_code_runs_only_where_nothing_can_be_written, ::test_every_release_action_is_pinned_to_a_full_commit, ::test_cosign_is_one_pinned_release_checked_against_its_digest_before_it_runs, ::test_the_signature_covers_the_pushed_digest_and_is_verified_before_anything_is_published, ::test_nothing_is_pushed_on_a_run_nobody_approved_or_over_a_published_version, ::test_the_build_checks_the_release_before_it_builds_anything, ::test_no_release_is_ever_tagged_latest, ::test_the_release_holds_no_secret_and_interpolates_nothing_into_a_script, ::test_the_export_carries_the_release_workflow_its_script_and_the_notes

Step-up in place (SU1 to SU15)​

The console's MFA step-up, as decided on 28 September 2026: the check stays on every route that had it, its window is thirty minutes, and the console asks for the factor in a dialog over the page instead of sending the person to Account security. Real PostgreSQL throughout; the client in Vitest; the case that prompted it in Chromium.

IDSetup/actionRequired resultTest
SU1A factor verified on a session, then the injected clock moved 29 and 31 minutes on, the session read every seven minutes so it stays alive; the console's step-up, a recovery-code replacement from the security page, and the definer function's own recovery change reached directly; a first-time enrollment 4 and 6 minutes after signing inAt 29 minutes the step-up passes and both changes go through; at 31 each is refused RECENT_AUTH_REQUIRED, the definer function included (0067). mfa.STEP_UP_WINDOW is thirty minutes. Enrollment at 4 minutes starts and at 6 is refused: the sign-in's own age keeps its five minutestests/test_mfa_sessions.py::test_a_verified_factor_steps_a_session_up_for_thirty_minutes, ::test_the_database_holds_the_same_thirty_minute_window, ::test_first_time_setup_still_needs_a_sign_in_within_five_minutes, ::test_security_changes_require_recent_factor_and_rotation_invalidates_old_token
SU2Migration 0067 applied from 0066 and rolled backOnly fresh's interval changes in account_security_change and user_security_change, from five minutes to thirty; every other five-minute interval stays; both keep their ACLs; the downgrade restores both definitions byte for bytetests/test_step_up_window_migration.py::test_only_the_recent_factor_interval_moves_and_the_downgrade_restores_it
SU3POST /api/console/v1/session/verify with an agent's bearer credential, with no session, with a wrong CSRF header, another Origin, text/plain, an unknown field, a 65-character code, and as a GET403 FORBIDDEN audited once; 401 SESSION_REQUIRED as JSON; 403 INVALID_CSRF; 403; 415; 400 INVALID_BODY; 400 naming code; 405; none of them touches the factor, whose code still works afterwards. A personal access token is refused by token_rules.pytests/test_console_api_step_up.py::test_only_a_signed_in_person_reaches_it, ::test_the_token_the_origin_and_the_body_are_checked_first
SU4An enrolled administrator whose factor is past the window: a wrong code, five wrong codes then a right one, an unused recovery code and the same one againA wrong code answers 400 INVALID_FACTOR, "That code could not be used.", records account_security.verification_failed, sets no cookie, and the change still asks; after five the right code is refused too, the page's own lock; a recovery code steps the session up once, records account_security.recovery_used, leaves nine, and is refused a second timetests/test_console_api_step_up.py::test_a_wrong_code_says_so_and_changes_nothing, ::test_five_wrong_codes_lock_verification_as_the_page_does, ::test_a_recovery_code_steps_up_once
SU5A token issue refused MFA_REQUIRED, a current code verified, the token issue sent again with the old CSRF token and then with the new one; a session still at the second step of signing in; an administrator with no factor; a deployment with no account securityThe refusal creates nothing. The code answers 200 {csrf_token} under no-store, sets both cookies HttpOnly and SameSite=Strict, ends the old session token and keeps the session id, and records account_security.verified. The old token's resend is refused INVALID_CSRF and creates nothing; the new one's issues the token, and GET /session hands over the same new token. The signing-in session is refused MFA_REQUIRED and keeps /mfa; no factor answers 409 CONFLICT; no account security, 503 UNAVAILABLEtests/test_console_api_step_up.py::test_a_current_code_rotates_the_session_and_the_change_goes_through_resent_once, ::test_a_session_still_signing_in_is_left_to_the_mfa_page, ::test_without_a_factor_or_account_security_it_refuses
SU6An account's password sign-in with a factor enrolled; its password changed twenty minutes on, then again thirty-five minutes on, verified in place and sent againThe change at twenty minutes goes through: the console's check and the database's agree. At thirty-five it is refused MFA_REQUIRED, the code (with the workspace header) answers a new token, the old token's resend is refused INVALID_CSRF, and the new token's goes throughtests/test_console_api_step_up.py::test_an_account_changes_its_password_twenty_minutes_on_and_after_stepping_up
SU7The console: a change refused MFA_REQUIRED then accepted; cancelled; refused again after a code; two refused together; a read refused MFA_REQUIRED; nothing registered to ask; a poll in flight when a code is checked. The Invite teammate dialog with a wrong code, a right code and Cancel. In Chromium, the case that prompted the change: an administrator with an authenticator, signed in with it thirty-four minutes earlier on the injected clock, opens Users, then Invite teammate, types an address and clicks InviteThe change is sent again once with the new CSRF token and the same body; Cancel returns the refusal with no navigation and the page says "This change was not made."; a second refusal is shown without a second question; two refusals share one question; a read still goes to /mfa, as does a change when nothing can ask; the code waits for the poll and later requests wait for the code. The dialog opens over the invitation's, which keeps the address; a wrong code says so and can be tried again; a right one sends the invitation, which appears under Pending invitations, without the page navigating; the session cookie has rotated and the page carries on with it; axe finds nothing in either scheme at 1280 and 390 px with the dialog open, nothing scrolls sideways, and the page records no policy or Trusted Types violationconsole/src/lib/client-config.test.ts ("a change refused for a factor verified too long ago"), console/src/components/StepUpDialog.test.tsx; tests/test_browser_console_step_up.py::test_an_invitation_asks_for_a_code_over_the_users_page_and_is_sent_without_leaving
SU8Every step-up prefix against the console's route table; an enrolled administrator whose factor is past the window registers a tenant identity provider, verifies a code, registers it, and then, past the window again, switches itEach prefix covers at least one change core serves, the hosted plugin's /invitations covers none of core's, and both /tenant/sign-in routes are under one. The first registration is refused MFA_REQUIRED and registers nothing; after the code the same registration goes through; the switch is refused MFA_REQUIRED and the provider stays a draft. Until 2 October 2026 the prefix read /sign-in/, which matched no route, so neither was askedtests/test_console_api_step_up.py::test_every_step_up_prefix_covers_a_change_core_serves, tests/test_console_api_sign_in.py::test_registering_or_switching_a_provider_asks_for_a_recent_factor
SU9An enrolled administrator whose factor is past the window creates, changes and disables an approval rule, assigns and unassigns an approver, and assigns and unassigns a space member, then renames a space; then verifies a code and sends the same seven changes againEach of the seven is refused MFA_REQUIRED before its body is read; the rename is not asked; after the code none of the seven is refused for the step-up. Added on 3 October 2026, since who approves a request and who acts in a space are as sensitive as people and accesstests/test_console_api_step_up.py::test_who_approves_and_who_acts_in_a_space_ask_for_a_recent_factor, ::test_every_step_up_prefix_covers_a_change_core_serves
SU10An enrolled administrator whose factor is past the window activates a validated policy, switches the mode to Observe only and back to Enforcing, and installs and refreshes the samples; then validates, retires, previews, edits and creates a policy and removes the samples; then verifies a code and sends the four changes againActivation, both directions of the mode switch and both samples routes are refused MFA_REQUIRED before their bodies are read, and no policy.bundle_activated or tenant.mode_changed event is written; validate, retire, preview, the rules, creation and sample removal are not asked; after the code none of the four is refused for the step-up; every exact path is held to a route core serves (decided on 8 October 2026)tests/test_console_api_step_up.py::test_activating_a_policy_and_changing_the_mode_ask_for_a_recent_factor, ::test_every_step_up_prefix_covers_a_change_core_serves
SU11A change refused MFA_REQUIRED on each step-up route the purpose table names; two changes refused together; a route with no entry; a cached agent whose label is hostile textThe question's first line names each change in the table's words, with numeric handles from the cache or the generic noun; two changes share one question and are listed; an unknown route keeps the generic sentence; no label, name or email appears; the lead says verification covers other protected changes; every core route guards.steps_up matches has an entry, and every entry is a served route or waits in PENDINGtests/test_console_step_up_purposes.py, console/src/lib/step-up-purpose.test.ts, console/src/lib/client-config.test.ts ("tells the question which changes were refused"), console/src/components/StepUpDialog.test.tsx ("the step-up's purpose line")
SU12An enrolled administrator with a saved passkey, past the window: options, then a valid assertion; the refused change sent again with the old and the new CSRF tokenOptions answer the challenge stored for this session; the assertion answers 200 {csrf_token} under no-store, rotates both cookies, records account_security.verified with method passkey; the old token's resend is refused INVALID_CSRF, the new one's goes throughtests/test_console_api_step_up.py::test_a_passkey_rotates_the_session_and_the_change_goes_through_resent_once
SU13Assertion failures: a wrong origin, no user verification, another account's passkey, an assertion made against another session's challenge. Challenge failures: the same valid assertion replayed after success, an assertion with no options fetched, one after the options expired. Then: no passkey saved; five assertion failures then a valid assertion; the request checks; a token; an agent bearerEach assertion failure answers 400 INVALID_FACTOR, records verification_failed and counts toward the lock; each challenge failure answers 400 with neither, and fresh options then succeed; no passkey saved answers 409 CONFLICT; after five failures the valid one answers 400 with no new event; a token is refused (the routes are TOKEN_REFUSED) and an agent bearer 403 FORBIDDEN; none but a success rotates the sessiontests/test_console_api_step_up.py::test_an_assertion_that_fails_verification_counts_and_is_audited, ::test_a_spent_or_missing_challenge_is_refused_without_counting, ::test_the_lock_refuses_a_valid_passkey_silently, ::test_options_without_a_saved_passkey_conflict, ::test_the_passkey_routes_check_the_request_first
SU14Chromium with a virtual authenticator, the console served over https://localhost with a throwaway certificate: an administrator saves a passkey, the factor ages past the window, a key is revoked from the agent page with Use a passkey; past the window again, a second key the same way; the dialog's own states in Vitest (a click asking the browser synchronously, a spent challenge, a cancelled prompt, stale options)The dialog reads "To revoke key N for Agent M, confirm it is you."; each key is revoked with one click and without the page navigating; axe finds nothing in either scheme at 1280 and 390 px with the dialog open; the browser is asked inside the click, options are fetched fresh after every attempt, kept after a cancelled prompt, and never used staletests/test_browser_console_agents_account.py::test_su14_a_passkey_steps_up_a_key_revocation_over_the_agent_page, console/src/components/StepUpDialog.test.tsx ("a passkey in the step-up")
SU15An enrolled workspace administrator whose factor is past the window switches the mode to Observe only, sets the emergency stop, asks for an admission, switches the mode again and releases the stop, without verifying a codeBoth mode switches are refused MFA_REQUIRED and no tenant.mode_changed event is written, so the session was stale throughout; the stop answers 200 naming the administrator and its reason, writes one tenant.stop_activated, and the admission is refused TENANT_STOPPED; the release answers 200 with no stop and writes one tenant.stop_released; guards.steps_up matches neither /tenant/stop nor /tenant/resume. The stop is the immediate tightening control and stays outside the step-up by design (THREAT_MODEL.md T4.48); its release is outside it today too. Added on 20 October 2026 for gap 10 of the product control evidence: until then a change that put /tenant/stop in a step-up set failed no testtests/test_console_api_step_up.py::test_su15_the_emergency_stop_is_set_and_released_without_a_recent_factor

First password (FP1 to FP7)​

An account that signs in only with Google or GitHub adds its first password from Account security, under the bar provider linking already uses. Real PostgreSQL throughout, including an owner that does not bypass row security.

IDSetup/actionRequired resultTest
FP1A provider-only account signed in just now, with a second session open, sets a first passwordThe password is stored as user_passwords holds every other one (scrypt) and signs the account in by address; account_security.password_set is recorded with only the session id, and user_security_events holds password_set; the other session ends and the one that made the change staystests/test_first_password.py::test_a_provider_account_sets_a_first_password_and_signs_in_with_it
FP2An account that already has a password asks for a first one; then the definer function's password_set is reached directlyPASSWORD_EXISTS; the database refuses as well, the stored password is unchanged and still signs in, and nothing is recordedtests/test_first_password.py::test_an_account_with_a_password_cannot_set_another_this_way
FP3The account's sign-in six minutes old; then the function reached directlyRECENT_AUTH_REQUIRED both ways; no password is writtentests/test_first_password.py::test_a_sign_in_older_than_five_minutes_is_refused
FP4An enrolled factor last verified 31 minutes ago; then the function reached directly; then a recovery code verifiedRefused RECENT_AUTH_REQUIRED both ways; after the verification the password is settests/test_first_password.py::test_an_enabled_factor_must_have_been_verified_recently
FP5A password below the minimumINVALID_PASSWORD; nothing written or recordedtests/test_first_password.py::test_a_password_below_the_minimum_is_refused_and_nothing_is_written
FP6The same change under a schema owner with the hosted owner's attributes (NOBYPASSRLS)The row is written and read back through that owner fenced to the account, and the password signs intests/test_first_password.py::test_a_first_password_is_written_by_an_owner_that_does_not_bypass_row_security
FP7Account security for a provider-only account: two different entries, then the same entry with characters outside ASCII; a sign-in six minutes old; an account with a password; a wrong CSRF token, a missing field and an extra one; migration 0070 applied and rolled back"not the same", then set, the form gone afterwards and the address and password signing in, and no response carrying the password; "Sign in again first"; no form, and the route answers that a password exists; 403 for each; the upgrade adds only the branch and its rotation entry, keeps the grants, never updates a password row, and the downgrade restores the function byte for bytetests/test_first_password_page.py::test_a_provider_account_adds_a_password_and_then_signs_in_with_it, ::test_a_sign_in_older_than_five_minutes_is_told_to_sign_in_again, ::test_an_account_with_a_password_is_offered_no_form_and_the_route_refuses, ::test_the_form_needs_its_csrf_and_its_own_fields; tests/test_first_password_migration.py::test_the_upgrade_adds_one_branch_and_the_downgrade_restores_the_function

Security signals (SG1 to SG17)​

An out-of-process EDR's verdict about the target decides an isolation through the operator's mapping, never on its own authority, and every way it can be missing fails closed (Security signals; threat rows T13.1 to T13.18). tests/signal_conformance.py holds the producer-facing rows every producer runs with its own envelope builder: the kernel's reference producer in tests/test_signal_conformance.py, and Defender for Endpoint's producer, integrations/mde-producer, in tests/test_mde_producer_conformance.py. Each runs through the module's one harness, check: first accepted, the control that the producer's own envelope is accepted and stored; then every row rows() returns, each refused with nothing stored (SG1's foreign account, header and query string, SG4, SG5, SG6's capability and subject kind outside the schema, SG7 and SG9); then conflicting_duplicate, which is SG8. SG2 and SG3 need a live producer token and a live agent token, which the module does not mint, so only the kernel runs them, in tests/test_signal_conformance.py against sources and credentials registered for real; SG5's admitted-record check, SG6's registration check and SG10 to SG17 are the kernel's own tests. Three cases are narrower than a reader might expect. A record from a source whose principal scope does not hold the agent does not apply (SG12) rather than being refused at the intake, because a resource-subject envelope names no principal and the scope is checked at resolution. A record after dispatch is not recorded as Monitor evidence (SG16), because Monitor does not surface signal records. And the run-subject rows (a signal for run A offered to run B, a run of another principal, an expired run) arrive with the first run-subject capability, as T13.11's run correlation does; signals have resource subjects only. Real PostgreSQL, the protected endpoint mock as the live provider, and HTTP through the application. Defender for Endpoint's producer posted to this intake in the 30 September 2026 live trial.

IDSetup/actionRequired resultTest
SG1An envelope naming an account this tenant does not have; another tenant or principal named in an x-tenant-id, x-principal-id or x-role header or in a query string403 INVALID_SUBJECT for the account, recorded against the source; 400 with the intake's own answer, before the envelope is read, for a header or a query string; nothing stored in either tenanttests/test_signal_conformance.py::test_sg1_to_sg9_a_hostile_or_broken_envelope_is_refused_and_stores_nothing, tests/test_signal_admit.py::test_another_tenants_account_is_an_invalid_subject, tests/test_signal_intake.py::test_a_request_shaped_outside_the_bounds_is_refused_and_stores_nothing
SG2An unknown, malformed, forged or wrong-kind token: an unknown source or tenant, a wrong secret, a revoked, expired or inactive source, another credential kind's prefix, another scheme401: a bearer token the writer cannot authenticate is INVALID_SOURCE whatever the reason, and a credential of another shape is refused before the body is read; no record stored, the source's rate and health untouched, and the reason recorded on the signal authentication-failure surfacetests/test_signal_conformance.py::test_sg2_an_unknown_or_wrong_kind_token_records_nothing, ::test_sg2_a_token_shaped_right_but_wrong_underneath_records_nothing, tests/test_signal_admit.py::test_an_unauthenticated_call_stores_and_records_nothing, tests/test_signal_intake.py::test_every_credential_refusal_answers_the_same_and_records_its_reason, ::test_a_credential_of_another_shape_is_refused_before_the_body_is_read
SG3An agent credential at /v1/signals; a producer token at every other route that takes a credentialRefused both ways: 401 at the intake with nothing stored, and 400, 401 or 403 everywhere elsetests/test_signal_conformance.py::test_sg3_credentials_are_refused_both_ways, tests/test_signal_intake.py::test_a_producer_token_opens_no_other_route, tests/test_route_authority.py::test_the_signal_intake_refuses_an_agent_credential, ::test_a_producer_token_reaches_nothing_but_the_signal_intake
SG4A body over 8 KiB, by raw bytes or by multi-byte content; a repeated key; a compressed body; a float or an exponent where the schema requires an integer400; nothing stored; an envelope of exactly 8,192 bytes is readtests/test_signal_conformance.py::test_sg1_to_sg9_a_hostile_or_broken_envelope_is_refused_and_stores_nothing, tests/test_signal_intake.py::test_a_body_outside_the_envelope_is_refused, ::test_an_envelope_of_exactly_the_bound_is_read_and_one_byte_more_is_not
SG5An unknown schema version or field, including a field for a prompt; secret-shaped text; a right-to-left override or another invisible character; a verdict with edge whitespace; an account id in another UUID spelling; a request reference, which resource_compromise.v1 does not take because the agent chooses its own reference; an admitted record's severity, attributes and evidence reference and digest400 INVALID_ENVELOPE; nothing stored; secret-shaped text never quoted back or logged; an admitted record's severity, attributes and evidence stay in security_signals, out of every plan, audit payload and agent answer and out of the approver's views, the console's and the classic approval page, and the administrator's, and its severity changes no decisiontests/test_signal_conformance.py::test_sg1_to_sg9_a_hostile_or_broken_envelope_is_refused_and_stores_nothing, tests/test_signal_envelope.py::test_anything_else_is_refused, ::test_invisible_and_control_characters_are_refused_in_free_text, tests/test_signal_intake.py::test_secret_shaped_text_is_refused_and_never_quoted, ::test_a_request_reference_is_refused_before_the_token_or_the_writer, tests/test_signal_views.py::test_severity_attributes_and_evidence_never_leave_the_record, ::test_the_classic_page_names_the_label_and_the_capability_and_nothing_of_the_record
SG6A capability or subject kind the source is not registered forOutside the envelope's schema: 400 INVALID_ENVELOPE, nothing stored. Inside the schema but outside the registration: refused by signal_admit as CAPABILITY_REFUSED or SUBJECT_REFUSED and recorded against the source; no envelope reaches that today, because the schema and every registration admit one capability and one subject kindtests/test_signal_conformance.py::test_sg1_to_sg9_a_hostile_or_broken_envelope_is_refused_and_stores_nothing, tests/test_signal_admit.py::test_a_field_outside_the_registration_is_refused_and_recorded
SG7A producer version outside the registered range, or another producer name403 INCOMPATIBLE_PRODUCER, recorded against the source; versions compare as numberstests/test_signal_conformance.py::test_sg1_to_sg9_a_hostile_or_broken_envelope_is_refused_and_stores_nothing, tests/test_signal_admit.py::test_a_field_outside_the_registration_is_refused_and_recorded, tests/test_signal_intake.py::test_the_writer_s_refusals_answer_their_codes_and_are_recorded
SG8The same event id with different content409 CONFLICTING_DUPLICATE; the first kept and the conflict counted against the source; the same content again answers its first receipttests/test_signal_conformance.py::test_sg8_a_conflicting_duplicate_keeps_the_first, tests/test_signal_admit.py::test_a_retry_answers_its_receipt_and_a_conflict_keeps_the_first, tests/test_signal_intake.py::test_accepted_then_a_retry_then_a_conflict
SG9An observation more than 60 seconds ahead of receipt, or 3,600 seconds old or more on arrival; a time written as an epoch number, without an offset or with a seventh fractional digit400 FUTURE_OBSERVATION, STALE_ON_ARRIVAL; 400 INVALID_ENVELOPE for a malformed timetests/test_signal_conformance.py::test_sg1_to_sg9_a_hostile_or_broken_envelope_is_refused_and_stores_nothing, tests/test_signal_admit.py::test_time_bounds, tests/test_signal_envelope.py::test_anything_but_an_rfc_3339_instant_is_refused_in_either_field
SG10A required signal missing, stale, expired by its producer, unmapped, from an inactive or revoked source, with no mapping entry, from one admitted source of two, or newest in a record observed or received after the decisionINVALID_CONTEXT: refused and audited, the agent answered 503, and nothing recorded or dispatchedtests/test_signal_resolution.py::test_every_way_the_fact_is_not_there_is_invalid_context, ::test_every_admitted_source_must_speak, ::test_a_record_observed_after_the_decision_refuses, ::test_a_record_received_after_the_decision_refuses, tests/test_signal_execution.py::test_no_signal_is_refused_audited_and_nothing_runs
SG11An approval over a signal whose source is revoked, or whose record goes stale, before the decision; an approved request whose source is revoked before it runsSTALE_AUTHORIZATION; nothing dispatchedtests/test_signal_execution.py::test_an_approval_cannot_rescue_a_revoked_source, ::test_a_decision_after_the_signal_goes_stale_is_refused, ::test_an_approved_request_cannot_run_on_a_revoked_source
SG12A record about another resource, account or resource type; from a source scoped to another agent, or to a group the agent is not in; from another space's source that is not offered; scoped to a request reference, including one the request namesDoes not apply, and INVALID_CONTEXT when required; the same source applies once offered; a request-scoped record never applies, and the source's newest unscoped record is read in its placetests/test_signal_resolution.py::test_every_way_the_fact_is_not_there_is_invalid_context, ::test_the_correlation_is_exact, ::test_a_source_scoped_to_another_agent_does_not_apply, ::test_a_group_scoped_source_applies_only_to_its_members, ::test_a_source_of_another_space_does_not_apply_unless_offered, ::test_the_statement_never_reads_a_source_of_another_space, ::test_a_request_scoped_record_never_applies_even_to_the_request_it_names, ::test_a_request_scoped_record_alone_is_no_record
SG13A required mapping admitting an agent_forwarded sourceRefused at validation at the source's location, by the check activation also runs; resolution refuses it tootests/test_signal_bundle_validation.py::test_an_agent_forwarded_source_is_refused_in_a_required_mapping, tests/test_signal_resolution.py::test_an_agent_forwarded_source_is_refused_in_a_required_mapping
SG14A mapping producing clean for a source not attesting liveness; a capability with no no_detection value over such a source; a clean re-applied to frozen records from such a sourceRefused at the threshold's location, or at the source's; resolution, evaluation and replay refuse it through signals/mapping.combinetests/test_signal_bundle_validation.py::test_clean_needs_a_source_that_attests_liveness, ::test_a_capability_without_no_detection_needs_a_source_that_attests_liveness, tests/test_signal_resolution.py::test_clean_needs_a_source_that_attests_liveness, tests/test_signal_mapping.py::test_clean_needs_every_record_from_a_source_that_attests_liveness, tests/test_signal_evaluation.py::test_a_forged_clean_over_a_source_without_liveness_is_refused, tests/test_signal_replay.py::test_a_candidate_reading_clean_from_a_source_without_liveness_cannot_be_read
SG15compromised arriving while a person decides, or a changed value found on the agent's retry; the same verdict re-reported, or a verdict the mapping reads alikeThe first two make the approval STALE_AUTHORIZATION; the last two keep it, and the approved request runs oncetests/test_signal_execution.py::test_compromised_arriving_while_a_person_decides_cancels_the_approval, ::test_an_agent_retrying_on_a_changed_value_goes_stale, ::test_a_heartbeat_of_the_same_verdict_keeps_the_approval, ::test_a_verdict_the_mapping_reads_alike_keeps_the_approval, ::test_an_agent_retrying_on_a_heartbeat_stays_pending, tests/test_signal_evidence.py::test_a_re_report_of_the_same_verdict_keeps_the_binding_and_changes_the_plan
SG16A record after dispatch; a record that changes the value while dispatch commitsThe first leaves the decision, the answer to a retry, the impact and the claim unchanged; the second refuses dispatch, and nothing reaches the providertests/test_signal_execution.py::test_a_record_after_dispatch_changes_nothing, ::test_a_record_arriving_while_dispatch_is_committed_refuses
SG17Replay with the producer offline; a candidate reading the frozen records differently; a candidate needing a record the plan never froze, or one the store could never activate over those records; a candidate budget over the signal fact, with earlier units it can and cannot readIdentical decisions; each candidate reading replayed as the live kernel would decide; UNRESOLVED with SIGNAL_EVIDENCE_UNAVAILABLE for a record never frozen and for a candidate that could never be activated; the candidate's budget counts earlier units by its own reading, and an earlier unit it cannot read leaves a later decision UNRESOLVED, counted only at a lower bound; the most records a fact may carry, at their widest, fit the decision capture replay readstests/test_signal_replay.py::test_the_original_bundle_reproduces_every_decision_with_no_producer, ::test_a_candidate_reading_is_replayed_and_an_unreadable_one_is_unresolved, ::test_a_candidate_admitting_an_unfrozen_source_cannot_be_read, ::test_each_candidate_reading_is_replayed_as_the_live_kernel_would_decide, ::test_a_candidate_that_could_never_be_activated_over_the_records_is_unreadable, ::test_a_candidate_budget_counts_earlier_units_by_the_candidates_reading, ::test_an_earlier_unit_the_candidate_cannot_read_leaves_a_signal_budget_unknown, ::test_four_records_at_maximum_width_fit_the_decision_capture

Protocol and connector packages (PK1 to PK10)​

The provider protocol and the connectors leave the server as two Apache-2.0 packages, execbound-protocol and execbound-connectors, which import nothing from it.

IDSetup/actionRequired resultTest
PK1Every module of both packages, and a planted file that imports the server or names a server module to importlibNeither package imports execbound or execbound_harness, the protocol imports no connector module, and the planted import is foundtests/test_connector_packages.py::test_neither_package_imports_the_server, ::test_the_protocol_imports_neither_the_connectors_nor_the_server, ::test_the_walk_refuses_a_planted_import, ::test_the_walk_lets_the_protocol_and_signed_literals_through
PK2Every helper, the catalog, the records, the connectors and the signal envelope at their old server pathsEach old name is the very object the package defines: one definition, so no copy can drift from historytests/test_connector_packages.py::test_the_server_names_the_protocols_helpers, ::test_there_is_one_production_catalog, ::test_the_server_names_the_protocols_records, ::test_the_server_names_the_connectors, ::test_the_signal_envelope_is_the_protocols
PK3Each frozen journal of the endpoint and identity contracts, re-signed by the protocol from its own record and keyThe frozen bytes back, byte for byte, and the server's JournalVerifier settles themtests/test_connector_packages.py::test_a_journal_the_protocol_signs_is_the_frozen_journal_and_the_server_verifies_it
PK4An executor outcome signed with the protocol alone, and the same envelope with its record changedThe server attests the first and refuses the secondtests/test_connector_packages.py::test_an_outcome_the_protocol_signs_is_one_the_server_attests
PK5A dispatch through the gatewayThe connector is handed exactly the ProviderCommand frozen from the dispatch, and nothing of the dispatch recordtests/test_protected_path.py::test_a_connector_receives_the_frozen_provider_command
PK6A connector that forges a journal under a key of its own and carries a verifier accepting it, on dispatch and on reconciliationINVALID_EVIDENCE from the server's verifier; the dispatch is retained INDETERMINATE and the reconciliation is refusedtests/test_protected_path.py::test_the_verifier_comes_from_the_server_not_the_connector, ::test_reconciliation_settles_with_the_server_verifier_too
PK7A connector that reports a configuration with a key of its choosing after the runtime is built, and one that ignores rotate_keysThe runtime's verifier refuses the forged journal, and a verifier handed out before a rotation answers with the rotated ringtests/test_protected_path.py::test_the_runtime_verifies_with_the_config_it_was_given_not_what_a_connector_reports, ::test_a_rotation_reaches_the_runtimes_verifier_whatever_the_connector_does
PK8Every call in the server to dispatch_owned or reconcile_operation, and a planted call naming no verifierEach passes the runtime's verifier; the planted call is foundtests/test_connector_packages.py::test_every_server_caller_settles_with_the_runtimes_verifier
PK9The code of both packages, and a planted module naming TerminalEvidenceNeither package names the evidence the kernel settles on; the planted name is foundtests/test_connector_packages.py::test_neither_package_can_build_the_evidence_the_kernel_settles_on
PK10An installed compose.yaml that starts execbound.provider.mock_app:create_mock_appThe old path, as uvicorn resolves it, is the factory the connectors package definestests/test_connector_packages.py::test_the_old_mock_app_path_still_starts

Approval routing (AR1 to AR23)​

A held request should never wait for a person who does not exist. An invitation can put an Approver straight into the reviewer group a rule routes work to, checked when it is created and again when it is accepted, and an invitation that expired stays visible with a way to send it again. Workspace settings states how long a held request can wait for each action the active policy can hold and where approvals are announced, warns when short approvals reach nobody, and the deadline dialog warns when a message can arrive after a short deadline. A held request records how many people could decide it when it was held; a workspace administrator is told on Home and Approvals when a held request has fewer people who can decide it than it needs, and Approval rules shows, for each Space and each action its active policy can hold, who can decide it and which resources nobody, or too few, can. Real PostgreSQL throughout, Vitest for the console clauses and Chromium for the browser ones. Rows are listed as their tests land.

IDSetup/actionRequired resultTest
AR1Migration 0083_invitation_reviewer_group from the previous head and backThe column and the function exist and the acceptance is patched; workspace_invitation_set_group is a definer the runtime may execute and PUBLIC may not; the downgrade refuses while a pending invitation names a group, and otherwise restores workspace_invitation_accept byte for byte and drops the column and the functiontests/test_invitation_reviewer_group_migration.py::test_ar1_the_set_group_function_is_the_runtimes_and_not_publics, ::test_ar1_the_acceptance_gains_step_8b_exactly_once, ::test_ar1_downgrade_refuses_a_pending_invitation_with_a_group, ::test_ar1_downgrade_restores_the_acceptance_byte_for_byte
AR2Invitations for Approver in Default naming: a group with no grants; a group with approver in Default; a group with Administrator; one with Policy manager; the same two with an invitation that also grants them; one with a workspace-wide approver grant; one with viewer in another Space; another tenant's group id. A Viewer-only and an Administrator-only invitation with a group. A pending invitation given a second group; a group named by someone without workspace-wide access.manageCreated with the group (first two, and an Administrator and Approver invitation with a group of no roles); every other case refused INVALID_BODY naming reviewer_group_id with no invitation and no invitation.created left behind; INVALID_STATE; FORBIDDENtests/test_invitation_reviewer_group.py::test_ar2_an_invitation_names_a_review_only_group, ::test_ar2_an_administrator_and_approver_invitation_may_name_a_group, ::test_ar2_an_invitation_without_a_group_records_none, ::test_ar2_a_group_granting_more_than_the_invitation_is_refused, ::test_ar2_a_malformed_group_id_is_refused_before_the_service, ::test_ar2_a_second_group_is_refused, ::test_ar2_a_narrowed_or_ordinary_actor_cannot_name_a_group, ::test_ar2_the_service_refuses_a_group_with_a_typed_code
AR3An enrolled administrator past the step-up window invites with a group; a personal access token invites with a groupMFA_REQUIRED and nothing created, then created with the group after a fresh factor; TOKEN_NOT_ALLOWED and nothing createdtests/test_invitation_reviewer_group.py::test_ar3_inviting_with_a_group_steps_up_and_refuses_a_token
AR4Acceptance with a password and by a signed-in account, each with a group a rule names; an invitation with no groupThe person is in the group with the invitation's grants; the chain reads access.set_user_roles, then access.group_member_added with the inviter as actor, then invitation.accepted recording the group as applied; the person decides a request the rule routes to the group and it commits once; the export replays complete; with no group, the events are as beforetests/test_invitation_reviewer_group.py::test_ar4_acceptance_adds_the_member_after_the_grants, ::test_ar4_an_invitation_without_a_group_accepts_as_before; tests/test_replay_verify.py::test_human_access_changes_keep_audit_history_replayable
AR5Acceptance after the group was deleted, after it gained an Administrator grant, after it gained a workspace-wide approver grant, after it gained viewer in another Space, and with the group at 100 membersThe person joins with the invitation's grants and without the group, invitation.accepted records GROUP_GONE, GROUP_ROLES, GROUP_SCOPE, GROUP_SCOPE and GROUP_FULL, no access.group_member_added is written, and nothing is refusedtests/test_invitation_reviewer_group.py::test_ar5_a_changed_group_is_skipped_and_recorded
AR6Two threads on two connections, twenty rounds: set_group_roles adding administrator to the group races an acceptance naming itEither the acceptance records GROUP_ROLES and the person is not a member, or the person is a member with its access.group_member_added and the role change's event follows the acceptance; both calls return every round, never a deadlock, a failed acceptance or a membership without its eventtests/test_invitation_reviewer_group.py::test_ar6_a_group_promotion_racing_an_acceptance_is_ordered
AR7The invitations card with pending, expired, accepted and revoked rows from the last 30 days; Invite again on the expired one; acceptance landingPending and expired shown, the expired one as Expired with only Invite again; Invite again sends the same address, grants and group, the old row is revoked with reason: EXPIRED and the new one is pending with the group; an invited Approver accepting with a password lands on /approvals; one accepting while signed in sees the joined page as beforetests/test_invitation_reviewer_group.py::test_ar7_inviting_again_replaces_an_expired_invitation_with_its_group, ::test_ar7_an_invited_approver_lands_on_approvals; Vitest console/src/components/directory/invitations.test.tsx
AR8Chromium: an administrator invites an Approver into a group from /people, the person accepts in another browser and decides a held request the group's rule routes to them; /people with the invite dialog open and a group chosen, in both schemes at 1280 and 390 pxThe person lands on Approvals and decides, the request commits; axe reports nothing, no horizontal scroll and no policy or Trusted Types violationtests/test_browser_invitations.py::test_ar8_an_invited_approver_joins_the_group_and_decides, ::test_ar8_the_invite_dialog_is_accessible
AR9Windows for an inventory and incident contract at 300 s with deadline 120, 3600 and off; bundle settings of 600 s for both kinds, and for one; an incident-required contract whose incident default is shorter than its inventory default; an observe-only mapping; a deny-only limit; an unknown contract, alone and beside a known one; two contracts serving one action; the tenant view under each deadline, after a mode change, a stop and a release, and with the current Space and "All spaces"120 by deadline; 300 by context twice; 600 by context, and 300 limited by the kind left at its default; the incident figure by context; absent; absent; unknown with no figure both times; the larger bound; every tenant answer carries the same windows, one Space when one is selected and each visible non-archived Space by name otherwise, a Space with no selection listed with no bundle and no actions. A REVIEW rule holds its action with its quorum, two take the largest, a hold-on-exceed limit holds every action it names, and a custom policy with approval policies holds every served action as not known, "up to" its largest quorumtests/test_approval_windows.py (every test); tests/test_console_api_settings.py::test_ar9_the_tenant_view_carries_approval_windows, ::test_the_windows_follow_the_current_space
AR10The readiness card under Enforce with a 300 s bound and: no destination; only a security-events destination; an email destination. In Observe with no destination; with every bound 600 s or more; with only some bounds shortOne warning naming both causes with a link to Approvals and the remedy; the same warning; none; none; none; the warning says "Some held requests". The deadline, its change line and Change deadline stay in the card, the announcements block renders inside it and not in "What this tenant is", and opening and closing the dialog sends no requestVitest console/src/components/tenant/readiness.test.tsx, TenantSettings.test.tsx
AR11The remedy in each editionCore renders the operator-documentation sentence, with the documentation link only where the deployment names one; the hosted build, through the ApprovalRemedy slot, renders its own sentence and not the operator's; no core console file contains the hosted sentenceVitest console/src/components/tenant/readiness.test.tsx, console/src/edition/core.test.tsx, and the hosted edition's own
AR12The deadline dialog with a webhook destination typing 120, 150, 599, 600, off, 12a, 119 and 3601; with an email destination typing 120 and 240; with only a security-events destination; with a measured slowest deliveryThe lapse warning in the hold tone and the field's description for 120, 150 and 599 and none for the rest; the fixed email hint at 120 and the lapse warning at 240, never both; none without an approval destination; the slowest delivery as a second sentence, with no cadence; nothing is sent while typing or on Change deadline without a reasonVitest console/src/components/tenant/DeadlineDialog.test.tsx
AR13Chromium: /tenant with the card and its warning, then with two destinations and the deadline dialog open showing its lapse warning, both schemes at 1280 and 390 pxaxe reports nothing, no horizontal scroll and no policy or Trusted Types violationtests/test_browser_console_tenant.py::test_ar13_readiness_is_accessible
AR14Migration 0084_reviewers_at_hold from the previous head and backapprovals.reviewers_at_hold (a non-negative integer) and the executions_created index exist; the runtime may insert the count and may not update it, and check_runtime refuses a database that grants the update; the downgrade drops bothtests/test_reviewers_at_hold_migration.py::test_ar14_the_runtime_inserts_the_hold_count_and_cannot_update_it, ::test_ar14_check_runtime_refuses_an_update_grant_on_the_count, ::test_ar14_the_index_exists_and_the_downgrade_drops_both
AR15Held requests with no rule; a rule naming a group of two people in the Space; an assignment in another Space; a group member whose Approver role covers another Space; a disabled rule; a quorum-2 policy with one eligible personreviewers_at_hold is 0, 2, 0, 0, 0 and 1 (below required_approvers 2); for each, eligible_reviewers, the administrator's live reviewers on Waiting on others and the assigned count matching_destinations returns are equaltests/test_approval_routing.py::test_ar15_a_held_request_records_who_could_decide_it; tests/test_console_api_approval_routing.py::test_ar15_the_three_counts_agree
AR16A request held with nobody, then a rule saved, then the reviewer decides; a request held with one reviewer, the rule disabled, then the reviewer decidesThe first commits exactly once and its record still reads 0; the second is refused NOT_FOUND as before and its record still reads 1tests/test_approval_routing.py::test_ar16_a_reviewer_added_after_the_hold_decides_and_it_executes_once, ::test_ar16_a_reviewer_removed_after_the_hold_is_refused, ::test_the_count_is_never_read_by_a_decision
AR17A rule save racing a hold on two threads, twenty-one rounds, a third of them started together and the rest with one side a moment aheadEach recorded count is the eligibility under whichever transaction the audit chain shows committed first; every admission is held and every save returns, never a partial count or a deadlocktests/test_approval_routing.py::test_ar17_a_rule_save_racing_a_hold_records_one_side
AR18The unrouted read with an open approval nobody can decide in one Space, an open quorum-2 approval one person can decide in another, a lapsed one recorded short, a routed one, one held before the record existed and one older than seven days; an administrator; an administrator seated in one Space; an approver; a personal access token; an agent credential and no sessionpending 2, pending_nobody 1 and the newest one's reference; recent 3, skipping the unrecorded and the old; the seated administrator and the approver 403; the token 200; the agent 403 audited once and no session 401. An approver's approval items carry reviewers_at_hold: null and an administrator's carry the numbertests/test_console_api_approval_routing.py::test_ar18_unrouted_counts_now_and_the_last_seven_days, ::test_ar18_a_seated_administrator_is_refused_both_reads, ::test_ar18_an_approver_is_refused_both_reads, ::test_ar18_a_token_may_read_coverage_and_unrouted, ::test_ar18_only_a_workspace_administrator_sees_the_hold_record; tests/test_console_api_human_access.py::test_access_endpoints_refuse_bearer_missing_session_and_non_admin
AR19Coverage over a rules bundle, a custom Cedar bundle with approval policies, an observe-only mapping, a Space with no selection and an archived SpaceThe rules action held by its review rule and its hold-on-exceed limit with quorum 1; the custom action known: false; the observe-only Space with no actions; the empty Space with policy: "none"; the archived Space absent; Spaces by nametests/test_approval_routing.py::test_ar19_coverage_lists_what_each_space_can_hold
AR20Coverage with a target held twice with nobody, one requested and never held, one held with exactly its quorum, one held with more, one older than the window, a quorum-2 target with one reviewer, then 25 more held gaps; past 50 Spaces; a scan bound of 3 groups with 3 and then 4held_uncovered, requested_uncovered and thin each hold the right targets, newest first, at most 20 rows with their true totals; the quorum-2 target is in held_uncovered, not thin; truncated past 50 Spaces, and past the group bound exactly when one more group existstests/test_approval_routing.py::test_ar20_coverage_finds_held_requested_and_thin_targets, ::test_ar20_coverage_truncates_past_its_bounds, ::test_coverage_on_a_populated_tenant
AR21A coverage read while another transaction holds the tenant fence; the answer's textIt completes in under two seconds without waiting for the fence; no person's id or address appears anywhere in ittests/test_approval_routing.py::test_ar21_coverage_does_not_wait_for_the_fence, ::test_ar21_coverage_names_no_reviewer
AR22The coverage card's Add to a rule and Assign a person, including a target outside the approvers page's list; Home's three outcomes for the needs card, Approvals and the policy page line; labels containing markup; Chromium: a request held with nobody, Home's line, Choose reviewers, a new rule from the cardEach dialog opens prefilled with the gap's target shown and checked and sends nothing until completed (a rule with a reason, an assignment with its confirm); Assign a person only in the write Space; the line in each Home outcome, and the empty state stops claiming every approval was decided; lines and calls only with workspace-wide access.manage, none on an open approval; markup as text; in Chromium the gap leaves the card once the rule is saved and the reviewer can decide the held requestVitest console/src/components/directory/coverage.test.tsx, unrouted.test.tsx, console/src/routes/-home.test.tsx, console/src/approvals/approvals.test.tsx, console/src/components/policy/coverage-line.test.tsx; tests/test_browser_console_routing.py::test_ar22_an_unrouted_request_is_shown_and_fixed_from_coverage
AR23Chromium: /approvers, Home and /approvals with the line, both schemes at 1280 and 390 pxaxe reports nothing, no horizontal scroll and no policy or Trusted Types violationtests/test_browser_console_routing.py::test_ar23_routing_pages_are_accessible

Console foundation (CF1 to CF14)​

The console prints every instant one way in the zone the viewer chose, names every agent and person one way on every page, and uses one word for each thing a person decides or sees decided in the approval flow. Numbers are the workspace's own counting numbers (migrations 0058 and 0062): display handles only, read inside the tenant fence, and never part of anything an agent receives.

IDSetup/actionRequired result
CF1In real Chromium with timezone_id="America/New_York", an approval for a held requestThe detail reads the request time with its date and EDT or EST, never "UTC" beside a local time; the title of that time reads the instant in UTC; the stop notice reads its time the same way
CF2The same viewer chooses UTC under My account, then opens the approval, Activity, Home and the Live board, then reloadsEvery time reads in UTC with "UTC"; the board's day reads "Today (UTC)"; the choice survives the reload; the live board keeps updating after the choice; with storage that refuses, the console shows local times and does not fail
CF3pnpm lint over the source tree, and console/scripts/bans.test.ts's fixtures for each time and name ban and for each exempt fileThe tree passes; each forbidden form is a lint error, including the Activity chip's former shape; src/lib/time.ts and src/components/directory/format.ts pass their own exemptions and nothing else does
CF4/board, /board/stream and /approvals?view=decided with valid, missing, out-of-range, malformed and repeated utc_offsetValid moves the start of the day; missing keeps UTC midnight; the rest are INVALID_REQUEST before any read and before the stream's first byte
CF5A held request on the boardexpires_at equals the approval's expiry; the ticker reads "N min left, by HH:MM ZONE" from it
CF6An unlabelled agent with one held and one executed request, read as an administratorIt reads "Agent 1" in Activity, the drawer, Home, the approval and its queue, the Live board's lane and ticker, Getting started and the palette; its agent page is "Agent 1"
CF7The same agent labelled "triage-bot", and a second agent also labelled "triage-bot"Every surface in CF6 reads "triage-bot" with "Agent 1" beside it; the second agent's lane and ticker cell read "triage-bot" with "Agent 2"
CF8An administrator stops the workspace, changes the mode and the deadline, acknowledges a finding and binds an agent; a person files a data request; an approver reads /session during the stopEach reference names the administrator by kind and number on the POST that made the change and on the next GET, beside the unchanged UUID; the request's requester carries their number; the approver's session carries stopped_by_ref: null and its banner reads "activated by an administrator"
CF9Two workspaces, each with an Agent 1, a User 1 and a held request, read in turnEach read names only its own principals; principal_facts across workspaces returns nothing
CF10An agent and a person labelled with markup, on the record table, the palette, the approval and the name promptThe label is the characters it is; no element it describes exists; nothing ran
CF11The agent OpenAPI document; a held request, its refusal by a person over HTTP and MCP, and a refusal before any plan over MCP, in a workspace with a labelled agent and numbered peopleThe document is unchanged; no answer carries a number, a kind or a principal's name
CF12Search as an administrator for agent 1, Agent #1 and an id prefix; as an approver; under a space view that excludes the agent. Search for user 2, User #2, a person's id prefix and a person's email, as an administrator with access.manage, as one without it and as an approver, with the person deactivated and with another workspace holding people of its ownThe administrator finds the unlabelled agent each way; the approver finds no agent; the excluded space's agent is not returned. Only the administrator with access.manage finds the person, by number and by id prefix, never by email, marked deactivated when they are; the result opens /people/<id>; the other workspace's people are never returned
CF13An unlabelled agent's page and an unlabelled person's page; save a name; save a refused nameThe prompt is under the heading; a saved name replaces the prompt and the heading after the server answers; the person's save asks for the step-up when it is due; a refused name shows the existing refusal and nothing changes
CF14In real Chromium at 1280 and 390 px, in light and dark: the approval detail, Activity with the drawer open, the Live board, Home and My accountNothing overflows the 16 px gutters or scrolls sideways; axe reports nothing; no policy violation; the approval words read Approve, Refuse, Refused and Lapsed

Tests live in tests/test_console_foundation.py (CF4, CF8, CF9, CF11, CF12 at the API), tests/test_principal_names.py (CF9's fenced read), tests/test_console_api_board.py (CF5), tests/test_console_api_monitoring.py, tests/test_console_api_agents.py and tests/test_account_api.py (CF8's acknowledgement, binding and queued request), and tests/test_browser_console_foundation.py (CF1, CF2, CF6, CF7, CF12's palette, CF13 for an agent, CF14). Two rows have no pytest node: CF3 is held by console/scripts/bans.test.ts, and CF10 by the console's component tests (console/src/components/PrincipalName.test.tsx, console/src/components/ui/CommandPalette.test.tsx, console/src/approvals/approvals.test.tsx and console/src/components/directory/agents.test.tsx), beside CF13's person case and its step-up in console/src/components/directory/people.test.tsx.

Approval delivery (AY1 to AY19)​

An approval notification is delivered while the approval can still be decided, says what the approver needs, and is followed up with how the approval ended where a destination asks. Each approval is created at a fixed T under the default 120-second deadline, so it expires at T + 120 and the fifteen-second lapse margin closes delivery at T + 105. Real PostgreSQL throughout, the clock injected. The reminder rows change the deadline to 600 s on the audited path, with facts valid for most of an hour. The hosted rows AY20 and AY21 are in the hosted inventory.

IDSetup/actionRequired resultTest
AY1A pending approval whose expires_at is 14 s after the drain's clock, with one webhook, one email and one Slack destinationEach row FAILED with LAPSED_BEFORE_DELIVERY and attempts 0, nothing sent through any transport, closed counts 3; the approval, the execution and the audit chain unchangedtests/test_approval_delivery.py::test_ay1_a_row_inside_the_lapse_margin_is_closed_unsent
AY2The same approval drained with 16 s leftEach destination sent once and DELIVEREDtests/test_approval_delivery.py::test_ay2_a_row_outside_the_margin_is_sent
AY3A webhook that fails for an approval with 60 s left; a Slack destination answering 429 with Retry-After: 120 for an approval with 30 s leftThe webhook row rescheduled PENDING at the next backoff (5 s); the Slack row settled FAILED with RECEIVER_RATE_LIMITED, attempts 1, and never claimed againtests/test_approval_delivery.py::test_ay3_a_failed_send_retries_while_the_retry_can_arrive, ::test_ay3_no_retry_lands_past_the_deadline
AY4The email cap reached, for an approval with 10 minutes left and then for one whose window is two hours; and AN4/AN5, E3 and E6 over a long and the default windowThe first FAILED with RATE_LIMITED at once; the second deferred an hour, PENDING with RATE_LIMITED; over a long window five attempts and the hour's deferral, over the 120 s window three attempts then FAILED, and a capped email FAILEDtests/test_approval_delivery.py::test_ay4_the_email_cap_never_defers_past_the_deadline, tests/test_approval_notifications.py::test_an4_an5_failed_sends_back_off_and_fail_visibly_without_touching_the_approval, tests/test_notification_email.py::test_e3_failures_back_off_and_fail_visibly_with_the_transport_code, ::test_e6_the_daily_cap_defers_a_long_window_and_fails_a_short_one
AY5The pending webhook body and notification ids under the new message fieldsThe body equals the checked-in bytes of test_the_webhook_body_keeps_its_documented_bytes with and without every new ApprovalMessage field set; a drained webhook's bytes equal the message's without the workspace, space, handle and send time; notification_id is uuid5(approval_id, destination_id)tests/test_notification_transports.py::test_ay5_new_fields_never_change_the_webhook_body, tests/test_approval_delivery.py::test_ay5_the_drained_webhook_keeps_its_bytes_and_notification_id, tests/test_notification_transports.py::test_the_webhook_body_keeps_its_documented_bytes
AY6The pending email for a workspace named Acme\r\nBcc: x@evil.test <b>, a space named Tier 1 "SOC", a two-approver quorum; the pending, reminder and close-out email for a workspace and space named in a non-Latin script; the name reduction and the line naming the workspace to choose, for names as written, reduced, accented, cut and with nothing left; the drained email for an agent labelled <script>alert(1)</script>, with one approval of two recorded; the window words and the deadline across midnightSubject [ExecBound · Acme Bcc: xevil.test b · EB-n] Decide by HH:MM:SS UTC: ... and the space as Tier 1 SOC; one Subject header and no Bcc header; the body as documented, the deadline to the second, "About N minutes to decide when this was sent.", "Requested by: Agent N", "Approvals recorded: 0 of 2" (and "1 of 2" after one approval), "Approve or refuse" and no "deny"; the agent label, the target's provider id and every argument value absent; 600 s reads "About 10 minutes", 119 s "About 1 minute", 59 s "Less than a minute"; a deadline on the next UTC day is dated in full; a name nothing of which survives is left out of the subject, the first line and the Space line, never "unknown", and the last sentence still says the address is a notification destination; an accented name folds to its letters; the line naming the workspace to choose names it alone only as written, gives a reduced or cut label as a hint beside the tenant id, and gives the tenant id alone only when nothing survivestests/test_notification_email.py::test_ay6_hostile_workspace_and_space_names_never_reach_a_header, ::test_ay6_a_name_nothing_of_which_survives_is_left_out_not_called_unknown, tests/test_notification_transports.py::test_ay6_a_name_safe_label_keeps_nothing_of_is_no_name, ::test_ay6_a_name_with_anything_left_is_its_label, ::test_ay6_the_choose_line_names_a_workspace_only_as_its_owner_wrote_it, ::test_the_rendered_email_is_plain_text_with_fixed_headers_and_labels_only, ::test_e2_the_drain_emails_once_with_the_documented_rendering, tests/test_approval_delivery.py::test_ay6_the_drain_names_the_agent_by_handle_and_counts_a_partial_quorum, tests/test_notification_transports.py::test_ay6_window_words_are_the_bare_duration, ::test_ay6_the_deadline_is_given_to_the_second_and_dated_across_midnight
AY7The Slack and Teams pending renderings, with and without a quorum, and with hostile workspace and space names; pending and close-out cards for names in a non-Latin script; pending, reminder and close-out cards for names holding each of a_b, x :smile:, example.com, a/b, -x and 1) x on its own, the longest such names with a quorum, the plain name SOC (EU) - East, a plain workspace with such a Space and the reverse, and an environment of prod_eu_1 or a.exampleEqual to the updated checked-in fixtures; header EB-n · <action> needs a decision; facts led by Decide by and "Time to decide" ("About N minutes when sent"), eight in all and nine with a quorum; every text plain_text; under 4096 bytes; the names reduced; no agent label in a drained card; a name nothing of which survives is left out of the facts and Slack's notification line, never "unknown"; a name Slack or Teams could format never reaches Slack's notification line, reaches Slack's blocks only as plain_text with emoji off, and reaches Teams only in text runs, the card's facts then one RichTextBlock each, whichever of the two names holds it; an environment Teams could format puts the facts in text runs the same way; a plain name keeps the one FactSet and is named in Slack's linetests/test_notification_chat.py::test_ay7_facts_lead_with_the_deadline, ::test_ay7_a_card_leaves_out_a_name_nothing_of_which_survives, ::test_ay7_slack_reads_a_name_it_could_format_only_as_plain_text, ::test_ay7_teams_reads_a_name_it_could_format_only_as_text_runs, ::test_ay7_a_plain_name_keeps_the_fact_set_and_the_notification_line, ::test_ay7_either_name_alone_puts_the_card_in_text_runs, ::test_ay7_an_environment_teams_could_format_puts_the_card_in_text_runs, ::test_rendering_matches_the_checked_in_fixture, ::test_hostile_labels_are_reduced_before_rendering, ::test_c1_an_approval_fans_out_to_slack_teams_and_a_webhook_once_each
AY8Five approvals ended through the real paths (approved, refused, lapsed by a late touch, lapsed untouched 31 s past expires_at, withdrawn by a policy change before the deadline) with destinations listing pending, closed, pending only, and pending, closed whose announcement failed; a still-PENDING approval 29 s past its deadline; then a close-out whose destination now lists only pendingExactly one approval.closed row per outcome for the first destination, APPROVED or REFUSED at decided_at, LAPSED at expires_at, WITHDRAWN at the drain's time, each delivered with its lowercase outcome; none for the second or third; none yet at 29 s; the switched-off row FAILED with MESSAGE_OFF, unsenttests/test_approval_delivery.py::test_ay8_each_outcome_is_followed_up_once_where_asked, ::test_ay8_a_close_out_whose_message_was_switched_off_is_not_sent
AY9The close-out renderings for each outcome and its webhook body; two drains racing over the same closed approval after both have read itEmail subjects [ExecBound · <workspace> · EB-n] Approved: ..., Refused, Lapsed without a decision, Closed without a decision, the fixed body, and In-Reply-To and References equal to the announcement's Message-ID; the Slack and Teams cards equal their checked-in fixtures with one link and no basic-page button; no "executed", person, agent or target, and "ran" only in the disclaimer; the webhook body equals its documented bytes and is under 4096 bytes; one row and one delivery under the racetests/test_notification_email.py::test_ay9_each_close_out_email_says_how_the_approval_ended_and_nothing_more, ::test_ay9_a_close_out_without_an_announcement_starts_its_own_thread, tests/test_notification_chat.py::test_ay9_a_close_out_card_matches_the_checked_in_fixture, ::test_ay9_each_outcome_has_its_header_and_one_link, tests/test_notification_transports.py::test_ay9_the_close_out_webhook_body_keeps_its_documented_bytes, ::test_ay9_a_close_out_has_no_other_outcome, tests/test_approval_delivery.py::test_ay9_two_drains_send_one_close_out, ::test_ay9_racing_close_outs_queue_one_row_and_raise_nothing
AY10A 600 s approval drained at +290 s, +305 s and +320 s, with a webhook and an email destination listing pending, reminder an escalation webhook listing reminder alone, and a webhook listing pending, closed; a 300 s and a 120 s approval drained after their halfway points; reminders whose retry finds the approval decided, or 14 s from its deadline; a reminder whose destination now lists only pending; 51 approvals due at once; an approval no reminder destination routes, due before one that is routed; two drains racing to queue one reminder; a reminder and a new request due under daily_limit = 10 with nine emails delivered; the reminder renderings and webhook bodyNone at +290 s; at +305 s one reminder per listing destination under uuid5(approval_id, destination_id + "#reminder"), the escalation destination never getting an announcement and the pending, closed webhook never a reminder; nothing more at +320 s; the approval, its execution and the audit chain unchanged and expires_at never moved; none for the 300 s or 120 s window; the late retries settled APPROVAL_CLOSED and LAPSED_BEFORE_DELIVERY; the switched-off row FAILED with MESSAGE_OFF, unsent; the first drain reminds the 50 with the soonest deadline and the second the 51st; the unrouted approval holds no routed one back; one row under the race; the reminder email FAILED with RATE_LIMITED at once and the new request sent as the tenth; the email subject [ExecBound · <workspace> · EB-n] Still waiting, decide by HH:MM:SS UTC: ... and first line "Still waiting for a decision.", the rest of the body the announcement's; the chat header EB-n · <action> still needs a decision with the announcement's facts and buttons; the webhook body the announcement's but for "kind":"approval.reminder"; an announcement is approval.pending or approval.reminder and nothing elsetests/test_approval_delivery.py::test_ay10_one_reminder_where_it_can_arrive, ::test_ay10_a_window_too_short_for_a_reminder_gets_none, ::test_ay10_a_reminder_follows_the_closed_and_lapse_rules, ::test_ay10_a_reminder_whose_message_was_switched_off_is_not_sent, ::test_ay10_more_than_fifty_due_reminders_are_all_reached, ::test_ay10_an_approval_no_reminder_destination_routes_holds_no_other_back, ::test_ay10_racing_reminders_queue_one_row_and_raise_nothing, ::test_ay10_reminders_respect_the_follow_up_cap, tests/test_notification_email.py::test_ay10_a_reminder_email_says_the_request_is_still_waiting, ::test_ay10_an_unnamed_reminder_dates_its_deadline_in_full, tests/test_notification_chat.py::test_ay10_a_reminder_card_is_the_announcement_still_needing_a_decision, ::test_ay10_a_reminder_without_a_reference_says_the_approval_is_still_needed, tests/test_notification_transports.py::test_ay10_a_reminder_webhook_body_is_the_announcement_with_its_kind, ::test_ay10_an_announcement_is_pending_or_a_reminder_and_nothing_else
AY11Configurations with messages absent, allowed, empty, repeated, ["closed"] alone, an unknown message, on security-events, and a reload that changes itAbsent loads as pending alone; pending, closed, pending, reminder, closed and reminder load; each other list refuses the file without quoting a URL or secret, and Destination holds the same rules without the file; the reload is refused by shape()tests/test_approval_delivery_config.py::test_ay11_a_destination_without_messages_receives_the_announcement_alone, ::test_ay11_each_allowed_list_loads, ::test_ay11_a_list_outside_the_rules_refuses_the_file_without_quoting_it, ::test_ay11_the_destination_holds_the_rules_without_the_file, ::test_ay11_a_reload_that_changes_messages_is_refused_by_the_shape
AY12Recovery's settle_orphaned over a refused approval holding an announcement, a reminder and a close-out rowThe first two settled APPROVAL_CLOSED; the close-out left PENDING and then delivered by the drain with outcome refusedtests/test_approval_delivery.py::test_ay12_recovery_never_settles_a_close_out_as_closed
AY13Migration 0080_notification_kinds up and down, with rows queued before it and with a close-out retainedHead and SCHEMA_REVISION agree; check_runtime passes and the runtime has no UPDATE on kind, outcome or closed_at; existing rows read approval.pending and keep their ids; a second row of one kind conflicts on approval_notifications_one_per_kind, and a close-out alone carries an outcome and its time; the three indexes exist; the downgrade refuses with a close-out retained and round-trips once none istests/test_notification_kinds_migration.py::test_ay13_the_head_is_the_new_revision_and_the_runtime_cannot_rewrite_a_kind, ::test_ay13_a_row_queued_before_the_upgrade_reads_pending_and_keeps_its_id, ::test_ay13_one_message_of_each_kind_and_a_close_out_alone_carries_its_outcome, ::test_ay13_the_downgrade_refuses_while_a_close_out_is_retained_and_round_trips_without
AY14The jobs service with and without an approval destination, a recover that runs 3 s while notify ticks every second, --once, and a job past its timeoutNotify scheduled only where a webhook, email, slack or teams destination exists; notify runs during the long recover and recover is never started twice; --once reports every job's outcome; a timed-out job is stopped by its own handle with code 124 and job.timed_outtests/test_jobs_schedule.py::test_ay14_notify_runs_only_where_an_approval_destination_is_configured, ::test_ay14_a_long_job_does_not_hold_notify_back, ::test_ay14_once_waits_for_every_job_it_started, ::test_ay14_a_timed_out_job_is_stopped_by_its_own_handle
AY15readTenant over seeded rows (five announcements delivered over six days with lags of 10 to 90 s, one lapsed, one closed, one refused by the relay, one eight days old, a close-out and another workspace's delivery), then four deliveries and none; the settings page in both schemes at 1280 and 390 pxdelivery reads 5 delivered, median 30 s, 90th percentile 70 s, slowest 90 s, 1 lapsed and 1 failed; below five deliveries both percentiles are null; with none every figure is empty; messages reads pending, closed for a destination configured closed, pending and is empty for the audit export; the Messages column reads "New requests, Outcomes" and the delivery line is as documented; axe clean and no page-level horizontal scrolltests/test_console_api_settings.py::test_ay15_the_tenant_read_reports_a_week_of_announcement_delivery, ::test_ay15_with_nothing_delivered_the_figures_are_empty, tests/test_browser_console_tenant.py::test_ay15_the_messages_column_and_delivery_line, console/src/components/tenant/TenantSettings.test.tsx ("names each destination's messages and says how fast notifications arrived", "adds no delivery line where nothing announces approvals"), console/src/components/tenant/delivery.test.ts
AY16Admission with destinations listing pending by default, reminder only and pending, closed; two admissions racing over the same approval's destinations; an announcement whose destination now lists only reminder; an approval's summary over every kindAnnouncements only for the first and third, under uuid5(approval_id, destination_id); the four-column ON CONFLICT keeps one row each under the race; the switched-off row FAILED with MESSAGE_OFF, unsent; the summary counts announcements only, a lapse as lapsed apart from failed, and delivery_times reads the announcements' first queueing and last deliverytests/test_approval_delivery.py::test_ay16_admission_queues_announcements_only_where_a_destination_lists_them, ::test_ay16_an_announcement_whose_message_was_switched_off_is_never_sent, ::test_ay16_the_summary_counts_announcements_and_lapses_apart, ::test_ay16_racing_announcements_queue_one_row_and_raise_nothing
AY17The deadline dialog with 120 typed, an email destination and no measurement; with 120 typed, an email destination and a measured 90th percentile of 90 s; with 200 and with 180 typed against a measurement; with off, 3601 or a word; with no approval destination; and the guided-setup step with and without a destinationThe fixed email hint; the measured hint alone; the measured hint under three times the 90th percentile; no hint for the others or without a destination; the hint is in the field's description, never an error, and submitting still sends exactly {deadline, reason}; guided setup states delivery, or that no destination is configured, right after the deadline sentence and nothing before the tenant is read; axe clean on the open dialog in both schemes at 1280 and 390 pxtests/test_browser_console_tenant.py::test_ay17_the_deadline_dialog_warns_against_measured_delivery, tests/test_browser_console_samples.py::test_ay17_guided_setup_states_delivery_after_the_deadline, console/src/components/tenant/DeadlineDialog.test.tsx, console/src/components/tenant/delivery.test.ts ("the deadline hint"), console/src/components/welcome/SampleChecks.test.tsx ("states how fast notifications arrive right after the deadline, or that none are sent", "says a held request is announced only in this console where no destination is configured", "says nothing of delivery before the tenant is read")
AY18daily_limit = 10 with nine emails delivered in the day; a close-out due before a new request's announcement, both for the same email destinationThe close-out settled FAILED with RATE_LIMITED at once, attempts 0 and its next attempt time unmoved; the new request's email sent as the tenthtests/test_approval_delivery.py::test_ay18_follow_ups_never_take_the_last_of_the_email_cap
AY19A request whose approval holds an announcement, a reminder and a close-out row, read through the execution detail and the approval detailEach deliveries item carries its kind; the timeline reads "Review notification queued.", "Reminder queued." and "Outcome message queued." and the delivered forms, never a second review notification for a follow-up; the technical details name each row "Delivery", "Reminder delivery" or "Outcome delivery"tests/test_request_references.py::test_ay19_each_delivery_carries_its_kind, console/src/components/RequestContext.test.tsx

Monitoring queue (MQ1 to MQ16)​

Monitoring becomes a queue an administrator works through every day. The group covers acknowledgement held to the spaces the caller sees and audited (MQ1 and MQ2), the findings queue, freshness and cross-links (MQ3 to MQ12), and the acknowledgement note, the write-once rule and bulk acknowledgement (MQ13 to MQ16). Rows are listed as their tests land.

IDSetup/actionRequired resultTest
MQ1An administrator narrowed to one space, and a workspace-wide one looking at one space, acknowledge a finding of another space, through the store and over HTTPRefused as FINDING_UNAVAILABLE, answered 404 NOT_FOUND with a body byte-identical to an unknown identifier's; the row is unchanged and no event is appended; the narrowed administrator still acknowledges a finding of their own space, and the workspace-wide one on All spaces acknowledges the othertests/test_monitoring_acknowledgement.py::test_mq1_an_administrator_cannot_acknowledge_a_finding_outside_the_spaces_they_see, tests/test_console_api_monitoring.py::test_mq1_acknowledging_outside_the_space_answers_as_unknown
MQ2Acknowledge in the browser, through a personal access token, and a second time; then decide and replayExactly one monitor.finding_acknowledged per finding acknowledged, whose payload is exactly finding_id, rule_version and actor_credential_id (the token's backing credential for the token, the session's own for the browser), with the finding's space on the row and no observation content; the repeat and a refusal append nothing; every later decision replays completetests/test_monitoring_acknowledgement.py::test_mq2_an_acknowledgement_appends_one_event_and_a_repeat_none, tests/test_console_api_monitoring.py::test_mq2_a_token_acknowledgement_names_its_credential, tests/test_replay_informational_kinds.py::test_an_acknowledged_finding_leaves_every_later_decision_replayable
MQ3The sidebar with 3 open findings and 2 quiet items; with none open and 2 quiet; with neither; an approver. The Findings and Connections tabs with and without counts. Home with 1 stale source and 1 overdue collection, with only the overdue one, and with neitherThe Monitoring entry links to /monitor?view=findings, ?focus=quiet and /monitor in turn; its pill shows 3, 2 and nothing, and its accessible name says what it counts; the entry is current on every /monitor view; an approver sees no entry and no tenant read is made. The tabs read "Findings, 3 open" and "Connections, 2 quiet", and are bare at zero. Home's row reads "2 monitoring sources or collections quiet" and links to /monitor?focus=quiet, still shows for an overdue collection alone, and is absent with neitherVitest: console/src/shell/shell.test.tsx, console/src/components/monitor/badge.test.ts, console/src/components/monitor/quiet.test.ts, console/src/components/monitor/MonitorPage.test.tsx, console/src/routes/-home.test.tsx
MQ4250 findings, 230 acknowledged, then ten open ones moved to another space; GET /monitor/findings with each state, no state, a bad state and an extra query key; an approver and an agent credentialEach state answers its findings newest first, at most 200; the open and acknowledged counts are right beyond 200 and per space; the snapshot's open_findings equals the open count; no state is open; a bad state is 400 INVALID_REQUEST; an extra key is refused; an approver is refused 403 and an agent credential 403 and audited. In the console the view reads only this route, sets no timer, asks again when the window regains focus, and filters with chips that keep the focustests/test_monitoring_acknowledgement.py::test_mq4_findings_read_by_state_counts_beyond_the_page, tests/test_console_api_monitoring.py::test_mq4_findings_answer_by_state_and_refuse_anything_else, tests/test_console_api_monitoring.py::test_the_monitor_routes_are_an_administrators, tests/test_console_api_monitoring.py::test_every_monitor_route_refuses_a_bearer_credential_and_a_missing_session; Vitest: console/src/components/monitor/Findings.test.tsx
MQ5One finding read by its identifier, by an upper-case identifier, by not-an-id, by an unknown identifier and by the identifier of a finding in a space the session does not seeThe first answers it; the other four answer the same 404 body, and the store refuses the hidden and the unknown one as FINDING_UNAVAILABLE; on All spaces a workspace-wide administrator reads the hidden onetests/test_monitoring_acknowledgement.py::test_mq5_one_finding_reads_inside_the_space_only, tests/test_console_api_monitoring.py::test_mq5_one_finding_answers_by_identifier_only_where_visible
MQ6An ungoverned-reach finding, a collection-health finding, a source-health finding and an observed finding, with markup in a label and a display name; one acknowledgedEach carries its subject: the agent with its class, sponsor state, sponsor_count and owner count and no sponsor list, the connection's label, the source's label, the observation's fields; the acknowledger is a kind, label and number, never an email; the snapshot, the list and the single read answer the same finding; the page renders every string as texttests/test_monitoring_acknowledgement.py::test_mq6_a_finding_names_its_agent_connection_source_and_acknowledger, tests/test_console_api_monitoring.py::test_mq6_markup_in_labels_travels_as_data; Vitest: console/src/components/monitor/Findings.test.tsx
MQ7Connections with a run 23 h and 25 h old; never run, registered 2 h and 25 h ago; BACKLOG with a fresh sync; complete runs with the last sync 25 h and 3 days old; ERROR 2 h and 25 h ago; evidence exactly 24 h old; revoked; overdue connections and a stale source in another spaceFor every case the verifier answers reporting exactly when collection_reporting holds, and overdue_since is set exactly where OVERDUE_CONNECTIONS counts the connection, at the same boundary; the API's connection row carries both; the setup module keeps no rule of its own; the tenant view, the overview and the report count overdue connections and stale sources per space, and the report's quiet figure is stale plus overdue. Connections never shows the allow tone unless reporting, says "Collection overdue" with "Overdue since", and puts quiet items firsttests/test_monitoring_freshness.py::test_mq7_every_surface_answers_the_same_for_every_case, tests/test_monitoring_freshness.py::test_mq7_no_surface_keeps_a_rule_of_its_own, tests/test_monitoring_freshness.py::test_mq7_overdue_and_source_counts_follow_the_space, tests/test_console_api_monitoring.py::test_mq7_the_connection_carries_its_freshness; Vitest: console/src/components/monitor/MonitorPage.test.tsx
MQ8The setup's Verify step answering awaiting_sync, then reporting; Stop listening; an error; ten minutes of awaiting_sync; a hidden tab; the dialog closedIt checks again every 10 s; stops on reporting, when asked, on the error with the existing copy and at ten minutes with its sentence; makes no call while hidden and resumes when visible; never starts a check while one is out; makes none after closingVitest: console/src/components/monitor/listening.test.ts, console/src/components/monitor/MonitorSetup.test.tsx
MQ9The Monitoring agent page for an unlinked and a linked agent; the Agents table; the directory page of a discovered agent; in Chromium, Govern from the Monitoring agent page and the way backGovern and Bind link to /agents/{agent_id}; a linked agent opens its governing agent, named by its number; operator commands sit folded under "Operator commands" where the edition offers them, and a hosted reader is told accepting a path is not in the console yet; the table's Govern and Linked links are right and an unlinked row with no reach keeps its text; the directory note links to /monitor/agents/{agent_id}; in Chromium the click lands on the agent page offering "Govern this agent", and its note returns to the Monitoring agent pagetests/test_browser_console_monitor.py::test_mq9_govern_from_the_monitoring_agent_page; Vitest: console/src/components/monitor/MonitorPage.test.tsx, console/src/components/directory/agents.test.tsx, and the hosted edition's own
MQ10An agent's findings with one in another space; two connections' stories, deliveries and coverage across two spaces; 250 stories whose three gap stories sort last by identifier; an observation that raised findings; Activity with a valid and an invalid story identifier; Inventory with ?story= matching and not matching; gap stories whose identifiers carry a shell character, begin with - or run to 91 characters; the assistant's finding citationThe agent page lists only the visible finding; coverage, inventory and deliveries hold only the visible space's rows; the gap stories come first, oldest gap first, within the 200; each observation names the findings raised on it; a valid story links to Inventory, which marks and scrolls to it, and an invalid one is text; an unmatched story says so and marks nothing; the report command appears only for an identifier the command accepts, with the fixed label, --story-id= and --hours 24; findings, deliveries, the agent page and the citation link to ?view=findings&state=all&open=; search values outside their list or pattern are droppedtests/test_monitoring_acknowledgement.py::test_mq10_the_agent_page_lists_only_findings_in_the_space, tests/test_monitoring_acknowledgement.py::test_mq10_coverage_inventory_and_deliveries_follow_the_space, tests/test_monitoring_acknowledgement.py::test_mq10_gap_stories_come_first_beyond_the_page, tests/test_monitoring_acknowledgement.py::test_mq10_an_observation_names_the_findings_it_raised; Vitest: console/src/components/monitor/search.test.ts, console/src/components/monitor/MonitorPage.test.tsx, console/src/components/assistant/assistant.test.tsx
MQ11Alert settings with no findings destination, and with three: one for every Space, one for the reader's Space and another workspace's, and one for that other Space alone; a delivery and an intent not routed; an administrator narrowed to one Space, and a configured Space ID that is no Space of the workspace; an overdue connection; in the core edition and in the hosted oneWith none, the first card says no findings destination is configured, so findings are not sent outside the console; with some, it lists each by id, kind, host, rules and Spaces and says who sets them, never an address or a secret; a Space the reader cannot read is counted and never named; an unknown Space ID is counted apart for a reader of every Space and as one they cannot see for a narrowed reader, and another workspace's Space is never named nor its ID shown; a destination whose every Space is unknown says it receives no findings; the delivery table lists the newest 200 deliveries with their destination, intents not routed among them, unfolded, in both editions; the local test receiver is folded in core and absent in hosted; the console API names the same, reading the names of only the Spaces a destination names; in Chromium, in both editions, the page is clean under axe in light and dark at 1280 and 390 px with no sideways scroll; the overdue sentence is each edition's ownVitest: console/src/components/monitor/Alerts.test.tsx, MonitorPage.test.tsx, and the hosted edition's own; tests/test_console_api_monitoring.py::test_mq11_the_snapshot_names_each_findings_destination_and_never_its_address, ::test_mq11_a_reader_narrowed_to_one_space_never_sees_another_spaces_name, ::test_mq11_a_narrowed_reader_counts_a_mistaken_space_id_as_a_space_they_cannot_see, ::test_mq11_a_workspace_wide_reader_sees_a_mistaken_space_id_as_unknown_never_unseen, ::test_mq11_another_workspaces_space_is_unknown_here_and_never_named, ::test_mq11_the_snapshot_reads_the_names_of_only_the_spaces_a_destination_names, ::test_mq11_each_listed_delivery_names_its_destination, tests/test_findings_delivery.py::test_alert_settings_lists_deliveries_and_unrouted_intents_but_not_a_routed_one, tests/test_browser_console_monitor.py::test_mq11_alert_settings_lists_destinations_and_deliveries_in_both_schemes; the hosted build's Chromium pass is among the hosted service's own tests
MQ12In Chromium: a finding acknowledged, then opened cold by its address; the chips; then Findings opened by link, Connections with an overdue connection and focus=quiet, Inventory with a marked story, Alert settings with the receiver open, and the Monitoring agent page, in light and dark at 1280 and 390 pxThe finding opens pinned and expanded; All lists it acknowledged and Open drops it from the address; exactly one card and one story are marked; axe finds nothing, nothing scrolls sideways, and no CSP or Trusted Types violation is recordedtests/test_browser_console_monitor.py::test_mq12_a_finding_link_opens_it_pinned_and_expanded, tests/test_browser_console_monitor.py::test_mq12_monitoring_is_clean_in_both_schemes_at_1280_and_390
MQ13Acknowledge with a note, with a note of only spaces, with a secret-shaped note, a control character and 501 characters, and with a note on a finding already acknowledged, through the store and over HTTP; then the assistant's finding toolThe note is trimmed, stored with the acknowledgement and carried as note in its one monitor.finding_acknowledged (no note key without one); a note of only spaces is none; the refused notes are INVALID_NOTE, answered 400 INVALID_BODY naming note, quoted in no error or answer, and change nothing; a note on an acknowledged finding is ACKNOWLEDGED, answered 409 CONFLICT, and saves nothing, while the repeat without a note stays the idempotent 200; an unknown body key is refused by name; the assistant's finding tool carries no note. In the console the note is posted, shown under the acknowledgement as text, kept after a refusal, and each refusal reads in the note's own wordstests/test_monitoring_acknowledgement.py::test_mq13_a_note_is_stored_with_the_acknowledgement_and_audited_once, tests/test_monitoring_acknowledgement.py::test_mq13_a_note_shaped_like_a_secret_is_refused_and_never_quoted, tests/test_monitoring_acknowledgement.py::test_mq13_a_note_on_an_acknowledged_finding_is_a_conflict_and_saves_nothing, tests/test_monitoring_acknowledgement.py::test_mq13_the_assistant_finding_tool_carries_no_note, tests/test_console_api_monitoring.py::test_mq13_the_note_over_http; Vitest: console/src/components/monitor/Findings.test.tsx
MQ14Bulk acknowledgement of five identifiers (two open, one acknowledged, one in a space the session does not see, one unknown) with a note; a duplicate, 51, none, a non-canonical identifier and a secret-shaped note; the same route through a personal access token; two administrators acknowledging overlapping sets at the same moment, twenty times; in Vitest, the confirmationOne outcome per identifier in request order (acknowledged, acknowledged, already_acknowledged, unavailable, unavailable), one event with the note for each finding acknowledged and the earlier note kept; every malformed batch is refused before any write, 400 INVALID_BODY naming finding_ids or note; the token is refused TOKEN_NOT_ALLOWED and nothing changes, while its single-finding acknowledgement still succeeds with its backing credential; under concurrency each finding is acknowledged once with one event and neither transaction fails. In the console nothing is sent until "Acknowledge N findings" is pressed, Cancel and a changed selection send nothing, the results line counts each outcome, names the titles and says when a note was saved only on the findings acknowledged now, and Select all takes at most 50tests/test_monitoring_acknowledgement.py::test_mq14_bulk_acknowledgement_reports_each_finding, tests/test_monitoring_acknowledgement.py::test_mq14_a_malformed_batch_is_refused_before_any_write, tests/test_monitoring_acknowledgement.py::test_mq14_a_bulk_note_is_screened_before_any_write, tests/test_monitoring_acknowledgement.py::test_mq14_concurrent_bulk_acknowledgements_acknowledge_each_finding_once, tests/test_console_api_monitoring.py::test_mq14_bulk_over_http, tests/test_console_api_monitoring.py::test_mq14_a_token_cannot_acknowledge_in_bulk; Vitest: console/src/components/monitor/Findings.test.tsx
MQ15The runtime role changing an acknowledged finding's acknowledger, its note, and both its time and acknowledger together; the same changes with the trigger dropped in a transaction rolled back; the migration applied, downgraded with a note retained, and downgraded cleanEach change is refused with SQLSTATE 23514 and the trigger's own message, monitor finding acknowledgement is final, and each goes through without the trigger, so the refusal is the trigger's; an open finding is still acknowledged; the upgrade adds the bounded nullable column, the runtime's update grant on it, the partial open index and the trigger, whose function no one but its owner may call and whose search path is fixed; UPDATE_COLUMNS and check_runtime agree; the downgrade refuses while a note is kept and otherwise removes all of it, keeps the earlier grant and forced row securitytests/test_monitoring_acknowledgement.py::test_mq15_the_database_refuses_to_change_a_finished_acknowledgement, tests/test_finding_acknowledgement_migration.py::test_mq15_upgrade_adds_a_bounded_note_its_grant_an_index_and_a_trigger, tests/test_finding_acknowledgement_migration.py::test_mq15_downgrade_refuses_while_a_note_is_kept_and_otherwise_restores, tests/test_finding_acknowledgement_migration.py::test_mq15_check_runtime_expects_the_new_grant
MQ16In Chromium: two open findings selected, one of them moved to another space while the session looks at the default one, then confirmed; Findings with the confirmation and with bulk results showing, in light and dark at 1280 and 390 pxThe confirmation names the count and takes the focus; the results line reads one acknowledged and one not in the space, with both titles, and the sidebar pill drops by one; axe finds nothing, nothing scrolls sideways, and no CSP or Trusted Types violation is recordedtests/test_browser_console_monitor.py::test_mq16_bulk_acknowledgement_confirms_and_reports_each, tests/test_browser_console_monitor.py::test_mq16_bulk_views_are_clean_in_both_schemes_at_1280_and_390

Policy lifecycle (PL1 to PL10)​

The policy pages put the preview before activation, let a Policy manager preview over the Spaces they manage, record why each console activation was made, compare a draft with the policy in use, calm the list, and carry rules between workspaces as a rules file. Real PostgreSQL throughout; the pages in Vitest. This is console evidence, not kernel evidence, so the group is not in the release manifest's acceptance prefixes.

IDSetup/actionRequired resultTest
PL1A validated policy opened; no preview run; a preview run over 7 days with changes; the activation dialog opened before and after; a policy active only in another Space openedThe stepper sits under "What this policy does" in the order Validate, Preview, Activate; nothing replays on arrival; the button reads "Preview the last 7 days" and follows the window chosen; step 3 reads "Not previewed", then the summary with transition counts; the dialog opens with the not-previewed line when none ran and with the summary when one did; the policy active elsewhere offers the preview as its current step, which the earlier page did notconsole/src/components/policy/lifecycle.test.tsx, console/src/components/policy/policy.test.tsx ("the policy words")
PL2A Policy manager of Space A (a viewer of B), with executions in A and B that the candidate decides differently, previews; an ADMIN-kind principal seated as ADMIN in A alone previews; a workspace-wide administrator previews the same; a manager's preview that cannot be computed; a manager of an empty Space previewsThe manager's and the narrowed administrator's answers count and list only A's executions, with scope: "spaces"; the workspace-wide administrator's lists both with scope: "workspace" and its counts are what they were; the unavailable preview answers scope: "spaces" for the manager and "workspace" for the administrator; the empty Space's manager counts nothingtests/test_policy_preview_spaces.py::test_a_policy_managers_preview_holds_only_their_spaces_decisions, ::test_a_narrowed_administrators_preview_holds_only_their_spaces_decisions, ::test_an_administrators_preview_is_unchanged, ::test_a_policy_managers_unavailable_preview_says_spaces, ::test_a_policy_manager_of_no_space_with_executions_sees_nothing_of_theirs, tests/test_admin_cli.py::test_bundle_preview_reports_changed_decisions_without_writes
PL3A Policy manager calls export_history directly; an approver and a viewer call the preview route; a manager of A previews a policy owned by B and not offeredexport_history refuses the manager as it did before (ExportError), and admits them only with permission="policy.manage", which only the preview passes; the approver and the viewer are refused 403 FORBIDDEN and nothing is replayed; the other Space's policy answers 404 and nothing is replayedtests/test_policy_preview_spaces.py::test_the_replay_export_still_refuses_a_policy_manager, ::test_a_policy_manager_previews_through_the_console_and_others_are_refused, ::test_another_spaces_bundle_is_not_found_for_a_manager
PL4Activation through the API with no reason, an empty one, a blank one, 501 characters and a secret-shaped one, then a plain one; the store with a blank, long or secret-shaped reason; the CLI with and without --reason, and with a blank one400 INVALID_BODY naming reason for each refused body, nothing activated and no event, and the value never echoed; the plain reason is in policy.bundle_activated's payload; the store refuses INVALID_REASON at reason and moves nothing; without a reason the payload has exactly the keys it had before, byte for byte; the CLI prints INVALID_REASON for the blank onetests/test_console_api_policy.py::test_activation_requires_a_reason_and_records_it, tests/test_policy_store.py::test_an_activation_records_its_reason_in_the_event, ::test_an_activation_without_a_reason_writes_todays_payload, ::test_an_activation_reason_shaped_like_a_secret_is_refused_unquoted, ::test_a_blank_or_long_activation_reason_is_refused, tests/test_admin_cli.py::test_bundle_lifecycle_through_the_cli
PL5Activations of one policy with two reasons and of another between them; a policy offered tenant-wide and activated in Space B with a reason, read by an administrator and by a Policy manager of Space A; the partial indexThe list's row and the detail carry the latest activation's note, its time, actor and number; a never-activated draft carries none; the manager never reads B's note, while the administrator does; audit_events_policy_activation exists, partial on policy.bundle_activatedtests/test_console_api_policy.py::test_the_list_and_the_detail_carry_the_latest_activation_note, ::test_a_note_from_a_space_the_reader_cannot_see_is_not_shown, ::test_the_activation_notes_index_exists
PL6A candidate that adds an allow, removes a deny, raises a ceiling, changes a condition and changes only a note, compared with the active policy; candidates that only map a second connector account for an existing action, only declare external_executor, only turn observe_only off, only change a mapping version, only raise a context setting's max_age_seconds, or only add a signal mapping; a Cedar candidate; no active policy; the active policy itself; a Space not chosenEach change carries its direction as policy/compare.py classifies it (an added allow, a removed deny, a raised ceiling: allows more; a changed condition: check; a note alone: none), and none of the mapping-only candidates reads as no change; Cedar is why_not: "cedar", no active is "no-active", the active policy is "is-active", all Spaces is "no-space"; another Space's policy that is not offered answers 404; nothing is replayed; the card leads each change with its word and renders rule text as texttests/test_policy_compare.py, tests/test_console_api_policy.py::test_the_comparison_names_each_change_against_this_spaces_active_policy, ::test_a_draft_that_only_adds_an_account_mapping_reads_as_allowing_more, ::test_the_comparison_says_why_it_cannot_compare, ::test_a_recognized_seed_compares_through_its_reviewed_rules, ::test_another_spaces_bundle_is_not_compared, console/src/components/policy/lifecycle.test.tsx ("changes from the active policy")
PL7A Space with one active, two drafts, one validated, one active in another Space and twelve retired versionsActive first, then drafts and validated newest first, then the one active elsewhere; "Show 12 retired versions" reveals a second table and sets ?retired=1; Back hides it; a version's note shows under its time as textconsole/src/components/policy/policy.test.tsx ("a calmer list")
PL8Download from a rules bundle with a tenant budget, a group budget, a selector budget, a note and context; from a Cedar bundle; from a recognized seed; a Policy manager of A downloading B's policy that is not offeredThe file parses with load_ruleset_file and equals the stored ruleset minus the group budget and the context; it holds no UUID; the selector budget and the note are kept as written; omitted_budgets names the group budget and the detail's rules_file says so before the click; Cedar and the seed answer 409 CONFLICT; the other Space's policy answers 404; the console builds the file from the answer as text and offers no download for Cedar or a seedtests/test_console_api_policy_rules_file.py::test_a_download_is_the_ruleset_file_the_cli_reads, ::test_a_download_carries_no_identifier, ::test_a_download_keeps_selector_budgets_and_notes_as_written, ::test_a_bundle_not_written_as_rules_cannot_be_downloaded, ::test_another_spaces_bundle_is_not_downloaded, console/src/components/policy/rulesfile.test.tsx ("download rules")
PL9Create from a rules file: the downloaded file in a second Space offered the same account; a file naming an unmapped action; an action served only by a signal mapping; mappings that cannot share a bundle; a qualified budget; context; a secret-shaped note; duplicate keys; not JSON; an array; version: 2; 513 KB; 270,000 two-byte characters; a 511 KB file of newlines; a body over the route's cap; the file beside a bundle or a template; a Policy manager in a Space they only viewThe first lands as a DRAFT owned by the second Space, over the mappings it may use, and is not active, with policy.bundle_created and no policy.bundle_activated; the others answer 400 at their locations (INVALID_BODY at ruleset.rules.0.action, SIGNAL_MAPPING_ONLY and MAPPINGS_CONFLICT at the action, INVALID_BODY at ruleset.budgets.0.group_id, ruleset.context, ruleset.rules.0.note and ruleset.version, and naming ruleset for the unreadable and oversized ones), the newline file passes the size checks, the body over the cap answers 413 TOO_LARGE, and the Space the person only views answers 403; each refusal writes nothing; the console refuses a file over 512 KB before reading it, words an action refusal from the person's own file, and keeps nothing in storagetests/test_console_api_policy_rules_file.py::test_a_rules_file_becomes_a_draft_over_this_spaces_mappings, ::test_a_rules_file_is_refused_at_its_location_and_writes_nothing, ::test_an_action_served_only_by_a_signal_mapping_is_named_as_such, ::test_two_mappings_that_cannot_share_a_bundle_are_named_at_the_action, ::test_an_oversized_rules_file_is_refused, ::test_a_rules_file_is_refused_beside_a_bundle_or_template, ::test_a_policy_manager_imports_only_into_a_space_they_manage, console/src/components/policy/rulesfile.test.tsx ("a draft from a rules file")
PL10Chromium: /policy, /policy?retired=1, an active policy and a validated one in both schemes at 1280 and 390 px, with the activation dialog open; the walk from a pasted draft to an activated policy with a reason; a rules file downloaded from one Space and uploaded in anotheraxe clean, no sideways scroll, no CSP or Trusted Types violation; nothing replays before the preview is asked for; the dialog opens on the preview's line; the reason shows under the time on the list afterwards; the downloaded file holds no UUID and lands as a draft in the other Spacetests/test_browser_console_policy.py::test_the_policy_pages_are_clean_in_both_schemes_and_at_phone_width, ::test_a_draft_is_pasted_validated_previewed_and_activated_with_what_changed_named, ::test_a_rules_file_downloaded_here_becomes_a_draft_there

Home, value reporting and the board (HV1 to HV17)​

Home says what ExecBound did. An approval past its deadline is classified at read time on the server's clock, as lapsed before a decision or approved but not used, and nothing is written until the recovery run's sweep. "Effect unknown" is its own open figure. One classification (surfaces/outcomes.py) serves both Home's value card and report and the Activity list each count opens. A denial links to the rule that decided it where the reader may open that policy. A person may turn on a plain-text weekly summary of counts, and stop it with one click from the email.

IDSetup/actionRequired result
HV1A pending approval past its deadline inside the window, an approved one past its deadline, and an unswept pending one that lapsed eight days ago, read through the overview before and after the recovery run, on one clockBefore: pending_approvals 0, lapsed_approvals 2 (the two undecided lapses), equal to the list outcome=lapsed&state=PENDING_APPROVAL opens; the two in-window rows under stale and bucketed by expires_at; the old lapse in no window figure; none in awaiting. No read appends an event or changes an approval. Sweeping the two in-window lapses leaves the window's figures as they were; the run then sweeps the old one
HV2FAILED_EFFECT_UNKNOWN, STALE_AUTHORIZATION and FAILED_NOT_EXECUTED rows, and one FAILED_EFFECT_UNKNOWN row changed ten days beforeunknown counts both effect-unknown rows, stale the other two, decisions is their sum, the series holds the windowed rows only, and ?state=FAILED_EFFECT_UNKNOWN lists both
HV3The board with one held request inside its deadline, one lapsed and one approved but not usedThe first is held for a person; the lapsed one is phase hollow, word lapsed, lapsed: true; the unused one unused: true; held 1 and lapsed 1 for the window and for today
HV4GET /executions/{id} and the list for an undecided lapse and an approved-but-unused approval, before the deadline, after it and after the sweep, and a request inside its deadlineapproval.lapsed and approval.unused flip with the server's clock alone, without a write, and say the same on both sides of the sweep; both false inside the deadline
HV5One request of every outcome, read by value.readEach count is one, except approved 2 (it holds the unused one), settled 2 (the reconciled row and the corrected one), would_refuse 2 (it holds the by-limit one) and held 6; the uncorrected unknown effect is not settled; the top action is the catalog's label; the median is the fixture's; denial_kind agrees with store.denial_category and with the SQL kind on every payload; settled needs a settled state; no request value reaches the assembled text
HV6For every outcome key, the report's count and GET /executions?outcome=<key>&from=<since>The list holds exactly the counted rows
HV7The report for an administrator, a legacy approver in scope, an approver with no scope, an administrator seated in a second space, and another workspace's administratorEach counts only what that reader may read; refused_before_decision is a number only for the workspace administrator
HV8/report and /report.csv: a bearer, no session, an unknown key, a bad range or offset, a workspace named =HYPERLINK("x"), and an account session's CSV with no, another's or its own generation403 audited, 401, 400, 400; the CSV is an attachment under no-store, every cell quoted, the name prefixed with ' and named once, with a space row; 409 WORKSPACE_CHANGED, 409, 200
HV9/executions with an unknown outcome, a from in the future, 32 days back, without a zone, beside since, malformed or empty400 INVALID_REQUEST each; outcome=lapsed and outcome=approved_unused list exactly their rows
HV10A denial under a ruleset bundle, a held request's review obligation and its limits, a limit code, and a denial under a Cedar-only bundle; the denial read by an administrator and by an approver who may not open the policybundle_id is the row's; rules names the deny rule, the review rule and the limits; the Cedar-only one has rules: [] and its recorded sentence; rule_id is unchanged; policy_readable is true exactly where GET /policy/{bundle}/rules answers
HV11The migrations, the grants and every definer function under the local owner and the restricted owner without bypassForced row security and the tenant policy on both tables; the runtime role's exact grants; enqueue fenced to its own tenant and refused without one; tenants, due and sent return identifiers or a count; unsubscribe ends only a matching active subscription started no later than its message; the downgrade refuses with a subscription and otherwise drops cleanly; the rejection index exists
HV12POST /settings/weekly-summary on, off and on again; a no-op; no address; a deployment without the summary; the harness refusals; an account in two workspaces whose second principal has no addressOwn row only, audited with via: settings; 409 CONFLICT; 409 with nothing created; 503 UNAVAILABLE; the account's address in both workspaces
HV13A week with activity, a week with none, an approver, subscribers deactivated before and after the enqueue, an addressless one, hostile labels, both caps, a refusing relay, a week past, an account in two workspaces, and the drain under the restricted owner; the template alone for a workspace named as written, one named in a non-Latin script, and a tenant id that is not one; the template alone for the longest link it takes with a long workspace name, with and without spaces, and with a line break written into its one-click header; a summary drained for a workspace named Acme & CoOne message per subscriber per week; the approver's counts are their scope; the empty week skipped with no SMTP traffic; no message for the first deactivated person and PRINCIPAL_INACTIVE for the second; NO_ADDRESS; no label, target, person or identifier in subject or body; List-Unsubscribe and List-Unsubscribe-Post, the first on one unfolded line as the bracketed link with no encoded word, in the template and in what the relay received, while the subject still folds, every other line within 78 columns and every encoded word within 75 characters; the line break refused on the way out; capped messages stay PENDING; failures back off and end FAILED; WEEK_PASSED; one summary per workspace at the account address; both workspaces delivered without bypass; the workspace chosen by name only where it is shown as written, else by the label as a hint beside the tenant id, or by the tenant id alone where nothing of the name survives, and "your workspace", never "unknown", where nothing of the name survives; the bad tenant id refused; the drained summary for Acme & Co says to choose the one named like Acme Co with that workspace's own tenant id
HV14The unsubscribe link: a GET; a valid POST; the same again; a forged, unknown, other workspace's, nonexistent workspace's and malformed link; an old link after renewing; the request shape; both limits; every 400 and each limit's 429, asked for as a page and not; the log around a GET, a forged link, a nonexistent workspace's link, a malformed link and a stop; a database fault while stopping, from the audit append and from the definerThe GET changes nothing and sets no cookie; the valid POST ends it with via: link; every POST answers the same status and body; the old link leaves the renewal active; no-referrer and no-store; the request log names no path; 429 past each limit; no-referrer on every 400 and 429 too; no ERROR line for the forged, nonexistent or malformed link, no secret, digest or link in any line, and one weekly_summary.unsubscribed line with the tenant and message ids alone; the fault answered with the same page, nothing ended, and one weekly_summary.refused line at ERROR with its code and no ids, nothing of the link in any line
HV15schedule.jobs_for and the runtime configuration with and without a relay and the flagweekly-summary-run is scheduled, on lock 9006, only with both
HV16In Chromium: Home with the card, a card number, the findings row, a lapsed record, a denial's rule link, /report and its CSV, the board with a lapsed shot, My account's summary card, an agent labelled with markupIn light and dark at 1280 and 390 px: no axe WCAG 2.2 AA violation, no policy or Trusted Types violation, no sideways scroll; the number opens Activity with its outcome pinned and its rows; the findings row opens /monitor?view=findings; the rule is marked and in view; the CSV is an attachment; the switch shows "On" only from the answer; the label renders as text
HV17The card's, the page's, the CSV's and the summary's wordsNone contains "prevent", "attack", "threat" or "blocked", except the one disclaimer that a refusal is not proof that harm was prevented

Tests live in tests/test_home_value.py (HV1 to HV7, HV10), tests/test_console_api_report.py (HV8, HV9), tests/test_weekly_summary_schema.py (HV11), tests/test_weekly_summary.py (HV13), tests/test_jobs_schedule.py (HV15), tests/test_console_api_weekly_summary.py (HV12), tests/test_summary_pages.py (HV14) and tests/test_browser_console_home_value.py (HV16); HV17 is held by console/src/components/home/home.test.tsx, the CSV and summary tests above.

Approval pages (AQ1 to AQ13)​

The console's approval pages: an administrator sees the approvals waiting on other people and can assign themselves to one in place, the view lives in the address, the decision bar restates what deciding does and where, a typed comment survives signing in again, the page says when the message reached its approvers against the deadline, and a lapsed approval tells an approver what happened. The decision path itself does not change. Real PostgreSQL for the reads, Vitest for the page, Chromium for the flows. AQ10 is in the hosted inventory.

IDSetup/actionRequired resultTest
AQ1An unassigned administrator, one approval assigned to an approverWaiting on others lists it with reviewers 1, reviewers_left 1 and time left; the detail answers reviewing false, no continuation and the same counts; a decision with a borrowed continuation is INVALID_CONTINUATION, audited, and changes nothing. records() refuses others to anyone but an administrator reading outside their own review scope, and it is the complement of their own scopetests/test_console_api_approvals.py::test_an_administrator_sees_approvals_waiting_on_others_and_cannot_decide_them, ::test_records_refuses_others_to_anyone_but_an_administrator_reading_outside_review, ::test_others_is_the_complement_of_the_administrators_own_scope, ::test_an_approval_the_administrator_reviews_is_not_waiting_on_others, ::test_the_reviewer_count_is_people_who_can_open_the_record, ::test_an_administrators_lapsed_view_covers_every_reviewer, tests/test_browser_console_approvals.py::test_an_administrator_chases_an_approval_waiting_on_someone_else
AQ2An approver asks for view=others403 FORBIDDEN; their rows and detail carry null reviewers, reviewers_left, assigned_to_you and your_review_elsewheretests/test_console_api_approvals.py::test_waiting_on_others_is_an_administrators_view
AQ3A space member administrator; approvals in two spacesOnly their space's approval is listed; the other's detail is NOT_FOUNDtests/test_console_api_approvals.py::test_waiting_on_others_stays_inside_the_administrators_spaces
AQ4The view chip, Back and a shared ?view=lapsed link; a non-administrator at ?view=othersThe chip and the list follow the address; the default is stripped; focus stays on the chip; the non-administrator sees Pending and the address loses view=others without a new history entry; a row's link carries the view, and Back and a reload return to itconsole/src/approvals/pages.test.tsx ("the view lives in the address"), console/src/approvals/search.test.ts, tests/test_browser_console_approvals.py::test_an_administrator_chases_an_approval_waiting_on_someone_else
AQ5Phone, 390 px, both schemesApprove and Refuse equal width, equal emphasis and 50 px; the bar names the effect, the deadline, the quorum and the workspace in full as text; the badge does not say "Waiting for you" to a reader who cannot decide; the last timeline entry scrolls clear of the bar; axe clean, no violations, no horizontal scrolltests/test_browser_console_approvals.py::test_the_phone_bar_names_the_effect_the_time_and_the_workspace, ::test_waiting_on_others_lapsed_and_the_waiting_panel_are_clean, console/src/approvals/pages.test.tsx ("the decision bar")
AQ6An administrator assigns themselves from the Waiting panel, factor older than thirty minutesThe step-up asks once; approval_scope.assigned is recorded; the detail then carries a continuation and the decision landstests/test_browser_console_approvals.py::test_assigning_yourself_asks_for_the_factor_and_then_the_decision_lands, console/src/approvals/pages.test.tsx ("the Waiting panel")
AQ7A typed comment, the session revoked, a poll answers 401, the person signs in again; then a comment typed on one approval and a move to anotherThe comment is restored and announced; after Approve no draft key remains; after sign-out none remains; the second approval shows its own draft or an empty field, and the first approval's key is untouchedtests/test_browser_console_approvals.py::test_a_typed_comment_survives_signing_in_again, console/src/approvals/drafts.test.tsx, console/src/lib/drafts.test.ts
AQ8An administrator who reviews an action on a target in space Y opens a space X approval of the same action and targetThe detail names Y in your_review_elsewhere; the dialog says the review moves from Y to X; after confirming, the assignment is in X and the Y approval waits on others; the detail's link_path is the core address, and the copied link is that path on the page's own origintests/test_console_api_approvals.py::test_assigning_yourself_moves_a_review_from_another_space, ::test_the_detail_carries_the_cores_approval_link, console/src/approvals/pages.test.tsx ("the Waiting panel", "the approval link in the Waiting panel")
AQ9Home's "approvals pending with an approver" row for each roleAn administrator's link opens /approvals?view=others; a policy manager's and a viewer's open Activity filtered to PENDING_APPROVALconsole/src/routes/-home.test.tsx
AQ11Delivery through the real drain: in time, inside the lapse margin, swept before delivery, decided before delivery, invalidated before delivery, approved and lapsed unusedThe margin is positive in time; lapsed 1 and late for the two lapses; closed 1 for the decided and the approved-unused; withdrawn 1 for the invalidated; notified never counts a lapsed message and otherwise reads as before; a delivery within 30 seconds of the deadline, or after it, is late; the delivery line tells each case apart, Waiting on others rows say Delivered, Sending or Not sent, and an administrator's Lapsed view flags only late rows on the approval deadline's clock, linking to Workspace settings only for someone who can change ittests/test_approval_notifications.py::test_a_message_the_sweep_beat_reads_as_lapsed_not_failed, ::test_a_message_the_sweep_beat_after_one_of_two_approvals_reads_as_lapsed, ::test_a_message_a_decision_beat_reads_as_closed, ::test_an_approved_approval_that_lapsed_unused_reads_as_closed, ::test_a_message_for_an_invalidated_approval_reads_as_withdrawn, ::test_the_records_row_carries_the_delivery_times_only_when_asked, tests/test_console_api_approvals.py::test_the_delivery_view_says_when_the_message_arrived, ::test_a_delivery_after_the_deadline_has_a_negative_margin_and_is_late, ::test_nobody_notified_reads_no_delivery, ::test_waiting_on_others_and_the_administrators_detail_carry_delivery, tests/test_browser_console_approvals.py::test_waiting_on_others_lapsed_and_the_waiting_panel_are_clean, console/src/approvals/delivery.test.tsx ("the delivery line", "late lapses in an administrator's Lapsed view", "delivery while a request waits on others")
AQ12An approver opens an approval that lapsed undecidedThe notice says it lapsed before anyone decided it, that nothing ran and that the agent must ask again, before and after the recovery run ends it; a decision refused as lapsed says the same; an administrator reads the execution-history advicetests/test_browser_console_approvals.py::test_an_approver_reads_what_happened_after_a_lapse, ::test_an_expired_approval_says_so_and_a_hostile_target_is_text, console/src/approvals/delivery.test.tsx ("what a lapsed approval says")
AQ13An approver who approved opens an approval that lapsed with one of two approvals recorded, and one that was approved and lapsed unusedThe notices say "lapsed before enough people approved it" and "was approved but lapsed before the agent used it", never "before anyone decided it"; the detail carries the quorum each reached, and an approval past its deadline reads as lapsed, not as waiting for the remaining approvers, before the sweep as after ittests/test_browser_console_approvals.py::test_an_approver_who_approved_is_not_told_nobody_decided, tests/test_console_api_approvals.py::test_an_expired_detail_carries_the_quorum_it_reached, ::test_an_approved_detail_that_lapsed_unused_reads_its_quorum_met

Agents, keys and account security (AK1 to AK12)​

An agent key's lifetime is a deliberate choice, a key records when it was last used, a rotation is recorded rather than inferred, and a used key that expires within seven days is announced on the agent's page and on Home. Real PostgreSQL for the functions, authentication and the routes, Vitest for the pages, Chromium for the flow.

IDSetup/actionRequired resultTest
AK1Every agent key form: the agent page's govern form and API keys card, Connect this agent, the API keys page dialog and the rotate dialog; a personal access tokenEach starts at "Choose a lifetime" with the hint, cannot be submitted until a lifetime is chosen, and sends the chosen value; a personal access token still starts at 30 daysconsole/src/components/directory/agent-keys.test.tsx ("choosing a key's lifetime"), console/src/components/directory/access.test.tsx, tests/test_browser_console_agents_account.py::test_ak6_issue_and_rotate_a_key_in_both_schemes
AK2A key authenticates three times within a minute, then again after last_used_at is backdated 61 seconds; a wrong secret, a revoked, an expired and an inactive principal's key, and an inactive tenant; a key issued 60 s ahead of the database's clock; a stamp that raises; a request through /v1/execute; credential_used called directlyOne stamp, then another; every refusal stamps nothing; the key issued ahead authenticates and stamps nothing; with the stamp raising, authentication still returns the identity, nothing is stamped and the transaction commits; the gateway stamps; the function stamps a live key of the fence's tenant once a minute and raises INVALID_TENANT or INVALID_CLOCK only for a missing fence or a clock 301 s offtests/test_key_last_used.py::test_ak2_authenticate_stamps_after_every_check_and_never_on_a_refusal, ::test_ak2_a_key_issued_ahead_of_the_database_clock_authenticates_and_stamps_nothing, ::test_ak2_a_stamp_that_raises_never_changes_authentication, ::test_ak2_the_gateway_path_is_unchanged, ::test_ak2_credential_used_stamps_once_a_minute_and_only_a_live_key
AK3An open transaction holding the key share lock an execution insert takes; an open transaction holding the key's row FOR UPDATE, as a revocation does; two authentications of one key at onceThe stamp lands within a second while the share lock is held; with the row locked, authentication returns within a second and stamps nothing; one stamp lands for the twotests/test_key_last_used.py::test_ak3_a_share_lock_from_an_open_execution_does_not_delay_the_stamp, ::test_ak3_a_locked_key_authenticates_at_once_without_a_stamp, ::test_ak3_two_authentications_at_once_stamp_once, ::test_ak3_credential_used_skips_a_locked_row
AK4The migration downgraded, upgraded and downgraded again; the runtime's catalog checkUpgrade adds both columns, the index and three definer functions owned by the owner whose ACL is exactly the owner's and the runtime's EXECUTE; the runtime keeps no UPDATE on credentials and no check constraint names last_used_at; check_runtime accepts the schema; the downgrade removes all of ittests/test_key_last_used.py::test_ak4_the_migration_adds_both_columns_and_three_functions_and_the_downgrade_removes_them, ::test_ak4_check_runtime_accepts_the_migrated_schema
AK5A used key expiring in 3 days; the same agent's second used key and a third issued without Rotate; then a key issued with replaces naming the first; keys never used, expiring in 8 days, never expiring, of an asleep or deactivated agent, revoked; seven qualifying agents; a narrowed administrator; an approver; a token; admin_credential_replaces and the issue route with another agent's key, a revoked, deleted or expired key, the new key itself and a key already namedGET /credentials/expiring lists the first key alone while the others exist and no row reads replaced; after Rotate it is replaced and gone; the others never notify; five agents and more 2, each by its soonest key, the same key the agent detail's expiring_key names; another space's key is absent for the narrowed administrator; an approver is refused 403 and a token may read; every invalid replacement raises INVALID_REPLACEMENT, answers 409 and issues nothing; Home lists at most five and links the resttests/test_console_api_expiring_keys.py, tests/test_key_last_used.py::test_ak5_admin_credential_replaces_records_a_rotation_and_refuses_the_rest, tests/test_console_api_agents.py::test_ak5_ak6_an_issue_with_replaces_records_the_rotation_and_refuses_the_rest, console/src/components/home/AccountNotices.test.tsx
AK6Rotate on a live key, from the agent pageA new key for the same agent naming the old key, behind the same step-up, shown once with the sentence saying where it goes; credential.issued carries replaces only then; the old key stays live and reads "live, replaced by a newer key"; the secret is in no query or mutation record, URL or storage once the dialog closes; a refusal shows no secrettests/test_browser_console_agents_account.py::test_ak6_issue_and_rotate_a_key_in_both_schemes, console/src/components/directory/agent-keys.test.tsx ("rotating a key"), tests/test_console_api_agents.py::test_ak5_ak6_an_issue_with_replaces_records_the_rotation_and_refuses_the_rest
AK7The agent page with ?section= set to each section, to an unknown value, and to connection on a discovered agent; a just-created agent with no section; a governed agent with requests and no section; an agent that makes its first request while Connection is open; a link with ?section=permissions through a bound agent's monitoring id; a reader who sees an agent without administering itEach known section renders alone and the strip marks it aria-current="page"; unknown and inapplicable values render the default; the just-created agent opens on Connection with the steps and the key form; the agent with requests opens on Overview with its summary and its Connection folds the steps under one line; a first request while watching keeps Connection open; Back restores the previous section; the canonical redirect keeps the section; the non-administering reader is offered no change; every section is axe-clean in both schemes at 1280 and 390 pxtests/test_browser_console_agents_account.py::test_ak7_the_agent_page_sections_open_and_read_in_both_schemes, console/src/components/directory/agent-sections.test.tsx ("the agent page's sections"), tests/test_console_api_agents.py::test_an_agent_the_reader_sees_but_does_not_administer_says_so, tests/test_browser_console_setup.py::test_the_listening_panel_links_the_first_request
AK8A recognised seed bundle, a rules bundle and a custom Cedar bundle on the agent page; recent activity with and without a target; a target label holding markupSeed and rules bundles show effect badges and sentences with ids linking to the bundle page or the rules form, with rules_origin saying which; the seed keeps its exact text under a closed "Exact policy documents"; custom Cedar keeps its summary and rules_origin null; each activity row has one link, to its Activity record, and names its target by provider identifier, rendered as texttests/test_console_api_agents.py::test_ak8_a_recognised_seed_reads_as_rules_and_keeps_its_exact_text, ::test_ak8_recent_rows_name_their_target, console/src/components/directory/agent-sections.test.tsx ("readable rules and linked activity")
AK9admin_member_factors called by an administrator, an approver, a deactivated administrator, another tenant's administrator, and with 501 ids; people with a legacy factor and no membership, an account factor through a membership, a stale enabled account_factors row beside a disabled user_factors row, and none; the function in a database owned by a role without superuser or BYPASSRLS; Users and the person pageOnly the active administrator of the tenant gets rows, one boolean each; the others raise INVALID_ACTOR; 501 raise INVALID_REQUEST; an agent or another tenant's id yields no row; the caller's account setting survives; the stale legacy row reads not enrolled; the account factor reads enrolled without bypass; GET /people and the detail carry second_factor, and Users and the person page say Enrolled or Nonetests/test_key_last_used.py::test_ak9_member_factors_answers_an_administrator_one_boolean_per_person, tests/test_member_factors_without_bypass.py::test_ak9_member_factors_reads_account_factors_without_bypass, tests/test_console_api_people.py::test_ak9_people_carry_their_second_factor_as_enforcement_reads_it, console/src/components/directory/people.test.tsx ("second-factor status and the history")
AK10My account for a person with an authenticator, two passkeys and seven recovery codes left; with none; on a deployment without account security; through a personal access tokenThe view's security states each figure and the card offers Manage; with none, Add a second factor; without account security, the not-configured sentence; a token reads the same security as its owner's session; no seed, digest or passkey id is in the answertests/test_console_api_settings.py::test_ak10_my_account_states_the_factor_its_passkeys_and_recovery_codes, console/src/components/settings/PersonalSettings.test.tsx ("the second-factor card")
AK11Home for an administrator without a factor, dismissed, reloaded; an approver; an administrator with a factor; a deployment without account security; storage that throwsThe card shows, then never again in that browser; absent for the others; with storage throwing it shows and dismisses for the page's lifetime without an error; Users, the person page, My account and Home are axe-clean in both schemes at 1280 and 390 pxtests/test_browser_console_agents_account.py::test_ak11_people_settings_and_home_show_second_factor_status, console/src/components/home/AccountNotices.test.tsx ("Home's second-factor card")
AK12The person page's History for an administrator with decisions and administrative events on a bundle, an agent, a person, a space and a credential; a narrowed administrator with a decision on an execution outside their spaces; a payload value that is not an identifierThree visible subheadings; each visible decision links to its Activity record by execution_id; the hidden one has a null execution_id and shows its prefix as text; bundle, agent and person subjects link to their pages by router-built links with the subject's kind and number; space and credential subjects stay text; a value that is not an identifier yields no subjecttests/test_console_api_people.py::test_ak12_a_decision_carries_its_approval_and_execution, ::test_ak12_a_decision_outside_a_narrowed_administrators_spaces_has_no_execution, ::test_ak12_administrative_events_name_their_subjects_by_kind, console/src/components/directory/people.test.tsx ("second-factor status and the history")

Working across workspaces (XW1 to XW12)​

An account that belongs to several workspaces sees, in its own list of them, what each makes of it and what entering it asks, and a count of its own waiting approvals in the others, never a record; a switch lands on the same page of the other workspace, through the second factor too, and never on a page its new session cannot open; a tab left behind says which workspace it showed and where the browser went, and keeps its section; the workspace menu is a keyboard listbox and the palette offers the same switch; and a request reference names its workspace for a person with several. Real PostgreSQL throughout; the client in Vitest; the pages in Chromium. The hosted review step's rows are in the hosted inventory.

IDSetup/actionRequired resultTest
XW1An account with three memberships (ADMIN in A, a viewer in B with an approver grant in one of B's spaces, an approver in C) lists its workspaces from AExactly the item fields. Kinds and roles are each workspace's own, and B's roles are ["viewer"]: the space-scoped grant is not a workspace role. A's item is current with no count. A workspace name holding markup is returned as the characters it istests/test_workspace_waiting.py::test_xw1_each_workspace_answers_its_own_kind_and_workspace_roles
XW2In C, approvals assigned to the account's principal directly and through a rule group, plus unassigned (assigned to someone else), expired, decided, other-space and permission-removed oneswaiting equals the pending queue's length read by a fresh session switched into C. next_lapse is the earliest assigned deadline floored to the minute, and null with nothing waitingtests/test_workspace_waiting.py::test_xw2_the_count_is_the_pending_queue_a_fresh_session_there_reads, ::test_xw2_a_principal_without_the_decide_permission_has_nothing_waiting, ::test_xw2_next_lapse_is_floored_and_never_overstates
XW3B requires directory sign-in; then C's policy requires a factor for all with the account holding no factor, then for admins with the account a member and then an ADMIN there, then the account enrols a factor, verified on this session longer ago than the step-up window and then within itentry is directory, then enrol while the account has no factor and factor once it has one, and open where none applies; with the factor verified within the window, open and counted wherever a switch would carry it (SN14), still directory where a directory is required. waiting_state is withheld with waiting and next_lapse null wherever entry is not open, and no count statement runs for that tenant (statement capture). The tenant setting is set back after each workspace's block, and an error inside one is the error raisedtests/test_workspace_waiting.py::test_xw3_entry_says_what_entering_asks_and_withholds_the_count, ::test_xw3_a_factor_turns_every_other_open_workspace_into_factor, ::test_xw3_a_recent_verification_opens_what_a_switch_would_carry_into, ::test_xw3_inside_sets_the_tenant_and_then_the_callers_back, ::test_xw3_an_error_inside_a_workspace_is_the_error_raised
XW4The list answered over HTTP with assignments waiting in another workspaceThe body holds none of that workspace's approval ids, execution ids, request numbers, target ids or names, agent ids or labels, or space names. A removed membership and an inactive tenant are absent. The workspace cookie alone is 401. A personal access token is refused. Every statement naming a membership's tenant ran under that tenant's setting, and every read of the setting before a workspace is entered saw the caller's (a statement listener records current_setting('execbound.tenant_id') beside each statement)tests/test_workspace_waiting.py::test_xw4_nothing_of_the_other_workspace_crosses, ::test_xw4_a_removed_membership_and_an_inactive_tenant_are_absent, ::test_xw4_a_personal_access_token_is_refused_the_list
XW530 memberships in 30 distinct tenants, and 120 assigned approvals in oneMemberships after the 25th answer not_counted. waiting is 100 for the one with 120tests/test_workspace_waiting.py::test_xw5_counting_stops_at_the_caps
XW6selectWorkspace with each section into an ADMIN destination, a viewer destination and an approver destination holding approvals.decide, with none, and with /ask, /policy/{id}, /activity?open=x, https://example.test/, //x, an empty string and an extra fieldEach section into ADMIN is answered as itself. For the viewer, sections it cannot open answer /, never /approvals. For the approver, sections it cannot open answer /approvals. With none, the session's start: / for the viewer and the administrator, /approvals for the approver. Every malformed value is 400 INVALID_BODY naming section, the extra field 400 INVALID_BODY naming that field, and nothing switches. Over every section, kind and permission set the answer is in the closed set and its rule holds; the server's roots and rules equal the console navigation'stests/test_workspace_sections.py::test_xw6_place_answers_the_section_exactly_when_its_rule_holds, ::test_xw6_a_viewer_starts_at_home_and_an_approver_on_approvals, ::test_xw6_place_refuses_to_answer_a_section_it_cannot_open, ::test_xw6_sections_and_rules_mirror_the_console_navigation, ::test_xw6_a_switch_answers_the_section_its_session_may_open, ::test_xw6_a_malformed_section_is_refused_and_nothing_switches, ::test_xw6_an_extra_field_is_refused_and_nothing_switches
XW7A switch into a workspace that asks for a factor, with section="/activity"; then the code; then a tampered, an expired and a duplicated return cookie; then GET /login?review=/agentsThe answer is /mfa with one signed cookie naming /activity, and after the code the person lands on /activity. A tampered or expired cookie lands where the session starts; a duplicated one is refused at the request boundary. remember_section still admits a section root alone. Since a sign-in link may name any core console page (SN1 to SN5), GET /login?review=/agents answers 200 with a hint naming /agents, and login_location("/activity") is /login?review=%2Factivitytests/test_workspace_sections.py::test_xw7_the_section_survives_the_second_factor, ::test_xw7_a_bad_return_cookie_lands_where_the_session_starts, ::test_xw7_a_sign_in_link_may_name_a_section_like_any_console_page, ::test_xw7_only_the_section_writer_is_held_to_sections
XW8Two tabs in Chromium on A at /policy/{id} and /board; the /board tab switches to B; then a sign-in again into A from a third tabThe left tab reads "This tab was showing A. This browser is now in B." and its link is /policy, never the id. After the sign-in again into A, which the server confirms, it reads "You signed in again" and its link reloads its own path; the tab that switched now names B and A. A stale request is still 409 WORKSPACE_CHANGED. Each page passes the audit at 1280 and 390 px in both schemestests/test_browser_workspaces.py::test_xw8_a_tab_left_behind_names_both_workspaces_and_keeps_its_section, console/src/lib/workspace-context.test.ts, console/src/lib/SessionProvider.workspace.test.tsx, console/src/lib/sections.test.ts, console/src/lib/client-config.test.ts
XW9The menu by keyboard and pointer, with 5 and 7 memberships, localStorage throwing, and a refused switchThe filter appears only with 7. Arrows, Enter, Escape (focus back on the trigger) and an outside press behave as designed. The order is current, then the workspaces the account entered most recently (SN10), then this browser's recent, then the rest, or without the local store when storage throws. Signing out and "Clear recent" clear the local store. Options are disabled while a switch is pending. A refusal shows the client's own sentencetests/test_browser_workspaces.py::test_xw9_the_menu_by_keyboard_and_pointer, console/src/shell/WorkspaceSwitcher.test.tsx, console/src/lib/workspaces.test.tsx, console/src/components/ui/palette-commands.test.tsx
XW10The palette with three memberships, a typed name, and a record search"Workspaces" lists the other two and the current one disabled. Selecting sends the same request with the current section, keeps the palette open with every workspace item disabled and "Opening {name}.", and the navigation happens even when the palette is closed before the answer. The records heading names the current workspaceconsole/src/shell/WorkspacePaletteGroup.test.tsx, console/src/components/ui/CommandPalette.test.tsx
XW11The execution drawer's reference with one membership and with two"EB-12" alone, then "EB-12 · {workspace}" as text. The approval detail names its workspace in its own eyebrowconsole/src/components/RequestRef.test.tsx, console/src/routes/-home.test.tsx
XW12The switcher open with a count, the chip with its dot, at 1280 and 390 px in light and darkNo axe-core violation, no policy or Trusted Types violation, no sideways scroll; at 390 px every option is at least 44 px tall and inside the viewport. The chip's accessible name is "Workspace {name}" with nothing waiting and gains the waiting phrase otherwisetests/test_browser_workspaces.py::test_xw12_the_switcher_shows_what_waits_elsewhere_and_passes_the_audit, tests/test_browser_workspaces.py::test_the_switcher_shows_the_whole_workspace_name

Sign-in, sessions and returning (SN1 to SN19, SN22)​

A person whose session ended, or who opens a link while signed out, signs in and is back on the page they were on, with its filters, through the second factor too; the signed hint that carries the place names only core's console pages in a closed grammar, and a hint it cannot use is ignored and clears an earlier one. The session view names the hard end no renewal passes and why, and the console warns two minutes before it, saying what is typed is kept only where it is. A new policy document is kept in the tab across a sign-in, for the same person, and only four files may import the draft store. A record and an agent have Copy link, and a record Copy reference. A switch within thirty minutes of a code carries that verification into the workspace it opens, for the same factor, and records where it came from for the account alone. Real PostgreSQL throughout; the client in Vitest; the pages in Chromium. Rows are listed as their tests land.

IDSetup/actionRequired resultTest
SN1Every entry of core_console_routes with fresh UUIDs, with and without approval links loaded, and both classic suffixes; then https://evil.example/, //evil.example, /approvals/../admin, /%2Fevil, /a\b, a fragment, a space, a control character, an uppercase UUID, a non-UUID parameter, a trailing slash, a 513-character input, a path not in the tree, a plugin console path, a value that is not a string, and the scoped approval with no approval links loaded; then the character checks alone, with every shape admittedEach core shape is its own canonical form; the scoped shape only where approval links are loaded; every other input is None. With the shapes replaced by one that admits anything, a second origin, a backslash, an encoded slash or backslash, a fragment, whitespace and a control character are still refusedtests/test_login_return.py::test_sn1_the_grammar_is_core_console_routes, ::test_sn1_the_character_checks_stand_without_the_shapes
SN2/activity with open, state, since, agent, target, action, outcome, cursor, q and from; unknown values; a duplicated key; seventeen fields; /approvals?view=others; /monitor?view=findings&state=acknowledged&open=<id>&focus=quiet&story=a:b and its setup and connect; /welcome?step=connect; /?range=7d&open=<id>; a free-text value on each page; a key on a page that keeps none; and the console's own enumerationsAllowed keys with valid values are kept in sorted order; cursor, q, from, story, setup, connect, invalid values and unknown keys are dropped; a duplicate or a seventeenth field refuses the target; the longest admitted target is at most 256 characters and holds no :. HOME_RANGES, APPROVAL_VIEWS (the array and the union), MONITOR_SEARCH_VIEWS, FINDING_STATES, the focus value and WELCOME_STEPS equal the console's constants, and Activity's states and windows equal the server'stests/test_login_return.py::test_sn2_only_known_keys_with_known_values_survive, ::test_sn2_the_enumerations_match_the_console
SN3A hint for /activity?open=<id>&state=DENIED written with extra keys out of order; then tampered, expired, duplicated, under an unknown key id and over 400 characters; a cookie signed as before this change for an approval path; a correctly signed value that is not its own canonical form; and the sign-in address for Home, an unusable address, a record and a Home rangeIt is stored canonical and read back; each damaged one falls back to the landing; the old cookie still returns its approval; the non-canonical value never returns. Home's bare address and an unusable one sign in plainly, the others carry the hinttests/test_login_return.py::test_sn3_a_hint_is_signed_short_lived_and_single, ::test_sn3_sign_in_carries_a_page_but_never_home_bare, tests/test_sign_in_surface.py::test_an_invalid_navigation_cookie_never_controls_the_login_destination
SN4Signed out, open /activity?open=<id>&state=DENIED&cursor=x; sign in by password; repeat through the Google stand-in303 to /login?review= the canonical target without cursor; both sign-ins land on /activity?open=<id>&state=DENIED and delete the hinttests/test_sign_in_surface.py::test_sn4_password_and_provider_sign_in_return_to_any_console_page
SN5GET /login?review= with each refused input from SN1; then the same with a valid review_return cookie already set200, the ordinary sign-in page, no new review_return cookie; the earlier cookie is deleted and the next sign-in lands on the landing pagetests/test_sign_in_surface.py::test_sn5_an_unusable_return_is_ignored_not_refused, ::test_sn5_an_unusable_return_deletes_an_earlier_one
SN6A session pending its factor opens /policy/<id>/rules; verifies a recovery code303 to /mfa with a hint naming the page; after the code, the page continues to /policy/<id>/rulestests/test_mfa_surface.py::test_sn6_the_second_step_returns_to_any_console_page
SN7A setup-credential session read every 60 s for 20 minutes on the injected clock, then a page load past the cadence; then left twelve hours and a minuteSigned in throughout, with new session and CSRF cookies of twelve hours at the reads seven and a half minutes after each extension (the eighth and sixteenth minutes) and on the page load; ended (401 SESSION_REQUIRED) after the idle gaptests/test_session_end.py::test_sn7_a_setup_credential_session_renews_while_it_is_read
SN8The session for a password account sign-in, the session a switch opens from it, a password sign-in through a reset code, a directory session, and a setup-credential session whose credential ends an hour after the idle limit read through the session view; then a renewalends_at is the sign-in credential's expiry, a moment short of two days after sign-in, with sign_in, for the account, password and directory sessions; the switched-to session ends at the account sign-in's two days with sign_in; the setup credential's expiry with setup_credential; a renewal moves expires_at and never ends_at or end_reasontests/test_session_end.py::test_sn8_the_view_names_the_hard_end_and_why, ::test_sn8_a_directory_session_ends_two_days_after_sign_in
SN90082_workspace_entry applied from its parent and rolled back, each anchor counted first; a password sign-in and a switch under an owner with the hosted owner's attributes (NOBYPASSRLS)Each anchor occurs once before the upgrade; only the two stamps change account_session_open and account_switch, both keep their grants, and the nullable timestamptz column appears, readable by the runtime and never writable; the downgrade restores both definitions byte for byte and drops the column. The sign-in stamps the membership it opens and leaves the other unstamped, and the switch stamps the destination's, each read back through that ownertests/test_workspace_entry_migration.py::test_sn9_only_the_fragments_change_and_the_downgrade_restores_them, ::test_sn9_an_owner_without_bypass_stamps_the_entry
SN10An account in A (older) and B, never having entered either; it signs in, switches to B, then signs in by password and through the Google stand-in; then B's membership is deactivated; then reactivated with B requiring its own directory; and the workspace list read from A after a switch to B and backThe first sign-in opens A, the oldest; both later sign-ins open B, entered last; then A; then A again. Each listed workspace carries its own membership's last_entered_at (A after B, a workspace never entered null), and the menu orders the current one first, then by when the account entered them, then this browser's recent ones, then the server's ordertests/test_workspace_switching.py::test_sn10_sign_in_opens_the_last_workspace_used, tests/test_workspace_waiting.py::test_sn10_the_workspace_list_carries_the_last_entry, console/src/lib/workspaces.test.tsx
SN11With approval links loaded, an account in A (entered last) and B: sign in by password and through the Google stand-in from /login?review= naming an approval in B; then a hint naming a workspace it does not belong to, its membership in B made inactive, and B requiring its own directory; then a session in A that opens B's addressThe hinted sign-ins open B, and an unhinted one after them opens B as the workspace entered last; the other three open A; the session in A gets the page and keeps A, with no new session cookietests/test_sign_in_surface.py::test_sn11_a_sign_in_opens_the_workspace_its_link_names
SN12A code accepted on one session; the same code from a second pending session five times within its window; the next step's code; then five wrong codes and a right one; the losing session of two racing one code; and the same used code on the verification pageEach repeat answers REUSED, records account_security.code_reused and no failure, and leaves the failure count at 0 and the factor unlocked; the next step's code verifies; five wrong codes still lock, and the lock refuses the right code and a used one alike; the race's loser is REUSED with nothing counted; the page says "That code was just used. Wait for the next code from your authenticator app, then enter it."tests/test_mfa_sessions.py::test_sn12_a_code_just_used_is_not_a_failure, ::test_totp_is_single_use_across_concurrent_sessions, tests/test_mfa_surface.py::test_sn12_the_page_says_a_code_was_just_used
SN13A switch into a workspace named <b>Team</b> whose policy asks for a factor, from an account with one; then a sign-in that asks for one; the switched challenge at 390 px in both schemesThe title, heading and intro read "Verify to open Team" as escaped text and never "Two-step verification" or "to finish signing in"; the sign-in keeps "Two-step verification" and "to finish signing in"; the switched challenge passes the page audit with the cursor in the code field and reads in both schemes at 1280 and 390 pxtests/test_mfa_surface.py::test_sn13_the_challenge_after_a_switch_names_the_workspace, tests/test_browser_accessibility.py::test_the_challenge_after_a_switch_passes_the_audit_in_both_schemes
SN14An account with an authenticator verified in A, the verification moved back through the admin engine (the clock stays inside the switch's five-minute fence) to 10 minutes, then switched to B; B's carried verification moved to 29 and 31 minutes; a verification at 31 minutes before a switch; one of a factor since replaced, called on account_switch directly because the session check refuses that session first; a factor removed at the same version; B asking every member for a factor of an account with none; the function's carry window; the workspace list at 10 and 31 minutes and with the factor removed; workspaces.carries asked directly before and after the factor is replaced or removedAt 10 minutes the switch asks nothing and B's session holds the source's own version, method and verification time; B's chain holds account_security.assurance_carried with exactly session_id, account_session_id, method and verified_at, and no identifier of A; the account's assurance_carried record names A, its session, B and the new session, and the security bell never lists it. B's step-up passes at 29 minutes and asks at 31. The older, replaced and removed factors, and the account with none, carry nothing and are asked (the last to set one up). The carry's interval equals mfa.STEP_UP_WINDOW. The list answers open with a count at 10 minutes, and the switch asks nothing; at 31 it answers factor, withheld, and the switch asks. With the factor removed the list answers enrol, withheld, and no count statement runs for B. carries answers true before either change and false after it, and the entry rule never answers open on a carry for an account with no enabled factor. The list's factor cases hold for a verification older than the window, and a recent one opens what the switch would carry into, never a workspace that requires its own directorytests/test_workspace_switching.py::test_sn14_assurance_carries_for_the_same_factor_within_the_window, ::test_sn14_the_window_never_restarts, ::test_sn14_an_older_or_changed_factor_still_asks, ::test_sn14_the_carry_window_is_the_step_up_window, ::test_sn14_entry_proof_matches_the_carry, ::test_sn14_carries_answers_for_the_factor_the_account_holds_now, tests/test_workspace_waiting.py::test_xw3_entry_says_what_entering_asks_and_withholds_the_count, ::test_xw3_a_factor_turns_every_other_open_workspace_into_factor, ::test_xw3_a_recent_verification_opens_what_a_switch_would_carry_into
SN15On real connections, a switch from a verified session in A to B, which asks every member for a factor, races the same session removing its factorBoth take the account lock first. The switch always goes through; the removal only when it committed first, since otherwise its session has been switched away. B's session carries a verification exactly when the factor was not removed, and only of the version current after both; requires_mfa and the switch's own answer agree that B asks exactly when nothing was carriedtests/test_workspace_switching.py::test_sn15_a_switch_and_a_factor_change_serialize
SN16The console client: a 401 on /activity?open=<id>&state=DENIED, an MFA_REQUIRED 401 on /agents/<id> and on /activity?state=DENIED, a workspace's approval with and without /classic, //other.example, a 600-character address, //login?review= the whole address; a reload of the address; the same hints, the client checking nothing itself; /login; /login; the draft store told to write what it holds before eachconsole/src/lib/client-config.test.ts
SN17A new policy document typed: written after 250 ms, at once when flushed, and by the client's flush event; its life thirty minutes from the last write on the server's clock; written two minutes before the session's hard end and restored after a sign-in that completes five minutes after that end; not restored to another person or 31 minutes after its last write; over 64 KB; storage throwing; removed on creation and on sign-out; restored into the open field and announced once; a keeping field marks its page; the lint fixtures importing the store, statically and lazily, from SecretDialog.tsx, from the hosted MintInvitation.tsx and from BundleList.tsx, and the configuration each file getsAs stated; the first two fixtures are lint errors and the third is not, and still refuses a hosted import; only the four keeping files and core's tests may import the storeconsole/src/lib/drafts.test.ts, console/src/lib/kept.test.tsx, console/src/components/policy/policy.test.tsx, console/src/approvals/drafts.test.tsx, console/scripts/bans.test.ts
SN18The notice at three minutes and at two minutes before ends_at, with each end_reason, with and without a keeping field, with storage refusing, on a device clock five minutes fast, and after a later ends_at arrives; Copy link and Copy reference with the clipboard granted and refused, in the drawer and on the agent pageNothing, then the copy and control for each case, at the server's two minutes ("kept" only with a keeping field and working storage; a setup credential's notice offers Help and no sign-in); gone once the end moves; the router's address on this origin exactly, never the address bar's, then the address as text to copyconsole/src/components/SessionEnding.test.tsx, console/src/components/CopyLink.test.tsx, console/src/components/directory/agent-keys.test.tsx
SN19In Chromium: signed out, open /activity?open=<id> and sign in; type a new policy document, end the session, press Create, sign in; bring a setup credential's end and a two-day end within two minutes; copy a record's link; each state in light and dark at 1280 and 390 pxThe drawer opens on the record and the clipboard holds the router's address; the document is restored and announced once; the setup-credential notice offers Help, whose page says how to keep signing in, and the two-day notice says typing is kept on the policy page and not on My account; axe finds nothing, no policy or Trusted Types violation, no sideways scroll, and the notices' controls are at least 44 px tall at 390 pxtests/test_browser_console_return.py::test_sn19_a_signed_out_record_link_opens_its_drawer_after_signing_in, ::test_sn19_a_new_policy_document_survives_the_session_ending, ::test_sn19_a_setup_credential_is_told_how_to_keep_signing_in, ::test_sn19_a_two_day_session_says_typing_is_kept_only_where_it_is, ::test_sn19_each_state_is_clean
SN220089_assurance_carry applied from its parent and rolled back, each of its four anchors counted first; a switch within the window under an owner with the hosted owner's attributes (NOBYPASSRLS); the account's record read as the runtime role under the account's own setting, another account's, and each workspace's alone; a row of another kind with a source column set, and a carry missing oneEach anchor occurs once; only the four fragments change account_switch, which keeps its grants; the four nullable uuid columns and the check user_security_events_carry appear, readable by the runtime and never writable; the downgrade restores the parent's definition byte for byte and drops both. The carried row, equal to the source's, and the account record naming both workspaces and sessions are written and read back through that owner. Only the account's own setting reads the record; the check refuses both other rowstests/test_assurance_carry_migration.py::test_sn22_only_the_fragments_change_and_the_downgrade_restores_them, ::test_sn22_an_owner_without_bypass_carries_and_records_the_source, ::test_sn22_only_the_account_reads_the_source

Monitoring connect (MC1 to MC23)​

An administrator connects Tines and Microsoft Entra from the console, collection and evaluation run on a schedule in every workspace, and a reporting source is added, rotated and revoked from the console, with honest copy wherever a deployment has not configured console connect.

IDSetup/actionRequired resultTest
MC1The schedule, request and lease columns' migration and the sealed keys' migration, each with its round trip and check_runtimeEvery new column and check exists and each check refuses its violation (a mode other than key_file, a half-set request or lease, an interval outside its kind's range); INTERRUPTED is an outcome; the runtime inserts only the columns that existed before (INSERT_COLUMNS) and updates none of the new ones, and check_runtime refuses a runtime with one insertable column too many, too few, or a table-level grant; the four functions are definers with a fixed search path that the runtime alone may call, and a claim holds a connection one to fifteen minutes; the request and schedule functions admit only an active administrator of an active workspace who administers the connection's space, and refuse an agent, the scheduler principal, a person who is not an administrator, a deactivated administrator, one narrowed to another space or seated only as a reviewer in the connection's space, and another workspace's administrator; the downgrade refuses while a connection records INTERRUPTED and otherwise restores every definition. A sealed connection holds both its ciphertext (48 to 8,192 bytes) and its collector key's id (ck1- and sixteen hex digits), any other neither, and only a Tines connection is sealed; the runtime inserts and updates neither; admin_create_sealed_connection applies the store's space, capacity and one-per-platform-per-space rules under its registry lock, admin_replace_sealed_key touches only an active sealed connection and collector_reseal only one sealed under the key it names and still holding the ciphertext it names; that downgrade refuses while a connection is sealed and otherwise round-trips. The consent migration admits platform_app only for Microsoft Entra, with no key fingerprint (every other connection keeps one) and always a consent, a moment and a person together, which no other connection records; monitor_connect_attempts forces the tenant fence in its initplan form, the runtime only reads it, each of its checks refuses its violation (the states, a directory exactly from sign-in on, a refusal's code and step, ten minutes, a label or a connection) and its state digest is unique across the deployment; monitor_directory_claims has no tenant column and the runtime no privilege on it, of any kind or column, which check_runtime refuses (PRIVILEGELESS_TABLES), and its one writer is a definer trigger check_runtime holds by name (TRIGGER_DEFINERS), which keeps it equal to the active Entra connections whoever writes them; one active Entra connection per directory across every tenant, the directory's case folded, and an operator registering one another workspace holds is refused DIRECTORY_UNAVAILABLE; the upgrade refuses, naming only a count, while two share one, and backfills the claims, run as an owner without BYPASSRLS; the attempt's principal and the consenter are guarded against the scheduler principal; admin_start_connect refuses a full workspace, an occupied space, a sixth live attempt and a twenty-first in a day, and an update for a connection that is not an active consented one; admin_record_signin and admin_complete_consent check the attempt's state digest, binding, nonce, expiry and order, the principal still administering its space and the directory claimed nowhere (or the update's own), and admin_refuse_connect ends only a live attempt for the holder of its state; that downgrade refuses while a connection is consented or any attempt exists and otherwise restores the fingerprint's NOT NULL. The creator migration gives every reporting source the administrator who minted it, null on a source made before it, held to a principal of the source's own tenant, written with the row and never updated by the runtime; its downgrade drops it and keeps every sourcetests/test_monitor_connect_schema.py
MC2Paste a Tines key from the console, and post a sentinel in every field of each new bodyA sealed row in the session's Space whose fingerprint matches, asked for its first collection; the collector's key opens it to the key; the gateway, built with the collector's public key, holds nothing that opens it and everything its configuration yields fails to, and nothing it loads imports the collector's half; the key is absent from every answer, the snapshot, every table but sealed_ct, the audit chain and the captured logs; a malformed body is INVALID_BODY by field location and echoes nothing; a secret-shaped label or team id, a second connection in the Space, a full workspace, no Space chosen and an archived Space are each refused with nothing written; the form adds no connection in a Space the administrator only reviews, an archived one or none chosen, saying why on its first step and going no further, so neither the key nor any factor is asked for, or, where a re-read once the session has moved finds such a Space only after the key is asked, saying so there and sending nothing, and words the server's FORBIDDEN as that Space being one they review; once the session has moved to another Space since the form's placement was read, it reads it again and connects nothing until it answerstests/test_monitor_sealing.py (the test_mc2_ cases), tests/test_surface_configuration.py (the test_mc2_ cases), tests/test_monitor_connect_store.py (the test_mc2_ cases), tests/test_console_api_monitoring_connect.py (the test_mc2_ cases), console/src/components/monitor/ConnectTines.test.tsx
MC3The collector opens sealed rowsIts own row opens with its own key; a ciphertext copied to another connection, tenant or kind is refused SEALED_KEY_MISMATCH; an unknown key id, no collector key, or a damaged ciphertext COLLECTOR_KEY_UNAVAILABLE; a re-sealed key that is not the registered one KEY_MISMATCH; each refusal is recorded on the connection and nothing reaches the fake platform; a key replaced after the pass read its due connections and before it claimed one is the key that run sends, and nothing else reaches the fake platform; collect-due --collector-key collects a sealed row, and a key file that is not one stops the run; boot writes the collector's key owner-only and refuses a malformed one, a repeated member name among them, without printing it; the jobs service reads it from a directory only its container mounts. A consented Microsoft Entra connection is read with the platform app: its file holds exactly a client id, a certificate and that certificate's RSA key (at least 2,048 bits), is checked whole and never printed; it authenticates with an RS256 client assertion naming the certificate by its SHA-256 thumbprint, for the directory's token endpoint, living five minutes with a fresh jti, which the fake token endpoint takes and refuses from another key, for another audience, expired or for another client; collect-due --platform-app collects a due consented connection, and records CLIENT_MISMATCH for one consented to another app's client id and COLLECTOR_KEY_UNAVAILABLE with no app, each with no request at all, the run itself checking the client id too; a file that is not one stops the run, and a path that names no file is none yet; the scout.entra block names the app's client id, an organizations or single-directory authority and a plain display name, is refused naming the field and never the value, and only beside scout.collector; boot writes the app's file owner-only and the jobs service reads it from the collector's directory alonetests/test_monitor_sealing.py (the test_mc3_ cases), tests/test_boot.py (the test_mc3_ cases), tests/test_jobs_schedule.py::test_mc3_the_collectors_key_is_read_from_its_own_directory_and_named_on_the_command, tests/test_jobs_schedule.py::test_mc3_the_platform_apps_credential_is_read_from_the_collectors_directory, tests/test_monitor_platform_app.py, tests/test_monitor_collect_due.py (the test_mc3_ cases), tests/test_surface_configuration.py (the test_mc3_ cases)
MC4collector-reseal to a new key, a key replaced while it runs, the collector during a rotation, and collector-keygenEvery sealed row, a revoked one included, opens with the new key and keeps its fingerprint; the old key opens nothing written after; a row under neither key is left alone and counted; a second pass finds nothing left; a key an administrator replaces after the re-seal read its row is kept, counted failed and moved by the next pass, never overwritten with the key it replaced; collect-due given --collector-key twice collects connections sealed to either key, and a path that names no file is no key; two different keys under one key id are refused; boot writes the key being retired owner-only beside the current one and the jobs service names both; keygen writes two owner-only files whose key id is the public key's digest, refuses an existing output and prints the key id alonetests/test_monitor_sealing.py (the test_mc4_ cases and test_mc2_keygen_writes_an_owner_only_pair_whose_id_is_derived), tests/test_boot.py (the test_mc4_ case), tests/test_jobs_schedule.py::test_mc3_the_collectors_key_is_read_from_its_own_directory_and_named_on_the_command
MC5When a connection is due, at each interval's edge, for both kinds and every credential mode; a request; a rate-limited run; the snapshotDue one interval after its last run of any outcome (Tines's audit interval, Entra's collection interval, null meaning the kind's default), from its registration if it never ran, at once when asked, not before a rate-limited run's Retry-After even when asked, and not while a run holds it; a request made after a claim survives that run; the Connections view's schedule and next due time come from the same rule, and the lease's id never leaves the database. A connection the scheduled collector opens itself is overdue at twice its own interval or a day, whichever is shorter, from its last run of any outcome (a sealed Tines connection at 30 minutes by default), a key_file one at a day, and OVERDUE_CONNECTIONS agrees with the rule one second before, at and after each edgetests/test_monitor_lease.py (the test_mc5_ cases), tests/test_console_api_monitoring.py::test_mc5_the_connection_carries_its_schedule_and_never_its_lease, tests/test_console_api_monitoring.py::test_mc5_an_entra_connection_carries_its_own_default_and_no_activity_interval, console/src/components/monitor/Connections.test.tsx
MC6Two claims on one connection from two database connections; a stale lease; a revocation mid-run; an expired lease; the scheduled actorExactly one claim holds the lease; a claim outside one to fifteen minutes is refused; an expired lease is recorded INTERRUPTED and the next claim takes it; every write with a lease the connection no longer carries raises LEASE_LOST, and on a revoked connection CONNECTION_REVOKED, changing nothing; revoking clears the lease; the scheduled actor collects inside its lease against the fake platform and is refused without a lease, under another workspace's fence and in a deactivated workspacetests/test_monitor_lease.py (the test_mc6_ cases)
MC7collect-due --all-tenants over three workspaces, one deactivated; a missing or wrong key file; the per-workspace cap and the budget; an operator's runEach active workspace's due connection is collected on its default intervals and its lease returned, the deactivated one is counted and never visited, and the exit is 0; a connection without its key file is counted no_key_file with nothing requested or recorded, and a malformed or wrong key file is recorded KEY_FILE_INVALID or KEY_MISMATCH without a request; the cap defers the rest to the next pass and the budget stops starting connections, and a delta pass starts only within the cap and budget the due collections left; --tenant with --credential-file runs as that ADMIN and refuses any other token; collect-tines and collect-entra refuse while another run holds the lease; a consented directory is collected with the platform app; no output, log line or report carries a key, and the log line counts the Entra delta passes that completed and those that failed beside what was collected; the jobs service schedules it on every installation, since the synthetic directory needs no key, and names on its command only the key files directory and the collector's keys and the platform app's credential this host holds, and boot writes the key files owner-onlytests/test_monitor_collect_due.py, tests/test_jobs_schedule.py::test_mc7_collection_is_scheduled_everywhere_and_names_only_what_this_host_holds, tests/test_jobs_schedule.py::test_the_jobs_command_schedules_the_drain_from_the_configuration_it_runs_with, tests/test_boot.py::test_mc7_writes_the_collectors_key_files_owner_only_and_scrubs_them, tests/test_boot.py::test_mc7_refuses_malformed_key_files_without_writing_or_printing_them
MC8Connect Microsoft Entra by consent against the fake Microsoft sign-in, and every refusal the binding makesThe start answers Microsoft's sign-in address on its pinned origin with exactly its parameters and sets the binding cookie HttpOnly, Secure, SameSite=None, path /, for ten minutes, with no-store; each refusal ends the attempt as refused with its code and the step that refused it, creates no connection and no event, logs monitor.connect_refused with the code alone, ends the cookie and lands on the Connections view: at the sign-in, another directory's or a non-Microsoft issuer, no administrator role, a reader's role only, no wids, another key, alg: none, HS256, another audience, another nonce, expired, not yet valid, issued in the future, no cookie, another attempt's cookie, Microsoft's own error, another origin or none, an attempt older than ten minutes and a repeated key, each without an admin consent address issued; at the consent, a long or missing scope, a repeated state or tenant, a tenant that differs, admin_consent not True, Microsoft's error (its error_uri and error_subcode ignored), no cookie and an expired attempt; a consent for an attempt that never signed in is out of order; a used state completes nothing and the attempt keeps how it ended; a state rewritten to name another workspace finds no attempt; a single-directory registration takes its own directory only; email, preferred_username, upn and name change nothing and no principal is looked up; a full workspace and an occupied space are refused at the start, before Microsoft, as are a sixth live attempt and a twenty-first in a day, and the console starts no consent for a new connection in a Space the administrator only reviews, saying why before any factor is asked, and, once the session has moved to another Space since the form's placement was read, reads it again and starts none until it answers; no state, nonce, binding, id_token or display name reaches a table, an event or a log linetests/test_monitor_consent.py (the test_mc8_ cases), console/src/components/monitor/ConnectEntra.test.tsx
MC9A directory already connected in another workspace, before the sign-in and between the sign-in and the consentRefused at the sign-in, with no admin consent address issued, and refused again at completion if it became connected in between; neither the page, the logs nor the attempt's row names the other workspace or its connectiontests/test_monitor_consent.py (the test_mc9_ cases)
MC10A successful consent, one with a parameter Microsoft adds later, and an administrator deactivated during an attemptMicrosoft's documented success redirect, scope included, creates one platform_app connection in the attempt's Space, created and consented by the attempt's principal, a collection asked for, and appends monitor.connection_created and monitor.consent_recorded; an unknown parameter is neither stored nor logged; an administrator deactivated after signing in creates nothing and is refused at the consent, and one deactivated before signing in is refused at the sign-intests/test_monitor_consent.py (the test_mc10_ cases)
MC11A permission refused after consent; Update consent; the return from MicrosoftThe connection reads "Consent needs updating" once a capability it had is refused after its last consent; a later consent hides it until the first probe after that consent, which shows it again while the capability is still refused and not once it is granted; Update consent records the new consent on the same connection and appends monitor.consent_recorded, and an update from another directory is refused at the sign-in; the page Microsoft returns the browser to says what the server recorded of the reader's own latest attempt, the connection made and its verification opened, or the sentence for a refusal before or after consent, says nothing for a return with no record, and takes the return out of the addresstests/test_monitor_consent.py (the test_mc11_ cases), tests/test_console_api_monitoring_connect.py (the test_mc11_ cases), console/src/components/monitor/Connections.test.tsx ("connecting Microsoft Entra and the return from Microsoft"), console/src/components/monitor/ConnectionActions.test.tsx ("a consented Microsoft Entra connection"), console/src/components/monitor/search.test.ts
MC12Each connection change from the console and from the operator's commandsCreating, replacing a key, asking for a collection, changing a schedule and revoking each append one informational event naming the connection and the credential that acted, with the connection's Space on the row and no key, ciphertext or fingerprint; a second request appends nothing; revocation keeps every row and clears a run's lease; create-connection and revoke-connection append the same events; a connection outside the session's Spaces does not exist for it and a revoked one takes no change; an administrator deactivated during a change leaves nothing; a tenant that never executed gains only its audit head; replay treats every kind as informational; the card names its credential, Collect now shows the server's answer, Schedule offers each kind's fixed choices in every mode, Revoke asks first and Replace key is a sealed Tines connection's alone; revoking a consented Microsoft Entra connection names the deployment's app and its client id and links Microsoft Entra's enterprise applications, because only the directory withdraws its consenttests/test_monitor_connect_store.py (the test_mc12_ cases), tests/test_console_api_monitoring_connect.py (the test_mc12_ cases), tests/test_replay_informational_kinds.py::test_monitoring_connection_changes_leave_every_later_decision_replayable, console/src/components/monitor/ConnectionActions.test.tsx
MC13Every connection route's authorityAn administrator's only: an approver 403; an agent credential refused and audited; no session 401; a missing CSRF token or another Origin 403; the step-up exactly on connecting Tines, replacing a key and revoking, with each purpose named; a personal access token refused exactly there and allowed to read the options, ask and schedule; without the collector's key in the configuration the options say unconfigured and connecting answers CONNECT_UNAVAILABLE; the same routes are served either way. Starting a Microsoft Entra consent is the same: an administrator's, behind the step-up with its purpose named "Connect Microsoft Entra", refused to a token, CONNECT_UNAVAILABLE without scout.entra; its answer carries one secret, the state; the options name the app, its client id and the reader's own latest attempt within ten minutes, never another person's and never a code; the two browser routes exist only where scout.entra is configured and answer 404 elsewhere. The reporting source routes are the same: an administrator's, an approver 403, an agent credential refused and audited, no session 401, a missing CSRF token or another Origin 403; minting, rotating and revoking ask for the step-up with each purpose named ("Create a reporting source", "Rotate a reporting source's token", "Revoke a reporting source") and refuse a personal access token, which may read a sourcetests/test_console_api_monitoring_connect.py (the test_mc13_ cases), tests/test_console_api_monitoring_sources.py (the test_mc13_ cases), tests/test_route_authority.py::test_a_scout_block_serves_exactly_the_same_routes, tests/test_console_step_up_purposes.py, tests/test_monitor_consent.py::test_mc13_the_browser_routes_exist_only_where_entra_is_configured
MC14Mint a reporting source from the console, and from the store and the command lineThe token comes back once, in a 201 with Cache-Control: no-store that the route sets itself, and no snapshot, source read or other answer carries it; it reports for its own story and is refused for another; the source records the administrator who minted it and lands in the session's Space, and the form names that Space as the server will place it, the one Space an administrator narrowed to it writes in included, refusing an archived one before anything is sent, and once the session has moved to another Space since that was read, reads it again and adds nothing until it answers; the store refuses a token living beyond thirty days for any caller, an archived Space, a Space that is not the tenant's and one its creator does not administer, and a label or story ID shaped like a secret, each with nothing written; the console offers 1, 7 or 30 days, 30 the default, and refuses any other lifetime, any heartbeat but 5, 15 or 60 minutes (a source registered every minute before keeps that interval, read, rotated and reported through as before), a story that already has an unrevoked source in the Space that can still take its events (SOURCE_EXISTS, for every caller, and once when two administrators mint it at the same moment, the console saying to rotate that source and never to revoke it; one that has kept its 10,000 events, which rotation does not reset, refuses no new source, one event short of them it still does, and a full workspace refuses that new source with the full one left as it was and still taking heartbeats), a full workspace (SOURCE_CAPACITY), no Space chosen and an archived Space, naming a malformed field and echoing nothing; the intake address comes from the configured origin, never the request's, even for a request served on another scheme than the configured one and carrying forged forwarding headers; the command line keeps 1 to 24 hours and records its creator; minting appends nothing to the audit chain; a mint or rotation whose answer did not arrive says it may have happened, never that nothing changed, and reads the sources again; the token dialog shows the token once in its field with the recipe below it, says it authorizes intake only, closes on its own button only (never on Escape or a press outside it) and leaves the token in no cache, storage or documenttests/test_console_api_monitoring_sources.py (the test_mc14_ cases), tests/test_monitoring_lifecycle.py (the test_mc14_ cases), console/src/components/monitor/AddSource.test.tsx, console/src/components/monitor/SourceActions.test.tsx (a rotation whose answer did not arrive), console/src/components/monitor/SourceTokenDialog.test.tsx
MC15Rotate and revoke a source from the consoleThe previous token reports for the grace chosen and not a second after, and at once stops with no grace; the rotating administrator is recorded; revocation refuses every token the source ever had at once, records who revoked it, and a revoked source can be neither rotated nor revoked again (CONFLICT); a source outside the session's Spaces, another workspace's, an unknown one and a malformed identifier are each 404; an administrator narrowed to other Spaces neither rotates nor revokes one, and each source, in the snapshot and its own read, says whether this administrator may change it, so the console offers no change to a source in a Space they only review and adds none there, saying why before any factor is asked, while the connect options name the session's Space, by its id and name, and whether it is administered; a source that has kept its 10,000 events says that rotating its token does not reset that count, that it still takes its story's heartbeats, and that the story is added again first and the source revoked once the story reports through the new token, never before, at the store's own limit, which intake enforces with nothing patched, and the console's lifetimes, heartbeats and graces are the ones the routes admit; the console's rotation shows the new token once, and its dialogs say that a source keeps one previous token, so rotating again inside a grace stops the earlier token at once; its revocation asks first, its answer is read in the transaction that revoked, so a read that fails afterwards cannot answer an error for a revocation that took effect, and a revocation whose answer did not arrive says it may have happenedtests/test_console_api_monitoring_sources.py (the test_mc15_ cases), tests/test_monitoring_lifecycle.py::test_mc15_an_administrator_narrowed_to_other_spaces_neither_rotates_nor_revokes, console/src/components/monitor/SourceActions.test.tsx, console/src/components/monitor/AddSource.test.tsx (a Space this administrator only reviews), console/src/components/monitor/SourceTokenDialog.test.tsx
MC16The card waiting for a new source's first heartbeatIt reads the source every ten seconds while the page is visible and never while it is hidden, stops after ten minutes and says to reload only from a read made once they are up (one more when they end, or on the reader's return when they ended while the page was hidden), each new source waiting its own ten minutes, which start when its own token dialog closes, after its mint, and a heartbeat the page's own snapshot of the source shows counts, on Connections and Inventory alike and after the card's ten minutes too; no heartbeat the console offers lets the health pass call a new source silent, or raise its never-reported finding, within ten minutes of its mint; once the health pass has called the source silent, which it does twice the heartbeat interval after the mint and so possibly while the card, whose ten minutes began later, still reads, the card says no heartbeat came and what to check rather than waiting beside it, and goes on reading for the rest of its ten minutes, so a first heartbeat after that verdict still flips it; a source revoked meanwhile, or no longer in a Space the reader sees, ends the wait with a sentence saying so, and a failed read says so and keeps trying within the ten minutes, while a last read that fails once they are up says the card has stopped checking on its own and to reload; for a source that expects its heartbeat every 15 or 60 minutes, whose first can be due after the ten minutes, the line once they are up says so, when the source would be marked stale and to reload later, never what to check unless the health pass has already called it silent; once stopped, it reads the source again each time the reader comes back to the page; on the first heartbeat it says the source is reporting with a link to its activity, in Chromium after a heartbeat the story posts with its tokenconsole/src/components/monitor/SourceWaiting.test.tsx, console/src/components/monitor/Connections.test.tsx, console/src/components/monitor/Inventory.test.tsx, tests/test_console_api_monitoring_sources.py::test_mc16_no_offered_heartbeat_calls_a_new_source_silent_within_ten_minutes_of_its_mint, tests/test_browser_monitoring_connect.py::test_mc16_mc17_add_a_reporting_source_and_see_its_first_heartbeat
MC17Connect Tines in Chromium against the fake Tines APIConnect Tines end to end; a scheduled pass collects with the collector's key and the verification reaches "Reporting"; the Connect Tines form, the card, the Schedule dialog and the Revoke dialog are axe-clean with no CSP violation and no sideways scroll in light and dark at 1280 and 390 px, the actions wrapping at 390; a schedule saved and the connection revoked show the server's answers; the key never reaches the page; the /monitor route chunk stays inside its 60 KB budget with each dialog in a chunk of its own. Connect Microsoft Entra in Chromium: the dialog is axe-clean in both schemes at both widths; Continue to Microsoft leaves for Microsoft's sign-in and nowhere else, with the binding cookie HttpOnly, Secure and SameSite=None; the fake Microsoft completes both callbacks with that browser's cookie; the return says the server's record, opens verification and leaves the address; the consented card and its Revoke dialog are axe-clean in both schemes at both widths; the state never reaches the page. Add a reporting source, the token dialog (its field scrolling inside itself at 390 px), the waiting card and each source's Rotate and Revoke dialogs are axe-clean in both schemes at both widths, and the token never reaches the page once its dialog closestests/test_browser_monitoring_connect.py::test_mc17_connect_tines_collect_and_verify_reporting, tests/test_browser_monitoring_connect.py::test_mc17_connect_microsoft_entra_to_microsofts_sign_in_and_back, tests/test_browser_monitoring_connect.py::test_mc16_mc17_add_a_reporting_source_and_see_its_first_heartbeat, console/src/components/monitor/Connections.test.tsx ("connecting from the console where it is configured")
MC18Monitoring with no connection, in an edition that offers operator commands and in one that does not, with an operator and a support address configured, with only one of them, and with neitherWith operator commands, the Connections empty state and the setup dialog's four operator steps are unchanged. Without them, both name who connects a provider: " connects this provider for this workspace for now. Email with the connection name and the Space it belongs in. Never send an API key, client secret or token by email.", beginning "Your service operator" where no operator is configured, and ending the first sentence after "for now." with no link where no address is; the dialog goes from the provider to Verify and shows no host step, no DATABASE_URL, no local-data and no command. Both are axe-clean with no CSP violation in light and dark at 1280 and 390 pxtests/test_browser_monitoring_connect.py::test_mc18_with_operator_commands_the_console_keeps_the_operator_steps, console/src/components/monitor/MonitorSetup.test.tsx ("where the edition offers no operator commands"), console/src/components/monitor/Connections.test.tsx, and the hosted edition's own, in its build in Chromium
MC19Report this story from InventoryWhere this deployment mints sources, a discovered story with an open coverage gap and no unrevoked source, a revoked one's story included, offers "Report this story", which opens Add a reporting source with the story's ID filled from the page's state, and says reporting shows what the story does and does not govern or block it; a story with no gap offers nothing, and neither does a story where the session's Space is one this administrator only reviews, nor any story while where a source lands is read again once the session has moved to another Space; once the source is minted, its row names it as able to report beside a gap that stays open until the next inventory pass, or, where the story's connection was revoked, beside a gap no inventory pass reassesses, and never says to rotate or revoke it; a story whose named source's token has expired says it is not reported now and where its token is renewed (Connections where this deployment mints, rotate-source where its readers run operator commands, and its Space's administrators to one who only reviews that Space), and one whose source is in a Space the reader does not see names it by its identifier alone, says nothing about its token and offers nothing; the operator's command stays behind its own disclosure; axe-clean in both schemes at both widthsconsole/src/components/monitor/Inventory.test.tsx, tests/test_browser_monitoring_connect.py::test_mc19_report_a_story_with_an_open_gap_from_inventory
MC20The secret sweep for a pasted key and a consentNo key in any table but sealed_ct, log line, page, answer, audit payload or browser record after a paste, a refusal or a close; the collector's private key and the platform app's credential only in the collector's environment: a secret no other service receives on the hosted service and the jobs container's own mount on a Community installation. No consent state, nonce, binding value, id_token or app display name in a table (only their digests), an event or a log line, and none in the browser once the start's answer is read; mc1. is a secret shape the log guard and the export check refuse. No reporting source token in any answer but the two that mint one, in any table (only its SHA-256), log line or audit payload, and none in the browser once its dialog closes; the log lines swept for it are every logger's at every level and ExecBound's own as a deployment writes them, field values included, which pytest's own capture does not seetests/test_monitor_connect_store.py::test_mc2_the_key_is_in_no_table_log_or_event_but_its_ciphertext, tests/test_console_api_monitoring_connect.py::test_mc2_a_pasted_key_is_sealed_and_appears_nowhere_else, tests/test_community_bundle.py::test_the_collectors_key_is_mounted_into_the_jobs_container_alone, tests/test_monitor_consent.py::test_mc10_a_consent_creates_one_connection_from_a_verified_administrator, tests/test_secrets.py, console/src/components/monitor/ConnectEntra.test.tsx, tests/test_console_api_monitoring_sources.py::test_mc14_a_minted_token_is_shown_once_and_reports_for_its_story_only, tests/test_console_api_monitoring_sources.py::test_mc20_no_source_token_is_in_a_table_a_log_line_or_an_audit_payload, console/src/components/monitor/SourceTokenDialog.test.tsx, and the hosted service's own tests
MC21process --all-tenants over two workspaces, each with a quiet heartbeat source, a reported consequential action and a collected agent's tool run pending, and a third deactivated; the same pass misfenced; another mode beside itOne pass evaluates every pending observation in both into findings, raises each quiet source and derives each observed reach; the deactivated workspace is counted and not visited, and one deactivated after the walk checked it is its own refused line; the exit is 0, no delivery is attempted without --deliver (FD13 is the pass with it), no audit event is appended and no scheduler principal is made; under another workspace's fence every step refuses; --config, --deliver-local or a limit outside 1 to 50 beside --all-tenants, and --deliver beside --deliver-local, is refused before anything runstests/test_monitor_process_all.py
MC22Reporting sources where the deployment has not configured console connectThe options say sources: unconfigured; minting and rotation answer CONNECT_UNAVAILABLE and change nothing; reading a source and revoking one made earlier still work; the console offers no Add a reporting source, no Rotate token and no Report this story, and still offers Revoke, in Chromium in the core buildtests/test_console_api_monitoring_sources.py (the test_mc22_ cases), console/src/components/monitor/SourceActions.test.tsx, console/src/components/monitor/Inventory.test.tsx, console/src/components/monitor/Connections.test.tsx ("reporting sources from the console"), tests/test_browser_monitoring_connect.py::test_mc22_without_console_connect_nothing_is_minted_and_a_source_is_still_revoked
MC23Getting started and Home in an edition whose readers run no operator commandsThe start-by-watching line appears only once the deployment says a provider can be connected from the console, linking Tines where it can and Microsoft Entra where only it can; the Discover card's link follows the same rule and keeps its sentence naming the service operator until then; nothing is read to decide it, and nothing changes, where the edition offers operator commandsconsole/src/components/welcome/WatchFirst.test.tsx, and the hosted edition's own, in its build in Chromium

Tests live in tests/test_monitor_connect_schema.py (MC1), tests/test_monitor_lease.py (MC5, MC6), tests/test_monitor_collect_due.py (MC7), tests/test_monitor_consent.py (MC8 to MC11), tests/test_console_api_monitoring_sources.py (MC13 to MC15, MC22), tests/test_monitor_process_all.py (MC21), tests/test_browser_monitoring_connect.py (MC16 to MC19 and MC22 in the core build) and in the other tests named in the rows; the hosted build's halves of MC18 and MC23 are the hosted service's own tests.

Microsoft sign-in (MI1 to MI6)​

A deployment may offer Microsoft work accounts beside Google and GitHub, through the multi-tenant organizations authority. The ID token is verified here against Microsoft's pinned key set, the issuer must be the token's own tenant's, personal accounts are refused, the subject is the tenant and object identifiers together, and the address is believed only when Microsoft says the account's tenant verified it. The hosted rows (MI7 to MI9) are documented with the hosted service. Real PostgreSQL throughout; the page in Chromium.

IDSetup/actionRequired resultTest
MI1A valid Microsoft ID token from the key-set stand-in; then each defect: alg none, HS256, RS512 and ES256, an unknown kid after one fetch, a bad signature, ver 1.0 or absent, tid missing, uppercase, not a UUID or the personal-account tenant, iss of another tenant, a placeholder or the v1 form, aud another client or a list, azp, exp past or not a number, iat skew, nbf an hour ahead or not a number, nonce wrong, absent or a lone surrogate, oid missing, uppercase or not a UUID, xms_edov absent, false, "true" or 1, email absent, empty, 255 characters or a listThe valid token yields subject <tid>:<oid> and the address, never sub or preferred_username; each defect its own code, before any address is read; a bad signature is refused before any claim, and another algorithm before any key is fetchedtests/test_microsoft_sign_in.py::test_mi1_the_token_is_verified_claim_by_claim, ::test_mi1_each_wrong_claim_is_its_own_refusal, ::test_mi1_an_address_of_the_maximum_length_is_read, ::test_mi1_a_not_before_within_the_skew_is_accepted, ::test_mi1_another_algorithm_is_refused_before_any_key_is_fetched, ::test_mi1_a_bad_signature_is_refused_before_any_claim_is_read, ::test_mi1_an_unknown_key_refetches_once_and_then_refuses, ::test_mi1_a_token_that_is_not_one_is_refused
MI2Configuration with and without sign_in.microsoft, alone and beside Google and GitHub; a redirect URI on Google's callback, on another origin or without /callback; the authorization address begin builds and the exchange complete makesThe provider exists only with its block and comes after Google and GitHub; each wrong URI refuses start; the address carries the organizations authority, openid email, S256, state, nonce and select_account and nothing else; the exchange posts the verifier, the secret and the scope to the pinned token endpoint and keeps only the ID token, held to the flow's nonce; without the block /login/microsoft answers 404 and form-action does not name login.microsoftonline.com, with it it doestests/test_microsoft_sign_in.py::test_mi2_the_provider_is_pinned_and_present_only_when_configured, ::test_mi2_a_token_from_the_exchange_is_held_to_the_flows_nonce, ::test_mi2_an_exchange_that_answers_anything_else_is_refused, ::test_mi2_each_provider_fetches_only_its_own_key_set, ::test_mi2_the_block_builds_the_provider_after_google_and_github, ::test_mi2_a_redirect_uri_that_is_not_this_deployments_callback_refuses_start, ::test_mi2_the_route_and_the_form_action_exist_only_with_the_block
MI3Through the provider stand-in: an unbound subject whose address matches an account; a link from Account security; the bound subject from an empty browser; the same object identifier under another tenant; a link from a sign-in older than five minutes, to an address that is not the account's, and from a session that has not verified its enabled factor; an account whose only workspace requires its directoryRefused with nothing created; linked; signs in and records human_sign_in.microsoft; refused as a different subject; each link refused until the factor is verified; refused for that workspacetests/test_sign_in_surface.py::test_mi3_microsoft_signs_in_and_links_by_subject_only, ::test_mi3_a_microsoft_link_needs_a_recent_sign_in_the_factor_and_the_same_address, ::test_mi3_a_workspace_that_requires_its_directory_is_never_opened_by_microsoft
MI40091_microsoft_sign_in from its parent and back, with the downgrade run from a fresh load of the module; a downgrade with one Microsoft binding present; both again under an owner with the hosted owner's attributes (NOBYPASSRLS)The five checks and two functions change only by 'microsoft', keep their names, owner, SECURITY DEFINER and grants, and forced row security is untouched; a microsoft binding inserts and an unknown provider does not; the downgrade restores every definition byte for byte; with the row present it refuses MICROSOFT_ROWS_PRESENT and leaves the revision and forced row security as they were, under either ownertests/test_microsoft_migration.py::test_mi4_only_the_lists_widen_and_the_downgrade_restores_them, ::test_mi4_a_downgrade_with_microsoft_rows_refuses, ::test_mi4_an_owner_without_bypass_widens_restores_and_refuses
MI5An owner links Microsoft and signs in with it, then the tenant's history is exported and verifiedhuman_sign_in.microsoft is written with the subject withheld as every provider's is, and is informational; the export verifies with no unknown semanticstests/test_microsoft_sign_in.py::test_mi5_a_microsoft_sign_in_replays
MI6/login with Google, GitHub and Microsoft configured in Chromium, light and dark, 1280 and 390 pxThree buttons in that order, each with its own decorative mark and at least 44 px tall inside the viewport; axe-core and the page's own checks find nothing; every text meets contrast; no horizontal scrolltests/test_browser_accessibility.py::test_mi6_the_login_page_with_microsoft_passes_the_audit

Replay regression fixtures (RF1 to RF12)​

replay-fixture turns an export, its head and up to eight candidate bundles into one versioned, sanitized file, and replay-fixture-check replays it offline and fails on any change of a classified decision (replay). RF1 to RF8, and RF10's committed fixtures, run on pure histories and need no database; RF9 builds from the signal-replay world, and RF10's demonstration runs the two-provider validation demonstration, on real PostgreSQL.

IDSetup/actionRequired resultTest
RF1A pure approved isolation with a stop, a labelled principal and one candidate; the same history without its human reviewEach builds and checks clean. The expectations hold every decision's recorded effect, effect, reasons, obligations, outcome, provenance, counts and dependencies, and each candidate's with its differences; event order and times are kept. The incomplete history is recorded with UNRESOLVED and its reasons, not refusedtests/test_replay_fixture.py::test_rf1_a_fixture_replays_to_its_recorded_outcomes, ::test_rf1_a_history_with_missing_facts_is_recorded_with_its_reasons
RF2One expected effect, reasons, outcome or dependency edited; a decision removed; completeness changed; a baseline and a candidate decision each recorded twice; a candidate's Cedar given a comment without re-recordingThe check names exactly the run, sequence and field that differ; a sequence with a decision too many is named as a decision difference, however alike the rows; the edited candidate fails as candidate 1 candidate_hashtests/test_replay_fixture.py::test_rf2_one_edited_expectation_fails_and_names_its_sequence, ::test_rf2_a_lost_decision_and_a_changed_completeness_are_named, ::test_rf2_a_decision_recorded_twice_is_named, ::test_rf2_a_candidate_edited_without_re_recording_fails_on_its_content_hash
RF3An edited event payload, head, bundle or candidate; an unknown format or version, a duplicate key, a float, an extra key or nine candidates; a fixture edited back to a source identifier, case id, reason, version, note, incident source version or owner-named writer; an export wrapped by hand in the fixture format; a fixture edited to hold a secret-shaped string in a candidate's policy text or in an expectation's reasonsRefused with the verification code (INVALID_CHAIN, HEAD_MISMATCH, INVALID_FROZEN_PLAN, INVALID_CANDIDATE), or as unavailable; the edited and the wrapped fixtures refused FIXTURE_NOT_SANITIZED, and the secret-holding ones PRIVATE_DATA without naming the value, by reading, checking and re-recording aliketests/test_replay_fixture.py::test_rf3_an_edited_history_is_refused, ::test_rf3_a_fixture_outside_the_format_is_unavailable, ::test_rf3_a_fixture_still_holding_source_text_is_refused_as_unsanitized, ::test_rf3_an_export_wrapped_by_hand_as_a_fixture_is_refused, ::test_rf3_a_fixture_edited_to_hold_a_secret_is_refused_by_reading
RF4One export built twice; a fixture re-recorded once and twiceByte-identical every timetests/test_replay_fixture.py::test_rf4_a_build_is_deterministic_and_rerecording_is_byte_identical
RF5RF1's fixture; the same history with the agent's case on its first transition; a history carrying every kind of label (an owner's operation ref, resource and mapping versions and rule notes, a reference and a hostname target, an incident's version and a context writer the owner named beside the catalog's, the case, an operator's change number as the settlement reason, a comment, stop reasons and a principal label); the same with the ref isolate and the versions 1 and 2 beside a Cedar comment holding only numbers; the owner's mapping version and ref named in a Cedar comment; settlement reasons that are and are not kernel codes; labels that are also kept words: the ref contain (the vendor's operation and the rule id), the comments approved, production and APPROVED and the stop reason incident; a comment or a stop reason that reads a word the fixture writes itself: its own field names complete, expected, baseline, format, labels and provenance, its expectations' UNRESOLVED and EFFECT, the journal key's id replay-fixture, and a case link pseudonym's https, case and invalid; a comment that reads a Cedar word (permit, forbid, when, principal, resource, Action) or the kernel reason code PROVIDER_RESPONSE the history's settlement writes; a comment that parses as JSON naming the resource beside a Cedar comment that names it; a signal fact's and other facts' source versions; a comment that reads host-000001 or resource-000001, the names the history's one host and one resource are given, with the survival search set aside and with it, and a comment that reads host-000002, a name no label is givenNo source UUID, dashed or undashed, in any case, and no resource id, idempotency key, stop reason, approval comment or principal label survives, every idempotency key being a pseudonym; the labelled principal's payload is empty; every UUID is a ranked pseudonym; the journal is re-signed under key id replay-fixture; an opaque digest's pseudonym never spells a small-integer UUID. The case becomes source-000001, case-000001 and https://case.invalid/url-000001, and a catalog ref is kept. Every kind becomes its typed pseudonym, the journal's expected version included, and the fixture checks and re-records clean; the short ref and versions are replaced only where they are whole, so endpoint.isolate, the journal's numbers and the Cedar comment's numbers are untouched, while the version and ref named in a Cedar comment become the pseudonyms their positions got, in the bundle and the candidate alike. PROVIDER_RESPONSE and INCONCLUSIVE_JOURNAL are kept and any other reason replaced. Every fact's source version but a signal fact's, and the journal's resulting version, become version pseudonyms; the owner's writer becomes writer-000001 and the catalog's is kept, each fact's writers still sorted. A label that is a kept word becomes its pseudonym where it was recorded while the plan's and journal's operation, the rule id, the payload field, the fact's value and Cedar's production, the state and the source kind stay as they are, and each such fixture checks and re-records clean; each word the fixture writes itself becomes the comment's or the reason's pseudonym where it was recorded and stays where the fixture wrote it, and the fixture checks and re-records clean; a comment that is a Cedar word or a kernel reason code becomes comment-000001 while every bundle's and candidate's Cedar text and the settlement's PROVIDER_RESPONSE stay as they were, and the fixture checks and re-records clean; the JSON comment's key lends no kept word, so the Cedar comment's resource id is replaced; no field a label is recorded at is a vocabulary field; each label is replaced once, from its own text, so the host, the resource (the journal's included) and the comment keep their own pseudonyms with the survival search set aside, a comment whose text is the host's or the resource's pseudonym is refused FIXTURE_NOT_SANITIZED with it, and one reading host-000002 checks cleantests/test_replay_fixture.py::test_rf5_no_source_identifier_or_label_survives, ::test_rf5_each_label_is_replaced_once_from_its_own_text, ::test_rf5_a_label_that_reads_as_another_labels_pseudonym_is_refused, ::test_rf5_the_agents_case_on_the_first_transition_never_reaches_a_fixture, ::test_rf5_every_kind_of_label_is_replaced_by_its_typed_pseudonym, ::test_rf5_a_short_version_or_a_ref_inside_a_catalog_name_is_replaced_only_where_it_is_one, ::test_rf5_an_owners_version_or_ref_inside_policy_text_is_replaced_there_too, ::test_rf5_a_kernel_reason_code_is_kept_and_any_other_reason_is_replaced, ::test_rf5_a_label_that_is_also_a_kept_word_is_replaced_only_where_it_was_recorded, ::test_rf5_a_label_that_is_a_word_the_fixture_writes_itself_still_becomes_a_fixture, ::test_rf5_a_label_that_is_a_cedar_word_or_a_kernel_reason_code_stays_where_the_kernel_wrote_it, ::test_rf5_text_a_person_typed_lends_no_kept_word, ::test_rf5_a_signal_facts_source_version_is_kept_and_any_other_facts_is_a_label, ::test_rf5_no_label_position_is_a_field_the_fixture_keeps, ::test_rf5_the_principal_label_and_other_informational_text_never_reach_a_fixture, ::test_rf5_the_journal_is_re_signed_under_a_published_fixture_key, ::test_rf5_an_opaque_digest_pseudonym_never_spells_a_small_identifier
RF6A candidate with a secret-shaped rule note; a candidate for another tenant, or nine candidates; a source checked against the wrong headPRIVATE_DATA with nothing written and nothing quoted; INVALID_CANDIDATE; HEAD_MISMATCHtests/test_replay_fixture.py::test_rf6_a_secret_shaped_candidate_note_is_refused_and_nothing_is_written, ::test_rf6_a_candidate_for_another_tenant_or_too_many_candidates_are_refused, ::test_rf6_a_source_that_does_not_verify_is_refused_with_its_code
RF7The sanitizer's substitution made to leave every value, to leave a candidate's Cedar comment naming the resource, which nothing replay binds reads, or to leave the bundle's Cedar comment naming the owner's mapping version; to turn a fact's value; the journal left unsigned; a one-word comment 00, a token of every +00:00 time the history keeps and no kept wordFIXTURE_NOT_SANITIZED, each comment found only by the search inside every string; FIXTURE_NOT_FAITHFUL; FIXTURE_NOT_FAITHFUL, nothing returned; FIXTURE_NOT_FAITHFUL, the comment's replacement having broken the timestests/test_replay_fixture.py::test_rf7_a_substitution_that_leaves_a_value_behind_is_refused, ::test_rf7_a_label_that_survives_inside_other_text_is_refused, ::test_rf7_a_version_left_inside_policy_text_is_refused, ::test_rf7_a_one_word_comment_that_is_a_token_of_a_time_is_refused, ::test_rf7_a_sanitized_history_that_replays_differently_is_refused, ::test_rf7_an_output_that_fails_verification_is_refused
RF8Both commands with .env loading and engine construction forbidden and no DATABASE_URL; a build and a re-record under umask 022; an edited expectation; an edited history; a refused candidate and an unreadable export; an existing file, the export or the head as the output; inputs beside --from-fixture, or an input without its headExit 0, and --from-fixture byte-identical; both files mode 0600; exit 1 naming the run, sequence and field and no value; exit 2 with INVALID_CHAIN; exit 2 naming a code and never a value or a path, nothing written; refused with the files untouched; refused, nothing writtentests/test_replay_fixture_cli.py::test_rf8_both_commands_run_without_an_environment_or_a_database, ::test_rf8_a_fixture_is_written_readable_by_its_owner_only, ::test_rf8_a_changed_expectation_exits_one_with_codes_and_numbers_only, ::test_rf8_an_edited_history_exits_two_with_its_code, ::test_rf8_refusals_name_a_code_and_never_a_value_or_a_path, ::test_rf8_an_existing_output_and_an_input_alias_are_refused, ::test_rf8_the_build_takes_its_inputs_or_a_fixture_never_both
RF9The signal-replay world: a cap on compromised hosts, two isolations on Medium with distinctive event ids, a principal label and a stop; candidates reading Medium as suspect, as clean, and as suspect under a suspect capTwo builds byte-identical and two checks alike; no source UUID or label in the fixture, every idempotency key and version a pseudonym, a signal fact's source version kept as its registration number and every other fact's a pseudonym; assert_secret_free holds on it and on every command's output; the recorded denial is HARD_LIMIT:compromised-cap, the clean reading UNRESOLVED with SIGNAL_EVIDENCE_UNAVAILABLE, and the capped one HARD_LIMIT:suspect-captests/test_replay_fixture_worlds.py::test_rf9_a_signal_world_fixture_is_deterministic_sanitized_and_checks
RF10The committed tests/fixtures/replay/signal-world-v1.json, two-provider-tenant-0-v1.json, checkpoint-world-v2.json and connector-world-v2.json; a fresh run of the validation demonstrationEach reads as sanitized, checks clean and re-records byte for byte. Between them the version 2 fixtures hold every kind of signed record and every settlement tier. The demonstration builds both tenants' tenant-<index>.fixture.json, and each checks clean with its decisions and candidatetests/test_replay_fixture.py::test_rf10_the_committed_fixtures_are_the_signal_world_and_the_demonstration, ::test_rf10_the_committed_version_2_fixtures_hold_every_kind_version_1_refused, ::test_rf10_each_committed_fixture_replays_and_rerecords_byte_for_byte, tests/test_validation_harness.py::test_fresh_validation_package_runs_all_boundaries
RF11A history settled by each kind of externally executed evidence: an executor's Ed25519 record and its ES256 attestation at ATTESTED, a provider's journal at PROVIDER_VERIFIED, an executor's word at ASSERTED and kept with no tier on an unsettled operation, and a Microsoft Graph connector record with no tierEach builds as a version 2 fixture, twice to the same bytes, checks clean, re-records byte for byte and keeps every decision's tier. signatures names the fixture key for exactly the kinds present, and every retained record verifies under it. Read with every attestation's header and claims opened, no source identifier remains anywhere, and each key id is a signer pseudonym. A key id spelling a word of the envelope (execbound, executor, ES256, connector-record) is replaced, and the attestation's domain and algorithm and the connector record's scheme stay wholetests/test_replay_fixture.py::test_rf11_each_kind_of_externally_executed_evidence_becomes_a_fixture, ::test_rf11_no_source_identifier_or_key_id_survives_inside_any_record, ::test_rf11_a_label_that_spells_a_word_of_the_envelope_leaves_the_envelope_whole
RF12A version 2 fixture whose executor record is signed again under any key but the fixture's; one with a fresh UUID written into an attestation's base64url claims; one whose attestation's signature or header is not base64url; one relabelled version 1; a version 1 fixture relabelled version 2; a history of dispatched operations aloneThe first three are refused on reading as FIXTURE_NOT_SANITIZED, never raised; the two relabelled ones as unavailable; the last is still written as version 1 with no signaturestests/test_replay_fixture.py::test_rf12_a_fixture_holding_a_record_another_key_signed_is_refused, ::test_rf12_an_identifier_hidden_in_an_attestations_claims_is_refused, ::test_rf12_a_malformed_attestation_is_refused_rather_than_raised, ::test_rf12_a_version_1_fixture_holding_evidence_version_1_never_wrote_is_unavailable, ::test_rf12_a_version_2_fixture_of_dispatched_operations_alone_is_unavailable, ::test_rf12_a_history_with_only_dispatched_evidence_is_still_written_as_version_1

Scheduled audit-chain verification (AV1 to AV7)​

audit-verify reads every workspace's chain on the live database again, as the runtime role with no credential, and places each retained checkpoint on it; the jobs service runs it hourly (operations). The tests damage a real chain in PostgreSQL with the owner role.

IDSetup/actionRequired resultTest
AV1Every seeded workspace's intact chain, one with a held request; the same chain read two events at a time; an event altered near its end, read that way; an event appended from another connection after the walk's first eventEvery chain verifies, the report names no workspace, nothing is logged as audit.chain_failed and no table changes; the paged read reaches the same result, and the late alteration is found at its own sequence; the appended event is not seen and the chain still ends at the head read firsttests/test_audit_verify.py::test_av1_every_intact_chain_verifies_and_the_pass_writes_nothing, ::test_av1_a_chain_is_read_a_page_at_a_time_and_a_late_break_is_found_where_it_is, ::test_av1_events_appended_while_a_chain_is_read_do_not_break_it
AV2One workspace's chain with an event altered, two events reordered, an interior event deleted, the tail truncated, or the stored head substituted; a rewrite that breaks one link, or shifts every later sequence, and re-hashes everything after it; the head moved back one with its event left in placeThat workspace alone fails CHAIN_BROKEN at the sequence of the damage, the other verifies, and one audit.chain_failed line at ERROR carries only its tenant, code and sequence; each rewrite is found at the changed event, by the link check and the sequence check respectively; the row past the head breaks the chain at its own sequencetests/test_audit_verify.py::test_av2_a_damaged_chain_fails_alone_and_is_logged_with_its_code_and_sequence, ::test_av2_a_rewrite_that_re_hashes_everything_after_still_fails_at_the_change, ::test_av2_rows_past_the_stored_head_break_the_chain_at_the_first_of_them
AV3Retained heads at genesis, at the first event and at the current head; a head from the future; a forged hash at a retained sequence and at genesis; a broken chain with a valid retained head; the tail removed with the head moved back to match, against the head retained before; a retained head for a workspace the directory does not hold, with every workspace reached and with named workspaces onlyEvery retained head is placed and the chain passes; BEHIND_CHECKPOINT and DIVERGES_FROM_CHECKPOINT at their sequences, genesis included; CHAIN_BROKEN outranks the checkpoint; the consistent truncation verifies alone and fails BEHIND_CHECKPOINT against the retained head; the missing workspace fails BEHIND_CHECKPOINT once every workspace was reached, and with named workspaces its head is counted as not placedtests/test_audit_verify.py::test_av3_retained_checkpoints_are_placed_on_the_chain, ::test_av3_a_consistent_truncation_verifies_alone_and_fails_against_a_retained_head, ::test_av3_genesis_divergence_and_a_broken_chain_outrank_the_checkpoints, ::test_av3_a_retained_head_for_a_workspace_the_directory_no_longer_holds_fails
AV4A checkpoints directory holding other files; the same head twice; two hashes at one sequence; a malformed file; a link to nothing named as a head; a directory that does not exist; more files than the limitOnly *.head.json entries are read; a repeated head counts once; CONFLICTING_CHECKPOINTS; INVALID_CHECKPOINT for the malformed file and the dangling link; CHECKPOINTS_UNREADABLE; TOO_MANY_CHECKPOINTStests/test_audit_verify.py::test_av4_checkpoint_files_are_strict_and_read_only_from_head_files, ::test_av4_too_many_checkpoint_files_are_refused
AV5An inactive workspace with an altered chain; a workspace whose chain cannot be read; a named workspace the directory does not holdThe inactive workspace is verified and fails, while a pass that acts still skips it; the unreadable workspace is failed and the run fails; the unknown workspace fails UNKNOWN_TENANT, never reported as verifiedtests/test_audit_verify.py::test_av5_an_inactive_workspace_is_verified_and_the_other_passes_still_skip_it, ::test_av5_a_workspace_whose_chain_cannot_be_read_fails_the_run, ::test_av5_a_workspace_the_directory_does_not_hold_is_not_reported_as_verified
AV6execbound audit-verify --all-tenants with a checkpoints directory, --tenant, an altered chain; no mode, both modes, a budget of 0; a malformed --checkpoint; a schema mismatch, a database error and the directory walk's own refusalExit 0 with the report; exit 1 with the report and a sentence naming the counts; exit 2 for each misuse; exit 2 with INVALID_CHECKPOINT before the database is read; exit 2 with the runtime check's sentence, database error or UNSAFE_JOB_POLICY, never a tracebacktests/test_audit_verify.py::test_av6_the_command_exits_0_when_every_chain_verifies_and_1_when_one_does_not, ::test_av6_the_modes_are_exclusive_and_the_budget_bounded, ::test_av6_a_checkpoint_it_cannot_use_stops_the_run_before_the_database_is_read, ::test_av6_a_schema_mismatch_or_a_database_error_exits_2_without_a_traceback
AV7The jobs service's table and the command it starts; the scheduler starting the job with a checkpoints directory and stopping it at its timeout beside another jobaudit-verify runs hourly on lock 9007 whatever else is configured, every lock is distinct, and --checkpoints /srv/private/checkpoints is passed only where that directory exists; the scheduler hands each job its checkpoints directory, and the job's own standard error reaches the service's log as written, even when the job is stopped at its timeout, while another job's does nottests/test_audit_verify.py::test_av7_the_jobs_service_runs_it_hourly_on_its_own_lock_with_the_checkpoints, ::test_av7_the_scheduler_starts_it_with_its_checkpoints_and_its_lines_reach_the_log_whole

Findings delivery (FD1 to FD15)​

Each monitoring finding is sent once to every configured destination whose classes list findings and whose rules and spaces admit it, from monitor-process --deliver (operations, Tines monitoring). The router, drain, command, migration and schema tests run on real PostgreSQL; the configuration, message and egress tests need no database. They use the loopback receiver, the SMTP double with a CA the tests mint, the Slack and Teams fakes, and a stand-in resolver and network for the egress guard; nothing reaches a real host. FD12's deadlines in seconds are measured by tests/test_egress_deadline.py, which takes the machine's timing lock and is marked timed, so a run that selects not timed leaves it out while FD12's deadline tests, which read no clock, still run.

IDSetup/actionRequired resultTest
FD1One finding and destinations that admit it by class, rule and Space, beside ones that list another rule, another Space, approvals alone or another workspace; a delivery another router already wrote; two routers at once, then a third; a router holding the intent mid-transaction beside a second; authority revoked while a router writes, then the scheduled pass; a limit of one with two intents waiting, and limits outside 1 to 50; a clock with no zoneOne delivery per admitting destination, with the id uuid5(finding, destination + "#finding"), and the intent ROUTED with its own id; nothing more from the second, the concurrent or the third router, and the second passes the held intent by without waiting and writes nothing; the revoked router is refused INVALID_ADMIN and every row it wrote rolls back, and the scheduled pass then routes; one intent is routed and the other waits; INVALID_LIMIT; INVALID_CLOCK, with nothing writtentests/test_findings_delivery.py::test_fd1_routing_writes_one_delivery_per_admitted_destination, ::test_fd1_a_second_router_or_two_at_once_add_nothing, ::test_fd1_a_router_passes_by_an_intent_another_router_holds, ::test_fd1_the_scheduled_pass_routes_and_authority_lost_mid_route_writes_nothing, ::test_the_router_routes_no_more_intents_than_its_limit, ::test_the_router_refuses_a_limit_outside_one_to_fifty, ::test_the_router_reads_its_clock_through_the_monitoring_check
FD2One finding routed to a webhook, an email, a Slack and a Teams destination, drained twice; the webhook body's bytes; the email's headers and body; the chat messages' shapes; each kind's identifiers, disclaimer and workspace sentence, for a source's finding and a directory's; an email-only drain; an email destination with no relay; a time raised in another zone, with microseconds, or with no zone; a renderer given another delivery's idEach delivered once, with one attempt, and the second drain sends nothing; the receiver stores the body under a signature it verified, and it is monitor.finding version 1 with tenant_id, created_at in UTC to the second and finding_url, pinned byte for byte by a fixture; the email is 7-bit text/plain with [ExecBound · <workspace>] Finding: <label>, Auto-Submitted, X-ExecBound-Delivery, X-ExecBound-Finding, a Message-ID from the delivery id, the link and the fixed line, over verified TLS, by the relay and never through the egress guard's client, which is built with nothing of the relay's; each chat message carries the workspace, Space, rule and time raised as facts, one "Open the finding" link and the identifiers, in the shape the fakes accept; the email and both chat messages carry the identifiers line, the disclaimer and the sentence naming the workspace to choose; an email destination with no relay is refused INVALID_CONFIGURATION before anything is leased; a time with no zone and another delivery's id are refusedtests/test_findings_delivery.py::test_fd2_each_kind_is_delivered_once_and_a_second_drain_sends_nothing, ::test_fd2_email_goes_through_the_relay_and_never_through_the_http_guard, ::test_fd2_an_email_destination_with_no_relay_is_refused_before_anything_is_leased, tests/test_findings_messages.py::test_fd2_the_webhook_body_is_pinned_byte_for_byte, ::test_fd2_the_time_raised_is_written_in_utc_whatever_zone_it_was_read_in, ::test_fd2_the_email_has_its_subject_headers_link_and_fixed_line, ::test_fd2_the_chat_messages_have_the_shapes_the_fakes_accept, ::test_fd2_every_kind_carries_the_identifiers_the_disclaimer_and_the_workspace_line, ::test_fd2_the_finding_email_is_7bit_so_its_source_reads_as_written, ::test_fd2_the_time_raised_is_aware_and_written_to_the_second, ::test_fd2_a_renderer_refuses_a_delivery_id_that_is_not_the_messages_own
FD3A Slack destination answering 500, then 200; a Teams destination answering 429 with Retry-After: 40; a Teams destination and a webhook answering 429 with a Retry-After date 45 s after the drain's clock, which runs ten minutes ahead of the host's; the signed sender's other statuses; two findings to one Slack destination in one drainTwo attempts, the second due 5 s after the first; the 429 is an attempt, RECEIVER_RATE_LIMITED, next due 40 s later; each dated 429 next due 45 s after the drain's moment, not the host's; a 429 is RECEIVER_RATE_LIMITED with its Retry-After, another 4xx RECEIVER_REFUSED, and a 3xx or a 5xx RECEIVER_UNAVAILABLE; the second message waits a whole second after the firsttests/test_findings_delivery.py::test_fd3_a_500_then_a_200_is_two_attempts_on_the_backoff, ::test_fd3_a_429_waits_its_retry_after_and_counts_as_an_attempt, ::test_fd3_a_429_with_an_http_date_waits_until_that_date_on_the_drains_clock, ::test_fd3_a_signed_429_with_an_http_date_waits_until_that_date_on_the_drains_clock, ::test_fd3_a_chat_destination_gets_at_most_one_message_a_second_within_a_drain, tests/test_egress.py::test_fd12_every_other_status_has_its_code, ::test_fd3_the_signed_sender_reads_a_retry_after_date_against_its_clock
FD4A webhook that refuses five times; a delivery whose fifth lease expired; a settled attempt, and deliveries closed because their destination was removed, lost findings, or their finding was acknowledgedFAILED with RECEIVER_REFUSED after attempts due 5, 25, 125 and 625 s apart, one delivery id throughout, nothing sent after the fifth, and the finding unchanged; DELIVERY_UNCERTAIN with no sixth send; each settled attempt and each closing writes one monitor.delivered line with identifiers, the state and the code, never the URL, the secret, the target or the story; a closing for a removed destination, a class turned off or an acknowledged finding is logged at INFO, and an uncertain one at WARNINGtests/test_findings_delivery.py::test_fd4_five_failures_end_failed_with_the_transports_code_and_leave_the_finding, ::test_fd4_a_fifth_expired_lease_is_uncertain_with_no_sixth_send, ::test_the_drain_logs_each_settled_attempt_with_identifiers_and_codes_alone, ::test_the_drain_logs_a_delivery_it_closes_uncertain_or_unsent, ::test_the_drain_logs_a_delivery_closed_for_an_acknowledged_finding_at_info
FD5A finding raised from a story with a canary target and story id, delivered to all four kinds from a workspace and Space named with markup and mentions; the renderers given names carrying markup, a mention, a link and a header line, names in a non-Latin script, a name safe_label reduces, names holding each of a_b, x :smile:, example.com, a/b, -x and 1) x and the longest such names, the plain name SOC (EU) - East, a plain workspace with such a Space and the reverse, the longest message there can be, and a link, label, rule, missing name or time outside the rules; a body that cannot be renderedNo body or subject carries the target, story id, action, source label or stored title, nor < or @here; no rendered body carries <, >, @ or onerror=, the subject carries no line break, and no Bcc header is read back; every body is at most 4096 bytes; a message with a link, label, rule or time outside the rules, or with no workspace or Space name, is refused, while any other name is reduced and accepted; a name nothing of which survives is left out of every kind, never "unknown", and every kind names the workspace to choose by its tenant id, beside the label as a hint where one survives, whenever the label is not the name as written; an accented name folds to its letters; a name a chat target could format never reaches Slack's notification line and reaches Teams only in text runs, whichever of the two names holds it, while a plain name keeps the FactSet and Slack's line; a body that cannot be rendered is refused under the lease and spends no attempttests/test_findings_delivery.py::test_fd5_no_string_a_source_reported_reaches_any_body, ::test_fd5_a_body_that_cannot_be_rendered_spends_no_attempt, tests/test_findings_messages.py::test_fd5_hostile_workspace_and_space_names_reach_no_body_as_markup, ::test_fd5_a_name_nothing_of_which_survives_is_left_out_and_chosen_by_tenant_id, ::test_fd5_a_reduced_name_still_shows_but_the_reader_chooses_by_tenant_id, ::test_fd5_slack_reads_a_name_it_could_format_only_as_plain_text, ::test_fd5_teams_reads_a_name_it_could_format_only_as_text_runs, ::test_fd5_a_plain_name_keeps_the_fact_set_and_the_notification_line, ::test_fd5_either_name_alone_puts_the_card_in_text_runs, ::test_fd5_every_body_is_bounded, ::test_fd5_a_link_or_label_outside_the_rules_is_refused
FD6Two drains at once over one delivery; a drain whose send outlives its 60-second lease while another drain delivers the row, and while another drain is still sending it; a drain that crashes after the receiver took the delivery; a clock with no zoneOne send and one attempt; the late settle writes and logs nothing and is not counted delivered, and the row stays DELIVERED, or stays the other drain's lease until that drain delivers it; the crashed delivery stays leased for 60 s, and the next drain sends it once more under the same delivery id; INVALID_CLOCK before anything is leasedtests/test_findings_delivery.py::test_fd6_concurrent_drains_send_each_delivery_once, ::test_fd6_a_settle_after_its_lease_expired_changes_nothing, ::test_fd6_a_late_settle_never_writes_over_the_lease_that_replaced_it, ::test_the_drain_reads_its_clock_through_the_monitoring_check, tests/test_monitoring_worker.py::test_receipt_then_worker_crash_recovers_same_delivery
FD7Destinations and files with and without classes, rules and spaces, inside and outside the rules; a reload changing each; the rules the database admits; an empty rule catalog; the configuration --deliver reads, with a relay, with one destination id twice in a workspace, with an origin outside the console's rule, with one inside it and outside a finding message's, or with each origin the fixtures useA destination or file without classes means approvals alone; each allowed one holds or loads; an empty, unknown or repeated class or rule, a repeated Space, a list given as anything else, rules or spaces without findings, messages or approvers without approvals, or any classes on the audit export refuses the destination, and the file without quoting it; the shape differs for each change, so a reload is refused; each of the 17 rules the database admits has a fixed label of at most 60 characters that safe_label leaves as it is, and an empty catalog admits no rule; the read takes the destinations, the relay and the origin alone, holds the origin to the console's own rule and to a finding message's, so the jobs service runs monitor-process without --deliver for an origin only the console takes, reads every origin the fixtures use, refuses one destination id twice in a workspace, and neither quotes nor chains the filetests/test_findings_delivery_config.py::test_fd7_a_destination_without_classes_is_an_approval_destination, ::test_fd7_each_allowed_destination_holds, ::test_fd7_the_destination_holds_the_rules_without_the_file, ::test_fd7_an_empty_catalog_admits_nothing, ::test_fd7_every_label_is_short_fixed_copy, ::test_fd7_an_old_file_still_means_approvals_only, ::test_fd7_each_allowed_file_loads, ::test_fd7_a_file_outside_the_rules_is_refused_without_quoting_it, ::test_fd7_a_reload_that_changes_classes_rules_or_spaces_is_refused_by_the_shape, ::test_read_outbound_reads_the_destinations_relay_and_origin_alone, ::test_read_outbound_reads_the_mail_relay, ::test_read_outbound_refuses_one_destination_id_twice_in_a_workspace, ::test_read_outbound_holds_the_origin_to_the_consoles_own_rule, ::test_read_outbound_holds_the_origin_to_the_finding_messages_rule_too, ::test_read_outbound_still_reads_every_origin_the_fixtures_use, ::test_the_console_configuration_refuses_an_origin_outside_its_rule, tests/test_findings_delivery.py::test_fd7_every_rule_the_database_admits_has_a_label
FD8A findings-only destination beside an approval one; a destination that loses approvals after a request was queued for it; the recovery pass more than a day later; the approval card's listing; the jobs service's notify decision and its approval kindsA findings-only destination is never queued an approval, never makes its workspace one the approval drain visits and never schedules notify; the row is settled DESTINATION_UNKNOWN unsent by the drain and by the recovery pass; the card lists approval destinations and the audit export, each with its classes, the audit export's empty; the jobs service names the approval kinds the notifier does; AN1 to AN12 and the AY rows still passtests/test_findings_delivery.py::test_fd8_a_findings_only_destination_is_never_queued_an_approval, ::test_fd8_a_row_whose_destination_became_findings_only_is_never_sent, ::test_fd8_the_recovery_pass_settles_a_row_whose_destination_became_findings_only, ::test_fd8_the_approval_card_lists_approval_destinations_and_the_audit_export, tests/test_findings_delivery_config.py::test_fd8_notify_is_scheduled_only_for_an_approval_destination, ::test_the_jobs_service_names_the_approval_kinds_the_notifier_does, tests/test_approval_notifications.py
FD9An intent routed with no destination, then with one; intents 23 h 59 min, 24 h and 24 h 1 s old when first routed; sixty intents more than a day old, every third acknowledged, beside a fresh one; more stale intents than a pass closes; a stale intent another transaction holds; deliveries whose destination is removed, or loses findings, before they are sent; deliveries routed before a restart that narrowed their destination's rules and spaces and then changed its URL; intents the earlier --deliver-local worker left in flight with its lease long lapsed, sent or given up onNo backfill: the later destination gets nothing; the two younger intents are routed and the oldest is closed TOO_OLD_TO_SEND with no delivery; one pass closes all sixty before it takes its batch, FINDING_ACKNOWLEDGED where the finding was acknowledged and TOO_OLD_TO_SEND otherwise, and routes the fresh one; the statement closes at most 5,000 stale intents a pass, oldest first, its ids chosen once, and the batch then routes or closes up to its own 50; the held intent is passed by without waiting; the deliveries are closed DESTINATION_UNKNOWN and CLASS_OFF with no attempt; the narrowed deliveries are still sent, each to the URL configured when it is sent; the local worker's intents are never routed, with no delivery written and each row as it was (ruling 3)tests/test_findings_delivery.py::test_fd9_no_backfill_an_intent_is_routed_once_to_the_destinations_configured_then, ::test_ruling_3_an_intent_the_local_worker_left_is_never_routed, ::test_fd9_an_intent_more_than_a_day_old_when_first_routed_is_closed_unsent, ::test_the_router_closes_a_stale_backlog_before_it_takes_its_batch, ::test_the_router_closes_at_most_its_stale_batch_a_pass_oldest_first, ::test_the_router_chooses_its_stale_ids_once, ::test_the_router_passes_by_a_stale_intent_another_transaction_holds, ::test_fd9_a_delivery_whose_destination_is_gone_or_lost_its_class_is_closed_unsent, ::test_ruling_4_a_routed_delivery_is_sent_as_its_destination_reads_at_send_time
FD10A finding acknowledged before routing, its intent fresh or two days old, and one acknowledged after routingThe intent is closed FINDING_ACKNOWLEDGED with no delivery, by the batch where it is fresh and by the stale statement where it is old; the delivery is closed FINDING_ACKNOWLEDGED unsenttests/test_findings_delivery.py::test_fd10_a_finding_acknowledged_before_routing_is_closed_unsent, ::test_fd10_a_finding_acknowledged_after_routing_is_not_sent
FD11A cap of ten with nine approval emails sent; ten findings emails sent before an approval announcement; a cap of one and findings deliveries a minute short of a day old and a day old; six deferrals in a row; no findings email, beside findings webhook deliveries, an earlier worker's delivered intent and an unused findings email destination; a findings drain and an announcement at once near the cap, in both orders; two findings drains at once, and a findings drain beside an approval follow-up in both orders, each held inside its transaction on real PostgreSQL; two announcements at once at nine of ten; a leased row deferred at the cap; deliveries that would close unsent while the cap is reached; a lapsed lease retried, for a finding and for an announcementThe findings email waits an hour, RATE_LIMITED, with no attempt, while an announcement would still be sent; the announcement is refused RATE_LIMITED; the younger delivery waits an hour and the day-old one fails RATE_LIMITED with no attempt; a deferral spends no attempt, and the send once the cap has room is the delivery's first; with no findings email the approval cap counts what it did before; a send under a live lease counts, so the day ends at the cap and never past it; under the workspace's email-cap lock two drains never both take the last of the cap or of the findings' share, the day ending at nine of ten with the tenth kept for an announcement, and of two announcements one is sent and the other refused RATE_LIMITED; the deferred row is PENDING again with its attempts and is sent an hour later; a delivery that would close unsent closes with its own code and is never deferred; a lapsed lease is never counted against its own retrytests/test_findings_delivery.py::test_fd11_a_findings_email_never_spends_the_announcement_reserve, ::test_fd11_findings_email_counts_toward_the_approval_cap, ::test_fd11_a_capped_findings_email_fails_once_its_delivery_is_a_day_old, ::test_fd11_a_capped_findings_email_waits_an_hour_until_its_delivery_is_a_day_old, ::test_fd11_a_deferral_spends_no_attempt_however_often_it_waits, ::test_fd11_with_no_findings_email_the_approval_cap_counts_what_it_did, ::test_fd11_a_findings_drain_beside_an_announcement_in_flight_never_takes_the_last_slot, ::test_fd11_an_announcement_beside_a_findings_send_in_flight_still_has_the_last_slot, ::test_fd11_two_findings_drains_at_once_never_spend_the_reserve, ::test_fd11_a_findings_drain_and_an_approval_follow_up_at_once_never_spend_the_reserve, ::test_fd11_two_announcements_at_once_never_pass_the_cap, ::test_fd11_a_leased_row_deferred_at_the_cap_is_pending_again_and_sent_an_hour_later, ::test_fd11_a_delivery_closed_unsent_is_closed_at_the_cap_and_never_deferred, ::test_fd11_a_lapsed_lease_never_counts_against_its_own_retry, ::test_fd11_with_no_findings_email_an_announcement_retried_after_its_lease_lapsed_is_sent
FD12Names that resolve to private, loopback, link-local, shared, multicast, reserved or unspecified addresses, to an IPv6 address carrying one (mapped, NAT64, IPv4-compatible, IPv4-translated, 6to4, Teredo), to a site-local address, or to an IPv6 address outside 2000::/3 carrying none; such an answer beside a public one, or after three public ones; a public address in its mapped, NAT64, IPv4-compatible and IPv4-translated forms; an address literal other than loopback; a first address that refuses before a second that answers; four addresses that all refuse; two sends to a receiver that would keep the connection open, its name pointed at a private address between them; a loopback literal; a name that does not resolve, a lookup that fails another way, a lookup with a bug in it, and one slower than the deadline; a TLS receiver behind its certificate's name and behind another; a server that trickles its headers, and one that never answers, in the clear and behind TLS; the chat sender, the signed sender and both drains behind a name that resolves to a private or loopback address, a Slack destination among them; a receiver whose connection is refused; a redirect, through a client that follows redirects; a body of 4097 bytes; an answer with a body; each accepted status and every other; the security event export answered 201; httpx's own line for a request, and a URL its log filter cannot cutRefused before any connection, the resolver having been asked: DESTINATION_NOT_PUBLIC for the chat and signed senders and the findings drain, and an ordinary failed attempt for the approval webhook; those four public forms pass, and a public 6to4 or Teredo address is refused; any other literal is checked like a name, and one that is not public is refused unconnected, and the loopback literal is reached unresolved; the second address answers; only the first three are tried, in the resolver's order; each send resolves, checks and connects again, so the second send is refused unconnected; the connection is made to the checked address; an unresolvable name, a failed lookup and a slow one are unavailable, not refused, the slow one given up unanswered, and a bug in the lookup is reported rather than taken for an unavailable receiver; the certificate is verified against the URL's name; the trickling and silent sends are cut off at their deadline, no timeout handed to the network exceeding it; a refused connection is unavailable, not refused by the guard; no redirect is followed; the body is refused INVALID_NOTIFICATION before a request; no response body is read; 200, 201, 202 and 204 are delivered for approvals and findings, and every other status gets the signed sender's code; the export counts only 200 and 204 and its cursor does not move on a 201; httpx's line names the request's origin alone, never its userinfo, path or query, and a URL the filter cannot cut is withheld from the line, which is kepttests/test_egress.py::test_fd12_a_name_that_resolves_to_an_address_that_is_not_public_is_refused, ::test_fd12_one_answer_that_is_not_public_refuses_the_name, ::test_fd12_an_answer_past_the_first_three_is_checked_too, ::test_fd12_a_public_address_is_public_in_each_form_it_takes, ::test_fd12_an_address_literal_other_than_loopback_is_checked_like_a_name, ::test_fd12_a_first_address_that_refuses_gives_way_to_the_second, ::test_fd12_at_most_three_addresses_are_tried_in_the_resolvers_order, ::test_fd12_every_send_resolves_and_connects_again, ::test_fd12_the_connection_is_made_to_the_address_that_was_checked, ::test_fd12_a_loopback_literal_is_reached_without_resolving, ::test_fd12_a_name_that_does_not_resolve_is_unavailable_not_refused, ::test_fd12_a_lookup_that_fails_in_any_other_way_is_unavailable_too, ::test_fd12_a_bug_in_the_lookup_is_reported_not_taken_for_an_unavailable_receiver, ::test_fd12_a_lookup_that_outlasts_the_deadline_is_given_up_as_unavailable, ::test_fd12_tls_is_verified_against_the_urls_own_name, ::test_fd12_a_send_that_trickles_is_cut_off_at_its_deadline, ::test_fd12_a_receiver_that_never_answers_is_cut_off_at_its_deadline, ::test_fd12_a_tls_receiver_that_never_answers_is_cut_off_at_its_deadline, ::test_fd12_the_chat_sender_names_the_refusal, ::test_fd12_the_webhook_sender_names_the_refusal, ::test_fd12_a_receiver_that_cannot_be_reached_is_unavailable_not_refused, ::test_fd12_no_redirect_is_followed, ::test_fd12_an_oversize_body_is_refused_before_any_request, ::test_fd12_no_response_body_is_ever_read, ::test_fd12_the_chat_sender_posts_what_it_is_given_and_never_reads_the_answer, ::test_fd12_each_accepted_status_is_delivered_by_both_senders, ::test_fd12_every_other_status_has_its_code, ::test_fd12_the_export_set_counts_only_200_and_204, ::test_fd12_httpx_logs_a_request_by_its_origin_alone, ::test_fd12_the_httpx_log_filter_never_raises_and_withholds_a_url_it_cannot_cut, tests/test_findings_delivery.py::test_fd12_the_approval_drain_refuses_a_name_that_resolves_to_loopback, ::test_fd12_the_findings_drain_refuses_a_name_that_resolves_to_loopback, tests/test_event_export.py::test_fd12_the_security_event_export_still_counts_only_200_and_204
FD13process --all-tenants --deliver over two workspaces, the same pass with each workspace's purge failing, and the same pass without --deliver beside a findings configuration; the router and drain misfenced; two workspaces that each name a destination soc; the scheduled evaluation given an outbound; process --config --deliver; --deliver beside --deliver-local or without EXECBOUND_RUNTIME_CONFIG; --deliver-local beside a runtime configuration naming a findings destination, one naming approvals alone, a missing one and a malformed one; the configuration read; a runtime configuration that read at one pass and is broken before the next, in both modes; from a file that never reads, an evaluation that stops the pass and one workspace's evaluation refused; deliveries, with and without --state, over 201 deliveries, for a revoked credential and for a state no delivery has; the command module's imports; SJ9's pinEach workspace's findings are routed and delivered under its own fence, and its line counts them, none failed or closed; a purge that fails leaves each workspace counted failed with its code and every finding delivered all the same; without --deliver no destination is read, every intent waits unrouted and nothing is sent, as MC21 holds; misfenced, both refuse INVALID_ADMIN and the other workspace is untouched; a drain sends only to its own workspace's soc; the scheduled evaluation sends before its one purge, its last step, and counts both; --config delivers its own workspace alone and returns exactly process's five keys and purged; each misuse exits 2 with its sentence, and --deliver-local is refused FINDINGS_DESTINATIONS_CONFIGURED only where a destination lists findings; no connector is built and no plugin loads; the broken file stops no evaluation: the pass raises the new finding, routes and sends nothing, logs monitor.delivery_refused at ERROR after its own line, naming the workspace under --config, and exits 2, while an evaluation that stops the pass logs no such line, and one workspace's contained refusal is counted in monitor.process_all's failed and still followed by monitor.delivery_refused; deliveries lists the newest 200 rows, newest first, ROUTED included, each with nine keys and never a destination's URL or secret, --state narrows it, and a revoked credential is refused INVALID_ADMIN and another state INVALID_STATE; building the parser never loads the worker; the pin names the router, the drain and the scheduled steptests/test_findings_delivery_cli.py::test_fd13_all_tenants_deliver_sends_each_workspaces_findings, ::test_fd13_all_tenants_deliver_sends_before_a_purge_that_fails, ::test_fd13_all_tenants_without_deliver_reads_no_destination_and_sends_nothing, ::test_fd13_each_workspace_is_routed_and_drained_under_its_own_fence, ::test_fd13_the_scheduled_evaluation_sends_before_it_purges, ::test_fd13_config_deliver_sends_as_the_configurations_administrator, ::test_fd13_deliver_is_refused_beside_deliver_local, ::test_fd13_deliver_needs_the_runtime_configuration, ::test_fd13_deliver_local_is_refused_where_a_findings_destination_is_configured, ::test_fd13_deliver_reads_no_connector_and_loads_no_plugin, ::test_fd13_a_runtime_configuration_broken_since_start_stops_no_evaluation, ::test_fd13_an_evaluation_that_fails_logs_no_delivery_refusal and ::test_fd13_a_contained_workspace_refusal_still_logs_the_broken_file (the two that start from a file that never reads), ::test_fd13_deliveries_lists_every_row_for_an_administrator, ::test_fd13_deliveries_lists_the_newest_200_rows_newest_first, ::test_fd13_deliveries_rechecks_the_administrator_and_names_only_a_delivery_state, ::test_the_commands_import_the_notifier_in_a_function_and_parse_without_the_worker, tests/test_findings_delivery.py::test_the_drain_sends_only_to_its_own_workspace_s_destination_of_a_shared_id, tests/test_scheduled_actor.py::test_sj9_only_the_pinned_functions_accept_a_scheduled_actor
FD14No runtime configuration; a fresh installation's, which names no destination; one naming a webhook with no classes, approvals alone, findings, or both; a file that does not read, a directory, and one nested past the parser's recursion limit; files that parse but whose cleartext origin, origin with a path or repeated destination id --deliver would refuse; the jobs command; the scheduler told to deliver and not--deliver is passed to monitor-process, under the job's own name and lock, wherever the configuration reads as --deliver reads it, findings destination or none, and never where it does not; every reader the service asks at start answers no for the nested file, so the service starts; the jobs command hands the scheduler that decision; the scheduler runs monitor-process with --deliver only when told, schedules every other job as before, and its jobs.started line says whichtests/test_jobs_schedule.py::test_fd14_monitor_process_delivers_wherever_a_runtime_configuration_reads, ::test_fd14_a_file_process_deliver_would_refuse_gets_no_deliver, ::test_fd14_serve_runs_monitor_process_with_deliver_only_when_told, ::test_the_jobs_command_schedules_the_drain_from_the_configuration_it_runs_with, ::test_a_configuration_nested_past_the_recursion_limit_answers_no_at_start
FD15Migration 0097 over a retained intent, up and down, as an owner that bypasses row security and as one that does not; the runtime's insert and update of a destination; a grant of UPDATE (destination_id)The intent keeps its id and state; one intent per finding and one delivery per finding and destination; ROUTED only without a destination, and no state outside the five; the identifier check holds; forced row security holds; the downgrade refuses FINDINGS_DELIVERIES_RETAINED while a delivery or a routed intent is retained, and otherwise restores 0096's every index, constraint and column, 0008's key among them; the runtime inserts a destination and is refused updating one; check_runtime refuses the granttests/test_findings_destinations_migration.py::test_fd15_the_intent_keeps_its_row_and_a_delivery_per_destination_is_admitted_once, ::test_fd15_the_downgrade_sees_every_tenant_as_the_hosted_owner, tests/test_monitoring_schema.py::test_fd15_the_runtime_inserts_a_destination_and_never_updates_one, ::test_fd15_one_intent_per_finding_and_one_delivery_per_destination, ::test_fd15_check_runtime_refuses_a_grant_of_the_destination

Trusted browsers (TB1 to TB10)​

A person who verifies their second factor at sign-in may trust that browser for thirty days, so its later sign-ins, and its entries into the account's other workspaces, skip the code (design). The trust satisfies the sign-in factor and nothing more: a step-up still asks, a security change ends it, My account lists and removes it, and a workspace administrator may forbid it. The review step a notification's workspace-scoped address opens is the hosted service's row. Real PostgreSQL throughout; the browser rows run in Chromium.

IDSetup/actionRequired resultTest
TB1A sign-in verified by an authenticator code, a recovery code and a passkey with "Trust this browser for 30 days" ticked; a password sign-in on the same browser next, and a Google stand-in's callback; the trust's label from a Chrome on Windows User-Agent; a session holding its own verificationThe cookie is HttpOnly, SameSite=Lax, Path=/, about thirty days long and tb1.-shaped; the next sign-in's GET /mfa answers 303 to the landing with new session and CSRF cookies and no account cookie; the session's assurance is trusted with the original verified_at, never now, and the workspace's chain records account_security.trusted_sign_in with the session, the trust and the original method and time, which a code sign-in and a tampered cookie never record; the provider's sign-in is trusted the same way; the trust is listed as "Chrome on Windows"tests/test_trusted_browser_sign_in.py::test_tb_ticking_the_box_sets_the_cookie_and_the_next_sign_in_skips_the_code, ::test_tb_provider_sign_in_honours_trust, ::test_tb_the_trust_lists_the_browser_that_was_trusted; tests/test_trusted_browsers.py::test_tb_grant_then_apply_skips_the_factor_with_the_original_time, ::test_tb_a_session_holding_its_own_verification_keeps_it
TB2The box left unticked; trust=on posted from Account security once signed in, and any other value; a tampered cookie; the code prompt of a workspace that forbids trustNo cookie is set and the next sign-in asks for the code; Account security shows no box, grants nothing for on and answers 403 for anything else; a tampered cookie shows the code prompt; a forbidding workspace's code, recovery and passkey forms offer no boxtests/test_trusted_browser_sign_in.py::test_tb_an_unticked_box_sets_no_cookie, ::test_tb_the_box_is_not_offered_once_signed_in, ::test_tb_a_tampered_cookie_shows_the_code_prompt, ::test_tb_a_workspace_that_forbids_trust_offers_no_box
TB3A trusted sign-in whose trust was granted two days earlier, then a step-up-guarded change; the store's recent-factor check and the database's fresh read for a trusted assurance, on an account session and a legacy oneThe change answers 401 MFA_REQUIRED until a real code is entered; RECENT_AUTH_REQUIRED from the store, and the definer functions refuse the trusted assurance as staletests/test_trusted_browser_sign_in.py::test_tb_trusted_sign_in_still_asks_for_step_up; tests/test_trusted_browsers.py::test_tb_a_trusted_session_still_fails_the_recent_factor_check, ::test_tb_a_trusted_assurance_is_not_fresh_for_a_legacy_session
TB4Two trusted browsers, then "Sign out other devices" from one; the same from a session of that person with no account sign-in, a setup credential's; a replaced authenticator; another account's cookie, a password change, thirty days, removal and a workspace that forbids trustBoth browsers ask for the code again; from the session with no account sign-in, the account's version moves, the trust no longer applies, every account sign-in of the account ends and the acting session stays; the replaced factor's trust, still unrevoked and unexpired, no longer applies; each refusal case leaves the session pending and writes nothingtests/test_trusted_browser_sign_in.py::test_tb_sign_out_other_devices_ends_every_trust, ::test_tb_a_replaced_factor_ends_trust; tests/test_trusted_browsers.py::test_tb_trust_is_refused_when, ::test_tb_sign_out_other_devices_from_a_session_with_no_account_sign_in_ends_trust
TB5Granting from a stale, trusted, wrong-method or earlier verification and in a forbidding workspace; an eleventh trust; two grants at once at ten; a sign-in whose grant is refusedEach grant is refused and nothing is stored; the oldest trust is revoked, leaving ten; ten live trusts after the race; the sign-in still completes, with no cookietests/test_trusted_browsers.py::test_tb_grant_is_refused_when, ::test_tb_an_eleventh_trust_revokes_the_oldest, ::test_tb_two_grants_at_once_leave_ten_live_trusts; tests/test_trusted_browser_sign_in.py::test_tb_a_refused_grant_still_signs_in
TB6The table read and written as the runtime role under another account's setting and its own; 0101_trusted_browsers applied and rolled backAnother account's rows are invisible and the runtime writes none, only the definer functions do; the downgrade drops the table, the functions and the column, deletes every trusted assurance and restores the method check and the three patched definitionstests/test_trusted_browsers.py::test_tb_the_table_is_account_isolated_and_runtime_read_only, ::test_tb_downgrade_drops_everything_and_restores_the_method_check
TB7My account with two trusts and this browser's cookie; Remove of the other one, an unknown one and this one, with the factor verified forty minutes earlier; Remove all; malformed bodies; the account's notices; the console card empty, listing two and confirming each removalsecurity.trusted lists both newest first with only browser_id, label, created_at, last_used_at, expires_at and this_browser, this browser marked and no secret or hash in the answer; removal asks for no step-up and answers the fresh view, clearing the trust cookie only when this browser's own trust goes; a bad id or an extra field is 400 INVALID_BODY; each add and remove is a notice; the card says how a browser comes to be trusted, marks "This browser" and posts only after its confirmationtests/test_console_api_trusted_browsers.py::test_tb_my_account_lists_and_removes_trust, ::test_tb_removing_this_browsers_trust_clears_its_cookie; tests/test_trusted_browsers.py::test_tb_listed_and_removed_records_events; console/src/components/settings/PersonalSettings.test.tsx
TB8An account trusted two days earlier, its code in A forty minutes old, lists its workspaces and switches to B, which asks for a factor, with and without the cookie and with a malformed one; B forbidding trust; the console menu in Chromium; a trusted session switchingWithout a usable cookie B is factor and withheld; with it B is open and counted, and the switch answers the section, not /mfa, with B's assurance trusted at the trust's two-day-old time and account_security.trusted_sign_in in B's chain, none in A's; a forbidding B stays factor and the switch answers /mfa; the menu says nothing of a second factor and opens B with no request to /mfa; a trusted assurance is never carriedtests/test_console_api_trusted_browsers.py::test_tb_a_trusted_browser_enters_another_workspace_with_no_code, ::test_tb_a_workspace_that_forbids_trust_is_entered_with_a_code; tests/test_browser_workspaces.py::test_tb_the_menu_opens_a_workspace_on_a_trusted_browser_with_no_code; tests/test_trusted_browsers.py::test_tb_a_trusted_session_does_not_carry_into_another_workspace
TB9A workspace administrator's Account security with the factor verified now, then forty minutes ago; the box posted off, with allow=yes and with an extra field, then on; a password sign-in on a trusted browser after each; an approver's page and post; the store's switch from another workspaceThe box "Allow trusted browsers in this workspace" starts ticked; turning it off answers the page with the notice and, with it off, GET /mfa shows the code prompt despite a valid cookie; anything but on is 403; turning it on with a stale factor says to verify first and changes nothing; turned on, the trusted sign-in goes straight on again; an approver is shown no box and refused 403; each change is in the audit chain, and only that workspace changestests/test_console_api_trusted_browsers.py::test_tb_the_admin_switch_forbids_trust_in_that_workspace, ::test_tb_only_a_workspace_administrator_sees_or_uses_the_switch; tests/test_trusted_browsers.py::test_tb_only_an_admin_sets_the_policy
TB10In Chromium, the code and recovery forms at 1280 and 390 px in both schemes; Tab from the code field, Space and Enter; only the trust cookie kept, then a password sign-in; the box left unticked; My account's Trusted browsers card holding two trusts, this browser's marked, at 1280 and 390 px in both schemesNo axe-core, page-audit or sideways-scroll finding, and none for the card, which lists both with "This browser" on the newest and records no policy violation; the label is at least 24 px tall, and 44 px at 390; the keyboard reaches and ticks the box and lands on Approvals; the cookie is HttpOnly, Lax and /; the next sign-in lands on Approvals with no code; unticked, it askstests/test_browser_trusted_browser.py::test_tb_the_box_is_keyboard_reachable_and_44px_on_a_phone, ::test_tb_an_unticked_box_leaves_the_next_sign_in_asking, ::test_tb_the_trusted_browsers_card_passes_the_audit_in_both_schemes