feat(tui): the compliance menu — admission flows, the scout handler, Shariah in force (#389 C3) - #403
Merged
Merged
Conversation
…Shariah in force (#389 C3) The console's third slice: the Compliance sub-menu (PRD §3), the scout-results admission handler (O6) and the "Shariah in force" browser (O10), all dispatching to the existing C1 services — the TUI stays thin (O2). Entry -> service dispatch (every one an existing service or repository function): - screen -> build_screen_report over screen_product (the one admission gate) - propose -> build_propose_view over parse_proposal/build_proposal_report - attest / attest-instrument / exempt / unexempt -> the exact repository writes the CLI commands make (upsert_asset_attestation / upsert_instrument_attestation / upsert_screen_exception / delete_screen_exception), same args, same echo lines - holdings -> gather_holdings + render_holdings (one Enter-gated get_accounts) - discover -> build_discover_report over list_products (Enter-gated, like d+Enter) - subscription show/attest/set -> the bodies extracted into subscription.py (apply_subscription_attest / apply_subscription_set / subscription_show_lines) — one implementation, two front-ends; the CLI commands delegate to them unchanged - withdrawals attest -> the CLI's own set_state writes and echo lines - purification -> build_report + render_purification_report (report-only) Typed contract (O3) preserved: withdrawals attest --enabled keeps the CLI's OWN gate (_require_interactive_confirmation with the command's exact wording, rendered in-console via the curses suspend/restore dance, failing closed); attest — marked "(typed)" by the PRD tree — ends its form with a typed gate demanding the asset code be typed back (never pre-filled, never piped; a wrong phrase writes nothing). Tests prove both gates refuse without the phrase. The scout handler (O6): lists the operator-local shortlists from config's proposals_dir (the existing documented key, default ~/keel/proposals — no new config born; empty state names the directory and the naming convention), renders the chosen file through the admission services (propose -> screen), and offers — never runs — the typed attest step per candidate. Drove a real proposal file end-to-end through the live loop in tests, including a refused typed phrase writing nothing. The Shariah-in-force browser (O10): attestations in force over the ACTIVE allowlist via the new service read gather_attestations_in_force (assets.py — same repository reads and (venue, product) keys as assets list/screen), exemptions in effect, rail 17's live state, and the fiqh-derived constraints each a VERBATIM quote from docs/fiqh-basis.md with a citation pinned to a real section heading (and the vocabulary anchored the same way; gharar rendered as not-stated-there rather than TUI-defined). The honesty lines — "keel is not a fatwa engine", "No scholarly review of keel's fiqh basis has occurred" — always visible and pinned two-sided against the document. New service reads: admission.list_shortlists (every shortlist, newest first, total); assets.gather_attestations_in_force (the allowlist-scoped assets-list read); the subscription writes/show extracted from the CLI bodies. Console gains four modes (compliance, compliance-view, scout-list, scout-view); the top menu's Compliance entry is no longer a placeholder. Fixes #389 Signed-off-by: Elmehdi Aitbrahim <eaitbrahim@gmail.com>
…olled lists, gated reads
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
C3 of the TUI-operator-console PRD (issue #389): the Compliance sub-menu (PRD §3), the scout-results admission handler (O6) and the "Shariah in force" browser (O10) — all dispatching to the existing C1 services; the TUI stays thin (O2). Test-first: the new tests were red before the implementation landed.
Entry → service dispatch (every entry, an existing service or repository function)
admission.build_screen_reportoverassets.screen_product(the one admission gate)admission.build_propose_viewoverproposer.parse_proposal/build_proposal_reportRepository.upsert_asset_attestation— the exact call/argskeel assets attestmakes, same echo lineRepository.upsert_instrument_attestation(product uppercased, wrapper vocabulary =KNOWN_WRAPPERS)Repository.upsert_screen_exception/delete_screen_exception(criterion restricted toWAIVABLE_CRITERIA, blank rationale refused)assets.gather_holdings+render_holdingsbehind ONE Enter-gatedget_accounts(opens ARMED, holds the result — the discover overlay's own gating story)admission.build_discover_reportover one Enter-gatedlist_productskeel/commands/subscription.py(subscription_show_lines/apply_subscription_attest/apply_subscription_set) — one implementation, two front-ends; the CLI commands delegate, byte-compatible (their tests unchanged and green)set_statewrites + echo linescompliance.purification.build_report+render_purification_report(report-only)The typed contract (O3), sacred
withdrawals attest --enabledkeeps the CLI's own gate —clis_typed_withdrawals_gatecalls_require_interactive_confirmation("attest withdrawals as ENABLED", …)verbatim, rendered in-console via the curses suspend/restore dance, failing closed;--suspendedstays ungated (the CLI's asymmetry). A declined gate means not a single state row is written (pinned).attest— marked "(typed)" by the PRD §3 tree — ends its form with a typed gate demanding the operator type the asset code back (the scout flow's attest step is the same form). Never pre-filled, never piped; a wrong phrase writes nothing (pinned for both the menu form and the scout flow, including end-to-end through the live loop)._run_terminal_form: suspend → prompts → restore) and their confirmation line toasts on the menu — every write shows what it did.The scout-results handler (O6)
Lists the operator-local shortlists from config's
proposals_dir(the already-documented key, default~/keel/proposals— the path comes from config, never a TUI-side guess; the empty state names the directory and the naming convention), lets the operator select one, renders it through the admission services (propose → screen,REJECTfor unattested candidates — the gate really ran), and offers — never runs — the typed attest step for a chosen candidate. Proposer-never-decider, in the console too. A real proposal file is driven end-to-end through the live loop in the tests, including a refused typed phrase writing nothing to the deployment's own database.The "Shariah in force" browser (O10)
For the ACTIVE profile, read-only, rendered from records alone:
assets.gather_attestations_in_force(theassets listrepository reads, scoped toconfig.allowlist, instruments keyed by the same(venue, product)the screen looks up) — each with source, ruling and recorded date; unattested allowlisted assets named as the fail-closed gap they are;docs/fiqh-basis.mdwith a citation pinned by test to a real section heading of that document — nothing on the screen is a TUI-authored fiqh summary; the vocabulary (qabd, riba, maisir, attestation, exemption, purification) is quoted from the document the same way, and gharar — which fiqh-basis does not state — is rendered as not-stated-there rather than defined (the document's own honesty rule, inherited);Service-layer additions (reads/extracts, not TUI logic)
admission.list_shortlists— every*shortlist.json, newest first, total, never creating the directory;assets.gather_attestations_in_force— the allowlist-scoped attestation inventory (O10's read);keel/commands/subscription.py.Tests & gates
New:
tests/commands/test_compliance_console.py(38 tests: menu model, every form's exact repository call via a recording repo, both typed gates' refusal, the scout browser, the shariah browser's sourcing) + 5run_liveloop-wiring tests (navigation, screen view offline + broker-never-constructed, form dispatch with the curses suspend dance recorded, the scout browser, and the end-to-end typed attest). Two C2-era placeholder pins intest_console.pyupdated: Compliance now lands instead of saying "lands in C3".uv run pytest -q— 3386 passed, 3 skippeduv run ruff check keel tests packages— cleanuv run mypy— cleanFixes #389