Skip to content

docs(v1.100 PR-24): contract seed v1 — authority restoration policy engine#493

Merged
itcmsgr merged 2 commits intomainfrom
feat/v1.100-pr-24-restore-contract-seed
Apr 20, 2026
Merged

docs(v1.100 PR-24): contract seed v1 — authority restoration policy engine#493
itcmsgr merged 2 commits intomainfrom
feat/v1.100-pr-24-restore-contract-seed

Conversation

@itcmsgr
Copy link
Copy Markdown
Owner

@itcmsgr itcmsgr commented Apr 20, 2026

This PR is a contract-seed only. It introduces no execution logic, no mutation, and no policy engine implementation. Its sole purpose is to freeze PR-24 restoration-policy semantics before code begins.

Scope

  • ✅ New document: internal/installer/restore/contract.md (338 lines)
  • No Go code
  • No CI workflow changes
  • No state-machine changes
  • No CLI flag wiring
  • No package skeleton beyond the contract file itself

Purpose

Lock the PR-24 design surface before any implementation code lands. Approval of this seed is the merge gate before the code phase begins.

Locked decisions captured in the seed

Lattice (normative, §6)

Lattice v2 with top-down precedence rule:

  1. Classifier hard-stops (AuthorityNFTBan, AuthorityExternal, AmbiguityConflictExternal) → always REFUSE
  2. Input/flag validity (--panel-auto-takeover without panel; --restore + --panel-auto-takeover together) → REFUSE
  3. Prior-record integrity gates (weak records never auto-proceed)
  4. Panel context gates (panel context is inert without --panel-auto-takeover)
  5. Proceed decisions (strong prior + explicit flag)

No later rule may override an earlier refusal. Earlier-rule output is final.

Locked amendments (applied during review before this commit)

  • NoRecord + --restore → REQUIRE_EXPLICIT_INTENT (not PROCEED). --restore carries an implicit target; with NoRecord the target does not exist. Applied in both Group 3.3 (AuthorityNone) and Group 4.2 (AmbiguityOrphanNFTBan).
  • Legacy prior records missing ActiveAtInstall classify as Incomplete. No defaulting to true, no defaulting to false, no inference.
  • Staleness window fixed at 365 days in PR-24; configurability deferred. Implementer has no latitude on this value.
  • StateRestoreDecided is constrained: policy-only, non-terminal for apply semantics, excluded from update-history.json, not evidence that restoration happened.
  • Filesystem purity enforced by static scan + exec-trace; no syscall-level enforcement claimed.

Output discipline (locked)

Exactly three outputs: PROCEED / REFUSE / REQUIRE_EXPLICIT_INTENT. No fourth. No default. No "soft proceed."

State-machine + exit codes (to be implemented later)

  • New terminals: StateRestoreRefused, StateRestoreIntentRequired
  • New exit codes: ExitRefused=5, ExitIntentRequired=6
  • Non-terminal marker: StateRestoreDecided (for PROCEED handoff only)

Forbidden surfaces (locked)

  • No kernel mutation (nft / iptables / ip)
  • No service mutation (systemctl)
  • No filesystem writes in restore package
  • No history-schema changes (update-history.json untouched)
  • No "best effort" / "fallback" / "silent takeover"
  • No restoration-execution code (belongs to PR-25+)

CI gates (to be implemented later)

Four new G4-RESTORE-* gates: decision-correctness, refusal-integrity, no-implicit-exec, determinism.

Merge-blocking real-host matrix (to be run at implementation time)

  • lab2 (Ubuntu/DEB): clean AuthorityNone + NoRecordREQUIRE_EXPLICIT_INTENT
  • lab4 (AlmaLinux/RPM): same
  • Dangerous branches (AuthorityExternal, AmbiguityConflictExternal, AmbiguityOrphanNFTBan, weak-record, panel-driven) are fixture-only — simulating them at kernel level would violate the no-mutation gate via the test harness.

Test plan

This PR has no runtime behavior to test. CI validates:

  • P0 SPDX header validation (pre-commit hook already PASS locally)
  • Policy / docs-quality gates
  • Lychee URL validation on any links in the seed

No Go build, no Go tests, no state-machine diffs should appear in this PR.

Follow-up (tracked in §15 of the seed)

  1. ActiveAtInstall population in new prior-record writes
  2. Staleness-window configurability knob
  3. Uninstall-history schema (carry-forward from PR-23)
  4. Panel-auto + prior-record-identity consistency (revisit in PR-25)

Review gate

Merging this seed indicates approval of the locked lattice, forbidden-surfaces list, state-machine contract, and exit-code contract. After merge, a separate authorization step gates the implementation PR. The implementation PR must implement exactly this contract — nothing more, nothing less.

🤖 Generated with Claude Code

…ngine

Locks the PR-24 design surface before any implementation code lands.
Per pre-commit review discipline: contract-first, not code-first.

Scope: authority restoration policy engine — decision only, no execution.
Three outputs: PROCEED / REFUSE / REQUIRE_EXPLICIT_INTENT. No fourth.

Locked decisions captured in this seed:
- Lattice v2 with top-down precedence rule (classifier hard-stops →
  input validity → prior-record gates → panel gates → proceed)
- NoRecord + --restore → REQUIRE_EXPLICIT_INTENT (no hidden default
  target when operator supplies restore flag against empty record)
- Legacy prior records missing ActiveAtInstall classify as Incomplete
  (no defaulting, no inference)
- Staleness window fixed at 365 days in PR-24; configurability deferred
- StateRestoreDecided explicitly constrained: policy-only,
  non-terminal for apply semantics, excluded from update-history.json,
  not evidence that restoration happened
- Filesystem purity enforced by static scan + exec-trace; no
  syscall-level enforcement claimed
- New terminal states (StateRestoreRefused, StateRestoreIntentRequired)
  and exit codes (ExitRefused=5, ExitIntentRequired=6)
- Four new CI gates in G4-RESTORE-* namespace
- Merge-blocking real-host matrix: lab2 + lab4 clean-state decision
  proof only; dangerous branches are fixture-only

No Go code, no CI workflow changes, no state-machine changes in this
commit. Implementation authorization is a separate user approval step.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 20, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@itcmsgr
Copy link
Copy Markdown
Owner Author

itcmsgr commented Apr 20, 2026

Review frame for PR-24 contract seed (PR #493)

This PR is policy-only. It introduces no execution logic, no mutation, and no implementation scaffolding. It exists solely to freeze restoration-policy semantics before code begins.

Please evaluate against these three guardrails:

1. No semantic drift

  • Do not introduce a fourth outcome, fallback behavior, or implicit paths.
  • Do not weaken refusal conditions or auto-upgrade REQUIRE_EXPLICIT_INTENT to PROCEED.
  • Any change that alters lattice semantics should be rejected or moved to a follow-up PR.

2. No scope bleed

  • No requests to add code, helpers, CLI wiring, state-machine entries, or CI scaffolding.
  • No "minimal implementation" or "prepare for later" changes.
  • This PR must remain a pure contract document.

3. Clarity on intent asymmetry

  • --restore requires a valid prior record (no record ⇒ REQUIRE_EXPLICIT_INTENT).
  • --panel-auto-takeover defines its own target (panel-native firewall) and does not depend on prior record.
  • If this asymmetry is unclear, fix wording — not behavior.

Out of scope for this PR

  • Any execution / restore mechanics (PR-25+)
  • History schema changes
  • State-machine or exit-code wiring
  • CI additions beyond doc-quality checks

Approval of this PR = approval of the locked lattice + precedence + forbidden surfaces + exit semantics. Implementation will be proposed in a separate PR after explicit authorization.

@itcmsgr
Copy link
Copy Markdown
Owner Author

itcmsgr commented Apr 20, 2026

PR ready for review. Contract seed only (policy, no implementation). Guardrails defined in top comment.

…ntic

Two wording-only edits per auditor review of PR #493. Neither changes
lattice behavior; §5 top-down precedence already produces the correct
outcome for the cells they describe.

1. §6 Group 5 wording updated — panel-auto handling spans Groups 3
   and 4, not only Group 3. Previously Group 5's explanatory sentence
   only referenced Group 3; it now explicitly mentions the absolute
   refusal under AmbiguityOrphanNFTBan (§6 Group 4.3).

2. §6 Group 4 precedence clarifier added — one line between the Group
   heading and 4.1 stating: 4.1 and 4.2 match on prior state for
   flags {none, --restore}; 4.3 matches --panel-auto-takeover
   regardless of prior. Resolves a potential reader ambiguity
   between 4.1 and 4.3 when both flags could theoretically apply.

Amendment history updated to record these as v1 auditor-wording
clarifications, separate from the original three seed corrections.

No Go code, no CI changes, no state-machine changes. Still policy-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@itcmsgr itcmsgr merged commit d2b5b44 into main Apr 20, 2026
53 checks passed
@itcmsgr itcmsgr deleted the feat/v1.100-pr-24-restore-contract-seed branch April 20, 2026 11:12
itcmsgr added a commit that referenced this pull request Apr 20, 2026
Implements the pure decision engine defined by the merged contract seed
(PR #493). PR-24 is POLICY ONLY — no kernel, service, or filesystem
mutation, no history write, no restore execution code.

Scope (locked per seed §2):
- internal/installer/restore/ decision engine
- --mode=restore CLI dispatcher
- state-machine entries: StateRestoreRefused, StateRestoreIntentRequired
  (terminal, non-failed, non-apply-terminal); StateRestoreDecided
  (non-terminal handoff marker)
- exit codes: ExitRefused=5, ExitIntentRequired=6 (distinct from
  generic failure to enable scriptability)
- 4 CI gates in G4-RESTORE-* namespace

Lattice (seed §6 v2 + locked amendments):
- Top-down precedence: classifier hard-stops → input validity →
  prior-record integrity → panel gates → proceed decisions
- AuthorityNFTBan / AuthorityExternal / AmbiguityConflictExternal →
  REFUSE absolutely (no flag may override)
- NoRecord + --restore → REQUIRE_EXPLICIT_INTENT (locked amendment:
  no implicit target)
- NoRecord + --panel-auto-takeover + panel → PROCEED (panel-auto
  carries its own target)
- Complete + ActiveAtInstall=false → REQUIRE_EXPLICIT_INTENT (any
  flag; restore semantics ambiguous between preserve-inactive and
  activate)
- Stale / Incomplete → REQUIRE_EXPLICIT_INTENT
- Orphan + --panel-auto-takeover → REFUSE (panel-auto must not fire
  over nftban residue)
- Staleness window fixed at 365 days (seed §3.B; configurability is a
  deferred follow-up)

Output is a closed enum of three values: PROCEED, REFUSE,
REQUIRE_EXPLICIT_INTENT. No fourth output; no default branch; no
fallthrough. Unreached code paths panic as contract-regression guards.

Tests (internal/installer/restore/engine_test.go):
- Rule-path coverage matrix — every Rule* constant must have a fixture
- Determinism — reflect.DeepEqual on two back-to-back evaluations
- Closed-enum output invariant
- Locked-amendment guards (NoRecord + --restore in both AuthorityNone
  and AmbiguityOrphanNFTBan paths)
- Hard-stop dominance — Group 1 refuses under every flag / prior /
  panel combination (4 * 5 * 2 * 3 = 120 cells per hard-stop)
- Orphan + panel-auto refusal under every prior state

CI gates (.github/workflows/ci-restore-canonization.yml):
- G4-RESTORE-NO-IMPLICIT-EXEC — static scan for forbidden symbols
  (exec.*, nft/iptables/systemctl literal calls, service helpers,
  os.Create/WriteFile/Rename/Remove/Mkdir, rebuild/switchop/services
  mutation helpers)
- G4-RESTORE-DECISION-CORRECTNESS — runs the full fixture matrix
  including rule-path coverage assertion
- G4-RESTORE-REFUSAL-INTEGRITY — structural check that restore package
  has no executor dependency AND dispatcher does not import mutation-
  capable packages
- G4-RESTORE-DETERMINISM — two independent test runs; normalized diff
  must be empty

Dispatcher (cmd/nftban-installer/restore_decide.go):
- Classifies authority via uninstall.Classify (single source of truth)
- Probes prior-record via uninstall.Probe (PR-P2-1 hardened schema)
- Reduces uninstall.PriorRecordState + 365-day window → restore.PriorState
- Detects panel via detect.DetectPanel
- Assembles DecisionInput; calls restore.Decide (pure)
- Preflight errors (malformed record, Ambiguous invariant violation)
  short-circuit to ExitFatal WITHOUT emitting a lattice output —
  keeps the three-output space closed (seed §9)
- Transitions state file to terminal (Refused / IntentRequired) or
  non-terminal (Decided)
- history.json write skipped: IsApplyTerminal=false for all three
  states + main.go gate now also excludes cfg.mode=="restore" as
  belt-and-braces defense

No real-host mutation. Decision-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
itcmsgr added a commit that referenced this pull request Apr 27, 2026
#510)

Appends the PR-25 execution contract to internal/installer/restore/
contract.md as a new "PART II — PR-25 execution contract" section
(§§16-29). This is the doc-only first PR of the PR-25 two-PR split,
mirroring the PR-24 PR #493 → PR #494 pattern. The implementation
PR opens in a separate branch after this one merges.

Origin:
The contract is a faithful normalization of the locked Q1-Q5
design decisions (recorded 2026-04-20 during PR-24 freeze Day 0
via the §12 protocol: Stage 1 scope classification + Stage 2
five-field answer + LOCK/REVISE/REJECT review). The v0 staging
sheet (memory/project_pr25_contract_sheet_v0.md) was reviewed and
locked 2026-04-27 prior to opening this PR.

Locked rule applied: "Normalize, do not expand."

Every clause in §§16-29 traces back to a Q1-Q5 lock or to V1100
contract §8. No design decisions were made in this PR.

Section map:
- §16 Purpose
- §17 Scope (Option A) + 2 named invariants
- §18 TargetAuthority concretization (Q2)
- §19 StateRestoreDecided downstream meaning (Q3)
- §20 Panel-auto target consistency (Q4)
- §21 Post-restore verification split (Q5)
- §22 State terminals + exit codes (candidates)
- §23 Execution shape (V1100 §8 ordered)
- §24 Inputs PR-25 may consume
- §25 Forbidden behaviors (consolidated)
- §26 Cross-lock consistency
- §27 What this contract does NOT contain (intentional)
- §28 Merge-blocking real-host matrix (code phase)
- §29 Reviewer checklist (code phase)

Verified live code anchors (2026-04-27):
- knownFirewallType set {ufw, firewalld, iptables, csf} at
  internal/installer/uninstall/prior.go:278-284
- writeHistory gate excluding cfg.mode == "restore" at
  cmd/nftban-installer/main.go:132
- Exit-code constants ExitCommitted=0/ExitFatal=4/ExitRefused=5/
  ExitIntentRequired=6 at internal/installer/state/machine.go:149-155

§1-§15 (PR-24 decision contract) are untouched.

Out of scope (locked):
- No code in this PR. PR-25 implementation is the next PR
  (feat/v1.100-pr25-restore-execution).
- No expansion of Q1-Q5 lock content.
- PR-26 contract stays out of scope.

Lifecycle completion lane (PR-25..PR-30) remains explicitly OPEN
but is now mid-re-entry: contract is the first deliberate step.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant