Claude/setup project structure 3 yei t#3
Merged
Conversation
Probe of MacFall7/M87-Spine-lite found a sibling Python project with a categorically different six-class taxonomy (SAFE_READ/SHELL_*/SCOPED_WRITE/ RESTRICTED_WRITE/SHELL_DANGEROUS on shell-vs-file lines with numeric risk scores and a 5-step pipeline). spine-lite-python's taxonomy stays canonical: state × boundary × reversibility axes with ordinal precedence, authored from spec. CLAUDE.md mission reworded; halt + operator resolution appended verbatim to RECEIPTS.md as the Phase 2 day 1 opening entry; porting-notes reframed from translation log to design history; surgical edits across nine docs pages drop the stale TS-reference framing. Posture enum members pinned in posture-and-hooks.md ahead of the Phase 2 ship.
Closed StrEnum with four members pinned by docs/concepts/posture-and-hooks.md: INTERACTIVE / AUTONOMOUS / DRY_RUN / LOCKED. Added to spine_lite.__all__ under the Phase 2 sub-option (a) decision recorded in RECEIPTS.md. Phase 3 will add the transition functions; the enum is what the manifest schema validates against in commit 3.
ToolDefinition (frozen, extra="forbid") declares a tool's name, optional description, non-empty effects tuple, optional permitted_postures, an operator-confirmation flag, and free-form metadata. Effects and postures are canonicalised on construction — deduplicated and sorted by enum declaration order — so JSON round-trip is byte-stable across runs and platforms. Manifest holds the dict[str, ToolDefinition] with a validator that enforces name == key. parse_manifest() wraps pydantic.ValidationError as ManifestError so callers catch a single typed exception rooted at SpineLiteError. Accepts dicts, JSON strings, or JSON bytes. Manifest, ToolDefinition, parse_manifest added to __all__. Tests cover canonicalisation, frozen-model immutability, schema rejection (unknown effects, unknown postures, extra fields, name/key mismatch, empty effects, empty postures), JSON round-trip, and byte-stable serialisation.
classify(tool_call, manifest) -> Decision is a pure function: same input, same output, every time. ToolCall and Decision are frozen + slotted + kw-only dataclasses. The Decision carries the tool name, a canonical effects tuple (PRECEDENCE-ordered, byte-stable), the dominant class, and a deterministic rationale string. Tool not declared → ManifestError. Tool declared → Decision with the manifest's stored effects. Phase 2 doesn't refine on the tool call's arguments — manifest is the spec; argument-aware classification is a later phase if needed. ToolCall, Decision, classify added to __all__. Tests cover the happy paths, dominance, canonical ordering, byte-stable rationale, frozen immutability, and the undeclared-tool error path. Module remains pure; Manifest import is TYPE_CHECKING-only to keep the import graph clean.
…ties Four authored fixtures in tests/fixtures/: - manifest_minimal.json — single READ tool - manifest_basic.json — six tools across the taxonomy with postures - manifest_full.json — all 6 effects, all 4 postures, metadata - decisions_basic.json — six expected (call, decision) pairs Parametrized tests confirm every fixture loads and round-trips JSON byte-stably (parse → dump → parse → dump → equal). Decision parity test walks each case in decisions_basic.json against manifest_basic.json and asserts effects + most_restrictive match. Hypothesis property tests at 1,000 examples each cover: - determinism: classify(call, manifest) yields the same Decision every call - dominance: most_restrictive is in the effects tuple - manifest fidelity: Decision.effects == ToolDefinition.effects - byte-stable rationale - round-trip stability: classify(call, M) == classify(call, parse(M.dump())) - argument independence: arguments don't influence Phase 2 classification mypy override added for tests.* to disable disallow_untyped_decorators — hypothesis's @given/@settings don't satisfy strict-decorator typing. Runtime modules stay strict. 99 tests passing, 100% coverage on every runtime module.
Version bumped in pyproject.toml and src/spine_lite/__init__.py; smoke test pinned to 0.2.0a0. CHANGELOG [0.2.0a0] section enumerates Posture, manifest, classifier, fixtures + property tests, the sibling-vs-parity reframing, and the docs-site moves. README status grid marks Phase 2 shipped. New docs/history/phase-2.md narrates the build (commit timeline, design choices recorded, verification, exit gate). RECEIPTS.md gains the Phase 2 exit receipt with the full gate table. mkdocs nav extended to include the Phase 2 history page. 11 of 11 exit-gate items clear in the sandbox; CI verification on push remains operator-side. Phase 3 gated on operator go.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Decisions noted. Phase 2 plan locked:
__all__extensionPosture values from
posture-and-hooks.mdare pinned:INTERACTIVE,AUTONOMOUS,DRY_RUN,LOCKED— proceeding without halting on the secondary gate.