Skip to content

Phase 5b: logging facade and redaction — documentation and phase record - #71

Merged
Wahbeh-Mohammad merged 11 commits into
mainfrom
19-phase-5b-logging-and-redaction-docs
Sep 18, 2026
Merged

Wahbeh-Mohammad merged 11 commits into
mainfrom
19-phase-5b-logging-and-redaction-docs

Conversation

@Wahbeh-Mohammad

Copy link
Copy Markdown
Contributor

Closes #19. Ninth and last PR of the phase-5 stack — the documentation and the phase record for phase 5b's two PRs below it. Targets the tests PR's branch. Its CLAUDE.md, READMEs, architecture.md and roadmap text are written on top of the reconciled 5a + 5c tip, so this is the tip at which the whole phase-5 stack's documentation is consistent; merging bottom-up lands it last.

What lands

13 files, +1,872 / −69, all Markdown.

  • The checklist, docs/work/mvp/phase5/phase5b/2026-09-09-phase5b-logging-and-redaction-checklist.md, written from the build: 28 own rows — 26 ✅, each naming its task and the test that proves it, with OBS-24 and OBS-10 stating the Ruby 3.2 floor's behaviour in the row (5c's P5-72, applied as P5-97); OBS-19 ⏳ to phase 8c Tasks 7, 9 and 15 (the header-drop policy's subject is a transport that drops; P5-32); OBS-37 ⏳ post-v1 with the async adapters (docs/first-release.md's OBS-32/OBS-37 entry). Plus fourteen cross-reference rows (XCUT-19's five clauses, XCUT-20, XCUT-11, CFG-24/CFG-25, CFG-21, CFG-14, CFG-16, SEAM-25 event shape only, BODY-19/BODY-22/BODY-34, BODY-20, OBS-23, PIPE-28, NFR-11) the way 4b, 4c, 5a and 5c carried theirs; what was built; the guards run red (48 mutations plus each review round's repair mutations, both interpreters); the audit groups run; thirty-one deviations from the plan's text (none lowers a gate); the findings routed; the postponed work; and one paragraph per review round recording its repair (the shape 5a's record used).
  • The phase 5b design's ledger gains an "As built" addendum, P5-91–P5-109: the split-reassembly redactor that never calls URI#to_s; Instrumentation.diagnostic; the async step's scope and settlement shape; one redactor per logging path; Keys::MESSAGE; the floor's compaction and restore; the top-level doubles; the step's span naming; then the four review rounds' rows — userinfo on every header route, unmatchable bad names and opaque queries, the structural header-name gate, the proxy URL shown through the redactor, the reserved-key table over all three OBS-5 sources, leading OWS, the UTF-8 fallback for a charset with no converter, every //-authority scrubbed per run, per-value header redaction, the async settlement on the source future. Numbering follows the phase-5 blocks fixed at dispatch. docs/sdk-design-ruby/ §8.1 and §10 are frozen; the consolidation of P5-16–P5-39 and P5-91–P5-109 and the addenda are a human's, stated in the roadmap note as every phase has. No frozen sentence is contradicted, so no C15.
  • docs/sdk-documentation/logging-and-redaction.md — new as-built page, sixteen fences run top to bottom as one script on 4.0.6 and 3.2.11 (122 checks, 0 fails, no credential in any printed result); architecture.md, the core README, README.md and docs/README.md updated to point at it. Three earlier as-built pages had described this layer as unbuilt and are corrected in place: tracing-and-metrics.md ("no pipeline step exists yet"), configuration.md (seven keys; "waits for that layer"), body.md ("nothing in core constructs either").
  • docs/first-release.md — one line corrected: the CTX-16 entry said the step "probes request.respond_to?(:context)"; as built the step probes nothing and names its span by the method token (P5-99). Nothing else in the file changes.
  • CLAUDE.md — the built-phases sentence now "Phases 0, 1, 2, 3a, 3b, 4a, 4b, 4c, 5a, 5b and 5c are built", the opening paragraph gains the logging layer, the lib-file count (126 → 141 under lib/dexpace/), the test-mirror exceptions (nine → eleven: instrumentation/render.rb, instrumentation/emitter.rb), the checklist count (eleven), and four lines in "Constraints that will bite" (redaction runs at #field and never at the sink; the sink is a duck type and core never requires logger; the emit-once latch releases its mutex before the sink call; a log-emission site is contained and a tracer or meter call never is). The roadmap gains the phase-5b status note after 5c's, naming what phases 2, 3b and 4 postponed here that landed (close_quietly's second route — the phase-2 comment asserting the drop is what changed; Hooks.notify's diagnostic; the body-logging caps' two wirings completing the item 5a half-supplied; P5-8 discharged), what it half-supplies (SEAM-25's shape only), the four review rounds, and three new inbound bullets for phase 10 (the design's stale verified facts 6 and 13; the unused-block warning the one-process gate cannot see; the four 3b/4b ceiling-reading tests).

Verification

  • bundle exec rake on Ruby 4.0.6 at this tip: exit 0, all seventeen gates green (2,050 / 58,450, 99.98%, YARD 0 undocumented), honest RuboCop 401 files clean.
  • ruby .claude/skills/housekeeping/probe.rb: no drift, all eight checks; verify_knowledge_structure.rb OK; the housekeeping and knowledge suites green.
  • Empty diff under docs/product-spec/, docs/sdk-design-ruby/, docs/knowledge/, docs/deviations.md, every earlier phase's documents, the phase-5 charter, and 5a's and 5c's documents.
  • The final reviewer re-derived every count CLAUDE.md and the status note state against the tree (141 lib files beside version.rb, 141 sig mirrors, eleven test-mirror exceptions, eleven checklists — the probe does not read the spelled-out lib count, so it was counted), read 28 checklist rows against their tests (26 proven; CFG-24/CFG-25 and CFG-16 partially — R3-1 and R3-2), confirmed the phase-8c tasks and the first-release.md entries exist where cited, and ran every page fence by hand on both interpreters.

Known follow-ups from the final review (not blocking)

  • The CFG-24/CFG-25 row's "the credential in neither channel" and P5-103's "the proxy URL through the redactor and never raw" hold for 30 of 38 spellings; R3-1's eight parsed-path spellings (on the code PR) need a ledger row beside P5-103/P5-107 and those two sentences re-scoped once the belt is per-run. R3-2's repair needs P5-109 and the AsyncStep class comment's "the order the sync path emits" paragraph updated — true of the log event, not yet of the instruments at BODY.
  • The roadmap note and this checklist record the review rounds as of round 2's repair; the round-3 findings are carried here and on the two PRs below, not in the record.
  • The as-built page uses a hand-rolled ArraySink and CountingMeter rather than the suite's doubles, so a reader needs nothing from test/support/.

@Wahbeh-Mohammad

Copy link
Copy Markdown
Contributor Author

Review record for the phase 5b stack (#69 → #70 → #71)

Four independent reviews, each by a fresh agent with no memory of the previous one, each re-running the gates itself on every tip and both interpreters, with a fix round by a fresh agent between each. The stack was cut from phase 5c's docs tip 032986b — itself rebased onto phase 5a's docs tip d5df0ca by a reconciliation agent at the start of the same run — and both bases were pinned and confirmed unchanged by every agent at start and finish. Every finding got a stable id, a severity, a file:line and the command output that was its evidence. approve required zero blocking and zero should-fix; the run was capped at four reviews and stopped at the fourth with its verdict still changes_requested, so the round-3 findings are carried into the PR bodies rather than fixed by the run.

Round Verdict Blocking Should-fix Nits Disposition
0 changes required 3 1 4 all 8 fixed
1 changes required 1 5 1 all 7 fixed
2 changes required 1 3 0 all 4 fixed (one dispute accepted for a sub-class)
3 (final) changes required 1 1 2 carried into the PR bodies

Nothing was skipped. The pattern across the four rounds is the point of the record: each round's blocking finding was a new layer of the redaction surface reached by the reviewer's own hostile inputs rather than by a mutation — a Location header's userinfo on the relative route (R0-3), the proxy warning's message field (R1-1), a non-whitespace prefix before the scheme (R2-1), the resolver's anchored belt (R3-1) — and each fix closed its class, after which the next reviewer found the next channel.

Round 0 → fixed in round 1

  • R0-1 blocking — logging_matrix_facts_test.rb's fact-3 case was order-dependent on the 3.2 floor (an earlier teardown's nil residue) and failed the 3.2.11 matrix row at the tests tip. Fixed on tests (f460c03): the case states each row's expected map, the same whether or not residue is present.
  • R0-2 blocking — the code tip was red under the honest RuboCop run (one 102-column line in the minimal diagnostics_test.rb repair). Fixed on code (6859bd4).
  • R0-3 blocking — OBS-11: Redactor#header_value('Location', '//user:secret@h/x') and 'http://user:secret@h/p x' returned the userinfo verbatim on the relative, surgery and sentinel-fallback routes, reaching the sink through the step at HEADERS. Fixed on code: the relative route rebuilds a network-path reference's authority with the placeholder; the surgery route substitutes the userinfo through an anchored per-pattern-timeout Regexp before cutting; the sentinel fallback runs that surgery (P5-100).
  • R0-4 should-fix — OBS-18's header-name gate lived only in the private Emitter, so event.field('http.request.header.authorization', 'Bearer SECRET') logged the value, and the as-built page showed it. Fixed on code: the gate is structural at Event#field by the reserved prefix (P5-102).
  • R0-5 nit — the as-built page's fence 8 results were false when the fences ran top to bottom (fence 5 left span.id in Fiber storage). Fixed on docs. R0-6 nit — the roadmap note's departure count. Fixed. R0-7 nit — a bad percent-encoding in a parameter name sentinelled the whole URL. Fixed on code (unmatchable name, value ***; P5-101). R0-8 nit — an opaque URI's query tail round-tripped unredacted. Fixed (P5-101).

Round 1 → fixed in round 2

  • R1-1 blocking — every malformed-proxy-URL path interpolated the raw URL into the warning text, and 5b's new http.instrumentation.config diagnostic carried it under Keys::MESSAGE, not a reserved key — HTTPS_PROXY=http://user:secret@proxy.corp wrote the credential into both channels. Fixed on code (5fd11af): the URL shown through Redactor::DEFAULT#header_value plus CFG-24's grammar belt, and the parser's message that repeated the value no longer quoted (P5-103).
  • R1-2 should-fix — reserved keys supplied through the logger's global context or the diagnostic fold bypassed the redactor. Fixed: the private ReservedKeys table applied to all three of OBS-5's sources (P5-104).
  • R1-3 should-fix — a leading space, tab or control before the scheme defeated the anchored surgery pattern. Fixed: a leading run of SP/HTAB/C0/DEL tolerated (P5-105).
  • R1-4 should-fix — Preview.render raised Encoding::ConverterNotFoundError for charset=utf-7, and the step's response event was lost to a diagnostic. Fixed: an EncodingError falls back to a UTF-8 decode with replacements (P5-106).
  • R1-5, R1-6 should-fix — two surviving mutations: the async failure event's OBS-24 bridge across a settling thread, and BODY-35's −1 declared-size filter. Fixed on tests with a case each.
  • R1-7 nit — P5-100 named only one non-authority spelling. Fixed on docs.

Round 2 → fixed in round 3

  • R2-1 blocking — any non-whitespace prefix before scheme://user:secret@host defeated the surgery pattern: a quoted HTTPS_PROXY wrote the client's own credential into the sink, and a bracketed Location reached it through the step. Fixed on code (fc93a29): the pattern is the unanchored //[^/?#]*@ applied with gsub, so every //-authority's userinfo is scrubbed wherever it sits in a parser-rejected value — <…>, quotes, parentheses, %20, +, @, NBSP, U+2028, obs-text, a doubled URL — linear to 1 MiB (P5-107). Dispute accepted for one sub-class: a value the parser accepts with credential-shaped text in its path (http:///user:pw@h/p, /http://…, a valid URI whose path spells a second authority) stays verbatim on the Location route, because OBS-14 forbids altering a path and RFC 3986 gives those no authority — documented and asserted.
  • R2-2 should-fix — a multi-valued Location was joined with ", " before redaction, so only the first value's userinfo was scrubbed. Fixed: per-value redaction before the join (P5-108).
  • R2-3 should-fix — on the async path a throwing meter was silently swallowed at BODY with a later settlement, and on an already-settled future the span was finished and the counter added twice. Fixed: the settlement work registered on the source future at every level, outside Future#then's rescue; add and finish exactly once in all six level/settlement combinations.
  • R2-4 should-fix — the OBS-1 zero-allocation assertion was flaky on 3.2.11 with a negative once-per-process delta. Fixed on tests: 5c's shared AllocationDelta helper now reports the figure two consecutive measurements agree on (0/60 after; a deviation recorded, 5c's suites re-run green).

Round 3 (final) — open, carried into the PR bodies

  • R3-1 blocking — proxy/resolution.rb:178: the resolver's belt CREDENTIAL_BEFORE_AT = \A[^/?#]*@ is anchored at the start of the shown value, so a proxy URL the parser accepts with the credential in its path — http:/user:secret@proxy.corp:3128 (a single-slash typo), http:///…, /http://…, //@…, socks5:/…, http:/ /…, http:/\… — 8 of 38 spellings, writes the operator's password into Kernel#warn and the http.instrumentation.config sink record on 4.0.6 and 3.2.11. The other 30 show ***:***@ or resolve. The reviewer prototyped a per-run gsub belt and reverted it: all 38 spellings clean with both owning suites green. R1-1's class through the one channel the two repairs did not reach; a proxy URL has no path worth preserving in a warning. Listed on the code PR; to be fixed there before merge.
  • R3-2 should-fix — async_step.rb:107: at BODY the derived future is fulfilled before the step's finish (then registered before on_settle), so a caller's 2 s continuation lands in http.request.duration and the span (2,000 ms at BODY; 0 ms at HEADERS and on the sync path). Fix: register the settlement on the source before deriving. Listed on the code PR.
  • R3-3 nit — the OBS-8 race test catches an unsynchronised latch probabilistically on 3.2.11 (4 of 5 re-runs). Listed on the tests PR.
  • R3-4 nit — the Redactor's YARD never says where it is applied. Listed on the code PR.

What the final reviewer verified, in its own runs

  1. Gates — code tip fc93a29: all seventeen individually on 4.0.6, all green including the SimpleCov floor (1,849 runs, 94.81%), honest RuboCop 385 files clean; the matrix set on 3.2.11 (94.83%). Tests tip 36952b4: full bundle exec rake green on 4.0.6 (2,050 runs / 58,450 assertions, 99.98%), RuboCop 401 files clean, three seeds identical, the matrix set on 3.2.11 and 3.4.10, the OBS-1 assertion 0/30 whole-file and 0/30 alone on the floor. Docs tip d98191e: full rake green, probe and knowledge verifiers clean, all sixteen page fences run as one script on both interpreters (122 checks, 0 fails, no credential in any result). The only non-pass in any round was the hostile-environment run's four pre-existing 3b/4b tests that read the live materialisation ceiling (phase 10 inbound bullet 42), unchanged across all four rounds and no 5b suite among them.
  2. Every prior finding individually — R2-1 through 17 prefixed Location spellings via the redactor and via a real pipeline at HEADERS, and a quoted/bracketed/doubled HTTPS_PROXY through the resolver, with M35–M37 red on both interpreters; R2-2 with M38/M39; R2-3 in all six level/settlement combinations with M40/M41/M56; R2-4 by 0/30 + 0/30 + 0/5 at the reviewer's seed with the helper still catching M02.
  3. The mutation battery — 56 single-edit mutants applied by the reviewer (47, 53 and 56 in the earlier rounds), every one caught, ten on 3.2.11 as well; M07 (the latch flip without the mutex) probabilistically on the floor (R3-3).
  4. The redaction battery by hand, both interpreters — 65 inputs through Redactor#url, 78 through #header_value, 25 hostile Location values through a real pipeline at HEADERS, 38 HTTPS_PROXY spellings through Proxy.resolve with Kernel#warn captured (the 8 leaks of R3-1); linearity of the surgery pattern on six adversarial shapes at 10 KiB, 100 KiB and 1 MiB.
  5. The layer by experiment — OBS-1 as identity and a 0.0 delta; OBS-6/OBS-7; OBS-8 with 16 threads and a re-entrant sink under a 10 s join; OBS-10/OBS-24 floor-aware; OBS-20 through a real pipeline (a raising sink → the transport's response and two http.instrumentation.log diagnostics; raising #info and #warn → the response, nothing emitted); the HEADERS payload, NONE, BODY with the cap from configuration, iso-8859-1 and octet-stream bodies; OBS-35; the four wirings; the step and the async step through real pipelines; 5c's independence subprocess (1 run, 0 failures) and diagnostics.rb alone defining only Diagnostics; the # Phase 5b: block moved above 5c's by hand.
  6. Layering — main ⊂ d5df0ca ⊂ 032986b ⊂ fc93a29 ⊂ 36952b4 ⊂ d98191e, all three bases unchanged; fifteen single-parent commits, subjects 45–68 characters, no attribution lines; every file in its layer (the code branch's test/ changes exactly the six pins a code change invalidated plus the manifest at 956 rows, 16 Keys and 8 Events rows equal to the constant counts, no row for Render, Emitter, ReservedKeys or CollisionLatch); the only earlier-phase lib files changed are Task 14's and Task 6's set, each a widening; sig/ 141 == 141; empty diffs under the frozen trees, docs/deviations.md, every earlier phase's documents, the charter, 5a's and 5c's.
  7. Report discrepancies — the fixer's "closed for its class" claim for R2-1, P5-103 and the CFG-24/CFG-25 row are false for the eight parsed-path proxy spellings (R3-1); the fixer's "the order the sync path emits" claim for P5-109 is true of the log event and not of the instruments at BODY (R3-2); assertion counts off by the registry-claim race branch; fence check counts differ by extractor.

Run: workflow wf_5509525a-dfc, 9 agents (1 reconciler, 1 implementer, 4 reviewers, 3 fixers), 4.3M tokens, 9.2 h.

@Wahbeh-Mohammad
Wahbeh-Mohammad force-pushed the 19-phase-5b-logging-and-redaction-tests branch from 36952b4 to a40dbc5 Compare September 18, 2026 08:56
@Wahbeh-Mohammad
Wahbeh-Mohammad force-pushed the 19-phase-5b-logging-and-redaction-docs branch from d98191e to 3c8160c Compare September 18, 2026 08:56
@Wahbeh-Mohammad
Wahbeh-Mohammad force-pushed the 19-phase-5b-logging-and-redaction-tests branch from a40dbc5 to 60d3e68 Compare September 18, 2026 09:04
@Wahbeh-Mohammad
Wahbeh-Mohammad force-pushed the 19-phase-5b-logging-and-redaction-docs branch from 3c8160c to ab6e06b Compare September 18, 2026 09:04
@Wahbeh-Mohammad
Wahbeh-Mohammad force-pushed the 19-phase-5b-logging-and-redaction-tests branch from 60d3e68 to f5a9941 Compare September 18, 2026 09:12
@Wahbeh-Mohammad
Wahbeh-Mohammad force-pushed the 19-phase-5b-logging-and-redaction-docs branch from ab6e06b to cfd699f Compare September 18, 2026 09:12
Add fourteen suites under test/dexpace/instrumentation/ -- twelve
mirrors of the phase-5b files plus the floor-straddling matrix facts as
a standing test and the four downstream wirings -- and rewrite 5c's
diagnostics mirror as this phase's, asserting the fold, the snapshot
bridge across a real thread boundary, and what the 3.2 floor makes of a
restored key, floor-aware through FiberStorageFacts. The two steps are
driven through the real Pipeline and AsyncPipeline over phase 2's
transport fakes and Completer, with 5c's recording tracer factory and
meter and 5a's FakeClock, and every configuration a suite consults is
built over FakeConfigSource seams so the process environment is never
read.

Add two top-level doubles under test/support/: RecordingSink, a real
in-memory sink with per-severity enablement, and DiagnosticContext, the
save-and-restore block for Fiber storage.

Every "never throws" claim is asserted on the substituted value; the
inert event is measured at zero allocations per chained call; and the
four tests the guard pass found missing are here: a sink that re-enters
the logger from inside its own write, the async path's header
redaction, a recording cursor whose fork raises, and the headers level
with a cap supplied. Forty-eight single-edit mutations of lib/ are
caught by these suites on 4.0.6 and 3.2.11.
Review round 0's findings, each with the suite that now runs red on
its revert. The redactor suite gains the three inputs that leaked
through Redactor#header_value -- a network-path reference on the
relative route, an authority the parser rejects on the surgery route,
and a userinfo on the exploding-policy fallback -- plus the `%zz`
parameter name that used to sentinel the whole URL and the opaque
URI's query-shaped tail (P5-100, P5-101). The step suite drives four
hostile Location values through a real pipeline at HEADERS and asserts
the credential in no payload. The event suite gains a HeaderGateTest
class: a credential header written straight into Event#field is
REDACTED, dropped in omit mode, and the name gate runs before the
URL-value redactor (P5-102).

Fact 3 of logging_matrix_facts_test.rb was order-dependent on the 3.2
floor: every teardown's `Fiber[OTHER] = nil` is retained there, so
`storage == prior` held for any test but the first and the assertion
"exact iff = nil deletes" failed on 12 of 13 orders. The expected map
is now stated for the row -- `prior` where `= nil` deletes,
`prior.merge(OTHER => nil)` on the floor -- which is the same map
whether or not the residue was already present. Green on 3.2.11 with
seeds 9818, 1 and 42 and standalone; the old spelling reproduces the
failure on seed 9818.
Twelve cases for review round 1 of phase 5b. The proxy resolver's
warning and its config diagnostic are driven with nine
credential-bearing malformed HTTPS_PROXY values -- the no-port,
out-of-range, non-numeric, space-in-host, no-host, double-@,
scheme-less, network-path and query-carrying spellings -- asserting the
placeholder in both channels and the credential in neither, and the
not-a-URI message named once without the parser's text (R1-1,
P5-103). The two ambient sources meet the reserved-key table: a
url.full, an Authorization and a Location in the logger's global
context are redacted once at build and the caller's Hash is untouched;
the unfiltered and the listed fold redact the same keys; omit mode
drops a non-allow-listed header from either source (R1-2, P5-104). A
Location with a leading SP, HTAB, VT, NUL or a trailing high byte
loses its userinfo through the redactor and through the step at
HEADERS over an inbound Headers built with the space, while the four
non-authority spellings are written back as given (R1-3, P5-105).
charset=utf-7 and iso-2022-jp-2 decode as UTF-8 at Preview.render and
the step at BODY still emits the http.response event (R1-4, P5-106).

The two mutations that survived round 1 now fail: a settlement failed
from a Thread whose own Fiber storage differs emits the failure event
under the caller's captured trace.id and span.id and restores the
settler's keys (R1-5); a chunked request and response body of declared
length -1 put no size field on either event at HEADERS (R1-6).

Three suites are split under Metrics/ClassLength: the redactor's
surgery-route cases move to SurgeryRouteTest, the step's header cases
to HeaderRedactionTest, and WritingTransport moves into the step
suite's shared Fixtures.
The surgery route: every prefix review round 2 named before a real
authority -- RFC 3986 Appendix C's delimiters, quotes, parentheses, a
word, an encoded space, `+`, `@`, a backslash, an NBSP, a line
separator, the BINARY obs-text spellings -- and a doubled proxy URL,
through Redactor#header_value, through a real pipeline at HEADERS over
inbound Headers, and through Proxy.resolve with a quoted, bracketed or
doubled HTTPS_PROXY (P5-107). The P5-105 assertion that a non-whitespace
prefix is written back verbatim is gone; the not-an-authority list is
now what the parser accepts without one and the backslash spellings, and
a path that spells a second authority is asserted as OBS-14's path.

Per-value redaction: two Locations through the step and an Array through
Event#field, each value redacted before the ", " join (P5-108).

The async step under a throwing meter at every level: a later settlement
raises into the settler while the caller still receives the response,
an inline settlement fails the request, and the counter and the span
finish are counted at exactly one each way (P5-109).

AllocationDelta#allocations_per_call returns the figure two consecutive
measurements agree on: on the 3.2.11 floor a one-time cost of 7 or 28
objects can land inside a measured block after the warm-up, once per
process and test-order dependent, so a single measurement came back
negative in roughly one whole-file run in fifteen and the exact zero
assertion failed it (R2-4). A change to 5c's support file; its five
allocation suites re-run green and the M02 guard still runs red.
The redactor suite's not-an-authority list gains a path-absolute
reference (`/http://user:secret@h/p`, which the parser accepts as a
path and the relative route writes back) and a `/ /` that is not a
`//` (P5-100, P5-107): both surfaced by re-running review round 2's
battery against the repaired redactor, and both are what RFC 3986
decides rather than what the surgery pattern reaches.
Write the phase-5b checklist: twenty-eight own rows (26 implemented,
OBS-19 deferred to phase 8c and OBS-37 post-v1) plus fourteen
cross-reference rows, the matrix facts re-run on all four interpreters,
the floor decision stated once, the forty-eight guards run red with
their messages, and twenty-seven departures from the plan's text. Add
the design ledger's as-built addendum, rows P5-91 to P5-99, correcting
the design's verified facts 6 and 13 beside the facts themselves.

Add docs/sdk-documentation/logging-and-redaction.md, every fence run on
4.0.6 and 3.2.11 with the three interpreter differences stated where
they appear, and point architecture.md, the core README, README.md and
docs/README.md at it. Bring the four earlier as-built sentences that
described this layer as unbuilt to what is true: the tracing page's
"no pipeline step exists yet", the configuration page's seven keys and
its proxy warning, and the body page's "nothing in core constructs
either".

Re-derive CLAUDE.md's claims from the tree: eleven built phases, one
hundred and forty files under lib/dexpace/ beside version.rb, eleven
private constants without a test mirror, eleven checklists, and four
constraints-that-bite lines for the logging layer. Append the phase-5b
status note to the roadmap after 5c's and three phase-10 inbound
bullets: the design's two stale verified facts, the unused-block warning
the one-process gate cannot see, and the four earlier tests that read
the live materialisation ceiling. Correct the one first-release line
that described the step's context probe.
Review round 0 closed three blocking findings and one should-fix on
the code and tests branches; this commit carries them into the
record. The design's as-built addendum gains P5-100 (OBS-11 on every
route of Redactor#header_value, and its collision with OBS-16's
"returned verbatim" resolved for OBS-11), P5-101 (a bad
percent-encoding in a parameter name is unmatchable, an opaque URI's
query-shaped tail is redacted) and P5-102 (OBS-18's name gate is
structural at Event#field), and two more "reads differently against
the source" bullets beside the build's four: R9's relative and
unparseable rows never considered an authority, and the reserved-key
table routed a header key through the value redactor alone.

The checklist's OBS-11, OBS-12, OBS-15, OBS-16, OBS-17 and OBS-18
rows state the repaired behaviour and cite the tests that hold it; a
second guard table records the ten mutations run red after the repair
on 4.0.6 and 3.2.11, with the two test-side and two docs-side findings
that have no mutation; deviations 28 to 31 and a findings-routed bullet
carry the round; the gate paragraph carries the re-proven figures
(2,031 runs, 99.98%, honest RuboCop clean at every tip, 385 files at
the code tip, three seeds on the floor).

The as-built page's first record no longer shows a credential
reaching the sink -- Authorization renders as REDACTED and the Location
example carries a userinfo that comes back as ***:***@ -- and fence 5
now clears the carrier it set, so the sixteen fences run top to bottom
in one process with every stated result holding on 4.0.6 and 3.2.11.
CLAUDE.md's redaction constraint states the name gate and the
every-route userinfo rule; the roadmap's status note counts thirty-one
departures, cites P5-91 to P5-102, and records the round in the shape
5a's note used.
The design's as-built addendum gains rows P5-103 through P5-106 --
the proxy warning's redacted URL, the reserved-key table over all
three of OBS-5's sources, the surgery pattern's tolerated leading
whitespace, and Preview.decode's UTF-8 fallback for a converter-less
charset -- two more "reads differently" entries against the design's
own text (the table stated at #field alone; "Encoding.find unreachable
from here"), a round-1 paragraph beside round 0's, and P5-100's closing
sentence extended to the backslash, triple-slash and non-scheme
spellings RFC 3986 excludes (R1-7).

The checklist's OBS-9, OBS-10, OBS-11, OBS-16, OBS-18, OBS-24, OBS-38,
OBS-39, XCUT-20 and CFG-24/CFG-25 rows state what changed and cite the
new tests; a third guard table records mutations 59 through 68 run red
on 4.0.6 and 3.2.11; deviations 32 through 37 itemise the round; the
findings-routed list closes its seven findings in this stack; and the
gate paragraph carries the re-proven figures (2,043 runs at the tests
and docs tips, 99.98%; the code tip at 94.81% on both rubies).

The as-built page shows the ambient sources redacted, a leading OWS
kept on the surgery route, the utf-7 preview and a credential-bearing
proxy URL named redacted in both channels, its sixteen fences re-run as
one script on 4.0.6 and 3.2.11; CLAUDE.md's redaction constraint states
the table's three sources, the leading-OWS route and the proxy warning;
the roadmap's phase-5b note records the round and counts thirty-seven
departures and P5-91 through P5-106.
The design's as-built addendum gains P5-107 (the surgery route
substitutes every //-authority wherever it sits), P5-108 (an Array
under a header key is redacted per value before the join) and P5-109
(the async settlement work sits on the source future, and the teardown
has one owner), the round-2 paragraph, P5-100's two parsed-path
spellings and a superseded closing clause on P5-105.

The checklist's OBS-1, OBS-11, OBS-16, OBS-17, OBS-20, OBS-34 and
CFG-24/CFG-25 rows state the round, the matrix table gains the floor's
one-time allocation cost, departure 15 reads the head's new shape, a
fourth guard table carries guards 69-76, and deviations 38-41 record
the three repairs and the change to 5c's allocation helper; the gate
figures are re-derived from the tree (2,050 runs, 5,655 / 5,656).

The as-built page's redactor fence gains a prefixed and a doubled
value, its prose states the every-authority rule, the per-value join
and the async step's one-owner teardown; CLAUDE.md's redaction and
containment constraints and the roadmap's phase-5b status note say the
same.
The code tip's 3.2.11 coverage is 94.83% (5,287 / 5,575) as run, not
the extrapolated 94.81% (…/5,576); the not-an-authority lists in the
checklist's OBS-11 row, P5-107's row and the as-built page name the
path-absolute reference and the `/ /` spelling the round-2 battery
re-run surfaced.
@Wahbeh-Mohammad
Wahbeh-Mohammad force-pushed the 19-phase-5b-logging-and-redaction-tests branch from f5a9941 to 5e420e6 Compare September 18, 2026 09:17
@Wahbeh-Mohammad
Wahbeh-Mohammad force-pushed the 19-phase-5b-logging-and-redaction-docs branch from cfd699f to da80b0b Compare September 18, 2026 09:17
@Wahbeh-Mohammad
Wahbeh-Mohammad changed the base branch from 19-phase-5b-logging-and-redaction-tests to main September 18, 2026 09:23
@Wahbeh-Mohammad
Wahbeh-Mohammad merged commit f1fe848 into main Sep 18, 2026
5 checks passed
@Wahbeh-Mohammad
Wahbeh-Mohammad deleted the 19-phase-5b-logging-and-redaction-docs branch September 18, 2026 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Phase 5b: Logging Facade and Redaction

1 participant