Files
docs/hexa/wiki/04_design/index.html

1373 lines
50 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="prev" href="../03_use_cases/03_wiring_runtime/">
<link rel="next" href="../05_philosophy/">
<link rel="icon" href="../assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.23">
<title>Design - Hexa Documentation</title>
<link rel="stylesheet" href="../assets/stylesheets/main.84d31ad4.min.css">
<link rel="stylesheet" href="../assets/stylesheets/palette.06af60db.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"JetBrains Mono"}</style>
<link rel="stylesheet" href="https://unpkg.com/dracula-prism/dist/css/dracula-prism.css">
<script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="slate" data-md-color-primary="blue-grey" data-md-color-accent="teal">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#design-extraction-pipeline-axis-icici" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href=".." title="Hexa Documentation" class="md-header__button md-logo" aria-label="Hexa Documentation" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10.25 2c.19 0 .36.11.44.26l2.22 3.96.09.28-.09.28-2.22 3.96c-.08.15-.25.26-.44.26h-4.5c-.19 0-.36-.11-.44-.26L3.09 6.78 3 6.5l.09-.28 2.22-3.96c.08-.15.25-.26.44-.26zm0 11c.19 0 .36.11.44.26l2.22 3.96.09.28-.09.28-2.22 3.96c-.08.15-.25.26-.44.26h-4.5c-.19 0-.36-.11-.44-.26l-2.22-3.96L3 17.5l.09-.28 2.22-3.96c.08-.15.25-.26.44-.26zm9.25-5.5c.19 0 .36.11.44.26l2.22 3.96.09.28-.09.28-2.22 3.96c-.08.15-.25.26-.44.26H15c-.19 0-.36-.11-.44-.26l-2.22-3.96-.09-.28.09-.28 2.22-3.96c.08-.15.25-.26.44-.26z"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Hexa Documentation
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Design
</span>
</div>
</div>
</div>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<a href="javascript:void(0)" class="md-search__icon md-icon" title="Share" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"/></svg>
</a>
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
<div class="md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href=".." class="md-tabs__link">
Home
</a>
</li>
<li class="md-tabs__item">
<a href="../01_overview/" class="md-tabs__link">
Overview
</a>
</li>
<li class="md-tabs__item">
<a href="../02_components/" class="md-tabs__link">
Core Components
</a>
</li>
<li class="md-tabs__item">
<a href="../03_use_cases/01_yaml_first/" class="md-tabs__link">
Use Cases
</a>
</li>
<li class="md-tabs__item md-tabs__item--active">
<a href="./" class="md-tabs__link">
Design
</a>
</li>
<li class="md-tabs__item">
<a href="../05_philosophy/" class="md-tabs__link">
Philosophy
</a>
</li>
<li class="md-tabs__item">
<a href="../06_best_practices/" class="md-tabs__link">
Best Practices
</a>
</li>
<li class="md-tabs__item">
<a href="../07_error_handling/" class="md-tabs__link">
Error Handling
</a>
</li>
<li class="md-tabs__item">
<a href="../08_testing_example/" class="md-tabs__link">
Testing
</a>
</li>
</ul>
</div>
</nav>
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--lifted md-nav--integrated" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href=".." title="Hexa Documentation" class="md-nav__button md-logo" aria-label="Hexa Documentation" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M10.25 2c.19 0 .36.11.44.26l2.22 3.96.09.28-.09.28-2.22 3.96c-.08.15-.25.26-.44.26h-4.5c-.19 0-.36-.11-.44-.26L3.09 6.78 3 6.5l.09-.28 2.22-3.96c.08-.15.25-.26.44-.26zm0 11c.19 0 .36.11.44.26l2.22 3.96.09.28-.09.28-2.22 3.96c-.08.15-.25.26-.44.26h-4.5c-.19 0-.36-.11-.44-.26l-2.22-3.96L3 17.5l.09-.28 2.22-3.96c.08-.15.25-.26.44-.26zm9.25-5.5c.19 0 .36.11.44.26l2.22 3.96.09.28-.09.28-2.22 3.96c-.08.15-.25.26-.44.26H15c-.19 0-.36-.11-.44-.26l-2.22-3.96-.09-.28.09-.28 2.22-3.96c.08-.15.25-.26.44-.26z"/></svg>
</a>
Hexa Documentation
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../01_overview/" class="md-nav__link">
<span class="md-ellipsis">
Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../02_components/" class="md-nav__link">
<span class="md-ellipsis">
Core Components
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_4" >
<label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="0">
<span class="md-ellipsis">
Use Cases
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
Use Cases
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_4_1" >
<label class="md-nav__link" for="__nav_4_1" id="__nav_4_1_label" tabindex="0">
<span class="md-ellipsis">
Contract Authoring
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_1_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_1">
<span class="md-nav__icon md-icon"></span>
Contract Authoring
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../03_use_cases/01_yaml_first/" class="md-nav__link">
<span class="md-ellipsis">
YAML First
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../03_use_cases/02_abc_first/" class="md-nav__link">
<span class="md-ellipsis">
ABC First
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_4_2" >
<label class="md-nav__link" for="__nav_4_2" id="__nav_4_2_label" tabindex="0">
<span class="md-ellipsis">
Wiring
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4_2">
<span class="md-nav__icon md-icon"></span>
Wiring
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../03_use_cases/03_wiring_runtime/" class="md-nav__link">
<span class="md-ellipsis">
Wiring & Runtime
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Design
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Design
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#file-map-samplesextraction_pipeline" class="md-nav__link">
<span class="md-ellipsis">
File map (samples/extraction_pipeline/)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#the-port-tree-abc-contract" class="md-nav__link">
<span class="md-ellipsis">
The port tree (ABC contract)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#generic-default-impl" class="md-nav__link">
<span class="md-ellipsis">
Generic default (Impl*)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#bank-variation-only-what-differs" class="md-nav__link">
<span class="md-ellipsis">
Bank variation (only what differs)
</span>
</a>
<nav class="md-nav" aria-label="Bank variation (only what differs)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#axis-banksaxispdfpy" class="md-nav__link">
<span class="md-ellipsis">
Axis (banks/axis/pdf.py)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#icici-banksicicipdfpy" class="md-nav__link">
<span class="md-ellipsis">
Icici (banks/icici/pdf.py)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#redundancy-rule-applied-in-both-banks" class="md-nav__link">
<span class="md-ellipsis">
Redundancy rule (applied in both banks)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#container-buildcls-in-hexacontainerpy" class="md-nav__link">
<span class="md-ellipsis">
Container (build(cls) in hexa/container.py)
</span>
</a>
<nav class="md-nav" aria-label="Container (build(cls) in hexa/container.py)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#control-flow-at-runtime-target" class="md-nav__link">
<span class="md-ellipsis">
Control flow at runtime (target)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#utilities-optional-hexa-agnostic" class="md-nav__link">
<span class="md-ellipsis">
Utilities (optional, hexa-agnostic)
</span>
</a>
<nav class="md-nav" aria-label="Utilities (optional, hexa-agnostic)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#shared-model" class="md-nav__link">
<span class="md-ellipsis">
Shared model
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#1-parse_yamlpath-portnode" class="md-nav__link">
<span class="md-ellipsis">
1. parse_yaml(path) -&gt; PortNode
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-generate_abcpath_yaml-out_pathnone-str" class="md-nav__link">
<span class="md-ellipsis">
2. generate_abc(path_yaml, out_path=None) -&gt; str
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-parse_abcmodule_or_path-portnode" class="md-nav__link">
<span class="md-ellipsis">
3. parse_abc(module_or_path) -&gt; PortNode
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-generate_yamlmodule_or_path-out_pathnone-str" class="md-nav__link">
<span class="md-ellipsis">
4. generate_yaml(module_or_path, out_path=None) -&gt; str
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#5-check_matchespath_a-path_b-bool" class="md-nav__link">
<span class="md-ellipsis">
5. check_matches(path_a, path_b) -&gt; bool
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#workflows-users-choice" class="md-nav__link">
<span class="md-ellipsis">
Workflows (user's choice)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#related" class="md-nav__link">
<span class="md-ellipsis">
Related
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../05_philosophy/" class="md-nav__link">
<span class="md-ellipsis">
Philosophy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../06_best_practices/" class="md-nav__link">
<span class="md-ellipsis">
Best Practices
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../07_error_handling/" class="md-nav__link">
<span class="md-ellipsis">
Error Handling
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../08_testing_example/" class="md-nav__link">
<span class="md-ellipsis">
Testing
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="design-extraction-pipeline-axis-icici">Design — Extraction Pipeline (Axis / Icici)<a class="headerlink" href="#design-extraction-pipeline-axis-icici" title="Permanent link">&para;</a></h1>
<blockquote>
<p><strong>Note:</strong> The extraction pipeline discussed below is a sample/example illustrating the hexa composition pattern.</p>
</blockquote>
<p>This document is the concrete counterpart to <a href="../05_philosophy/">Philosophy</a>: where the files are, what the tree looks like for both banks, and how a future container instantiates it. Self-sufficient for a fresh agent.</p>
<hr />
<h2 id="file-map-samplesextraction_pipeline">File map (<code>samples/extraction_pipeline/</code>)<a class="headerlink" href="#file-map-samplesextraction_pipeline" title="Permanent link">&para;</a></h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Layer</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>extraction_pipeline_abc.py</code></td>
<td>ABC contracts</td>
<td>All port ABCs + <code>ExtractionPipeline</code> root. Declares attributes, the <code>ExtractionSource</code> dataclass, port slots, <code>@abstractmethod</code>s.</td>
</tr>
<tr>
<td><code>extraction_pipeline_impl.py</code></td>
<td>Generic <code>Impl*</code></td>
<td>Concrete default implementations of every port; <code>ImplExtractionPipeline</code> root; <code>clean_num</code> helper.</td>
</tr>
<tr>
<td><code>extraction_pipeline_ambiguity.py</code></td>
<td>Shared logic</td>
<td>Ported <code>ResolutionContext</code>, <code>AmbiguityHandler</code>, <code>AmountBalanceNotFound</code>, <code>validate_signs</code> — used by <code>ImplAmountBalancePort</code>.</td>
</tr>
<tr>
<td><code>extraction_pipeline_banks.py</code></td>
<td>Composition root</td>
<td><code>AxisExtractionPipeline(ImplExtractionPipeline)</code> + <code>IciciExtractionPipeline</code> (each re-pins <code>txn_dicts</code>).</td>
</tr>
<tr>
<td><code>banks/axis/pdf.py</code></td>
<td>Bank specialization</td>
<td><code>AxisNumberPort</code>, <code>AxisDescPort</code>, <code>AxisAmountBalancePort</code>, <code>AxisTransactionParserPort</code>, <code>AxisTxnDictsPort</code>.</td>
</tr>
<tr>
<td><code>banks/icici/pdf.py</code></td>
<td>Bank specialization</td>
<td><code>Icici*</code> mirror of the above + Icici-only <code>adjust_balance</code>/<code>missing_number_candidates</code>.</td>
</tr>
<tr>
<td><code>extraction_pipeline.yaml</code></td>
<td>Contract spec</td>
<td>Declarative spec of the port tree; interchangeable with <code>_abc.py</code> via the optional utilities.</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="the-port-tree-abc-contract">The port tree (ABC contract)<a class="headerlink" href="#the-port-tree-abc-contract" title="Permanent link">&para;</a></h2>
<div class="language-text highlight"><span class="filename">Text Only</span><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a>ExtractionPipeline
<a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a>├── source / pipeline / trust_fallback [attributes; source is a nested struct]
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a>├── ingest → IngestPort (source → content)
<a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a>├── raw_lines → RawLinesPort (content → raw_lines)
<a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a>├── txn_blocks → TxnBlocksPort (raw_lines → txn_blocks)
<a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a>│ ├── bucket_finder → BucketFinderPort
<a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a>│ └── splitter → SplitterPort
<a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a>├── txn_dicts → TxnDictsPort (txn_blocks → txn_dicts)
<a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a>│ └── parser → TransactionParserPort
<a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a>│ ├── number → NumberPort
<a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a>│ ├── date → DatePort
<a id="__codelineno-0-12" name="__codelineno-0-12" href="#__codelineno-0-12"></a>│ ├── desc → DescPort
<a id="__codelineno-0-13" name="__codelineno-0-13" href="#__codelineno-0-13"></a>│ └── amount_balance → AmountBalancePort
<a id="__codelineno-0-14" name="__codelineno-0-14" href="#__codelineno-0-14"></a>│ ├── number → NumberPort
<a id="__codelineno-0-15" name="__codelineno-0-15" href="#__codelineno-0-15"></a>│ └── ambiguity → AmbiguityPort
<a id="__codelineno-0-16" name="__codelineno-0-16" href="#__codelineno-0-16"></a>└── raw_expense → RawExpensePort (txn_dicts → list[RawExpense], terminal)
</code></pre></div>
<hr />
<h2 id="generic-default-impl">Generic default (<code>Impl*</code>)<a class="headerlink" href="#generic-default-impl" title="Permanent link">&para;</a></h2>
<p><code>ImplExtractionPipeline</code> pins every stage slot to a concrete <code>Impl*</code> port:</p>
<div class="language-text highlight"><span class="filename">Text Only</span><pre><span></span><code><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a>ImplExtractionPipeline
<a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a>├── ingest: ImplIngestPort
<a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a>├── raw_lines: ImplRawLinesPort
<a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a>├── txn_blocks: ImplTxnBlocksPort
<a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a>│ ├── bucket_finder: ImplBucketFinderPort
<a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a>│ └── splitter: ImplSplitterPort
<a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a>├── txn_dicts: ImplTxnDictsPort
<a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a>│ └── parser: ImplTransactionParserPort
<a id="__codelineno-1-9" name="__codelineno-1-9" href="#__codelineno-1-9"></a>│ ├── number: ImplNumberPort
<a id="__codelineno-1-10" name="__codelineno-1-10" href="#__codelineno-1-10"></a>│ ├── date: ImplDatePort
<a id="__codelineno-1-11" name="__codelineno-1-11" href="#__codelineno-1-11"></a>│ ├── desc: ImplDescPort
<a id="__codelineno-1-12" name="__codelineno-1-12" href="#__codelineno-1-12"></a>│ └── amount_balance: ImplAmountBalancePort
<a id="__codelineno-1-13" name="__codelineno-1-13" href="#__codelineno-1-13"></a>│ ├── number: ImplNumberPort
<a id="__codelineno-1-14" name="__codelineno-1-14" href="#__codelineno-1-14"></a>│ └── ambiguity: ImplAmbiguityPort
<a id="__codelineno-1-15" name="__codelineno-1-15" href="#__codelineno-1-15"></a>└── raw_expense: ImplRawExpensePort
</code></pre></div>
<hr />
<h2 id="bank-variation-only-what-differs">Bank variation (only what differs)<a class="headerlink" href="#bank-variation-only-what-differs" title="Permanent link">&para;</a></h2>
<p>The root class re-pins only <code>txn_dicts</code>. Everything else inherits <code>Impl*</code>.</p>
<h3 id="axis-banksaxispdfpy">Axis (<code>banks/axis/pdf.py</code>)<a class="headerlink" href="#axis-banksaxispdfpy" title="Permanent link">&para;</a></h3>
<div class="language-python highlight"><span class="filename">Python</span><pre><span></span><code><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="k">class</span><span class="w"> </span><span class="nc">AxisExtractionPipeline</span><span class="p">(</span><span class="n">ImplExtractionPipeline</span><span class="p">):</span>
<a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a> <span class="n">txn_dicts</span><span class="p">:</span> <span class="n">AxisTxnDictsPort</span>
</code></pre></div>
<div class="language-python highlight"><span class="filename">Python</span><pre><span></span><code><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="n">AxisTxnDictsPort</span><span class="p">(</span><span class="n">ImplTxnDictsPort</span><span class="p">)</span>
<a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a> <span class="err">└─</span> <span class="n">parser</span><span class="p">:</span> <span class="n">AxisTransactionParserPort</span><span class="p">(</span><span class="n">ImplTransactionParserPort</span><span class="p">)</span>
<a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a> <span class="err">├─</span> <span class="n">number</span><span class="p">:</span> <span class="n">AxisNumberPort</span> <span class="c1"># NUMBER_RE, all clean numbers</span>
<a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a> <span class="err">├─</span> <span class="n">desc</span><span class="p">:</span> <span class="n">AxisDescPort</span> <span class="c1"># STARTTERS = [upi/, imps/, neft-, neft/, ach/, ach-, 2a/]</span>
<a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a> <span class="err">└─</span> <span class="n">amount_balance</span><span class="p">:</span> <span class="n">AxisAmountBalancePort</span><span class="p">(</span><span class="n">ImplAmountBalancePort</span><span class="p">)</span>
<a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a> <span class="err">└─</span> <span class="n">number</span><span class="p">:</span> <span class="n">AxisNumberPort</span> <span class="c1"># re-pin back to axis number port</span>
</code></pre></div>
<p>Notes:</p>
<ul>
<li><code>date</code> is <strong>not</strong> redeclared on <code>AxisTransactionParserPort</code> — it inherits <code>ImplDatePort</code> (correct already, adds no behavior).</li>
<li><code>amount_balance.ambiguity</code> is not redeclared — inherits <code>ImplAmbiguityPort</code>.</li>
</ul>
<h3 id="icici-banksicicipdfpy">Icici (<code>banks/icici/pdf.py</code>)<a class="headerlink" href="#icici-banksicicipdfpy" title="Permanent link">&para;</a></h3>
<div class="language-python highlight"><span class="filename">Python</span><pre><span></span><code><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="k">class</span><span class="w"> </span><span class="nc">IciciExtractionPipeline</span><span class="p">(</span><span class="n">ImplExtractionPipeline</span><span class="p">):</span>
<a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a> <span class="n">txn_dicts</span><span class="p">:</span> <span class="n">IciciTxnDictsPort</span>
</code></pre></div>
<div class="language-python highlight"><span class="filename">Python</span><pre><span></span><code><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="n">IciciTxnDictsPort</span><span class="p">(</span><span class="n">ImplTxnDictsPort</span><span class="p">)</span>
<a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a> <span class="err">└─</span> <span class="n">parser</span><span class="p">:</span> <span class="n">IciciTransactionParserPort</span><span class="p">(</span><span class="n">ImplTransactionParserPort</span><span class="p">)</span>
<a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a> <span class="err">├─</span> <span class="n">number</span><span class="p">:</span> <span class="n">IciciNumberPort</span> <span class="c1"># NUMBER_RE, returns decimals[-2:] (last 2)</span>
<a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a> <span class="err">├─</span> <span class="n">desc</span><span class="p">:</span> <span class="n">IciciDescPort</span> <span class="c1"># STARTTERS + fix_ocr (UPl→UPI, ..., ICIC]→ICICI)</span>
<a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a> <span class="err">└─</span> <span class="n">amount_balance</span><span class="p">:</span> <span class="n">IciciAmountBalancePort</span><span class="p">(</span><span class="n">ImplAmountBalancePort</span><span class="p">)</span>
<a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a> <span class="err">├─</span> <span class="n">number</span><span class="p">:</span> <span class="n">IciciNumberPort</span> <span class="c1"># re-pin to icici number port</span>
<a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a> <span class="err">├─</span> <span class="n">adjust_balance</span><span class="p">:</span> <span class="c1"># neg-markers [(-), (-}, {-}, {-) , ()] → -abs(balance)</span>
<a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a> <span class="err">└─</span> <span class="n">missing_number_candidates</span><span class="p">:</span> <span class="c1"># Icici-only one-number hook</span>
</code></pre></div>
<hr />
<h2 id="redundancy-rule-applied-in-both-banks">Redundancy rule (applied in both banks)<a class="headerlink" href="#redundancy-rule-applied-in-both-banks" title="Permanent link">&para;</a></h2>
<p>Only redeclare a slot you are actually <strong>changing</strong> from <code>Impl*</code>. If a slot's behavior is already correct from the parent <code>Impl*</code>, <strong>omit it</strong>. This keeps the diff between a bank and <code>Impl*</code> minimal and unambiguous.</p>
<blockquote>
<p><code>date: ImplDatePort</code> was previously redeclared redundantly and has been removed — it added mental load on the extender for zero behavior change. (Fidelity audit: it is still concrete <code>ImplDatePort</code> in <code>ImplTransactionParserPort</code>, so behavior is unchanged.)</p>
</blockquote>
<hr />
<h2 id="container-buildcls-in-hexacontainerpy">Container (<code>build(cls)</code> in <code>hexa/container.py</code>)<a class="headerlink" href="#container-buildcls-in-hexacontainerpy" title="Permanent link">&para;</a></h2>
<p>The annotations are metadata; a small reflection builder turns a root class into a wired instance:</p>
<div class="language-text highlight"><span class="filename">Text Only</span><pre><span></span><code><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a>build(AxisExtractionPipeline) → wired AxisExtractionPipeline
</code></pre></div>
<p>Algorithm (<code>build(cls)</code>):</p>
<ol>
<li>Walk <code>cls.__annotations__</code>, merged across the MRO so inherited slot annotations are visible (a bank subclass only <em>adds/overrides</em> a slot; the rest come from <code>Impl*</code>).</li>
<li>For each port slot whose annotated type is a concrete <code>Impl*</code>/bank class (not an ABC, not a builtin), instantiate it.</li>
<li>Recurse into that child — repeat until leaves (classes that declare no further port slots).</li>
<li><code>setattr(parent, slot, child)</code> to wire each slot onto the parent instance.</li>
<li>Apply config defaults from the class-level annotated attributes.</li>
</ol>
<p>Selection is <strong>fully static</strong>: the annotated type <em>is</em> the chosen implementation. The container holds no per-bank branch logic — <code>Axis</code> vs <code>Icici</code> is decided purely by which root class you call <code>build</code> on.</p>
<h3 id="control-flow-at-runtime-target">Control flow at runtime (target)<a class="headerlink" href="#control-flow-at-runtime-target" title="Permanent link">&para;</a></h3>
<p>A leaf-stage port exposes one entry method; stages chain data through the shared <code>run(source)</code> signature on the root:</p>
<div class="language-text highlight"><span class="filename">Text Only</span><pre><span></span><code><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a>run(source)
<a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a> ingest.materialize(source) → content
<a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a> raw_lines.extract(content) → raw_lines
<a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a> txn_blocks.extract(raw_lines) → {opening_balance: [blocks]}
<a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a> txn_dicts.extract(txn_blocks) → [txn dicts]
<a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a> raw_expense.build(txn_dicts) → [RawExpense] (terminal)
</code></pre></div>
<p>The stage ports map naturally onto dagpipe <code>Node</code>s (<code>ingest</code>, <code>raw_lines</code>, <code>txn_blocks</code>, <code>txn_dicts</code>, <code>raw_expense</code>), each node's <code>resolve</code> delegating to its wired port subtree, connected as a dagpipe <code>Graph</code> and run via <code>Engine</code>. That merge is a separate, future step.</p>
<hr />
<h2 id="utilities-optional-hexa-agnostic">Utilities (optional, hexa-agnostic)<a class="headerlink" href="#utilities-optional-hexa-agnostic" title="Permanent link">&para;</a></h2>
<p>The hexa utilities are implemented in <code>hexa/</code> (the package root) and they are <strong>agnostic of the extraction pipeline sample</strong>. It ships a set of <strong>optional</strong> code-gen / validation utilities so users can choose their own workflow — they are never required. A user is free to:</p>
<ul>
<li><strong>hand-write</strong> an ABC file and never touch YAML, or</li>
<li><strong>start from YAML</strong> and generate the ABC file, or</li>
<li><strong>start from an ABC file</strong> and emit YAML for it, or</li>
<li>use the ABC/YAML only as a <strong>spec</strong> (neither generated from the other).</li>
</ul>
<p>The utilities only ever translate between two interchangeable representations of the same <em>contract</em> — the <code>.yaml</code> spec and the <code>_abc.py</code> module. They never generate or manage the <code>Impl*</code>/bank files (those carry behavior and slot choice, which is a human decision).</p>
<h3 id="shared-model">Shared model<a class="headerlink" href="#shared-model" title="Permanent link">&para;</a></h3>
<p>All utilities serialize through one neutral model, a <code>PortNode</code> tree. It is NOT tied to the extraction sample — any port tree fits.</p>
<div class="language-python highlight"><span class="filename">Python</span><pre><span></span><code><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="nd">@dataclass</span>
<a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a><span class="k">class</span><span class="w"> </span><span class="nc">PortNode</span><span class="p">:</span>
<a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span> <span class="c1"># slot name, e.g. "parser", "amount_balance"</span>
<a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a> <span class="n">kind</span><span class="p">:</span> <span class="nb">str</span> <span class="c1"># "leaf" | "port" | "parent"</span>
<a id="__codelineno-8-5" name="__codelineno-8-5" href="#__codelineno-8-5"></a> <span class="n">port_cls</span><span class="p">:</span> <span class="nb">str</span> <span class="c1"># ABC class name, e.g. "TransactionParserPort"</span>
<a id="__codelineno-8-6" name="__codelineno-8-6" href="#__codelineno-8-6"></a> <span class="n">attributes</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">ConfigValue</span><span class="p">]</span> <span class="c1"># annotated attributes: name -&gt; type expr,</span>
<a id="__codelineno-8-7" name="__codelineno-8-7" href="#__codelineno-8-7"></a> <span class="c1"># or a nested struct dict for grouped values</span>
<a id="__codelineno-8-8" name="__codelineno-8-8" href="#__codelineno-8-8"></a> <span class="n">children</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="s2">"PortNode"</span><span class="p">]</span>
<a id="__codelineno-8-9" name="__codelineno-8-9" href="#__codelineno-8-9"></a> <span class="n">methods</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">MethodSpec</span><span class="p">]</span> <span class="c1"># abstract methods</span>
</code></pre></div>
<h3 id="1-parse_yamlpath-portnode">1. <code>parse_yaml(path) -&gt; PortNode</code><a class="headerlink" href="#1-parse_yamlpath-portnode" title="Permanent link">&para;</a></h3>
<p>Read a YAML spec into the <code>PortNode</code> tree (YAML → model).</p>
<ul>
<li>Parses completely (structural validation only, no type-checking).</li>
<li>Supports the sample grammar (see <code>extraction_pipeline.yaml</code>): a root class whose inline attributes (scalars and nested structs), port slots, and reserved <code>methods:</code> recurse into child ports.</li>
<li>Raises <code>ValueError</code> with file/line on structural errors.</li>
</ul>
<h3 id="2-generate_abcpath_yaml-out_pathnone-str">2. <code>generate_abc(path_yaml, out_path=None) -&gt; str</code><a class="headerlink" href="#2-generate_abcpath_yaml-out_pathnone-str" title="Permanent link">&para;</a></h3>
<p>Generate <code>_abc.py</code> source from a YAML spec (YAML <strong></strong> ABC).</p>
<ul>
<li><code>parse_yaml(...)</code> → write one <code>class &lt;PortCls&gt;(ABC)</code> per <code>PortNode</code> with attribute annotations (nested structs become synthesized <code>@dataclass</code>es), port-slot annotations, and <code>@abstractmethod</code> stubs, matching the style of the hand-written <code>extraction_pipeline_abc.py</code>.</li>
<li>Deterministic (YAML-order) output so it is idempotent / diff-friendly.</li>
<li><code>out_path</code> optional; always returns the generated source.</li>
</ul>
<h3 id="3-parse_abcmodule_or_path-portnode">3. <code>parse_abc(module_or_path) -&gt; PortNode</code><a class="headerlink" href="#3-parse_abcmodule_or_path-portnode" title="Permanent link">&para;</a></h3>
<p>Reflect over an ABC module into the <code>PortNode</code> tree (ABC → model).</p>
<ul>
<li>Reads <code>__annotations__</code> / <code>@abstractmethod</code> from generic ABC classes (no sample assumptions) to reconstruct the same <code>PortNode</code> tree.</li>
</ul>
<h3 id="4-generate_yamlmodule_or_path-out_pathnone-str">4. <code>generate_yaml(module_or_path, out_path=None) -&gt; str</code><a class="headerlink" href="#4-generate_yamlmodule_or_path-out_pathnone-str" title="Permanent link">&para;</a></h3>
<p>Generate a <code>.yaml</code> spec from an ABC module (ABC <strong></strong> YAML).</p>
<ul>
<li><code>parse_abc(...)</code> → write the reverse of <code>generate_abc</code>.</li>
<li>Lets a user author the ABC file first and emit YAML for it.</li>
</ul>
<h3 id="5-check_matchespath_a-path_b-bool">5. <code>check_matches(path_a, path_b) -&gt; bool</code><a class="headerlink" href="#5-check_matchespath_a-path_b-bool" title="Permanent link">&para;</a></h3>
<p>Verify two representations agree — YAML vs ABC, either direction.</p>
<ul>
<li>Builds both <code>PortNode</code> models (<code>parse_yaml</code> + <code>parse_abc</code>) and compares: classes exist and are <code>ABC</code>s, attributes match, port slots match, <code>@abstractmethod</code> signatures match (missing keyword-only params treated conservatively).</li>
<li>Returns <code>True</code> only if the whole tree matches; otherwise <code>False</code> (or a diff).</li>
</ul>
<h3 id="workflows-users-choice">Workflows (user's choice)<a class="headerlink" href="#workflows-users-choice" title="Permanent link">&para;</a></h3>
<div class="language-text highlight"><span class="filename">Text Only</span><pre><span></span><code><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a># YAML-first
<a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a>edit spec.yaml
<a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a> → generate_abc(spec.yaml, abc.py) # regenerate ABCs
<a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a> → hand-write/update Impl* + banks
<a id="__codelineno-9-5" name="__codelineno-9-5" href="#__codelineno-9-5"></a> → check_matches(spec.yaml, abc.py) == True # guard
<a id="__codelineno-9-6" name="__codelineno-9-6" href="#__codelineno-9-6"></a>
<a id="__codelineno-9-7" name="__codelineno-9-7" href="#__codelineno-9-7"></a># ABC-first
<a id="__codelineno-9-8" name="__codelineno-9-8" href="#__codelineno-9-8"></a>edit abc.py
<a id="__codelineno-9-9" name="__codelineno-9-9" href="#__codelineno-9-9"></a> → generate_yaml(abc.py, spec.yaml) # emit YAML spec
<a id="__codelineno-9-10" name="__codelineno-9-10" href="#__codelineno-9-10"></a> → check_matches(spec.yaml, abc.py) == True
<a id="__codelineno-9-11" name="__codelineno-9-11" href="#__codelineno-9-11"></a>
<a id="__codelineno-9-12" name="__codelineno-9-12" href="#__codelineno-9-12"></a># hand-written both (no utilities at all)
<a id="__codelineno-9-13" name="__codelineno-9-13" href="#__codelineno-9-13"></a>edit abc.py + spec.yaml independently # optional check_matches as a guard
</code></pre></div>
<p><code>Impl*</code>/bank files are always hand-extended on top and are never generated.</p>
<hr />
<h2 id="related">Related<a class="headerlink" href="#related" title="Permanent link">&para;</a></h2>
<ul>
<li><a href="../05_philosophy/">05 Philosophy</a> · <a href="../03_use_cases/03_wiring_runtime/">03 Wiring &amp; runtime</a> · <a href="../01_overview/">Overview</a></li>
</ul>
</article>
</div>
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<nav class="md-footer__inner md-grid" aria-label="Footer" >
<a href="../03_use_cases/03_wiring_runtime/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Wiring &amp; Runtime">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</div>
<div class="md-footer__title">
<span class="md-footer__direction">
Previous
</span>
<div class="md-ellipsis">
Wiring & Runtime
</div>
</div>
</a>
<a href="../05_philosophy/" class="md-footer__link md-footer__link--next" aria-label="Next: Philosophy">
<div class="md-footer__title">
<span class="md-footer__direction">
Next
</span>
<div class="md-ellipsis">
Philosophy
</div>
</div>
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11z"/></svg>
</div>
</a>
</nav>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "..", "features": ["navigation.tabs", "navigation.expand", "navigation.sections", "navigation.footer", "navigation.top", "navigation.instant", "toc.integrate", "content.code.annotate", "content.code.copy", "content.code.select", "content.code.line_numbers", "content.tabs.link", "content.tooltips", "content.action.edit", "search.suggest", "search.highlight", "search.share", "header.autohide", "announce.dismiss", "footer.social"], "search": "../assets/javascripts/workers/search.973d3a69.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="../assets/javascripts/bundle.f55a23d4.min.js"></script>
</body>
</html>