Module Contract Standard v1 — minimum standard for a lawful module (DRAFT)
Module Contract Standard v1
Status: DRAFT — not enacted. Defines the minimum standard for a lawful module under the modular architecture (HP v4.7 DRAFT, Điều M-1..M-6). Schemas here are normative once enacted; until then they are the working v1 proposal. Date: 2026-06-12.
Design lineage (deliberate reuse, not invention): FIX7 manifest.json (authority strings, denial flags, hash pins, mutation ledger, packet_tree = sha256(HASH_MANIFEST.txt)), O11 patch-as-information-unit (patch.meta.yaml, trust ladder, reject-unread on missing meta), Đ41 §2A task ledger + S0–S5 DB classes, TKT base policies (bad-input probes, evidence ceiling, no PASS-token leakage), Đ30/Đ31 contract files (owner/tier/enabled/grace), Đ44 Family Registry/SCMR (envelope + conformance), Đ35 paired-DOT doctrine.
All five artifacts are data (JSON/YAML), machine-validated by a fail-closed checker. Prose may accompany them; prose never substitutes. NT14 test applies: each artifact must answer — where is the data, who acts, when does it run, what thresholds, how is it checked, what happens on failure.
1. MODULE_CONTRACT.v1 — what the module promises
contract_id: <module_id>.contract # immutable
contract_version: MAJOR.MINOR # MAJOR = breaking (Class C), MINOR = compatible (Class B)
module_id: <snake_case, = family_code> # namespace prefix for all module-local IDs
operations: # exposed surface — the ONLY legal entry points
- op_id: <module_id>.<op_name>
kind: pg_function | rest_endpoint | dot_pair | event | view
input_schema: <JSON Schema ref + sha256>
output_schema: <JSON Schema ref + sha256>
errors: [<error_code>: <semantics>]
idempotency: idempotent | at_least_once | exactly_once_keyed
timeout_ms: <int>
fallback: degrade | queue | fail # consumer-visible failure behavior
invariants: # machine-checkable promises (SQL/check refs)
- inv_id, statement, check_ref
authority_contract: # what this module may NEVER do (deny-list, fail-closed)
denied: [production_write, ddl, secrets_read, approval_author,
kernel_registry_write, other_module_internals, ...]
granted_scopes: [<explicit narrow grants, each with grantor + expiry>]
mutation_contract: # the ONLY state this module writes
writes:
- target: <physical_target_ref> # pg.<db>.<schema>.<table> | kb.<path> | qdrant.<collection>
via: <op_id | dot_code> # never direct/ad-hoc
dot_pair: <DOT-XXX primary / DOT-YYY checker> # NT12 within scope
rollback_contract:
unit: per_change # every promoted change reversible on its own
method: reverse_patch | compensating_op | snapshot_restore
proof_required: staging # PROVEN_IN_STAGING before promotion (kernel doctrine)
max_rollback_time: <duration>
evidence_contract:
test_result_required: true # MODULE_TEST_RESULT.v1 per promotion
bad_input_min_classes: 8 # see §6
evidence_ceiling: L0..L3 # TKT levels; L4+ claims forbidden
compatibility:
provides: <contract_version>
consumes: [{module_id, contract_version_pin: ">=X.Y <X+1"}]
deprecation_policy: <window + migration note required for Class C>
promotion_policy:
classes_allowed: [A, B, C] # D/E never originate in a module lane
level_map: {A: 1, B: 2, C: 3} # minimum pipeline level per class
contract_hash: sha256(<canonical serialization>)
2. MODULE_MANIFEST.v1 — what the module is
manifest_version: 1
module_id: <id>
module_version: <semver>
status: proposed | active | deprecated | retired
owner: {seat: <Đ37 agency/person>, contact: <ref>}
contract_pointer: <kb path or pg ref>
contract_hash: <sha256>
module_registry_pointer: <pg.<db>.<schema> | kb.<path>> # the module's own registry slice
module_registry_hash: <tree/content hash> # drift-checked (paired DOT)
declared_surfaces: # diffable boundary — classifier input
repo_paths: [modules/<module_id>/**]
kb_paths: [knowledge/<...>/**]
pg_objects: [<tables/functions/views owned>]
dot_codes: [DOT-...]
routes: [/...]
dependencies: [{module_id, contract_version_pin}] # contracts only, never internals
sandbox:
db_access_class_max: S2 # Đ41 ceiling for module lanes
deny_charter_ref: <path> # O11-style, fail-closed
promotion_state: L0 | L1 | L2 | L3 | L4
compatibility_state: compatible | degraded | incompatible # computed, not declared
aggregates: # published rollups for global pivots/Đ43
counts: {<kind>: <int>, ...}
last_published_at: <ts>
envelope_hash: sha256(HASH_MANIFEST.txt) # FIX7 packet_tree convention
The global registry stores exactly this envelope (plus kernel bookkeeping). Internal objects stay in the module registry slice (HP v4.7 Điều M-5.3 globalization test: cross-module / authority-bearing / production-bearing / kernel-bearing only).
3. MODULE_TEST_RESULT.v1 — proof per promotion
module_id / module_version / contract_hash # binds result to exact contract
suite:
local_tests: {total, passed, failed, skipped(reason required)}
contract_tests: {schema_validation, invariant_checks, surface_diff_check: PASS|FAIL}
bad_input_probes: {classes_covered: [...], total, fail_closed, any_fail_open: false, # MUST be false
detector_correctness_verified: true, pass_token_leak_check: PASS}
consumer_retests: [{module_id, pin, result}] # Class B/C only
evidence_level_claimed: L0 | L1 | L2 | L3 # ceiling; higher claims auto-FAIL
exit_codes_ref: <byte-stable exit_codes.json>
result: PASS | FAIL | BLOCKED_WITH_EXACT_GAP # Đ41 vocabulary; no other verdicts
result_hash: sha256(...)
BLOCKED_WITH_EXACT_GAP is the only legal substitute for missing tests, and it must name the exact gap (Đ41 §2A rule).
4. MODULE_PROMOTION_PACKET.v1 — what crosses a lane gate
A directory/KB subtree following the FIX7 skeleton, minimum members:
| File | Content |
|---|---|
manifest.json |
MODULE_MANIFEST.v1 snapshot + final_status + explicit denial flags (production_mutation:false, …) + consumed-input hash pins + executed-mutations ledger (before/after sha256 + revision) |
MODULE_TEST_RESULT.json |
§3 artifact |
MODULE_ROLLBACK.json |
§5 artifact incl. staging proof refs |
HASH_MANIFEST.txt + packet_tree.sha256 |
per-file sha256; tree = sha256(HASH_MANIFEST.txt) |
commands.sh / RERUN.sh |
self-verify + fresh-from-source byte-exact reconstruction |
class_decision.json |
classifier output: computed class, inputs (diff summary, contract delta), classifier version+hash |
| consumer sign-offs | Class C only: one signed ack per affected consumer owner |
Class A/B anti-ceremony cap (HP v4.7 Điều M-3.4): for Class A, only manifest.json, MODULE_TEST_RESULT.json, and MODULE_ROLLBACK.json (with class_decision.json generated automatically) may be required. Demanding more is itself a violation; expanding the required set is a Class D change.
5. MODULE_ROLLBACK.v1 — local rollback as data
change_ref: <patch/packet id>
method: reverse_patch | compensating_op | snapshot_restore
artifacts: [<reverse patch / compensating script refs + sha256>]
staging_proof:
performed_at: <ts>
environment: <mktemp path | sandbox db/schema | sandbox_run_id>
sequence: baseline → apply → rollback → byte-exact-to-pin verify
verdict: PROVEN_IN_STAGING # required before promotion
validator: <ref> # must gate ROLLBACK_APPLY_DID_NOT_MUTATE
# and ROLLBACK_NOT_RESTORED_TO_PIN
production_applicability: NOT_APPLICABLE | <per-action grant ref> # default NOT_APPLICABLE
max_execution_time: <duration>
cleanup_command: <one command> # Đ41 S2 rule, verified evidence
6. Required capabilities of a lawful module
- Input/output adapter: all external interaction through declared operations validating against published schemas; raw access to module internals from outside = violation (both sides).
- Isolated namespace: all module-local IDs carry the
module_idprefix; no arbitrary global-ID minting; global IDs only via kernel birth/registration paths. - Contract tests: schema validation + invariant checks + surface-diff check, runnable by one command, exit-code stable.
- Bad-input tests: mandatory probe suite covering at least these classes — omitted required file, tampered hash, fabricated base/pin, PASS-string injection, schema-invalid input at each adapter, out-of-scope diff (boundary escape), path traversal/symlink escape, unauthorized-surface write attempt. Requirements: 100% fail-closed,
any_fail_open=false, detector-correctness (probe fails for the right reason), no success-token leakage in names/output. - Compatibility declaration: provides/consumes pins per §1; computed
compatibility_statemaintained by the drift-checker DOT pair. - Promotion class discipline: every change carries a computed
class_decision.json; the module never self-declares its class. - Paired checker: at least one DOT pair (writer + checker) per mutation target (NT12 in scope); an idle checker is healthy, a missing one is illegal.
7. Forbidden patterns (fail-closed; any occurrence = violation, packet rejected unread)
| # | Forbidden pattern | Why / enforcement |
|---|---|---|
| F1 | Direct global-registry write without adapter (INSERT into Family Registry/collection_registry/dot_tools/birth_registry/normative tables from module code) | Kernel registries are written only via kernel paths (birth functions, registered DOTs, APR). Checker: mutation_contract targets ∩ kernel tables = ∅ |
| F2 | Direct production surface call (prod PG, Directus admin, deploy, REAL_RUN, QT001, permits, cutover, prod toggles) | Modules end at S2. Production = Class E lane with per-action Owner grants. Probe class in §6.4 |
| F3 | Dependency on another module's internal files/tables/functions | Contracts only. Checker: imports/refs resolved against consumed contracts; anything else fails |
| F4 | Undeclared shared mutable state (shared tables, files, caches not in any mutation_contract) | Two manifests claiming the same write target without a bus contract = both degraded; writes to undeclared targets = reject |
| F5 | Arbitrary global object ID creation (minting codes/addresses outside the module namespace without kernel birth) | Identity is kernel authority (Đ0-G). Namespace-prefix check + birth-path audit |
| F6 | Self-authorized authority changes (module editing its own authority_contract, granted_scopes, deny charter, class mapping, or approver routing) | Authority changes are Class D minimum, decided outside the module. Contract checker pins authority sections to the last externally-approved hash |
| F7 | Self-declared blast-radius class or evidence level above ceiling (L4+) | Classifier output only; TKT overclaim rule — auto-FAIL |
| F8 | Sandbox→prod leakage: prod secrets/roles/network in module env; unverified cleanup; untagged sandbox rows | Đ41 S2 + O11 charter; scrubbed-env requirement |
| F9 | PASS-token leakage / probe suites that cannot fail | TKT detector-correctness rule; suite with any_fail_open=true is itself a FAIL |
8. Minimum lifecycle of a lawful module
proposed (envelope registered, contract v0, maturity M0) → active (contract v1 enacted-for-module, checker pair live in block mode, L1+ promotion passed) → deprecated (no new consumers; existing pins honored through deprecation window) → retired (preservation law: nothing deleted; envelope + slice archived, supersedes edge recorded). A module may not be active without: owner seat, contract hash, drift checker, bad-input suite, rollback method. — End of standard v1.