|
| 1 | +# ADR-007: Accept PD-1~PD-7 architecture decisions |
| 2 | + |
| 3 | +Date: 2026-07-14 |
| 4 | + |
| 5 | +## Status |
| 6 | + |
| 7 | +Accepted |
| 8 | + |
| 9 | +## Context |
| 10 | + |
| 11 | +Phase 1 requires implementation-level agreement on the structural decisions that shape Manifest schema, Recipe evaluation, post-trade state, identity claims, enforcement actions, governance, and lifecycle controls. |
| 12 | + |
| 13 | +These decisions are architecture-level foundations. They should be recorded separately from BUIDL-like demo work and RFQ/API implementation work. |
| 14 | + |
| 15 | +## Decision |
| 16 | + |
| 17 | +Corner Store accepts PD-1~PD-7 as the Phase 1 architecture baseline. |
| 18 | + |
| 19 | +### PD-1: Manifest schema and extensibility |
| 20 | + |
| 21 | +Use an explicit `ManifestCore` for stable, human-readable asset state, and move policy-specific requirements into registry-backed `RecipeBinding` entries. |
| 22 | + |
| 23 | +- `ManifestCore` keeps only common core fields. |
| 24 | +- New regulatory policies should not require adding fixed fields to `ManifestCore`. |
| 25 | +- Policy requirements are attached through `RecipeBinding[]`. |
| 26 | +- Recipe identifiers should move toward canonical `bytes32 recipeKey` values managed by a registry. |
| 27 | +- Raw recipe keys should not be exposed directly to normal users/operators. |
| 28 | +- Onboarding should use curated profiles, validation, and simulation. |
| 29 | +- Trade-time execution should use a precompiled compliance plan, not dynamic alias/key resolution. |
| 30 | + |
| 31 | +Open implementation details: |
| 32 | + |
| 33 | +- canonical recipe key naming convention |
| 34 | +- `factsPacked` bit layout ownership |
| 35 | +- gas-bound caps such as max recipes and max elements per evaluation |
| 36 | +- exact compiled plan struct shape |
| 37 | + |
| 38 | +### PD-2: Multi-Recipe evaluation model |
| 39 | + |
| 40 | +Use a Manifest-level multi-Recipe binding model. |
| 41 | + |
| 42 | +Recipes define reusable compliance checks. A Manifest decides how each Recipe is applied through `RecipeBinding`. |
| 43 | + |
| 44 | +`RecipeBinding` must support: |
| 45 | + |
| 46 | +- `REQUIRED_BLOCKING`: mandatory blocking checks. Multiple required recipes are evaluated as AND. |
| 47 | +- `PATH_OPTION`: alternative compliance paths. Recipes with the same `pathGroupId` form an OR group. Each path group passes if at least one recipe in that group passes. Multiple path groups are combined as AND across groups. |
| 48 | +- `FLAG_ONLY`: non-blocking surveillance, reporting, or warning checks. Failure does not block execution but must be logged or surfaced. |
| 49 | + |
| 50 | +Failure reporting must use deterministic `reasonCode` severity, not array order. Binding priority may be used only as a tie-breaker if needed. |
| 51 | + |
| 52 | +The current `issuanceRecipeId + fundRecipeId` layout is transitional. The target model is `RecipeBinding[]`. |
| 53 | + |
| 54 | +### PD-3: Post-trade state model and commit semantics |
| 55 | + |
| 56 | +Use a dual-path state model with post-trade commit. |
| 57 | + |
| 58 | +- Acquisition timestamp is anchored to successful token transfer. |
| 59 | +- Router execution timestamp is recorded separately as execution context. |
| 60 | +- Reliance logs use event-first recording with minimal on-chain commitment hashes. |
| 61 | +- Post-trade commits are idempotent by `executionId`. |
| 62 | +- Replaying the same commit with the same `commitHash` is a no-op. |
| 63 | +- Reusing the same `executionId` with different commit data must revert. |
| 64 | + |
| 65 | +### PD-4: Investor qualification claims and TA integration |
| 66 | + |
| 67 | +Use the ERC-3643/T-REX identity model as the primary interface for investor qualification. |
| 68 | + |
| 69 | +Corner Store should not invent a separate AI/QP identity model. AI, QP, KYC, AML, sanctions, and similar investor facts should be represented as required claim topics checked through the ERC-3643-style identity pipeline: |
| 70 | + |
| 71 | +- Identity Registry resolves wallet to ONCHAINID. |
| 72 | +- Claim Topics Registry defines which claim topics are required for a token/profile. |
| 73 | +- Trusted Issuers Registry defines which issuers may issue those claims. |
| 74 | +- ONCHAINID/IERC735 claims provide topic, issuer, signature, data, and URI. |
| 75 | + |
| 76 | +Claim topic direction: |
| 77 | + |
| 78 | +- AI and QP are explicit claim topics in the project-level claim topic registry. |
| 79 | +- Use ERC-3643-compatible `uint256` claim topic identifiers. |
| 80 | +- Do not assume AI/QP topic numbers are globally standardized. |
| 81 | +- Initial project topics are `ACCREDITED_INVESTOR = 1001` and `QUALIFIED_PURCHASER = 1002`. |
| 82 | + |
| 83 | +Expiry/freshness direction: |
| 84 | + |
| 85 | +- Claim data should include `issuedAt` and `expiresAt` where the issuer provides structured data. |
| 86 | +- Elements may also apply max-age/freshness rules by claim type. |
| 87 | +- If an external issuer does not expose structured expiry data, the adapter must define how freshness is derived or mark the integration as unsupported for production. |
| 88 | + |
| 89 | +Fixture and TA integration direction: |
| 90 | + |
| 91 | +- Tests should use a generic ERC-3643-style TrustedIssuer fixture. |
| 92 | +- BUIDL-like demos may label that fixture as a Securitize-like Transfer Agent profile for explanation only. |
| 93 | +- The fixture must not imply real Securitize compatibility unless an actual integration adapter is implemented and verified. |
| 94 | +- Securitize/DS Protocol integration should be supported through an adapter boundary, not by replacing the ERC-3643 identity model. |
| 95 | +- Actual Securitize/TA integration is deferred to a follow-up refinement issue because it requires official/current details for issuer addresses, claim/topic mapping, revocation, expiry, and production authorization. |
| 96 | + |
| 97 | +### PD-5: Enforcement actions and result handling |
| 98 | + |
| 99 | +Use an explicit enforcement action model with a small closed set of core actions for v1. |
| 100 | + |
| 101 | +V1 core actions: |
| 102 | + |
| 103 | +- `BLOCK`: failed result blocks execution. |
| 104 | +- `FLAG_ONLY`: failed result does not block execution. The finding must be surfaced through flags and events. |
| 105 | +- `OPERATOR_REVIEW`: v1 treats this as blocking. Pending execution or delayed approval is out of scope for v1. |
| 106 | + |
| 107 | +Default action and override: |
| 108 | + |
| 109 | +- Elements define default enforcement actions. |
| 110 | +- `RecipeBinding` may override enforcement only through constrained override modes. |
| 111 | +- Override changes how an Element result is applied; it does not modify the Element logic itself. |
| 112 | +- Accepted override modes are `USE_ELEMENT_DEFAULT`, `ESCALATE_TO_BLOCK`, `ESCALATE_TO_OPERATOR_REVIEW`, and `FORCE_FLAG_ONLY`. |
| 113 | +- Escalation is allowed by default. |
| 114 | +- Downgrading a blocking result to `FLAG_ONLY` is governance-restricted and must not be available through normal onboarding. |
| 115 | + |
| 116 | +`evaluate()` should return both blocking status and non-blocking findings: |
| 117 | + |
| 118 | +```solidity |
| 119 | +struct EvaluationResult { |
| 120 | + bool allowed; |
| 121 | + uint16 blockReason; |
| 122 | + uint256 flagsBitmap; |
| 123 | + bytes32 evaluationHash; |
| 124 | +} |
| 125 | +``` |
| 126 | + |
| 127 | +Enforcement overrides must be resolved into a bounded compiled plan at registration/update time. Trade-time evaluation must not perform dynamic recipe compilation or unbounded override resolution. |
| 128 | + |
| 129 | +Core actions are intentionally not open-ended because each action has execution semantics the Router must understand. Future extensions should first use `reasonCode`, `actionDetail`, or `flagsBitmap`. New execution semantics require a versioned extension and explicit Router support. |
| 130 | + |
| 131 | +### PD-6: Governance, timelock, and emergency authority |
| 132 | + |
| 133 | +Use a role-separated governance model with multisig, timelock, and emergency guardrails. |
| 134 | + |
| 135 | +Signer configuration: |
| 136 | + |
| 137 | +- Governance authority is assigned to an external Safe-style multisig. |
| 138 | +- Corner Store contracts should not implement `n-of-m` signer logic directly. |
| 139 | +- Signer set and threshold changes are handled by the multisig itself without Corner Store contract upgrades. |
| 140 | +- V1 operational target is `2-of-3` for practicality. |
| 141 | +- Production regulated deployments should consider `3-of-5` or stronger separation across protocol, compliance, legal, operations, and external/audit roles. |
| 142 | + |
| 143 | +Governance principle: |
| 144 | + |
| 145 | +- Tightening or stopping risk may be immediate. |
| 146 | +- Relaxing compliance, reopening execution, or expanding trust must require timelock. |
| 147 | + |
| 148 | +Emergency pause reason codes: |
| 149 | + |
| 150 | +- `SECURITY_INCIDENT` |
| 151 | +- `COMPLIANCE_INCIDENT` |
| 152 | +- `IDENTITY_OR_CLAIM_FAILURE` |
| 153 | +- `LEGAL_REQUEST` |
| 154 | +- `MARKET_INTEGRITY` |
| 155 | +- `OPERATOR_ERROR` |
| 156 | +- `OTHER` |
| 157 | + |
| 158 | +Immediate actions are limited to tightening or stopping risk: |
| 159 | + |
| 160 | +- global pause |
| 161 | +- asset pause |
| 162 | +- venue pause |
| 163 | +- issuer disable |
| 164 | +- enforcement escalation |
| 165 | + |
| 166 | +The following require multisig plus timelock: |
| 167 | + |
| 168 | +- unpause |
| 169 | +- compliance relaxation |
| 170 | +- trusted issuer addition |
| 171 | +- required claim removal |
| 172 | +- recipe removal |
| 173 | +- `BLOCK` to `FLAG_ONLY` downgrade |
| 174 | +- router / engine / registry replacement |
| 175 | +- manifest major version changes |
| 176 | + |
| 177 | +All governance actions must emit append-only events with actor, old value, new value, reason code or reason hash, and effective time. |
| 178 | + |
| 179 | +### PD-7: Lifecycle versioning, pause, and record preservation |
| 180 | + |
| 181 | +Use a versioned lifecycle and record-preservation model. |
| 182 | + |
| 183 | +Manifest versioning: |
| 184 | + |
| 185 | +- Manifest version increments when compliance semantics change. |
| 186 | +- Non-semantic metadata changes are tracked separately. |
| 187 | +- Compliance semantic changes include `RecipeBinding` changes, required claim topic changes, TrustedIssuer changes, enforcement action changes, supported venue/engine changes, and manifest major profile changes. |
| 188 | + |
| 189 | +Lifecycle history events should use structured reason codes plus optional reason hashes. |
| 190 | + |
| 191 | +Recommended lifecycle reason codes: |
| 192 | + |
| 193 | +- `REGULATORY_UPDATE` |
| 194 | +- `LEGAL_REQUEST` |
| 195 | +- `ISSUER_UPDATE` |
| 196 | +- `CLAIM_TOPIC_UPDATE` |
| 197 | +- `RECIPE_UPDATE` |
| 198 | +- `VENUE_UPDATE` |
| 199 | +- `SECURITY_INCIDENT` |
| 200 | +- `COMPLIANCE_INCIDENT` |
| 201 | +- `IDENTITY_OR_CLAIM_FAILURE` |
| 202 | +- `OPERATOR_ERROR` |
| 203 | +- `MIGRATION` |
| 204 | +- `OTHER` |
| 205 | + |
| 206 | +All Corner Store DEX executions must enter through an approved Router. The Router is the primary enforcement point for global, asset, and venue pause checks. |
| 207 | + |
| 208 | +Pause state should be stored in a central `PauseController` or lifecycle registry so future routers/adapters share the same source of truth. |
| 209 | + |
| 210 | +Intended split: |
| 211 | + |
| 212 | +- Router: execution entrypoint and pause enforcement point. |
| 213 | +- PauseController / lifecycle registry: pause state and lifecycle history source of truth. |
| 214 | + |
| 215 | +On-chain record preservation is limited to critical state, hashes, and append-only events: |
| 216 | + |
| 217 | +- current manifest version |
| 218 | +- current manifest hash |
| 219 | +- old/new manifest hash events |
| 220 | +- reasonCode |
| 221 | +- reasonHash |
| 222 | +- actor |
| 223 | +- effective time |
| 224 | +- execution / reliance commit hash |
| 225 | + |
| 226 | +Full manifest documents, recipe details, legal/compliance memos, claim evidence, operator tickets, and indexer-exported transaction reports are preserved off-chain and anchored by hashes. |
| 227 | + |
| 228 | +## Consequences |
| 229 | + |
| 230 | +- PD-1~PD-7 are no longer open structural questions for Phase 1; remaining work is implementation specification and follow-up issues. |
| 231 | +- Current code that still uses transitional structures, such as `issuanceRecipeId + fundRecipeId`, should be migrated through separate implementation work. |
| 232 | +- Securitize/TA integration remains an adapter/refinement issue, not a hard dependency of the Phase 1 architecture baseline. |
| 233 | + |
| 234 | +## References |
| 235 | + |
| 236 | +- [Phase 1 structural decisions](../architecture/phase1-structural-decisions-proposed.md) |
| 237 | +- [Decision register](./decision-register.md) |
| 238 | +- [ERC-3643 Claim Topics Registry](https://docs.erc3643.org/erc-3643/smart-contracts-library/onchain-identities/claim-topics-registry) |
| 239 | +- [ERC-3643 Trusted Issuers Registry](https://docs.erc3643.org/erc-3643/smart-contracts-library/onchain-identities/trusted-issuers-registry) |
| 240 | +- [ERC-3643 ONCHAINID Interface](https://docs.erc3643.org/erc-3643/smart-contracts-library/onchain-identities/onchainid-interface) |
| 241 | +- [Securitize DS Protocol Compliance Service](https://medium.com/securitize/ds-protocol-the-compliance-service-b6fe472d625d) |
0 commit comments