Plan S: Multi-Jurisdiction Foundation
On this page
- Status
- Context
- Pre-flight audit findings
- What this plan does NOT touch
- Project-convention conformance
- Per-MR execution checklist (no skipping)
- Architecture summary (full content lives across ADR-032 + ADRs 033-037)
- Service-boundary table
- Verification — what "umbrella program complete" looks like
- Sequencing + estimated calendar
- Risk register
- Out of scope (deferred)
- Next action
Status
| Step | Description | Status |
|---|---|---|
1 |
Closure of superseded work + epic stubs filed at once + memory updates. File umbrella Epic &44 + child epic stubs &45 (Plan T) + &46 (Plan U) + &47 (Plan V) + tracking issue #557 (M6/M7 deferred webMethods broker config destination). Close Epic &43 with supersession comment. Close issues #547-#556 individually with cross-ref comments. Memory updates: NEW |
Done (2026-06-08) — Epic &44 + &45 + &46 + &47 filed + tracking #557 filed via |
2 |
ADR-032 authoring + filing — original scope. Drafted in its own plan-mode session for external review. Title: "Multi-Jurisdiction Partner Registry and Transport Abstraction". Scope: (a) |
Done (2026-06-09) — filed via single docs MR. Body lives at |
3 |
Plan T umbrella body — Adapter Registry Pivot (keystone child plan; restructured 2026-06-09). Plan T body authoring iterated through 5 contextless reviewer rounds + 3 user-driven rounds (8 rounds total). Architectural depth surfaced during iteration justified restructuring into 3 sub-plans (T1 Foundations & Traits / T2 Registry Migration / T3 Open Closures & Hardening) under a Plan T umbrella. Phase A (Step 2 follow-up) shipped ADR-038 (Trait-Object & Registry Patterns) + ADR-032 amendments A1-A11 + closed-aggregator tracking #558 via !657 / sha |
Done (2026-06-09) — umbrella body filed via !658 / |
4 |
Plan T1 — Foundations & Traits authored + filed. Drafted in own plan-mode session per |
Done (2026-06-09) — body filed via !659 / |
5 |
Plan T1 executed end-to-end. All T1.1-T1.9 Done; child epic |
Done (2026-06-10) — 8 step MRs !662-!669 + T1.9 audit-archive MR; epic &51 closed; T1.5 |
6 |
Plan T2 — Registry Migration authored + filed. Drafted in own plan-mode session. Body at |
Done (2026-06-09) — body filed via !660 / |
7 |
Plan T2 executed end-to-end. All T2.1-T2.5 Done; child epic |
Done (2026-06-10) — 5 MRs (!673 / !674 / !676 / !677 + the archive MR); body at |
8 |
Plan T3 — Open Closures & Hardening authored + filed. Drafted in own plan-mode session. Body at |
Done (2026-06-09) — body filed via the Phase E docs MR (see CHANGELOG § Unreleased, adapter-registry-pivot-t3-open-closures entry) |
9 |
Plan T3 executed end-to-end + Plan T umbrella audit + archive. All T3.1-T3.8 Done; child epic |
Done (2026-06-11) — Plan T3 executed in 8 MRs (!679-!685 + !686 archive); epics |
10 |
ADR-034 — Terminology Resolution authored + filed. Drafted in its own plan-mode session for external review. Body lives at |
Done (2026-06-11) — filed via !688 / |
11 |
ADR-036 — Token + Theme Export authored + filed. Drafted in its own plan-mode session for external review. Body lives at |
Done (2026-06-11) — filed via !689 / |
12 |
Plan U — State Bundle Pattern (SCOPE EXPANDED) authored + filed. Drafted in its own plan-mode session for external review. Body lives at |
Done (2026-06-12) — body filed via !690 / |
13 |
Plan U executed end-to-end. All Plan U steps Done; child epic &46 closed; Plan U body archived. Multi-crate feature-flag matrix verified across |
Done (2026-06-15) — Plan U executed U1–U12 (epic &46; #584–#595 closed) + archived ( |
14 |
Plan V — Transport + Substrate authored + filed. Drafted in its own plan-mode session for external review. Body lives at |
Done (2026-06-15) — body filed via !703 / |
15 |
Plan V executed end-to-end. All Plan V steps Done; child epic &47 closed; Plan V body archived. |
Done (2026-06-15) — Plan V executed V1–V8 (epic &47; #597–#604 closed) + archived ( |
16 |
ADR-033 — Plugin Manifest + Render Contract authored + filed. Drafted in its own plan-mode session for external review. Body lives at |
Done (2026-06-16) — filed via !712 / |
17 |
Plan W — Plugin Manifest + Render Runtime authored + filed. Drafted in its own plan-mode session for external review. Body lives at |
Done (2026-06-16) — body filed via !713 / |
18 |
Plan W executed end-to-end. All Plan W steps Done; child epic closed; Plan W body archived. |
Done (2026-06-16) — Plan W executed W1–W8 (epic &48; 605–#612 closed) + archived ( |
19 |
ADR-035 — Composition Layer Engine authored + filed. Drafted in its own plan-mode session for external review. Body lives at |
Done (2026-06-17) — filed via !724 / |
20 |
Plan X — Composition Layer Engine authored + filed. Drafted in its own plan-mode session for external review. Body lives at |
Done (2026-06-17) — body filed via !725 / |
21 |
Plan X executed end-to-end. All Plan X steps Done; child epic closed; Plan X body archived. NEW |
Done (2026-06-18) — Plan X executed X1–X10 (epic &49; #618–#627 closed) + archived ( |
22 |
ADR-037 — Field Ownership + Authz Extension authored + filed. Drafted in its own plan-mode session for external review. Body lives at |
Done (2026-06-18) — ADR-037 (Field Ownership + Authz Extension) filed at |
23 |
Plan Y — Field Ownership + Authz Extension authored + filed. Drafted in its own plan-mode session for external review. Body lives at |
Done (2026-06-19) — Plan Y body authored + filed at |
24 |
Plan Y executed end-to-end. Plan Y execution is the |
Done (2026-06-19) — Y1 the |
25 |
Umbrella program-completion audit + archive. Standard close-out per |
Done (2026-06-19) — this archive MR. Plan S COMPLETE. Program-completion audit run as a 7-slice fan-out + adversarial completeness critic + synthesis (Ultracode workflow): ALL slices |
Epic: &44 (filed at Step 1)
Child epics: &45 (Plan T), &46 (Plan U), &47 (Plan V), &48 (Plan W), &49 (Plan X), &50 (Plan Y) — all 6 child epic stubs filed; iids locked-in. W/X/Y were filed at this Phase 2 commit MR (matching the Step 1 precedent for T/U/V).
ADRs: ADR-032 (in flight; original scope), ADR-033 (Plugin Manifest; Step 11), ADR-034 (Terminology; Step 5), ADR-035 (Composition Engine; Step 14), ADR-036 (Theme; Step 6), ADR-037 (Field Ownership; Step 17)
Issues: filed per-step under &44 + child epics; tracking issue #557 for M6/M7 deferred work
Branch prefix: docs/plan-s-step<N>- for umbrella; <type>/adr-NNN- for ADR-only MRs; <type>/plan-<letter>-step<N>- for child code-execution MRs
*Milestone: TBD
Context
CRAIG ships as open-source CCWIS with a stated multi-jurisdiction mission. Six jurisdiction-variability dimensions are already abstracted across prior plans (rules, admin units, IdP, authz, ICPC, i18n stack). The partners + broker and UI composability dimensions are the last two unaddressed axes before 1.0.
Plan S (Phase 1, !653) addressed partners + broker via 11 closure surfaces opened by ErasedAdapter + AdapterRegistry + StateBundle + BundleContribution + OutboundTransport. ADR-032 anchored; Plans T/U/V execute.
Phase 2 (this re-authoring, 2026-06-08 evening) adds UI composability surfaced by the design team’s response bundle (!654 / sha 8777674f). The 5 engineering contracts (The Five Engineering Contracts) each extend the same BundleContribution aggregate Phase 1 established:
| Contract | Field added to BundleContribution |
ADR + step | Implementation plan + step |
|---|---|---|---|
1. Plugin manifest + render |
|
ADR-033 (Step 11) |
Plan W (Steps 12-13) — runtime in BFF |
2. Terminology dictionary |
|
ADR-034 (Step 5) |
Plan U Step 10 — Fluent overlay |
3. Composition + persistence |
|
ADR-035 (Step 14) |
Plan X (Steps 15-16) — NEW |
4. Token + theme export |
|
ADR-036 (Step 6) |
Plan U Step 9 — CSS route + token migration |
5. Field ownership + authz |
|
ADR-037 (Step 17) |
Plan Y (Steps 18-19) — backend enforcement |
The architectural pattern is shared. Same BundleContribution aggregate. Same boot orchestrator validation. Each contract = one field + one validation step + one registry materialization. The trait grows additively across plans (no field type is mentioned in code before its plan’s first MR introduces it).
Pre-1.0 + no production users = expanding scope here is moderate (~12-14 working weeks total program vs ~5-7 for partner-only). Post-1.0 retrofitting the UI composability layer costs substantially more.
Pre-flight audit findings
Phase 1 findings + new Phase 2 findings:
-
ExchangeAdapteris NOT object-safe — RPITIT; per-crate macro is the seam. -
Object-safe registry precedent —
ClaimsExtractor;StaticActorJwksRegistry;Store::from_config. -
Blanket impl is wrong; per-crate macro is right.
-
StandardAdapteris behaviorally Value-typed. -
10 per-partner crates take
reqwest::Clientdirectly → Plan V Step 2 sequenced after Plan T2 archived. -
DB CHECK constraint closure surface → dual-site validation.
-
No
jurisdiction_codecolumn onexchange_partnerstoday — 1-deployment-1-jurisdiction preserved. -
PartnerTypetaxonomy closure opens viaPartnerTypeRegistry. -
Federal AFCARS/NCANDS mapping interface required — closed enum + bundle-provided mapping enforced at boot.
-
Hardcoded
jurisdiction: "georgia"defaults at 4 production sites — removed in Plan T3 Step T3.6. -
StateBundle::contribute(&self) → BundleContributionaggregate. -
Seed + mock-server closure surfaces addressed by bundle pattern.
-
Create/update flow closure surface — registry-driven validation at API handler.
Phase 2 additions:
-
CRAIG already has Fluent-based i18n (
fluent-bundle+fluent-syntax+unic-langidatservices/craig-web/src/i18n.rs; locales atservices/craig-web/locales/{en,…}). Plan U Step 10 + ADR-034 extend this existing infrastructure; the design team’s TOML-format proposal at Contract 2 is SUPERSEDED by the Fluent convention (ADR-034 also updates Contract 2 to align). -
Canopy has a near-complete composition reference in the canopy repo at
/home/bitskrieg/code/canopy/crates/canopy-composition/(NOT in CRAIG today — Plan X Step 1 ports it). Public surface:CompositionLoader+UserDelta+cache+audit+PluginSourcetrait + role filtering + RFC 6902 JSON Patch + invalidate-on-write. Plan X Step 1 ports this into NEW CRAIGcrates/craig-compositionwith adaptations toBundleContribution. -
Composition baselines are ops territory (user direction 2026-06-08): UI does NOT handle merges/conflicts/PR creation/git workflow. Ops updates baselines via normal git operations against
rulesets/<jurisdiction>/. Studio writes live overrides + user deltas ONLY. -
Plugin manifest uses
linkme-style compile-time registration per canopy precedent (CANOPY_PLUGINSdistributed slice in canopy repo’scrates/canopy-composition/src/source.rs). Plan W Step 2 ports. -
Red is reserved exclusively for danger (design-team locked decision); future build-time lint enforces; PR-review responsibility until.
-
Every plugin must implement all four panel states — build-time lint at
xtask lints four-state-contract(Plan W Step 4). -
Two-audience model for plugins (this revision clarifies): plugin AUTHORS write Rust crates with
#[craig_plugin]macro; jurisdiction OPERATORS use config (rulesets/<jurisdiction>/dashboards.toml) to reference plugins by slug. The design team’s "everything is config, no Rust" tagline describes the OPERATOR experience; plugin AUTHORING is still Rust. -
craig-web(BFF) has NO DB/MQ deps today —services/craig-web/Cargo.tomlhas nosqlx/craig-db/craig-mq/lapin. Plans X + Y must NOT add these deps to the BFF. Composition + field-ownership enforcement land in BACKEND services (Plan X spawns NEWcraig-compositionservice; Plan Y enforces at existing/relevant backend services likecraig-cases). -
CRAIG CSS uses
--color-*token naming (e.g.tokens.cssdeclares--color-primary). Design-team-defined names are--primary/--accent/etc. ADR-036 + Plan U Step 9 ship the migration + a back-compat alias layer (--color-primary: var(--primary);) for grace period through Plan U execution. -
Strict CSP forbids inline
<style>(per Plan C F-018). ADR-036 emits theme tokens via a generated same-origin CSS route atGET /assets/theme.css, NOT inline. -
Feature-flag matrix needs 5 crates (not just
craig-exchange):craig-exchange+craig-web+craig-seed+craig-mock-server+craig-reportingeach declare their ownstate-gaandstate-tx-stubfeatures in their respective Cargo.toml files.
What this plan does NOT touch
-
Other jurisdiction-variability dimensions (rules / admin units / IdP / authz core / ICPC / i18n stack) — already abstracted
-
Operator-side multi-tenancy (one binary serving N states concurrently)
-
Per-state workflow / BPM beyond rulesets
-
Per-state data retention + reporting beyond AFCARS/NCANDS
-
RetryPolicy+IdempotencyPolicyforWebMethodsTransport(#557; GA DHS docs blocker) -
BrokerContractcross-state generalization beyondWebMethodsTransport -
Cross-state PartnerType taxonomy governance + composition harmonization
-
In-UI baseline editing (baselines stay in ops/git)
-
Red-is-danger build-time lint (future sub-plan)
-
A11y annotation sweep (design open thread)
-
Notifications model alignment with
craig-mq(design open thread) -
Print/legal output formats for AFCARS + NCANDS (design open thread)
-
Sign-in / generic IdP deeper config story (design open thread)
-
Studio→Git baseline-editing UI (explicitly out: ops handles baselines via normal git)
Project-convention conformance
| Convention | Source | Applied where |
|---|---|---|
AsciiDoc plan body with ADR-030 Status table |
|
All Status cells + child plan bodies + ADR Status blocks |
Status vocabulary tokens |
ADR-030 §1 |
Every Status cell |
GitLab epic + step issues via |
Plan N/Q/R precedent + recent session (!653/!654) |
Step 1 (DONE) + Phase 2 commit (W/X/Y stubs) + each child plan filing step |
Branch naming |
the |
Each MR |
Commit subjects ≤ 72 chars + type-prefix + |
the |
Every commit |
Token-gated pre-commit D1-D8 via fresh Explore subagent |
|
Every commit |
Pre-push battery green; never |
|
Every push |
CHANGELOG |
Every MR |
|
|
|
Every MR |
|
|
After every Status cell update |
|
|
Every step touching code |
|
|
Every step |
|
|
Every step touching tests |
|
|
Every step adding/removing deps |
No squash-merge |
the git-workflow standard’s merge-don’t-squash rule |
Every MR |
MR creation via |
Every MR |
|
Skip CI pipeline; merge immediately; retry on 405 with 15s sleep |
Every MR |
|
Wait for main before branching; cleanup after merge |
Branch hygiene (wait for main before branching; clean up after merge) |
Every step transition |
CLAUDE.md § Project status active-program line at archive (+ a |
|
Step 20 |
Plan-completion audit subagent |
|
Step 20 + each child archive |
3-4 contextless reviewer passes per plan body + per ADR body |
|
Every plan body + every ADR body |
Pre-1.0 destructive migrations + reseed |
Plan T2 Step T2.4 + Plan X Step 5 + Plan Y Step 3 commits cite |
|
Plain-text "ADR-NNN (anticipated)" cross-refs when target file doesn’t exist yet; convert to |
this revision |
ADR-032 finalization + Status-cell descriptions + Context cross-refs |
Documentation Update Checklist scope: umbrella touches |
|
Step 1 + Step 20; detailed updates in each child plan |
Per-MR execution checklist (no skipping)
-
Pre-branch: standard cleanup sequence
-
Branch: per step’s template
-
Implement per step’s
Files: -
Verify:
cargo fmt --all,cargo nextest run -p xtask --bin xtaskwhen xtask changed,cargo clippy -p <touched-crate> --all-targets — -D warnings,cargo xtask validate --skip-devstack --skip-docker,cargo xtask quality-budgets --report8/8 LOCKED,cargo xtask axis-coverage0 drift,cargo macheteif deps changed -
CHANGELOG with test-count reconciliation
-
Stage + token-gated commit: extract
PRECOMMIT_TOKEN→ fresh Explore subagent for D1-D8 → re-commit with token + step’s titled subject -
Push:
git push -u origin <branch>; verify exit code; verify remote withgit ls-remote -
Open MR via API:
POST /merge_requestswithsquash: false -
Merge immediately:
PUT /merge?should_remove_source_branch=true&squash=false -
Sync + cleanup: post-merge sequence
-
Close issue:
PUT /issues/<id>withstate_event: close(when applicable) -
Update plan body Status cell at next MR (or piggyback)
-
Memory sync when applicable: if the MR introduces new project state (new ADR/plan landing, child plan archive, scope shift, gate flip), update
project_multi_jurisdiction_foundation.md+MEMORY.mdindex in the same MR. For intermediate code-only step MRs that don’t change project state, no memory edit required. Perdelivery-protocol.md § Context Hygiene— keep memory tight, not append-only.
Architecture summary (full content lives across ADR-032 + ADRs 033-037)
The pivot rests on five core abstractions shared across both phases. Each abstraction is jurisdiction-neutral; bundles contribute the per-state specifics.
-
ErasedAdapterseam trait + per-crateimpl_erased_adapter!macro (ADR-032 §1.1). -
Atomically-built immutable registries (ADR-032 §1.2 + sibling ADRs) — all populated at boot from validated `BundleContribution`s, never mutated post-boot. Dual-site validation (boot + request) closes TOCTOU. Each registry lands in a specific child plan; no registry exists in code before its plan’s first MR introduces it.
-
StateBundletrait +BundleContributionaggregate (grows additively) (ADR-032 §2.1).Phase 1 fields ship in Plan T Step 2 (and ONLY Phase 1 fields exist in
craig-exchange-contractsafter Plan T’s keystone work):// craig-exchange-contracts — after Plan T Step 2 pub struct BundleContribution { pub adapters: Vec<(&'static str, Arc<dyn ErasedAdapter>)>, pub audit_codecs: Vec<(&'static str, Arc<dyn AuditCodec>)>, pub mock_routes: Vec<(&'static str, MockRouteFactory)>, pub partner_types: Vec<PartnerTypeMeta>, pub seed_data: SeedContribution, }Phase 2 fields added additively by each ADR’s implementation plan (each field’s type ships in the SAME MR that adds the field to
BundleContribution):-
Plan W Step 1 →
pub plugins: Vec<PluginManifest>(+PluginManifestdefined in NEWcraig-plugin-contracts) -
Plan U Step 10 →
pub terminology: TerminologyContribution(+TerminologyContributiondefined) -
Plan X Step 1 →
pub compositions: CompositionContribution(+CompositionContributiondefined in NEWcraig-composition) -
Plan U Step 9 →
pub theme: ThemeContribution(+ThemeContributiondefined) -
Plan Y Step 1 →
pub field_ownership: FieldOwnershipContribution(+FieldOwnershipContributiondefined)The end-state shape (after Step 19) is the union of all 10 fields. No field type appears in any cross-crate reference before its plan’s MR lands.
-
-
OutboundTransporttrait + concrete impls co-located incrates/craig-exchange-transport(ADR-032 §3.1). -
5-layer top-down composition merge (ADR-035) — user delta → role override → jurisdiction live override → jurisdiction baseline → product default. Ops manages baselines via git; Studio writes live overrides + user deltas. Resolution lives in NEW backend service
services/craig-composition; BFF is a client.
Service-boundary table
Plans X + Y create or extend service boundaries. The BFF (craig-web) stays free of new DB/MQ deps; new state lives in dedicated backend services.
| Surface | Hosting service | Why |
|---|---|---|
Plugin manifest registry + render |
|
Plugins fetch their own data via reqwest; no DB or MQ needed for plugin runtime; existing Askama integration sufficient. |
Theme CSS route |
|
|
Terminology overlay |
|
Extends existing Fluent loader; no new deps; bundles contribute |
Composition resolution + storage + invalidation |
NEW |
Requires sqlx + craig-mq + craig-db. BFF stays a client (HTTP). |
Field ownership tables + propose-approve queue + enforcement |
OWNING backend per surface (initially |
Existing zen-engine authz stack lives in backend services; BFF stays free of authz enforcement. |
Verification — what "umbrella program complete" looks like
Each criterion runnable as a single command. Greps that include AsciiDoc table-cell escapes (\|) unescape to | when copied to a shell.
-
Closed enums removed:
git grep -nE "^(pub )?enum (ExchangeAdapterKind|AnyAdapter|PartnerType)\b" — '*.rs' | wc -lreturns0— the three runtime-switch enums were deleted in Plan T2/T3. NB:PartnerAuditEventis RETAINED by design (it is the closed typed audit-event union theAuditCodectrait produces — ADR-038 §2 trait-location; SHINES/noop have no codec per it), NOT a runtime-switch enum, so it intentionally remains incrates/craig-partner-audit. -
State-neutral build works across all 5 bundle-consuming crates:
for c in craig-exchange craig-web craig-seed craig-mock-server craig-reporting; do cargo check -p $c --no-default-features --features state-tx-stub || exit 1; doneexits 0. -
Georgia build unchanged across the same 5 crates: same loop with
state-gafeature; exits 0; full workspace nextest withstate-gais green. -
Transport abstraction is the only wire path (all 11 consumers — 10 partner adapters + the SHINES
StandardAdapter):git grep -nE "reqwest::Client|self\.client\.(post\|get\|put\|delete)" crates/craig-partner-*/src/adapter.rsANDgit grep -nE "reqwest::(Client\|Error\|StatusCode)" services/craig-exchange/src/adapters/standard.rsboth return only//////doc-comments + the intended*Transport::new(reqwest::Client)constructor seam — no live wire call. (The SHINES check flagged at Plan V Step V8 is folded in here; Plan V’s archived §Cross-cutting-invariants covers both.) -
CHECK constraint dropped:
psql -c "SELECT COUNT(*) FROM pg_constraint WHERE conname LIKE 'exchange_partners_adapter_kind_%'"returns 0. -
Web + CLI registry-driven selectors: grep templates + clap args.
-
API validation is registry-driven:
git grep -nE "is_known_adapter_kind\|is_known_partner_type" services/craig-exchange/src/api/returns matches;git grep -nE "default_adapter_kind\|serde\(default = " services/craig-exchange/src/api/partners_dtos.rsreturns zero. -
Seed is state-neutral:
cargo run --bin craig-seed --no-default-features --features state-tx-stub | grep -ci 'caps\|cprs\|smile\|stars\|wic\|ies\|ions\|tcm\|doe_slds\|empi\|shines\|georgia'returns 0. -
Jurisdiction defaults removed: no PRODUCTION code defaults jurisdiction to
"georgia"(the last production default was removed in Plan T3.6).git grep -nE 'jurisdiction.[:=]."georgia"' crates/ services/ tools/ | grep -v 'tests/\|examples/\|fixtures/'returns only matches inside inline[cfg(test)]modules (georgia is the reference jurisdiction in fixtures) — the criterion’s path filter does not exclude inline test modules, so confirm with a[cfg(test)]-aware scan that non-test hits are zero. -
Federal mapping validated at boot: bootstrap path contains validation block iterating
partner_types_registry.keys()assertingfederal_mapping_registry.contains_key(…). -
Plugin manifest infrastructure exists:
crates/craig-plugin-contracts/exists +#[craig_plugin]macro compiles + reference plugin atplugins/example/builds +xtask lints four-state-contractpasses. -
Composition service exists: NEW
services/craig-composition/exists;composition_overridestable migration ships; invalidate-on-write cache + RabbitMQ fanout cross-replica-tested in devstack; BFF calls composition service via HTTP (no sqlx/craig-mq/lapin deps added toservices/craig-web/Cargo.toml). -
Terminology overlay extends Fluent:
services/craig-web/locales/<jurisdiction>/<lang>/<bundle>.ftlfiles load via bundle contributions; fallback chain (jurisdiction → product default → key-as-literal) works. -
Theme contribution served from CSS route:
curl -s http://localhost:8080/assets/theme.css | grep -E "--primary:|--accent:"returns matches;grep -rn '<style>' services/craig-web/templates/returns zero matches (no inline styles). -
Theme token migration complete:
git grep -nE "var\(--color-primary\)|var\(--color-accent\)" services/craig-web/static/css/returns zero (or only references the alias layer in a single file). -
Field-permission EVALUATION capability shipped (ADR-037 §2/§3, surface-agnostic — Plan Y was re-scoped to deliver exactly this):
git grep -n 'resolve_field_permission' crates/craig-authz/src/engine.rsreturns matches +git grep -nE 'enum FieldPermission' crates/craig-authz/src/types.rsreturns one. The surface-bound APPLICATION (ADR-037 §4–§7 —field_ownership.<surface>.<field>predicates at the owning backend,pending_edits_<surface>, BFF lock-icon + Studio) is DEFERRED to Phase 11 (the CWCA provider portal), tracked by #634 under epic &50 (kept open) — NOT a Plan S deliverable. -
ADRs 032-037 exist + linked:
[ -f docs/modules/ROOT/pages/adrs/adr-032-multi-jurisdiction-partner-registry-and-transport.adoc -a -f docs/modules/ROOT/pages/adrs/adr-033-plugin-manifest-and-render-contract.adoc -a -f docs/modules/ROOT/pages/adrs/adr-034-terminology-resolution.adoc -a -f docs/modules/ROOT/pages/adrs/adr-035-composition-layer-engine.adoc -a -f docs/modules/ROOT/pages/adrs/adr-036-token-and-theme-export.adoc -a -f docs/modules/ROOT/pages/adrs/adr-037-field-ownership-authz.adoc ] && grep -cE 'adr-03[2-7]' docs/modules/ROOT/nav.adocreturns 6. -
multi-jurisdiction-extensibility.adocexists + walks the TX stub: file atdocs/modules/ROOT/pages/multi-jurisdiction-extensibility.adoccontainscraig-state-tx-stub. -
All quality gates green:
cargo xtask validate --skip-devstack --skip-dockerexits 0;cargo xtask quality-budgets --reportshows 8/8 LOCKED. -
Plan body archived: scratch absent + archive present + Plan S row removed from Active in nav.adoc.
Sequencing + estimated calendar
| Phase | Activity | Plan-mode sessions | Calendar |
|---|---|---|---|
0 (Phase 1) |
Plan S initial filing + Step 1 closure |
1 (past) |
Done 2026-06-08 |
0.5 (Phase 2) |
Plan S re-authoring (this document) + iteration to clean |
1 (now) |
~1 day |
1 |
Step 2: ADR-032 finalization (expand for BundleContribution-grows-additively + plain-text refs) + filing |
0 (already drafted) |
~1-2 days |
2 |
Step 3: Plan T umbrella body authoring + filing (replaces single-Plan-T body per Phase B restructure 2026-06-09) |
1 |
~1 day |
3 |
Step 4: Plan T1 (Foundations & Traits) authoring + filing |
1 |
~1-2 days |
4 |
Step 5: Plan T1 execution (~9 child MRs) |
0 |
~1.5 weeks |
5 |
Step 6: Plan T2 (Registry Migration) authoring + filing |
1 |
~1 day |
6 |
Step 7: Plan T2 execution (~5 child MRs; gated on Plan T1 archived + F-065 closed) |
0 |
~1 week |
7 |
Step 8: Plan T3 (Open Closures & Hardening) authoring + filing (CAN parallel Plan T2 execution) |
1 |
~1-2 days |
8 |
Step 9: Plan T3 execution + Plan T umbrella audit + archive (~8 child MRs + 1 umbrella archive) |
0 |
~1.5 weeks |
9 |
Steps 10-11: ADRs 034 + 036 authoring + filing |
2 |
~2-3 days |
9.5 |
Gate: ADRs 034 + 036 Done before Plan U authoring starts (Plan U body cites both) |
0 |
— |
10 |
Steps 12-13: Plan U authoring + execution (~10 child MRs) |
1 |
~2 weeks |
11 |
Steps 14-15: Plan V authoring + execution (~8 child MRs; can parallel Plan U after Plan T2 archived) |
1 |
~2 weeks (parallel-OK) |
12 |
Step 16: ADR-033 authoring + filing |
1 |
~2 days |
13 |
Steps 17-18: Plan W authoring + execution (~8 child MRs) |
1 |
~2-2.5 weeks |
14 |
Step 19: ADR-035 authoring + filing |
1 |
~2 days |
15 |
Steps 20-21: Plan X authoring + execution (~10 child MRs; canopy port + NEW backend service) |
1 |
~3-3.5 weeks |
16 |
Step 22: ADR-037 authoring + filing |
1 |
~2 days |
17 |
Steps 23-24: Plan Y authoring + execution (~7 child MRs) |
1 |
~2 weeks |
18 |
Step 25: Umbrella audit + archive |
0 |
0.5 day |
Total |
25 umbrella steps (was 20 pre-Phase-B); ~76 child MRs (was ~54 — Plan T umbrella alone has ~22 child MRs across T1/T2/T3 vs original ~11 single-Plan-T estimate) + 7 ADR MRs (was 6; added ADR-038) |
14 plan-mode review sessions (was 11; +3 sub-plan sessions for Plan T1/T2/T3) |
~14-16 working weeks (was ~12-14) |
Risk register
| Risk | Mitigation |
|---|---|
|
Compile-fail at the per-call-site invocation; no silent surprise. |
CHECK-drop allows DB to hold unregistered |
Boot + per-request validation closes TOCTOU. |
|
Plan T1 Step T1.1 audit characterizes; macro likely passthrough variant. |
Plan V constructor refactor conflicts with Plan T macro adoption |
Plan V Step 2 hard-sequenced after Plan T2 archived. |
Cargo features cascade |
Build-time controls compile; env var controls activate. Empty |
Child plans expand past step estimate |
Each plan sizes its own scope; umbrella calendar is working estimate. |
|
Per-deployment registry; cross-state alignment is governance. |
Bundle author forgets federal mapping entry |
Boot validation fails-fast. |
Operator sets wrong |
Boot cross-checks against bundle |
Umbrella Status table carries |
Step 20 manual archive fallback per Plan L precedent. |
ADR-032 references ADRs 033-037 with broken xrefs |
Plain-text "ADR-NNN (anticipated)" form until target files land; convert to |
|
The shape is documented as growing additively; no code references a field before its plan’s MR adds it. |
Composition multi-replica invalidation event lost |
10-minute TTL cache fallback bounds staleness; Plan X Step 6 ships + tests the fallback. |
User-delta JSONB schema drift |
|
Studio live-override writes land out-of-order across replicas |
Last-write-wins per key; |
Terminology overlay collisions across bundles |
Multi-bundle deployments are rare per |
Theme |
ADR-036 documents; PR review until lint ships; future build-time lint is its own sub-plan. |
Red used for branding by a future state bundle |
Same as above. |
Field ownership omits a CWCA field |
Plan Y Step 1 boot validation: every field on every multi-tenant edit surface MUST have a |
Plugin’s data endpoint unreachable |
Per-plugin cache + circuit breaker (Plan W Step 6); failed plugin renders four-state error block, not global error. |
Fluent overlay path scheme conflicts with existing loader |
Plan U Step 10 ships loader change scoped to |
Canopy port carries assumptions not valid in CRAIG |
Plan X Step 1 explicit adaptation step; canopy’s |
BFF gains DB/MQ deps despite the ownership boundary |
Verification §12 explicitly checks |
CSP violation from inline theme styles |
Verification §14 greps templates for |
|
Alias layer ( |
Plan U execution waits on ADRs 034 + 036 across two plan-mode sessions (delays Plan U start) |
ADRs 034 + 036 are small (Fluent overlay + CSS route + token names); ~2-3 days total. Sequencing accepts the delay rather than blocking Plan U on parallel-authored ADRs. |
Out of scope (deferred)
-
Operator-side multi-tenancy
-
Per-state workflow / BPM beyond rulesets
-
Per-state data retention + reporting beyond AFCARS/NCANDS
-
RetryPolicy+IdempotencyPolicyforWebMethodsTransport(#557) -
BrokerContractcross-state generalization beyondWebMethodsTransport -
Per-state UI brand layers (theme is bundle-level; agency-specific assets are operator concern)
-
Plan G Step 6 / #462 cross-handler DRY scan
-
Cross-state PartnerType taxonomy governance
-
In-UI baseline editing for composition (ops/git)
-
Red-is-danger build-time lint
-
--color-*alias layer removal (small post-Plan-U sub-plan after CSS consumer migration) -
A11y annotation sweep (design open thread)
-
Notifications model alignment with
craig-mq(design open thread) -
Print/legal output for AFCARS + NCANDS (design open thread)
-
Sign-in / generic IdP deeper config story (design open thread)
-
Studio→Git baseline-editing UI (explicit user direction: ops handles via normal git)
Next action
-
Continue iteration of this re-authored Plan S body via 2-3 contextless subagent review rounds per
delivery-protocol.md:131-136. -
Apply round feedback.
-
Surface for user review round 2.
-
Once clean: execute the Phase 2 re-authoring commit MR with full scope below.
Phase 2 re-authoring commit MR scope
Single docs MR. Branch docs/plan-s-phase-2-re-authoring. Ships:
-
REPLACE
docs/modules/ROOT/pages/plans/multi-jurisdiction-foundation.adocwith the re-authored body (this scratch content moved + SCRATCH header dropped). -
FILE 3 NEW child epic stubs via
glab api POST /groups/…/epics(lock iids matching Step 1 precedent). One stub per child plan with a one-line description pointing at the umbrella; full description added when the child plan’s body is authored:-
Plan W — Plugin Manifest + Render Runtime
-
Plan X — Composition Layer Engine (depends on NEW
craig-compositionbackend service) -
Plan Y — Field Ownership + Authz Extension (backend service enforcement)
-
After filing: edit the Status cells for Steps 11/12/14/15/17/18 to replace
&<W|X|Y>placeholders with the actual iids returned by the API.
-
-
UPDATE
project_multi_jurisdiction_foundation.mdmemory — replace T/U/V-only fact statement with expanded T-Y scope; reference 5 design contracts; cross-link new ADRs; add "Plan letters in flight" subsection (T/U/V Phase 1; W/X/Y Phase 2; Z stays available) and "Calendar shift" note (~5-7 weeks → ~12-14 weeks). -
UPDATE
MEMORY.mdindex — Plan S entry’s description grows to include Phase 2 additions. -
NEW CHANGELOG entry under
docs(plans, multi-jurisdiction-foundation)describing Phase 2 re-authoring. -
Verification:
cargo xtask docs plan-lintclean;cargo xtask validate --skip-devstack --skip-dockergreen; pre-commit D1-D8 via fresh Explore subagent (docs-only MR; expect all PASS/N/A). -
Token-gated commit with
Co-Authored-By:trailer from current system prompt. -
MR:
POST /merge_requestswithsquash: false; immediatePUT /mergewith retry-on-405 loop. -
Post-merge cleanup: standard sequence.
After the Phase 2 commit
-
Resume Step 2 (ADR-032 finalization) — apply expanded-scope BundleContribution-grows-additively language + plain-text "ADR-NNN (anticipated)" cross-refs to ADRs 033-037; commit + merge per the same checklist (uncommitted ADR-032 at
docs/modules/ROOT/pages/adrs/adr-032-multi-jurisdiction-partner-registry-and-transport.adocstill in working tree from Phase 1). -
Continue per Status table.