of a page * * Attributes (all on the contents element except where noted): * wa-toc-element="contents" | "link" | "table" | "ix-trigger" * -- structural markers. Multiple * "table" elements are allowed * and each receives a TOC copy. * wa-toc-offsettop="" -- click-scroll offset only * (e.g. clear a fixed navbar) * wa-toc-offsetbottom="" -- shifts active line down * wa-toc-activeline="" -- where headings activate * during scroll. Default 33vh. * wa-toc-headings="" -- restrict which heading levels * are collected. Default h2..h6. * wa-toc-hideurlhash="true" -- suppress #hash on click * wa-toc-ancestoractive="true" -- mark ancestors active too * wa-toc-instance="" -- (on a shared parent) scopes * multiple TOCs on one page * * In-text directives (inside heading plain text, stripped at render): * [wa-toc-omit] -- exclude this heading * [wa-toc-h2] .. [wa-toc-h6] -- override heading level in * the TOC only * * Active state uses Webflow's native `.w--current` class so styling can be * configured directly in the Webflow Designer. */ (function () { 'use strict'; var ACTIVE_CLASS = 'w--current'; var ATTR = 'wa-toc-element'; var DIRECTIVE_RE = /\[wa-toc-(omit|h([2-6]))\]/i; var DEFAULT_HEADING_SELECTOR = 'h2, h3, h4, h5, h6'; // ---------- utilities -------------------------------------------------- /** * Slugify heading text into an id. Mirrors Webflow's native id generation * closely enough for hash navigation: lowercase, spaces 鈫 hyphens, drop * non-alphanumeric except hyphens, collapse runs of hyphens. */ function slugify(text) { return String(text) .toLowerCase() .trim() .replace(/[\s_]+/g, '-') .replace(/[^a-z0-9\-]/g, '') .replace(/-+/g, '-') .replace(/^-|-$/g, ''); } /** Ensure a slug is unique within a Set, suffixing -2, -3, ... if needed. */ function uniqueSlug(base, used) { if (!base) base = 'section'; var slug = base; var i = 2; while (used.has(slug)) { slug = base + '-' + i++; } used.add(slug); return slug; } /** * Convert a CSS length string (e.g. "8rem", "120px", "10vh") to pixels, * resolved against the document root. Returns 0 on failure. */ function cssLengthToPx(value) { if (!value) return 0; var probe = document.createElement('div'); probe.style.position = 'absolute'; probe.style.visibility = 'hidden'; probe.style.height = value; probe.style.width = '0'; document.body.appendChild(probe); var px = probe.getBoundingClientRect().height; document.body.removeChild(probe); return isFinite(px) ? px : 0; } /** * Parse the wa-toc-headings attribute into a CSS selector. Accepts: * "h2,h3" 鈫 "h2, h3" * "h2 h3 h4" 鈫 "h2, h3, h4" * "2,3" 鈫 "h2, h3" * "H2, h3" 鈫 "h2, h3" (case-insensitive) * Tokens outside h2..h6 are dropped. Returns the default selector when * the input is empty or yields no valid levels 鈥 keeps behavior safe. */ function parseHeadingLevels(raw) { if (!raw) return DEFAULT_HEADING_SELECTOR; var tokens = String(raw) .toLowerCase() .split(/[\s,]+/); var levels = []; var seen = {}; for (var i = 0; i < tokens.length; i++) { var tok = tokens[i].trim(); if (!tok) continue; // Accept "h2" or "2". var m = /^h?([2-6])$/.exec(tok); if (!m) continue; var tag = 'h' + m[1]; if (seen[tag]) continue; seen[tag] = true; levels.push(tag); } if (!levels.length) return DEFAULT_HEADING_SELECTOR; return levels.join(', '); } /** Find the closest ancestor (or self) carrying wa-toc-instance. */ function instanceOf(el) { var node = el; while (node && node.nodeType === 1) { if (node.hasAttribute('wa-toc-instance')) { return node.getAttribute('wa-toc-instance'); } node = node.parentElement; } return ''; // default unnamed instance } /** Find the link template within a given root, matching wa-toc-element="link". */ function findLinkTemplate(root) { return root.querySelector('[' + ATTR + '="link"]'); } /** * The link template may be applied directly to an , or to a text * element nested inside an . Resolve to the actual we should clone. */ function resolveAnchorTemplate(linkEl) { if (linkEl.tagName === 'A') return linkEl; var anchor = linkEl.closest('a'); return anchor || linkEl; // fall back to the marked element itself } /** * Within a cloned link, find the text-bearing element that originally had * wa-toc-element="link". If the marker was on the anchor itself, the * anchor is the text holder. */ function findTextHolder(clonedAnchor, originalMarker) { if (originalMarker.tagName === 'A') return clonedAnchor; // The marker was a descendant; find the same descendant in the clone by // walking the same path. var path = []; var node = originalMarker; var rootAnchor = originalMarker.closest('a'); while (node && node !== rootAnchor) { var parent = node.parentElement; if (!parent) break; path.unshift(Array.prototype.indexOf.call(parent.children, node)); node = parent; } var current = clonedAnchor; for (var i = 0; i < path.length; i++) { current = current.children[path[i]]; if (!current) return clonedAnchor; } return current; } // ---------- per-instance pipeline ------------------------------------- function buildInstance(contentsEl) { var instanceId = instanceOf(contentsEl); // Locate the link template in the same instance. var linkMarker = null; var allLinks = document.querySelectorAll('[' + ATTR + '="link"]'); for (var i = 0; i < allLinks.length; i++) { if (instanceOf(allLinks[i]) === instanceId) { linkMarker = allLinks[i]; break; } } if (!linkMarker) return null; // nothing to do var anchorTemplate = resolveAnchorTemplate(linkMarker); // Locate every wa-toc-element="table" in the same instance. The TOC will // be rendered into each one 鈥 same headings, same active-state tracking, // independent styling contexts. If none are present, fall back to a // single mount at the link template's parent (Finsweet-compatible). var mountEls = []; var allTables = document.querySelectorAll('[' + ATTR + '="table"]'); for (var j = 0; j < allTables.length; j++) { if (instanceOf(allTables[j]) === instanceId) { mountEls.push(allTables[j]); } } if (!mountEls.length) { var fallback = anchorTemplate.parentElement; if (!fallback) return null; mountEls.push(fallback); } // Read config off the contents element. var offsetTopVal = cssLengthToPx(contentsEl.getAttribute('wa-toc-offsettop')); var offsetBotVal = cssLengthToPx(contentsEl.getAttribute('wa-toc-offsetbottom')); var hideHash = contentsEl.getAttribute('wa-toc-hideurlhash') === 'true'; var ancestorMode = contentsEl.getAttribute('wa-toc-ancestoractive') === 'true'; var activeLineAttr = contentsEl.getAttribute('wa-toc-activeline'); var activeLineRaw = activeLineAttr; // keep raw for vh re-resolution on resize var headingSelector = parseHeadingLevels(contentsEl.getAttribute('wa-toc-headings')); // Collect heading elements in document order, applying directives. var rawHeadings = contentsEl.querySelectorAll(headingSelector); var headings = []; var usedIds = new Set(); for (var k = 0; k < rawHeadings.length; k++) { var h = rawHeadings[k]; var text = h.textContent || ''; var levelOverride = null; var omit = false; // Strip *all* directive occurrences from the rendered heading text and // capture the first relevant one. We also clear them from the live DOM // so readers don't see "[wa-toc-h4]My heading". var cleaned = text; var match; while ((match = DIRECTIVE_RE.exec(cleaned))) { if (match[1].toLowerCase() === 'omit') { omit = true; } else if (match[2]) { levelOverride = parseInt(match[2], 10); } cleaned = cleaned.slice(0, match.index) + cleaned.slice(match.index + match[0].length); } cleaned = cleaned.trim(); if (cleaned !== text) { // Replace directive markers in text nodes only, preserving inline // markup like / children. stripDirectivesInPlace(h); } if (omit || !cleaned) continue; // Assign / preserve id for hash linking. var id = h.id; if (!id) { id = uniqueSlug(slugify(cleaned), usedIds); h.id = id; } else { usedIds.add(id); } var actualLevel = parseInt(h.tagName.charAt(1), 10); var displayLevel = levelOverride || actualLevel; headings.push({ el: h, id: id, text: cleaned, level: displayLevel, }); } if (!headings.length) return null; // The TOC must start at H2. If somebody overrode levels, normalize so the // shallowest level encountered renders at the outermost nesting depth. var minLevel = headings.reduce(function (m, h) { return Math.min(m, h.level); }, 6); // Build the nested DOM. We need *wrappers* so children of an H# can be // appended next to (not inside) the link itself. Per Finsweet's docs: // "Each Heading link template must be enclosed in a div wrapper, and // this div wrapper should be a child of the div associated with the // preceding Heading level." // // We model this with a per-level "wrapper" element. The first child of // the wrapper is the link; subsequent children are nested wrappers. var rootContainer = document.createElement('div'); rootContainer.setAttribute('wa-toc-element', 'list'); var entries = []; // parallel array: { link, wrapper, heading } var stack = [{ level: minLevel - 1, wrapper: rootContainer }]; for (var n = 0; n < headings.length; n++) { var heading = headings[n]; // Pop until the top of stack is the parent level (one shallower). while (stack.length > 1 && stack[stack.length - 1].level >= heading.level) { stack.pop(); } var parentWrapper = stack[stack.length - 1].wrapper; // Build wrapper for this heading. var wrapper = document.createElement('div'); wrapper.setAttribute('wa-toc-element', 'h' + heading.level + '-wrapper'); // Clone the link template. var link = anchorTemplate.cloneNode(true); // Remove the marker attribute on the clone to avoid re-detection. var markersInClone = link.querySelectorAll('[' + ATTR + '="link"]'); for (var mi = 0; mi < markersInClone.length; mi++) { markersInClone[mi].removeAttribute(ATTR); } if (link.getAttribute(ATTR) === 'link') link.removeAttribute(ATTR); // Set the text on the resolved text holder. var holder = findTextHolder(link, linkMarker); holder.textContent = heading.text; // Set href and tag with entry index so we can find this same link // inside each cloned mount and wire it up. link.setAttribute('href', '#' + heading.id); link.setAttribute('data-wa-toc-idx', String(entries.length)); wrapper.appendChild(link); parentWrapper.appendChild(wrapper); entries.push({ heading: heading, // Filled in below: one cloned link per mount target. links: [], ixTriggers: [], }); stack.push({ level: heading.level, wrapper: wrapper }); } // Mount the built tree into every target. We clone for *every* mount // (including the first) so `rootContainer` stays intact across the loop // and serves as a clean source for each subsequent mount. Querying // inside each mount by data-wa-toc-idx lets us collect the per-mount // link nodes back into the corresponding entry. function mountInto(target, treeChildren) { while (target.firstChild) target.removeChild(target.firstChild); for (var c = 0; c < treeChildren.length; c++) target.appendChild(treeChildren[c]); // Pull this mount's links into entries. var mountedLinks = target.querySelectorAll('[data-wa-toc-idx]'); for (var ml = 0; ml < mountedLinks.length; ml++) { var idx = parseInt(mountedLinks[ml].getAttribute('data-wa-toc-idx'), 10); if (entries[idx]) entries[idx].links.push(mountedLinks[ml]); // Per Finsweet ix-trigger semantics: triggers live inside the link // template, fire on this entry's active transitions. var triggers = mountedLinks[ml].querySelectorAll('[' + ATTR + '="ix-trigger"]'); for (var tg = 0; tg < triggers.length; tg++) { entries[idx].ixTriggers.push(triggers[tg]); } } } for (var t = 0; t < mountEls.length; t++) { var cloned = rootContainer.cloneNode(true); var children = Array.prototype.slice.call(cloned.children); mountInto(mountEls[t], children); } // Strip the temporary index marker now that all mounts have been wired. for (var en = 0; en < entries.length; en++) { for (var lk = 0; lk < entries[en].links.length; lk++) { entries[en].links[lk].removeAttribute('data-wa-toc-idx'); } } // Click handling: smooth scroll, hash control. Listener runs in capture // phase and stops propagation so any external listener (e.g. Webflow's // own anchor handling, or a parent click handler on the link wrapper) // can't run a competing scroll. We also reread offsetTopVal on each // click in case the page has resized 鈥 vh-based offsets need this. function onLinkClick(entry, ev) { ev.preventDefault(); ev.stopPropagation(); var liveOffsetTop = cssLengthToPx(contentsEl.getAttribute('wa-toc-offsettop')); var targetTop = entry.heading.el.getBoundingClientRect().top + window.pageYOffset - liveOffsetTop; window.scrollTo({ top: targetTop, behavior: 'smooth' }); if (!hideHash) { if (history.replaceState) { history.replaceState(null, '', '#' + entry.heading.id); } else { location.hash = '#' + entry.heading.id; } } } entries.forEach(function (entry) { entry.links.forEach(function (link) { link.addEventListener( 'click', function (ev) { onLinkClick(entry, ev); }, true, ); }); }); return { contentsEl: contentsEl, entries: entries, offsetTop: offsetTopVal, offsetBottom: offsetBotVal, activeLineRaw: activeLineRaw, ancestorMode: ancestorMode, activeIndex: -1, previousIxState: new WeakMap(), }; } /** * Walk text nodes inside `el` and remove [wa-toc-omit] / [wa-toc-h#] markers * so they don't appear in the rendered page. */ function stripDirectivesInPlace(el) { var walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null); var node; var toFix = []; while ((node = walker.nextNode())) { if (DIRECTIVE_RE.test(node.nodeValue)) toFix.push(node); } toFix.forEach(function (n) { n.nodeValue = n.nodeValue.replace(/\[wa-toc-(omit|h[2-6])\]/gi, '').trim(); }); } // ---------- active-link tracking -------------------------------------- /** * Default active-line position when wa-toc-activeline isn't set. * 1/3 of viewport height 鈥 a heading activates as soon as it scrolls up * into the upper third of the viewport, while still comfortably visible. */ var DEFAULT_ACTIVE_LINE_FRACTION = 1 / 3; /** * Resolve the active-line position (in px from viewport top) for an * instance. wa-toc-activeline accepts any CSS length; if absent, falls * back to a fraction of viewport height. Recomputed on every call so * vh-based values track resizes naturally. */ function resolveActiveLine(instance) { if (instance.activeLineRaw) { var px = cssLengthToPx(instance.activeLineRaw); if (px > 0) return px; } var viewportH = window.innerHeight || document.documentElement.clientHeight; return viewportH * DEFAULT_ACTIVE_LINE_FRACTION; } /** * Determine which heading owns the viewport. * * Rule: the active heading is the *last* one whose top has crossed the * "active line" 鈥 a horizontal line in the viewport configured by * wa-toc-activeline (default: 1/3 of viewport height). * * `wa-toc-offsetbottom` extends the line further down 鈥 i.e. the previous * heading stays active until the next heading reaches `offsetBottom` past * the active line. * * Note: this is independent of `wa-toc-offsettop`, which only affects * smooth-scroll-on-click (so a fixed navbar can be cleared without * shifting where headings activate). * * Entries are scanned in document order and we take the maximum match * rather than break early, so the result is correct even if CSS reorders * elements relative to DOM order. * * Returns -1 when no heading has yet reached the active line. */ function computeActiveIndex(instance) { var entries = instance.entries; if (!entries.length) return -1; var threshold = resolveActiveLine(instance) + instance.offsetBottom; var active = -1; for (var i = 0; i < entries.length; i++) { // viewport-relative top of this heading var top = entries[i].heading.el.getBoundingClientRect().top; if (top <= threshold) { active = i; // keep the latest match 鈥 do NOT break } } return active; } /** * Apply active state. Always clears every link first so external sources * of `.w--current` (e.g. Webflow's URL-hash matching) can't leave stale * classes around. We don't early-out on `newIndex === activeIndex` for * that same reason 鈥 it's cheap to re-set and guarantees correctness. * * Each entry may have multiple link clones (one per mount target). The * active class is applied uniformly to all clones so every rendered TOC * stays in sync. */ function applyActive(instance, newIndex) { var entries = instance.entries; function setClass(entry, on) { for (var li = 0; li < entry.links.length; li++) { if (on) entry.links[li].classList.add(ACTIVE_CLASS); else entry.links[li].classList.remove(ACTIVE_CLASS); } } // Clear all. for (var i = 0; i < entries.length; i++) setClass(entries[i], false); if (newIndex >= 0 && newIndex < entries.length) { // Mark the directly-active entry. var activeEntry = entries[newIndex]; setClass(activeEntry, true); // Optionally mark ancestors. An ancestor of entry N is the most recent // earlier entry whose level is strictly shallower, walking up until we // run out of shallower levels. if (instance.ancestorMode) { var currentLevel = activeEntry.heading.level; for (var k = newIndex - 1; k >= 0 && currentLevel > 1; k--) { if (entries[k].heading.level < currentLevel) { setClass(entries[k], true); currentLevel = entries[k].heading.level; } } } } // Fire ix-trigger transitions only when the index actually changed. We // dispatch on every cloned trigger across all mounts so Webflow IX2 // animations run uniformly in each rendered TOC. if (newIndex !== instance.activeIndex) { for (var j = 0; j < entries.length; j++) { var entry = entries[j]; if (!entry.ixTriggers || !entry.ixTriggers.length) continue; // Read state from the first clone 鈥 they're kept in sync. var isActive = entry.links.length > 0 && entry.links[0].classList.contains(ACTIVE_CLASS); var was = instance.previousIxState.get(entry) === true; if (isActive !== was) { entry.ixTriggers.forEach(function (t) { t.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })); }); instance.previousIxState.set(entry, isActive); } } instance.activeIndex = newIndex; } } // ---------- bootstrap -------------------------------------------------- function init() { var contentsEls = document.querySelectorAll('[' + ATTR + '="contents"]'); var instances = []; contentsEls.forEach(function (el) { var inst = buildInstance(el); if (inst) instances.push(inst); }); if (!instances.length) return; function update() { for (var i = 0; i < instances.length; i++) { applyActive(instances[i], computeActiveIndex(instances[i])); } } // Throttle to one update per frame. var ticking = false; function onScroll() { if (ticking) return; ticking = true; requestAnimationFrame(function () { update(); ticking = false; }); } window.addEventListener('scroll', onScroll, { passive: true }); window.addEventListener('resize', onScroll); update(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();

成人VR视频

Skip to main content

Invisible Judgments: How AI can help judges see what we've never seen before

The Hon. Maritza Dominguez Braswell
August 10, 2026
By
The Hon. Maritza Dominguez Braswell
August 12, 2026
August 12, 2026
9 min
This is some text inside of a div block.

Most conversations about judicial AI focus on two questions: First, can we trust it? And second, how much time will it save? Both questions are important, but the underlying assumption is that AI will simply drop into our existing workflows and we'll continue to do the same work, just faster. I see it differently.

Key takeaways

  • AI's real opportunity is in augmentation, not speed.
  • True augmentation will come from rethinking our workflows, and reimagining how we perform certain tasks.
  • The work of judges involves far more than simply issuing rulings. Every ruling is built from invisible "micro-judgments" that dictate framing, anchoring, and assumptions.
  • Designed and used poorly, AI can bury these framings and assumptions deeper than ever before. But designed and used well, AI can give judges something no tool has ever offered: the ability to see our own minds at work in real time.
  • This could change how we 鈥渏udge,鈥 for the better.

The biases we bring

There's a body of research on the biases judges bring to the bench. In one , researchers from Cornell and Vanderbilt universities found that anchoring, framing, and other bias influenced judicial decision-making in ways that could produce errors. A found that irrelevant numeric information also had an anchoring effect and skewed damages and sentences. And while there鈥檚 when they know about it and are motivated to correct for it, the research suggests that awareness in the abstract isn鈥檛 enough.

Could awareness in the moment of a decision make a difference? What if AI could help us see our biases precisely when they surface? What if we could test our inclinations in real time or pause on the assumptions we鈥檙e making before taking the next step?

If designed for this purpose, AI can place critical interruptions inside our workflows, reflect our cognitive process back to us, and augment us in new and important ways.

To explain how that's possible, and why it matters, I鈥檒l start with a short reflection on judicial decisions.

Judgment is not one decision

We talk about the work of judges as though it happens in singular moments: A judge grants or denies the motion, admits or excludes the evidence, dismisses or permits a claim. Long before we decide anything, however, dozens of cognitive acts and tasks are strung together in preparation for the ultimate decision. Which filing do I read first? How do I organize the record? What鈥檚 the sequence of events? Which facts deserve the most attention? What are all the relevant authorities? Which authority is most on point?

None of these individual inflection points鈥攐r what I call micro-judgments鈥攔esult in a ruling on their own. Yet every single one shapes it. This is because a judicial decision is not a destination, it's an architecture built from dozens of micro-judgments that accumulate over time. Each one scaffolds to another, and each one makes some conclusions easier to reach and others harder to see. By the time we sit down to decide, much of the deciding has already happened.

To be clear, some of the work inside this architecture is arguably computational, and AI may eventually do it better than we can. Other work should never be entrusted to an AI system and should remain firmly human. But my focus here is not on who or what performs each individual task, it鈥檚 on whether the technology helps us see the consequential judgments along the way.

None of these individual inflection points鈥攐r what I call micro-judgments鈥攔esult in a ruling on their own. Yet every single one shapes it.

Today, with or without AI, many of the micro-judgments inside the architecture of judging are entirely invisible. Think about how a bench memo works. A law clerk reads the record, frames the issues, builds the chronology, and selects the authority. Accepting some, or all of it, involves many micro-judgments, but we don鈥檛 pause to examine every single one. The clerk's initial thinking dissolves into the memo, my initial reactions to the memo dissolve into my feedback and my own research.

The framing, the anchoring, the assumptions, often get lost in the mix. If you ask me to reconstruct every micro-judgment that shaped a ruling, I could give you an overview of my process, but I wouldn't be able to pinpoint every single micro-judgment. That鈥檚 because we can鈥檛 watch our own reasoning as it forms.

At least, until now.

The AI breakthrough

AI is the first technology in the history of judging that can systematically reflect a judge's own cognitive process back to the judge in real time.

We鈥檝e always caught glimpses of our own leanings: a pointed question at oral argument, a tentative ruling, or a good clerk that pushes back. They all help us reflect on our own cognitive process. However, these glimpses are partial, or dependent on someone else鈥檚 choices about how they interact with us. AI is the first tool that can do this systematically and inside our own workflows.

AI can ask reflective questions, record our first instincts and hold them until the end, notice which facts we keep returning to and which arguments we never touch. It can compare what we emphasize against what the record reflects. It can be designed to hold up a mirror to our thinking.

But that鈥檚 the key鈥攊t needs to be designed that way.

Today鈥檚 tools primarily run in the other direction. Ask a system to analyze an issue, and it compresses the chronology, the framing, the research prioritization, and the outline into seconds, folding those intermediate steps into the background and presenting the user with a polished answer. Every micro-judgment gets made more quickly and more quietly than ever, whether by us or by the system. And when AI systems collapse our biases into their own biases, mixing and mashing without opportunity for interruption and correction, it鈥檚 dangerous. In my view, far more dangerous than hallucinations, a topic we can鈥檛 seem to get enough of these days.

In short, AI can bury the traces of judicial cognition deeper than any tool before; or, it can expose them. The design determines the path.

What exposure looks like: micro-judgment checkpoints

Judges can already use AI to expose some of these micro-judgments. For example, I use standing system instructions, deliberate prompts, and custom projects to direct the system into deliberate reflections and pauses that help me consciously shape what comes next. But these self-created checkpoints work imperfectly and inconsistently. Moreover, they depend entirely on a judge knowing how to set these up and remembering to make these demands of the system. It isn't scalable or sustainable.

Judicial decision-making is a complicated architecture that depends on the countless micro-judgments that shape a judge鈥檚 final decision.

The real progress would be in the design. And while some tools now offer usage recaps that summarize the topics we work on and the ways we tend to use the system, those summaries reflect general habits. They say nothing about my biases, assumptions, or leanings.

An AI system shouldn't reflect every micro-judgment, of course. If it narrates everything then the important checkpoints get buried in noise. Instead, it should pause on the micro-judgments most likely to change the direction of my decision-making, prompt me in a way that sparks genuine reflection, and give me the opportunity to take an informed next step.

Here are a few examples of how that might look in practice:

Issue framing 鈥 Before offering anything, the system asks me to frame the issue, then shows my framing next to the parties鈥. If mine tracks one brief almost word-for-word, is that framing right, or have I anchored?

Holding my first instinct 鈥 The system records my tentative lean after my first pass, then shows it to me later. If my analysis matches my instinct exactly, is that confidence, or untested bias?

Body of work reflection 鈥 The system identifies patterns from my prior decisions. Do I credit the same authority? Skew one direction too often? Reason inconsistently across similar cases?

Materiality and assumptions 鈥 The system flags the facts I seem to be assuming and whether the record supports them, before the assumptions harden and I press on.

For decades, the answer to bias has been training. We learn how our biases work in a conference room and then hope we retain enough to catch them at the right moments on the bench. Today, we have the opportunity to design systems around how bias works and force the systems to engage us at the precise moment at which our biases would otherwise go unchecked.

The risks

A system that flags gaps could push the judge outside the record and the parties鈥 arguments, if not properly restricted. Thus, it would be important for these checkpoints to stay bound to, for example, the parties' submissions.

Additionally, a system that stores my first instincts, leans, and patterns, is holding a record of my deliberative process. That record belongs in the same category as my notes and my draft opinions. It shouldn鈥檛 be stored as a dataset, mined for analytics, or used to build profiles for how judges decide. Judicial analytics built from our public rulings already make judges uneasy, and . This type of internal and iterative process would require even greater protection.

There鈥檚 also a question about the mirror itself. The system鈥檚 reflections are in essence micro-judgments too, and imperfect ones. Thus, checkpoints should be built as questions rather than conclusions, keeping the judge in control.

We also shouldn鈥檛 assume that seeing bias automatically fixes it. A poorly built checkpoint could harden a first instinct rather than test it, or it could give us the false sense that we鈥檝e successfully interrupted a bias. Like anything else, the design should be validated and not simply presumed to work.

Finally, it鈥檚 likely these checkpoints will slow us down if not built correctly. A well-designed checkpoint should take seconds, arrive at natural pauses in the work, and never interrupt for the sake of interrupting.

A call to action

I suspect that what I鈥檓 contemplating here is not easy (or enticing) to build. Checkpoints add friction that metrics punish, and meaningful reflection requires systems that are designed around a body of work rather than a single session. For some platforms, that might mean rebuilding rather than simply adding a feature. Moreover, the reflections themselves must be grounded to avoid hallucinations and more bias.

Still, vendors build what buyers demand, and we should demand systems that make us better, not just faster. Public confidence in the , dropping 24 percentage points in just four years. The causes are complicated and some are beyond any one judge鈥檚 control. But when confidence is this low, we should be looking for very opportunity to improve. 聽

A closing thought

Judicial decision-making is a complicated architecture that depends on the countless micro-judgments that shape a judge鈥檚 final decision. For all of judicial history, those micro-judgments have been largely invisible, even to the judges making them.

Today, we are building tools that could make that worse鈥r better.

Built and used carelessly, AI can bury the traces of our cognition deeper. Built and used correctly, however, AI can do something no tool has ever done before: show us our own minds at work, at the moments that matter most.

You can find more insights from Judge Braswell here

Follow us on social

Have questions?

Get in touch with one of our solutions experts....
成人VR视频 Institute logo

Featured Event

Table of
Contents
H2
H3
H4
H5
H6
August 12, 2026
Invisible Judgments: How AI can help judges see what we've never seen before
Most conversations about judicial AI focus on two questions: First, can we trust it? And second, how much time will it save? Both questions are important, but the underlying assumption is that AI will simply drop into our existing workflows and we'll continue to do the same work, just faster. I see it differently.
9 min
August 12, 2026
AI for Justice
Invisible Judgments: How AI can help judges see what we've never seen before
The Hon. Maritza Dominguez Braswell
U.S. Magistrate Judge
District of Colorado
Headshot of The Hon. Maritza Dominguez Braswell
Court operations
State Courts
Legal judgment
Judiciary
Government professionals
Legal professionals
AI in courts
The human side of AI: The growing risks of ubiquitous use of AI on talent
How AI is hollowing out the legal profession's judgment pipeline 鈥 and how to fix it
The AI adoption board game: Why law firm leaders can't afford to play it safe