Skip to content

Commit cf97018

Browse files
committed
chore(consolidation): add governance & verification docs; engine contract; make canonical_full_run import-safe; add determinism regression test
Docs: VERIFICATION_SPINE, GOVERNANCE_SPINE, ENGINE_CONTRACT, SE_STATE Scripts: canonical_full_run made import-safe Tests: add tests/ci/test_canonical_full_run_regression.py Other: various supporting changes from consolidation work
1 parent 63b45d2 commit cf97018

70 files changed

Lines changed: 2623 additions & 19 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

RELEASE_MANIFEST.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
"artifacts": [
33
{
44
"path": "src/shieldcraft/observability/__init__.py",
5-
"sha256": "0dd1049f6ca9bb20cbbae92b02571426f81429fc4bbce84c714f7592cce686b6"
5+
"sha256": "4e7c6d6ee8a124adbf88dbb952a2b2dca2134961cf160b98882be01bab03c403"
66
},
77
{
88
"path": "src/shieldcraft/persona/__init__.py",
99
"sha256": "83d9f0efbda45198c8e4c0db773222af09363ae7ce65335579edcd2897353153"
1010
},
1111
{
1212
"path": "src/shieldcraft/persona/persona_event_v1.schema.json",
13-
"sha256": "5ae47a563d0679f08a20f8d371e36bd0f4069a8396e38a9c7f8ca07f1763484f"
13+
"sha256": "0bc40af4652094fffc1e382c23aa419b322b9bed737a7f5b3cf38a399ab7951a"
1414
},
1515
{
1616
"path": "src/shieldcraft/persona/persona_v1.schema.json",

docs/SE_STATE.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
**SE State (Reference)**
2+
3+
This short reference documents the canonical artifacts and files used to observe SE runs and their verification status.
4+
5+
Primary artifacts:
6+
7+
- `manifest.json` — run-level manifest with generated outputs and lineage.
8+
- `summary.json` — run-level metrics and determinism flag.
9+
- `canonical_preview.json` — canonicalized preview payload used for determinism checks.
10+
- `generated_checklist.json` — checklist used to derive tests and enforce invariants.
11+
12+
Recommended checks for CI:
13+
14+
- Confirm `summary.json` exists and `determinism_match` is `true` for deterministic runs.
15+
- Verify `manifest.json` and `summary.json` fingerprints match baseline expectations for self-build jobs.

docs/engine/ENGINE_CONTRACT.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
**Engine Contract (v1)**
2+
3+
Summary:
4+
5+
- The Engine guarantees: validation against the canonical DSL, deterministic generation (when configured), and auditable artifact emission for self-host runs.
6+
7+
Responsibilities:
8+
9+
- Validate input specs against `spec/schemas/se_dsl_v1.schema.json` before building ASTs.
10+
- Emit deterministic artifacts (manifest.json, summary.json, canonical_preview.json) when `determinism` is required by spec metadata.
11+
- Respect opt-in enforcement flags (e.g., TAC via `SHIELDCRAFT_ENFORCE_TEST_ATTACHMENT`).
12+
13+
Failure semantics:
14+
15+
- Determinism violations are considered CI-blocking unless explicitly allowlisted in governance contracts.
16+
- Validation failures should surface as `schema_error` with a clear error payload.
17+
18+
Observability & audit:
19+
20+
- The engine writes determinism snapshots and emits readiness state for external monitoring. Forensic bundles are produced for self-build mismatches.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
**Governance Spine (v1)**
2+
3+
Purpose:
4+
5+
- Establish authoritative policies for spec contracts, verification, and release gating within ShieldCraft Engine.
6+
7+
Core responsibilities:
8+
9+
- Maintain and publish authoritative contracts and invariants (see `CONTRACTS.md`).
10+
- Owns decision logs and rationale for opt-in guards (e.g., TAC enforcement).
11+
- Onboard and document owners for verification, persona, and engine contracts.
12+
13+
Key artifacts and references:
14+
15+
- `docs/governance/CONTRACTS.md` — concrete contracts and required artifacts.
16+
- `docs/governance/VERIFICATION_SPINE.md` — verification responsibilities and artifacts.
17+
- `docs/persona/PERSONA_PROTOCOL.md` — persona governance and non-interference rules.
18+
19+
Change management:
20+
21+
- All governance changes must be recorded in `docs/governance/decision_log.md` and audited via `scripts/audit_docs.py`.

docs/governance/VERIFICATION_SPINE.md

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,31 @@
22

33
The Verification Spine is a first-class governance subsystem of ShieldCraft Engine.
44

5-
Its role is to validate SE outputs against structural, semantic, and epistemic guarantees.
5+
Purpose:
66

7-
This document defines the existence and scope of the spine only. Verification properties and enforcement logic are defined elsewhere.
7+
- **Goal:** Ensure outputs from the ShieldCraft pipeline meet structural, semantic, and determinism guarantees required for decision-grade artifacts.
8+
- **Scope:** Specification validation, checklist verification, determinism snapshots, readiness evaluation, and artifact-level parity checks.
9+
10+
Responsibilities:
11+
12+
- **Define** blocking and advisory verification gates.
13+
- **Emit** deterministic snapshots and canonical digests for regression tests.
14+
- **Provide** audit-friendly artifacts for external validation (summary.json, manifest.json, canonical_preview.json).
15+
16+
Artifacts:
17+
18+
- `summary.json`: run-level metrics and determinism flag.
19+
- `canonical_preview.json`: canonicalized preview payload used for byte-level determinism checks.
20+
- `generated_checklist.json`: checklist items used for verification and test generation.
21+
- `persona_events_v1.json`: persona event traces when persona is enabled.
22+
23+
Decision points and owners:
24+
25+
- **Verification Owner:** `verification@shieldcraft` (team-level owner responsible for policy and CI gating).
26+
- **Determinism Policy:** Engine and spec maintainers. Determinism violations are treated as CI-blocking regressions unless an allowlist is in place.
27+
28+
Enforcement:
29+
30+
- Verification is applied at preflight and self-host stages. Blocking invariants are enforced only when configured via TAC or authoritative spec flags.
31+
32+
See also: `docs/governance/CONTRACTS.md`, `docs/persona/PERSONA_PROTOCOL.md`, and `spec/se_dsl_v1.spec.json` for concrete contracts.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# SE Readiness Signal
2+
3+
This document defines the SE Readiness signal emitted by the Engine. The readiness
4+
signal is a verification-only artifact and does not change runtime behavior. It
5+
indicates whether the spec + checklist have passed a set of deterministic
6+
verification gates.
7+
8+
Gates included:
9+
10+
- `spec_fuzz_stability`: deterministic spec fuzzing detects contradictions or drift.
11+
- `tests_attached`: every checklist item must have explicit, traceable tests attached.
12+
- `persona_no_veto`: no active persona vetoes may be present.
13+
- `determinism_replay`: recorded seeds + snapshot must replay identically.
14+
15+
Readiness is explicit: the Engine attaches `_readiness` (structured verdict) and
16+
`_readiness_report` (human-readable text) to generated checklist outputs. The
17+
readiness report always contains either a clear `OK` or `NOT READY` state and
18+
reasons for any failures.
19+
20+
This signal is used for operational gating (CI, self-host runs) and for audit.

scripts/attach_test_refs.py

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import re
2+
import json
3+
from pathlib import Path
4+
from collections import defaultdict, Counter
5+
6+
ROOT = Path('.')
7+
TEST_ROOT = ROOT / 'tests'
8+
CHECKLIST_PATH = Path('artifacts/canonical_full_run/run1/generated_checklist.json')
9+
OUT_DIR = Path('artifacts/test_linkage')
10+
OUT_DIR.mkdir(parents=True, exist_ok=True)
11+
12+
# Build test registry
13+
# For each test file, capture: file path, list of test functions, markers, raw content
14+
registry = []
15+
hex_id_re = re.compile(r"[0-9a-f]{10,}")
16+
17+
def extract_tests_from_file(p: Path):
18+
txt = p.read_text()
19+
functions = re.findall(r"def\s+(test_[A-Za-z0-9_]+)", txt)
20+
markers = re.findall(r"@pytest\.mark\.([A-Za-z0-9_]+)", txt)
21+
# build list of full test ids: file::function
22+
tests = [f"{str(p)}::{fn}" for fn in functions]
23+
return {
24+
'path': str(p),
25+
'functions': functions,
26+
'markers': markers,
27+
'tests_full': tests,
28+
'content': txt,
29+
}
30+
31+
for f in sorted(TEST_ROOT.rglob('test_*.py')):
32+
registry.append(extract_tests_from_file(f))
33+
34+
# Index by signals: id substrings, pointers, file names
35+
id_index = defaultdict(list) # id -> list of test_full
36+
ptr_index = defaultdict(list)
37+
file_index = defaultdict(list)
38+
39+
for entry in registry:
40+
content = entry['content']
41+
# find hex ids in content
42+
for m in hex_id_re.findall(content):
43+
id_index[m].extend(entry['tests_full'])
44+
# find pointer-like strings ("/something") appearing in content
45+
ptrs = re.findall(r"(/[-A-Za-z0-9_/$]+)", content)
46+
for p in ptrs:
47+
ptr_index[p].extend(entry['tests_full'])
48+
# index by file stem
49+
stem = Path(entry['path']).stem
50+
file_index[stem].extend(entry['tests_full'])
51+
52+
# Load checklist
53+
items = json.loads(CHECKLIST_PATH.read_text())
54+
55+
attached = {}
56+
items_with = 0
57+
items_without = 0
58+
unlinked_by_category = Counter()
59+
60+
for it in items:
61+
itid = it.get('id')
62+
ptr = it.get('ptr')
63+
category = it.get('category') or 'unknown'
64+
matches = set()
65+
# Direct ID match
66+
if itid:
67+
# hex ids may be longer/shorter; match any registry id that contains this substring
68+
for key, tests in id_index.items():
69+
if itid in key or key in itid:
70+
matches.update(tests)
71+
# direct ptr match
72+
if ptr:
73+
if ptr in ptr_index:
74+
matches.update(ptr_index[ptr])
75+
# also canonical pointer variations: /$schema -> $schema
76+
short = ptr.lstrip('/')
77+
for k, tests in file_index.items():
78+
if short.startswith(k) or k.startswith(short):
79+
matches.update(tests)
80+
# Also search for exact id in any test content (substring scan)
81+
if itid:
82+
for entry in registry:
83+
if itid in entry['content']:
84+
matches.update(entry['tests_full'])
85+
# Stabilize ordering
86+
matches = sorted(set(matches))
87+
# Rule: attach only when clear direct match exists
88+
# 'Clear' = at least one test path that contains the exact id or ptr or has function name referencing ptr
89+
authoritative = []
90+
for t in matches:
91+
# inspect file content for exact id or ptr
92+
fpath, fn = t.split('::')
93+
content = Path(fpath).read_text()
94+
if itid and itid in content:
95+
authoritative.append(t)
96+
elif ptr and ptr in content:
97+
authoritative.append(t)
98+
else:
99+
# check if fn name contains meaningful words from ptr
100+
if ptr:
101+
short = ptr.strip('/').replace('/', '_')
102+
if short and short in fn:
103+
authoritative.append(t)
104+
authoritative = sorted(set(authoritative))
105+
106+
if authoritative:
107+
attached[itid] = authoritative
108+
items_with += 1
109+
else:
110+
attached[itid] = []
111+
items_without += 1
112+
unlinked_by_category[category] += 1
113+
114+
# Write report
115+
report = {
116+
'total_checklist_items': len(items),
117+
'items_with_test_refs': items_with,
118+
'items_without_test_refs': items_without,
119+
'unlinked_by_category': dict(sorted(unlinked_by_category.items())),
120+
'attached_refs': dict(sorted(attached.items())),
121+
'gate_report': {
122+
'gate': 'tests_attached',
123+
'mode': 'report_only',
124+
'do_not_halt': True,
125+
'linked_count': items_with,
126+
'total_count': len(items),
127+
'percent_linked': round((items_with / len(items)) * 100, 2) if len(items) else 0.0,
128+
'blocking_invariants': []
129+
}
130+
}
131+
132+
OUT = OUT_DIR / 'report.json'
133+
OUT.write_text(json.dumps(report, indent=2, sort_keys=True))
134+
print(json.dumps(report, indent=2, sort_keys=True))

scripts/audit_docs.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import json
2+
from pathlib import Path
3+
4+
ROOT = Path('docs')
5+
OUT = Path('artifacts/governance')
6+
OUT.mkdir(parents=True, exist_ok=True)
7+
8+
categories = {
9+
'governance': [],
10+
'spec': [],
11+
'verification': [],
12+
'personas': [],
13+
'engine': [],
14+
'derived': []
15+
}
16+
17+
for p in sorted(ROOT.rglob('*.md')):
18+
rel = str(p.relative_to(ROOT))
19+
if rel.startswith('governance'):
20+
categories['governance'].append(rel)
21+
elif rel.startswith('persona') or rel.startswith('personas'):
22+
categories['personas'].append(rel)
23+
elif rel.startswith('verification'):
24+
categories['verification'].append(rel)
25+
elif rel.startswith('engine'):
26+
categories['engine'].append(rel)
27+
elif rel.startswith('spec'):
28+
categories['spec'].append(rel)
29+
else:
30+
categories['derived'].append(rel)
31+
32+
report = {'categories': categories, 'total_files': sum(len(v) for v in categories.values())}
33+
report_path = OUT / 'doc_classification_report.json'
34+
report_path.write_text(json.dumps(report, indent=2))
35+
print(json.dumps(report, indent=2))

0 commit comments

Comments
 (0)