Repository navigation
Develop - #1128
Merged
Merged
Develop#1128
Conversation
The operator broke out of its wait on a final-looking word anywhere in the scheduler's answer, and started t-post-cl's module at 16:36:36.703 while that realm's rotation was still writing generations until 16:36:37.159. The module then read a JWKS with no new signing key. It now waits for the run's own state and then for a signing kid the JWKS did not have before.
In t-jwt-cl, oidcc-claims-essential timed out, and creating the next module
met the suite still stopping it ("setStatus() called but status is the same:
INTERRUPTED -> INTERRUPTED"), so the plan lost every remaining module. The
stop is now waited on, and a creation that still meets it is made once more.
oidcc-claims-essential timed out once in t-jwt-cl on 2026-10-26, in one plan of twenty-four, with no request on the service and no error from the browser. The module's status and the browser's asked and visited addresses are logged before it is stopped, and a module that timed out is run once more; one that hangs again is reported as before.
…ery person (#985). On an installation of fifty million people every `users` query in the reports application met the ten-second cap, `username equals rcbj` included: the reader built the group index, paged every person, fetched each entry again and applied the filter only as rows were offered, and a row that did not match kept the walk going. The store already answers the question through the keyed digests of uid, mail and entryUUID and the trigram index over the RDN value, which sign-in and the portal's delegate search use. The catalog now says which operators the store indexes for each field of `users` (`indexed`: username for eq, in, contains and startsWith; mail and entryUuid for eq and in), published on the catalog API, the OpenAPI document and the source page. The users reader reads the plan's filter first: an indexed leaf, one arm of an and, or every arm of an or becomes a lookup through the directory's own doors, only those rows are offered, and the whole filter still applies to them. A synchronous read that would still have to see everybody on a windowed directory is refused before the walk starts (STS-REPORT-0036, result_too_large, naming the indexed fields), and in auto mode the API queues it as a job instead. The memory directory walks as before. tests/report_query.js drives the planner, every lookup door, the refusal, the auto and job distinction and the memory fallback against a counted directory double. docs/reporting.md and report/CLAUDE.md carry the rule.
…n, growing filter rows and a save box (#986). Six things rcbj asked for on 2026-10-26, every one drawn by the browser runtime from a /report-api answer, as the surface rule has it. The bar starts with the trust realm the page is showing, on the console's switcher shape: a select of the realms and a Go button where the service has several, the one realm's name otherwise. A new GET /report-api/realms answers the current realm and, where realms are active, every realm with its id, name and prefix. Choosing another realm leaves the page for that realm's report application at the same path, where the runtime signs in as any first load does, because the token in hand is audienced to the realm that issued it. Under the bar a link opens the reporting page of the documentation site. Under the card the service version is drawn from the index, which now carries common/version.js's record as the console's shell does; tests/version.js lists report_api.ts among the drawers. The query form starts with one filter row and a + beside the last row adds the next: the runtime clones the row, renames its controls to the next index, empties them and moves the +. The document reader takes as many rows as the form holds, up to the sixteen an and may carry. A Save query box reveals the Name field and the Save button; unticked, the form only runs. Sign out moves from the bar into the user menu, which is therefore drawn for every signed-in person; its account-switching section still appears only with several accounts on. tests/report_query.js holds the realms view, the realm field's two shapes, the footer, a row with and without the +, the variable reader over a form double and the OpenAPI entries. The browser's cloning and the navigation are not held in process.
…query once Save query is ticked (#986). The realm field, the language chooser and the user menu move into a smaller right-justified bar above the navigation bar, which keeps the pages and Refresh. Enter in the Name box ran the query instead of saving it: a form submitted that way activates its default button, the first submit button in document order that is not disabled, and a hidden button still counts. On 8081 that run then became a job, and the job page's row count was what came back. Save is now first in the document and disabled as well as hidden until the Save query box is ticked; a CSS order rule still draws it after Run.
… a date and weekdays, and draw the top bar as one (#986). Every job now records why it was queued (every-person, asked, limit, source, run or schedule), the view carries it, and the job page says it in a sentence: an auto-mode query whose filter the directory cannot answer from an index reads every person, and until now the page only showed that it had become a job. A definition's owner is a subject, which no reader can place; the list and the page show the display name or the username, resolved through the subject resolver and the entry, and the subject stays on the API. The schedule was a free box for a cron expression. It is a date-time in UTC and seven weekday boxes now: weekdays ticked compose a weekly expression at that time, none composes that date every year, and the sentence under the controls says which and shows the expression the API keeps, so one written by hand that the editor cannot draw is still seen. The top row is drawn as a bar like the navigation bar, and one rule gives its selects, buttons and the user menu's summary the same box: the language chooser came out with the browser's own background and the menu with its own shape.
#499 moved the MEDIUM line to 3 and left the evaluators' factors alone, so a single address signal lifts a familiar sign-in to MEDIUM less often than it did: a Tor exit (×5) from a model score of 0.6, where a line at 1 needed 0.2. The ticket offered three ways out — raise the factors in proportion, move the HIGH line with the MEDIUM one, or decide on the signal itself — and this takes the third. The factors are evidence about the sign-in and θ is the population's prior odds (Freeman et al., Eq. (4)); rescaling one by the other would count the prior twice. And what a loaded list says is about the ADDRESS, not about this person's habits, so what to do about it is a decision, and decisions are policy. The built-in role-issuance document gains two template parameters and the rules they build. `stepUpSignals` (default `tor-exit, reputation, operator-deny`; `none` builds no rule) adds `risk-signal-step-up` after the two MEDIUM rules: below MEDIUM, a sign-in carrying one of them is refused until it carries a second factor. `refuseSignals` (empty by default, for #226's reason) adds `risk-signal-refuse` after `risk-high`: a sign-in carrying one is refused at any level, however many factors it presented. The MEDIUM rules exclude the refuse list, so the risk rules stay mutually exclusive and a Deny still carries one instruction. The applications `neverLockOut` names are stepped up or alarmed on either list through the same `elevated` test as HIGH, never refused; STS-RISK-0038's description says so. tests/risk_decisions.js B8–B16 hold it: LOW from each listed signal asks for a second factor and is permitted once one is carried, a signal off the list leaves LOW to the roles, `none` builds no rule, the list is the realm's, a refuse list refuses at LOW and at MEDIUM, the console is never refused on either, and the rules sit where ordered-deny-overrides needs them. The step-up rule removed is caught by seven assertions. docs/risk-scoring.md and risk/CLAUDE.md carry the reasoning.
The route was registered by the realm switch and left undescribed, which the metadata drift check reports; the row says what the application draws from it.
…ps, give a group an address, and edit the query with the New Query controls (#989). The definition page's groups box becomes the console's search-and-results pane: a text search over the realm's groups at GET /report-api/groups, five a page with Previous and Next, an Add beside each hit, and the chosen groups in a list with a Remove each. Save posts the definition and then the list to the share endpoint. The query is edited with the New Query form's own controls, filled from the saved document; a filter the rows cannot draw is shown as JSON and carried back until a row is filled in. Save and Delete are buttons at the foot, in a two-column editor. The shared groups are also who is emailed the result. A group entry may carry one mail attribute, given at the create or set and cleared through the group page's Email address form and POST /admin-api/groups/set-mail; the mail channel gains a group recipient, resolved by the directory, so the address never comes from a request. When a job finishes with Notify on, each shared group with an address is sent the notice, and each without is STS-REPORT-0037, logged and on the audit row, while the others are still sent to. tests/report_query.js holds the search, the recipients split, the form's prefill and the pane; tests/mail.js the group recipient; and tests/directory_group_writes.js the address on the entry. The browser's Add, Remove and search, and a notice to a real transport, are not held in process.
…make the editor's columns one height (#989). Every field of the reports application carries a title on its label, the console's shape, from sentences in the seven languages. Under the definition page's Run box a sentence names the parameters the saved filter holds, or says it holds none and the box is ignored, and gives the shape of a parameter leaf and one example run object; the two JSON examples ride in as message values, since a brace in a catalog message is a parameter to the message format. The editor's two columns stretch to one height, each drawn as a panel.
…e it took, and why a run did not happen (#989). A schedule was set and no job was seen, and the page gave no way to tell "not due yet" from "skipped" or "off". The definition view now carries nextRunAt and lastSlotAt beside the notes the schedule job leaves, and the page draws them under the editor with one sentence on how a schedule runs: an enabled schedule is checked about once a minute, the most recent occurrence not yet taken is queued as a job, the first within a minute of saving, and a save with Enabled clear keeps the schedule and never runs.
…dules (#992). Every definition that carries a schedule, with its next run, the occurrence it last took, the notes a skipped run left and its most recent scheduled jobs. A report:use token sees the definitions it owns or is shared; report:admin sees the whole realm and may name one owner, by subject or by username. A report:use token that names another owner is refused (STS-REPORT-0038) rather than narrowed to its own, so an answer never means something other than what was asked.
…ubble (#989). Download of a completed job said only that something went wrong. The page's API helper read every application/json answer as the API's own JSON, so a result saved in JSON format came back parsed with no bytes to hand to the browser. A result is now read as bytes whatever its type, a refusal still as JSON for its reason, and a failed download names the reason or the HTTP status. Every act now reports in a status bubble at the top of the card, the console's own: saved, deleted, queued as a job, a refused run or save, a failed download. A refusal no longer repaints the page, so the form stays as it was and the reason sits above it.
…ires. sts_passkey_report created its person with invent: false and nothing else, so in the single-node (product) mode the realm's attribute policy refused the create with 400 and the job failed on 2026-10-26; the memory mode had hidden it. The four attributes every person must hold are passed, as the other passkey jobs do.
A PDF downloaded from the jobs tab clipped every cell at its column's edge and drew the rest of the value nowhere, which a reader could not tell from a short value. A cell is now laid out on as many lines as its column needs: broken at a space where one falls within the line, a word longer than the line broken where the line ends, a CR or LF in the value a break of its own. A cell draws at most 256 WinAnsi bytes, after which it is cut and ends in `...` inside the cap, so a cut is visible too. A row is as tall as its tallest cell, and a page holds forty LINES of data rather than forty rows, so forty single-line rows still fill one. A row that does not fit in what is left of a page starts the next page whole; a row taller than a whole page continues on the next, because a row cut at the page's foot is the same clipping seen from below. The header wraps as well, and its extra lines come out of every page's data budget so the table never runs into the page number. The page cap is applied to the pages the layout needs, so a wrapped report can be refused where a clipped one was not; the alternative is a page count that lies. The layout is a character count over Helvetica's average advance, the heuristic the clipping already used, because the file carries no font metrics. tests/report_query.js holds it: a long value drawn whole on several lines, none wider than the column; a two-line row moving a report onto a second page, and starting that page rather than splitting; a value over 256 bytes cut to 253 and ending in `...`; a 256-byte cell in a three-character column drawn whole across three pages; a blank cell, a line feed, and the forty-line page. With no wrapping at all, six of them go red. docs/reporting.md and report/CLAUDE.md say the rest.
…wers (#672). "Times you have signed in" on /portal said 0 for everybody since the portal's first day (2026-09-06). admin_stats.userDetail() answers { user, tokens, artifacts } and keeps the count on user.authentications, the row /admin/users draws, which was right all along; the Overview read detail.authentications, a member that shape never had, so Number(undefined || 0) was the figure on every account page. Nothing failed: the page drew a number, the number was a number, and the console beside it disagreed quietly. The view now reads detail.user.authentications, and null with no row as before, so the page draws no figure rather than a zero it cannot stand behind. Two tests hold it. tests/portal_overview_count.js builds the Overview's view from the real register after real recordAuthentication() calls, in process, because the claim is about the shape one module answers and another reads: three sign-ins are three, a fourth makes four, a person with no row gets null, and the count is on user and nowhere else. tests/protocol/sts_portal_sessions.js asserts over HTTP, after the owner's real sign-in, that the operation's JSON and the drawn page both carry a figure of at least one, with a bounded wait for a worker that is a change-log pull behind.
…#507). The session-ID cache has refused a resumption under another server name since 2026-10-07 (RFC 6066 section 3), and TLS 1.2 session tickets went on resuming under any name: node resumes a ticket inside OpenSSL with no event, OpenSSL compares no name on a hit, and nothing node exposes carries the name a ticket was made under — `servername` is false after a TLS 1.2 hit and the session's DER holds no name, with or without an SNI callback answering a context (shown by hand against a bare node server). What a resumed TLS 1.2 session does keep is the master secret of the session it resumes. So the listener records, at the end of every full TLS 1.2 handshake, the name the hello offered under a SHA-256 of that session's master secret (read from getSession()'s SSL_SESSION, never the secret itself), and on every resumed TLS 1.2 connection looks it up and closes the connection when the name differs (STS-TLS-0052) or this node has no record (STS-TLS-0053). Closed rather than resumed afresh, because by secureConnection the handshake is over; prepended, so nothing reads the connection first. The record is per listener and per process, bounded by 4096 entries and the listener's session lifetime, and a replicated shared store (tls.ticketNames, a CELL-tier store beside tls.presentedChains) carries it to the node that did not seal a ticket under the cluster's shared key; nothing waits for a row, since a mismatch must close at once. Of the ticket's four options this is the first. Turning TLS 1.2 tickets off makes TLS 1.3 tickets stateful and every TLS 1.3 resumption a per-process one; node exposes no ticket callback to carry the name in; and no hook permits a full-handshake fallback once OpenSSL has accepted the ticket. TLS 1.3 is left alone on purpose: RFC 8446 section 4.2.11 removes the server's check and section 4.6.1 binds the client to one name, and OpenSSL resumes a TLS 1.3 PSK under another name. The tlsfuzzer plan's stale entries: the session-ID exceptions of test-sessionID-resumption and test-extended-master-secret-extension are the cluster mode's only now (the cache resumes on one node), and test-resumption-with-wrong-ciphers stays out for the right reason — every probe offers only CBC suites, which the BCP 195 list refuses before any session exists; the cipher check on a resumption is OpenSSL's, which answers illegal_parameter as the script expects. tests/listener_tls_policy.js L5d and L5e: a ticket made under one name is resumed and then closed unanswered under another or under none, and resumed and answered under its own; a TLS 1.3 ticket is resumed and answered under another name.
# Conflicts: # docs/error-codes.md
…ole pages its tables (#997). Both lists showed everything on one page; the jobs API paged by a cursor the page never followed. GET /report-api/definitions and GET /report-api/jobs now take page and per (fifty unless given, at most two hundred) and answer page, pages, per and total beside the rows; the jobs list still answers a cursor walk with after and limit. The two pages draw the console's pager above and below the table: first and previous, a window of seven page numbers with the current one marked, next and last, the line saying page x of y and rows a to b of n, and a rows-per-page choice. Every page is a link under the list's own address with page and per in the query, so a page can be linked to and the back button works; the choice of size moves to page one the same way.
admin_stats.js's users register is realms.map({ persist: 'admin_stats.users',
merge: 'own' }), and that facade journals a set(), a delete() and a clear()
and nothing else. A record was set once, in userRecord() at creation, and
then edited where it stood: recordAuthentication() incremented
authentications, pushed the event, moved lastAt and bumped the protocol and
method counts; noteKnownIdentity() wrote knownBy. So the row in the store
was the record as it stood at the first flush after its creation, one
authentication, and it was never rewritten.
On 8081 (product mode, postgres, two request workers) an account with
sixty-two accepted credentials in the audit log read authentications 1, with
firstAt and lastAt equal and twelve days old. The audit rows' own
authenticationsSoFar climbed 2, 3, ... 8 within one worker's life and read 2
again after each restart, because the restart restored the frozen row and
the other worker read the same frozen row through the fan-in. sts_changes
held six rows for the store in two days, all record creations. The portal's
"Times you have signed in" (#672) and the console's user page both draw the
figure, so #672's fix to the page changed nothing a person could see there.
Development mode on the memory store never restarts and never persists,
which is why #672's tests passed.
touchUserRecord() re-sets the key after the edits, once per sign-in, the
answer persistence/CLAUDE.md gives for a store of mutable rows and the one
the CAEP and RISC registers already use. The cost is one minted-own change
row per sign-in, which the read barrier does not wait on. The eviction past
MAX_USERS is unchanged.
tests/user_register_journal.js holds it against the minted journal and a
stub store: the first sign-in writes the row; a second leaves the journal
dirty and the next flush writes the row again, with two; the written record
carries both events and a moved lastAt; a fresh module state restoring from
the store answers the stored count; a person made by hand is written with
the knownBy set after creation. Without the re-set the second flush writes
nothing for the person and the stored count stays 1. The admin console and
user-facing pages docs say what the count now is.
A new report source, `credentialHolders`: one row per person, per mechanism, per role, read from what the directory already keeps. A passkey's role is the one chosen at its enrolment (`primary` or `mfa`, the key's own `role`, which sign-in enforces); its algorithm and lane are `keyAlgorithm()`'s. An authenticator app and an emailed code are `mfa`; a certificate and a Kerberos key are `primary`. The row carries how many credentials of that kind the person holds, their distinct algorithms and lanes, the earliest enrolment, the latest use, the RFC 8176 methods they have signed in with, the last multi-factor sign-in, and their groups. Nothing new is stored or indexed and nothing changes what is sealed. A filter on `mechanism` reads that mechanism's holders through the store's asked-names index (`holdersAsync()`, now on the directory module's exports as well as the credential store's), bounded by the holders; a filter on `memberOf` reads the group's members by name. A query naming neither reads every mechanism's holders, which a windowed directory refuses synchronously (STS-REPORT-0036) and `auto` mode turns into a job. Recovery codes and app passwords are not listed, because their attributes are outside that index. The census is the engine's count: `aggregate: "count"` with `groupBy` on `mechanism`, `role`, `algorithms` or `lanes`, narrowed to a community by a `memberOf` filter. `tests/report_query.js`'s `holders()` drives it against the directory double; `docs/reporting.md` and `report/CLAUDE.md` describe it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s for a certificate; the coverage notes, the crypto page and the reasoning in ldap/CLAUDE.md say the same.
…e is STS-LDAP-0187.
…ificate (#1061). identityOf()/checkSocket() take { stored: true }: a certificate whose chain runs through no authority this service holds is the one person or application entry of the realm storing its DER in userCertificate, found by the SHA-256 through the directory store's value index (windowed) or a checked index on its own clock (resident), never by common name or subject. Every door that reads a certificate as a person or application asks that way: /tls/sign-in and the sign-in screen, SCIM, the XACML gates, Shared Signals, WS-Trust and LDAP SASL EXTERNAL. The handshake no longer seeds a directory entry from an outside certificate. The console's /admin-api twin stores and removes a certificate (add-certificate, remove-certificate, GET /users/certificates). New codes per door; STS-LDAP-0182 retired.
… docs. The person page draws Stored certificates (Credentials, Factors) over GET /admin-api/users/certificates with Store and Remove; six translations. Coverage notes and the SCIM, LDAP and setting prose say an outside certificate is the one entry storing it. tests/stored_certificates.js holds the mapping, the admin actions and /tls/sign-in, the sign-in screen, SCIM and the XACML gates over real handshakes; the SSF, WS-Trust and LDAP SASL tests gain the outside cases; revocation_status and credential_seeds_no_entry store the foreign leaves they present or assert that nothing is seeded. pep-credential.js gains storeOnEntry()/--store-on, and the XACML, console bootstrap, global logout and pooling jobs store their leaves. The docs pages of every door carry the rule, how to store a certificate and the upgrade note.
…anged prose. The resident index is rebuilt whenever its clock moved, not only on a miss: it answers how many entries store a certificate, and a second holder left the first hit good and the count wrong. The revocation case presents a stored certificate whose CRL cannot be fetched, under hard-fail. The ldap, scim, settings and stsmetadata catalogs carry the new English and its six translations (and zh-Hant-HK's two).
…at the next realm load, not after ten minutes of STS-STORE-0088.
Every listener sent the leaf, the Issuing CA and the Intermediate, and left the Root out, which RFC 8446 section 4.4.2 allows. Every Root is called CN=sts Root CA, O=sts, so a client never handed the current one saw only a name and could match it to an older Root it already held. common/pki.js chainThroughRoot() is now the one place a reported chain is completed: the leaf, the stored chain, and the Root that signs its top, checked by signature. tls/tls_server.js presentedBundlePem() builds every socket's bundle from it, and the main port, the debugger, the custom and realm listeners, LDAPS, the channel between cells and SPIFFE's gRPC listeners all take their bundle from there. What a certificate is stored with (chainPem) is unchanged.
…1064). common/pki.js chainThroughRoot() completes every chain this service reports about its own certificates: the leaf, the stored chain, and the Root that signs its top, checked by signature. It accepts PEM or bare base64. * JOSE: every published JWK x5c (the realm JWKS and its standby keys, the pinned and grouped signers, the certified key pairs, /crypto/metadata) goes through helpers.x5cOf(); jose_certificate_header.js takes its token-header chains from chainThroughRoot() under its existing memo. * XML: helpers.x509DataXml() writes every ds:X509Data, the leaf first. Every signature's KeyInfo (crypto.js signXml() takes it as keyInfoXml, handed over by the seven signers) and every metadata KeyDescriptor, signing and encryption (SAML 2.0, WS-Federation, the back channel's listener keys, a federation relationship's own metadata) carry the chain and the Root. The vendored xmldsig.js is unchanged. * The remote PEP's listener certificate bundle and the console's chain download gain the Root too. HAIP 1.0 forbids the trust anchor in the x5c of a credential, a Status List Token and a signed OpenID4VP request; those keep it out, and the OpenID4VP verifier's x5c now says so at its call into chainThroughRoot().
…es nothing: the disable ended what it had to, and the enable superseded it.
…drive it by its documented 400 in the read sweep (#1061).
). tests/tls_presented_root.js completes a real handshake on the bundle every listener presents and counts four certificates arriving, the last of them this process's Root by fingerprint, verified by a client trusting that Root alone. It holds chainThroughRoot() (matched by signature, a foreign chain answered as it came, withoutRoot, bare base64), a published x5c and an XML X509Data ending at the Root with the leaf first, an XML signature carrying the chain still verifying here and under xml-crypto reading KeyInfo, and the listeners taking their bundle from presentedBundlePem(). docs/configure-tls.md says what the handshake sends and how to compare thumbprints; docs/pki.md lists every place a chain is reported and the four signed objects that keep the Root out. tls/CLAUDE.md and common/CLAUDE.md (3w) carry the reasoning.
tests/pki.js and the local protocol job sts_jwt_bearer_grant.js counted three members in an issued key pair's x5c; with the Root it is four. tests/tls_presented_root.js certifies the XML key itself before reading its chain, as tests/jose_certificate_header.js does, so it passes on its own and not only after an earlier file has certified it.
…ed, a refusal floats (#1066). The simplified view of /admin/users/new had no uid box, and nothing showed which fields the realm's attribute policy requires. The username box moves into the field grid as the first cell of the Name group, in both views. It still posts `username` and never `field.uid`, so one form cannot name two uids. Every field the policy requires carries fg-required: a red rule and an asterisk, beside the word "required", in the shared grid cell, so a person's Attributes tab outlines the same fields. The tile counts the policy's required attributes; it was a constant 1. A refused create floats in kit.flash(), as the application pages' refusals do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ner (#1066). WebKit.refusalBanner() draws a refusal as the application pages do: a kit.flash() warning with a heading and the reasons as a list. A refused create, a refused Fill, the Service account tab's owners and destination, and the shared owner-protection block now use it. That block also sits on the Groups, Roles and Applications Owners tabs, which float the same way. A refusal that came back as ?error= already floated through ConsoleRuntime.draw(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n force (#1066). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rid (#1066). rcbj withdrew the uid cell: the username box at the top of the form is the entry's uid. The form is drawn as it was on develop. The note under the username no longer calls it the only required field, because the attribute policy always requires cn and sn as well, outlined in the grid below. The outlined required fields, the policy-counted tile and the floating refusals stay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5d19086 described the endpoint on the metadata page without rewriting the endpoints and stsmetadata catalogs, so server_prose_catalogs failed on the English alone. The English is regenerated from the source and the two keys carry their six translations (es, fil, fr, sv, zh-Hans, zh-Hant).
…of the request-walk guard (#1061). certificateHolders() rebuilds its index over every entry when its clock moved, and GET /admin-api/users/certificates and the add/remove operations reach it from a request. The walk is the memory branch only: a windowed process visits directoryWindow.eachResident() — the resident containers — and asks the store's usercertificatesha256 index for the people and devices. Run #5's memory mode failed no_full_directory_walk_in_requests on it.
…s secrets have Copy buttons (#1068). A page shown once was drawn with no `up`, so its section was the last crumb, which is never a link. The page after a create had no way back to Directory → Users. ConsoleRuntime now hands the shell `once.up || { href: active, leaf: title }`, so every one-time page links to its section. A create and a credential reset answer WebAnswers.personTrail(): Admin console › Users › <person> › <title>, with the person's page linked through trailBar()'s new `via` crumbs. WebAnswers.secretBlock() draws each value shown once (a password, an activation or reset link, an app password, a new realm's password) with WebKit.copyButton() under it, which draw() already reveals and wires. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a read of the data-key rows, not dropped as malformed (#1070). applyChange() reported every change whose sealed name named a data encryption key the pulling process had not read yet as STS-STORE-0014 at error and dropped it: a new realm's seed rows, ~1,400 lines a full run. keystore.namesUnheldDek() now tells that apart from a malformed name; the data-key rows are read again (once per page, in prefetch()) and the change applied. A key still not held after a read is skipped under the new STS-STORE-0089, said once per key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.