diff --git a/README.md b/README.md index 0b53408..e5a4a98 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,11 @@ pytest test_stop_machine.py -v - All transitions explicit - RED is terminal +## Docs + +- [Geometry Export Spec v0.1](docs/geometry_export_spec_v0.1.md) — log schema, artefact paths, and determinism rules for Geometry Layer v0 (experimental, analysis-only) + + ## License MIT diff --git a/docs/GEOMETRY_LAYER_V0_FIT_REPORT_dddc878.md b/docs/GEOMETRY_LAYER_V0_FIT_REPORT_dddc878.md new file mode 100644 index 0000000..23f450a --- /dev/null +++ b/docs/GEOMETRY_LAYER_V0_FIT_REPORT_dddc878.md @@ -0,0 +1,114 @@ +# Geometry Layer v0 — Build Fit Report + +> **Repo:** LalaSkye/stop-machine +> **Commit pin:** dddc878 +> **Date:** 2026-02-23 +> **Status:** OK TO PROCEED +> **Scope:** NON_EXEC (design + integration check only) + +--- + +## 1. Repo Layout (Actual @ dddc878) + +``` +stop-machine/ +├── .github/workflows/ci.yml +├── examples/ (5 demo scripts) +├── primitives/ +│ ├── ambiguity-detector/ (detector.py, test_detector.py) +│ ├── authority-gate-v0/ (STUB — raises RuntimeError) +│ ├── consistency-tester/ (tester.py, test_tester.py) +│ ├── envelope-gate/ (gate.py, rules.py, envelope_parser.py, cli.py, tests, conftest) +│ ├── invariant-lock/ (invariant_lock.py, test_invariant_lock.py) +│ ├── no-optimisation-wrapper/ (wrapper.py, test_wrapper.py) +│ └── stop-machine-v0/ (STUB — raises RuntimeError) +├── ALVIANTECH_COMMS_CENTER_v0.1.md +├── CANONICAL.md +├── GATE_LOG_v0.1.md +├── LICENSE (MIT) +├── README.md +├── stop_machine.py +└── test_stop_machine.py +``` + +**Key facts:** +- Pure Python, no packaging (no pyproject.toml, setup.cfg, requirements.txt) +- Only dependency: pytest (pip install pytest) +- No `__init__.py` anywhere; imports use `importlib.util.spec_from_file_location` +- No existing `docs/`, `analysis/`, or `scripts/` directories +- Two v0 stub folders raise RuntimeError on import; CI drift alarms enforce this + +--- + +## 2. CI Structure (Actual) + +Single workflow: `.github/workflows/ci.yml` +- Trigger: push/PR to main +- Matrix: Python 3.10, 3.11, 3.12 on ubuntu-latest +- Steps: checkout, setup-python, pip install pytest, 2 drift alarms (grep), run primitive tests, run root tests +- No artefact uploads; no continue-on-error jobs; everything gating +- CI status: GREEN on main (54 runs, latest passing in 12s) + +--- + +## 3. Runtime Architecture + +- `stop_machine.py`: 3-state FSM (GREEN/AMBER/RED), ~80 LOC, zero imports beyond enum +- `envelope-gate`: Most complex primitive (4 source files, 18 rules, ALLOW/HOLD/DENY/SILENCE exit algebra) +- All primitives: pure functions, frozen dataclasses, deterministic, no side effects +- Import pattern: `_load_local()` via importlib; sys.modules collision risk documented in conftest.py + +--- + +## 4. Proposed Slot-In Paths + +| Addition | Path | Rationale | +|----------|------|-----------| +| Analysis code | `analysis/` (new top-level) | No collision; not importable by runtime | +| Geometry spec | `docs/geometry_export_spec_v0.1.md` | Establishes docs/ pattern | +| Fit report | `docs/GEOMETRY_LAYER_V0_FIT_REPORT_dddc878.md` | This file | +| Adversarial tests | `primitives/envelope-gate/test_envelope_gate_adversarial.py` | Discovered by existing `pytest primitives -v` | +| Log schema | Defined in docs spec; emitted as JSONL | Separate from existing Markdown gate log | +| CI job | `geometry-analysis` in ci.yml | First non-gating job; first artefact upload | + +--- + +## 5. Conflicts and Resolutions + +| Conflict | Resolution | +|----------|------------| +| No docs/ folder exists | Creating it establishes the pattern cleanly | +| Existing Markdown gate log vs JSONL | Geometry logs are entirely separate path + format | +| sys.modules collision risk | Analysis operates on emitted logs only; if must load runtime, use unique module names | +| No continue-on-error precedent | geometry-analysis job will be documented as first non-gating job | +| No artefact upload precedent | Define canonical path in spec before first use | + +--- + +## 6. Risk List + +1. **Import collision via _load_local**: Analysis must not use bare module names like "gate" or "rules" +2. **Logging failures changing behaviour**: Emission wrapped in try/except; failure = no log, not altered gate result +3. **CI brittleness**: Missing logs treated as "no data"; geometry job uses continue-on-error +4. **Packaging leak**: No packaging exists currently; if added later, exclude analysis/ +5. **Markdown log contamination**: Geometry JSONL uses completely separate path from GATE_LOG_v0.1.md + +--- + +## 7. Absolute Invariants (Must Hold) + +- No change to ALLOW/HOLD/DENY/SILENCE exit algebra +- Runtime code never imports from analysis/, docs/, or artifacts/ +- Logging is side-effect free; absence of logs changes nothing +- CI geometry job is non-gating (continue-on-error: true) +- Deterministic output: same input = byte-identical JSONL + +--- + +## 8. Verdict + +**OK TO PROCEED.** No HOLD conditions triggered. + +--- + +**END — GEOMETRY_LAYER_V0_FIT_REPORT_dddc878** diff --git a/docs/geometry_export_spec_v0.1.md b/docs/geometry_export_spec_v0.1.md new file mode 100644 index 0000000..90d6fb8 --- /dev/null +++ b/docs/geometry_export_spec_v0.1.md @@ -0,0 +1,159 @@ +# Geometry Export Spec v0.1 + +> **Repo:** LalaSkye/stop-machine +> **Commit pin:** dddc878 +> **Status:** DRAFT +> **Scope:** Analysis-only instrumentation (no runtime semantic change) +> **MCCS dependency:** None + +--- + +## 1. Purpose + +Define the log schema, artefact path conventions, and determinism rules +for Geometry Layer v0. This layer emits structured events from the +envelope-gate conformance checker to enable offline transition-graph +reconstruction and optionality analysis. + +**This spec covers logging and observability only. It does not change +ALLOW / HOLD / DENY / SILENCE outcomes.** + +--- + +## 2. Artefact Path Convention + +``` +artifacts/geometry/v0/stop-machine/dddc878/${RUN_ID}/ +``` + +- In CI: `RUN_ID = ${{ github.run_id }}` +- Local runs: `RUN_ID = "local"` + +All artefacts within a run are JSON Lines (`.jsonl`) files. + +--- + +## 3. Log Format + +- **Format:** JSON Lines (one JSON object per line) +- **Encoding:** UTF-8 +- **Key ordering:** Canonical (sorted keys via `json.dumps(sort_keys=True)`) +- **Timestamps:** No wall-clock timestamps. Use monotonic integer counter + or omit entirely. Analysis scripts may add external timestamps. + +--- + +## 4. Event Schema (v0.1) + +Each line in a `.jsonl` file MUST be a valid JSON object conforming to: + +```json +{ + "schema_version": "0.1", + "primitive": "envelope-gate", + "event": "gate_evaluated", + "envelope_id": "", + "exit": "ALLOW|HOLD|DENY|SILENCE", + "violations": ["R0_MISSING_HEADER", "ENUM_INVALID_SENDER"], + "input_hash": "", + "result_hash": "" +} +``` + +### Field definitions + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `schema_version` | string | yes | Always `"0.1"` for this spec version | +| `primitive` | string | yes | Primitive that emitted the event | +| `event` | string | yes | Event type identifier | +| `envelope_id` | string or null | yes | `msg_id` from the envelope, or null | +| `exit` | string | yes | Gate exit decision (ALLOW/HOLD/DENY/SILENCE) | +| `violations` | array of strings | yes | Violation code identifiers (may be empty) | +| `input_hash` | string | yes | SHA-256 hex digest of canonical envelope raw text | +| `result_hash` | string | yes | SHA-256 hex digest of canonical result fields | + +### Hashing rules + +- `input_hash`: `sha256(envelope.raw.encode("utf-8")).hexdigest()` +- `result_hash`: `sha256(canonical_result_string.encode("utf-8")).hexdigest()` + where `canonical_result_string = json.dumps({"exit": exit, "violations": sorted_violations}, sort_keys=True)` + +--- + +## 5. Emission Rules + +- Emission is **OFF by default**. +- Enabled only when the environment variable `GEOMETRY_LOG_PATH` is set + to a writable file path. +- All writes are append-only. +- Emission is wrapped in `try/except Exception: pass`. +- If the path is invalid or the write fails: **do nothing**. +- Absence of logs MUST NOT change gate behaviour. + +--- + +## 6. Determinism Requirements + +- Same envelope raw text, same rules, same commit = identical JSONL output. +- No wall-clock time in emitted events. +- Key ordering is canonical (sorted). +- Violation lists are sorted. +- Hashes are computed from canonical representations. +- Replaying the same inputs twice MUST produce byte-identical JSONL. + +--- + +## 7. Transition Graph Reconstruction (Analysis-Only) + +Analysis scripts in `analysis/` may reconstruct a transition graph from +collected JSONL events: + +- Each `gate_evaluated` event represents a node (state) and edge + (transition from input to exit decision). +- `|Omega(t)|` (reachable state count) is a candidate measure computed + offline from the collected graph. +- Interpretation of `|Omega(t)|` is **out of scope for v0**. + +--- + +## 8. Runtime / Non-Runtime Boundary + +| Path | Classification | May import from runtime? | +|------|---------------|-------------------------| +| `stop_machine.py` | Runtime | N/A | +| `primitives/**/*.py` | Runtime | N/A | +| `analysis/**` | Non-runtime | Yes (by file path only) | +| `docs/**` | Non-runtime | No | +| `artifacts/**` | Non-runtime | No | +| `examples/**` | Non-runtime | No | + +**Runtime code MUST NOT import from analysis/, docs/, or artifacts/.** + +If analysis code must load runtime modules, it MUST use file-path-based +loading with unique module names to avoid `sys.modules` collisions: +`module_name = "geom_" + sha256(path)[:12]` + +--- + +## 9. CI Integration + +- A `geometry-analysis` CI job runs after tests. +- It MUST use `continue-on-error: true` and `if: always()`. +- It uploads artefacts from `artifacts/geometry/**`. +- It does NOT gate merges. + +--- + +## 10. What This Spec Does NOT Cover + +- MCCS API hooks or certification handshake +- Metric branding or wrapper-vs-substrate equivalence +- FOI-specific reporting +- Any change to exit algebra or decision mapping + +Those remain downstream and will reference this spec if needed. + +--- + +**END — geometry_export_spec_v0.1**