Conversation
…or orphan-CSF-on-DA — DOC SEED Authority gap discovered during dns2 Gate B run #1 (2026-04-29T12:33:02Z): on a real DirectAdmin host with a real CSF install where Gate A canonical takeover succeeded, the classifier returns Authority=AuthorityAmbiguous + Ambiguity=AmbiguityConflictExternal + external=csf because csf-residue (/etc/csf/, /usr/sbin/csf.disabled, lfd.service unit-file, etc.) is intact post-canonical-install per §17.2 invariant. The lattice correctly refused at G1/AmbiguityConflictExternal per the locked §6 Group 1 hard-stop. Amendment 2's G1/AuthorityNFTBan/OrphanProceed was scoped to non-ambiguous AuthorityNFTBan; on srv3 (no real csf install) the classifier returned that; on dns2 (real csf install + canonical takeover) the classifier returns AmbiguityConflictExternal. Same operator intent, different lattice path. Auditor disposition (2026-04-29) approved Option A (narrow lattice extension mirroring Amendment 2). Options B (manual residue cleanup) and C (classifier semantic patch within PR-26 scope) rejected. This amendment appends Part VI (§§62–69) to internal/installer/restore/ contract.md: §62 pinned sentence + scope + invariants + new INV-AMD3-CONFLICT-EXTERNAL-CSF-NARROW §63 G1/AmbiguityConflictExternal split (entirely within Group 1; §5 precedence preserved) §64 evidence predicate (§54/§64 combined; §54 untouched, predicate scoped to §62 entry conditions) §65 forbidden behaviors (extends §25, §34, §38.2, §55) §66 test requirements (unit tests, regression tests, CI grep gates) §67 test matrix — 15 rows including AMD3-13 (empty external defensive guard), AMD3-14 (rule-label assertion for downstream consumers), AMD3-15 (multi-external defensive guard) §68 sequencing recommendation (10 sequential gates to PR-26 final merge) §69 rejected alternatives (Options B, C, D + any-pre-code-A-mutation rejection) Doc-only commit. Single file. No production code change. No CI change. No engine.go or engine_test.go edit. No §54 modification (Amendment 2's predicate stays scoped to AuthorityNFTBan). No classifier semantic change. No §32 ordering change. No new mutation surface. No new state terminal. No new exit code. No host action. Code phase opens in a separate amendment-3-code-A PR after this seed merges and the auditor approves the code-A scope. dns2 stays in canonical post-Gate-A state until code-A merges + fresh Tier 1 + fresh signoff + Gate B retry pre-execution audit returns GO. The Gate B run #1 REFUSE was non-mutating; no R-1 cleanup, no fresh Gate A run, no snapshot rollback needed. PR-26 final remains non-mergeable until amendment-3-code-A lands AND Gate B retry produces StateRestoreExecuted AND post-B auditor returns GO. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
10 tasks
itcmsgr
added a commit
that referenced
this pull request
Apr 29, 2026
…n-CSF split (#523) Implements the §63 lattice extension + §64 evidence predicate from the Amendment 3 doc seed (#522). Decision-layer only. Lattice changes (engine.go): - 3 new rule constants: G1/AmbiguityConflictExternal/default → REFUSE (preserves pre-Amendment-3 hard-stop) G1/AmbiguityConflictExternal/OrphanProceed → PROCEED PanelNative/csf G1/AmbiguityConflictExternal/EvidenceMismatch → REFUSE (predicate any-false) - decideAmbiguityConflictExternal() function mirrors decideAuthorityNFTBan() in shape: Group 2 precedence preserved → quintuple-check (csf + DA + NoRecord + --panel-auto-takeover + --accept-orphan-nftban) → §64 predicate delegation. - Decide() now calls decideAmbiguityConflictExternal(in) for the AuthorityAmbiguous + AmbiguityConflictExternal branch (replaces the inline REFUSE). Evidence predicate (types.go): - New ExternalIndicator string field on DecisionInput (carries the classifier's external-authority string; required for §62 entry condition). - New AllTrueAmendment3() helper on OrphanEvidence: identical to AllTrue() EXCEPT row E.12 (NoConflictExternal) is omitted — the §62 entry IS AmbiguityConflictExternal so requiring "no conflict external" is incompatible by construction. - New FailedRowIDAmendment3() helper returns AMD3-E.{N} stable IDs so structured logs and Code-D evidence-records distinguish which predicate fired. Test matrix (engine_amendment3_test.go — new file): - 15-row §67 matrix (AMD3-1 through AMD3-15) including the 3 auditor- required defensive-guard rows: AMD3-13 empty external, AMD3-14 rule- label assertion ("amendment-3 orphan-intent" reason substring), AMD3-15 multi-external "csf,ufw". - TestAmd3_RuleConstants pins canonical rule strings. - TestAmd3_AllTrueAmendment3_OmitsE12 verifies E.12 is excluded. - TestAmd3_FailedRowIDAmendment3_SkipsE12 verifies row-walk skips E.12. - TestAmd3_NilEvidence_AMD3E0 verifies nil-receiver sentinel. Regression updates (engine_test.go, engine_amendment2_test.go): - 2 pre-existing fixtures asserting the old "G1/AmbiguityConflictExternal" rule string updated to RuleG1AmbConflictExtDefault. Behavior unchanged (still REFUSE); only the rule sub-classifier name shifts. Same pattern as Amendment 2's AuthorityNFTBan/default rename. - declaredRules() in engine_test.go updated to include the 3 new sub-rule constants (RuleG1AmbiguityConflictExt umbrella retained for grep parity). - 2 sentinel fixtures added to allFixtures pinning the new OrphanProceed and EvidenceMismatch rules for coverage assertion (full §67 matrix lives in engine_amendment3_test.go). NOT touched (in scope per operator): - internal/installer/uninstall/* (classifier — semantic unchanged) - internal/installer/restore/execute.go (mutation surface unchanged) - internal/installer/state/* (state machine unchanged) - cmd/nftban-installer/main.go (history gate unchanged) - cmd/nftban-installer/flags.go (flag surface unchanged) - .github/workflows/* (CI unchanged) - §32 11-step ordering (unchanged) - Amendment 2's §54 predicate (untouched; AllTrue() preserved for the AuthorityNFTBan path; AllTrueAmendment3() is a new sibling) Test results (lab4): - go test ./internal/installer/restore/... → ok - go test ./cmd/nftban-installer/... → ok - go test ./... → 64 packages ok, 0 FAIL No host action. No binary rebuild. No nftban-installer invocation. dns2 stays in canonical post-Gate-A state. Closes part of PR-26 final closure path: Gate B retry on dns2 unblocks once this PR merges + fresh Tier 1 binary is built + reachability monitor activates + pre-execution Gate B retry audit returns GO. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
AmbiguityConflictExternal + external=csfon a real DirectAdmin host with a real CSF install where Gate A canonical takeover succeeded, because csf-residue (/etc/csf/,/usr/sbin/csf.disabled,lfd.service) is intact post-canonical-install per §17.2 invariant. The lattice correctly refused at the lockedG1/AmbiguityConflictExternalrow.G1/AuthorityNFTBan/OrphanProceedwas scoped to the non-ambiguousAuthorityNFTBanclassifier state. On srv3 (no real csf install) the classifier returned that. On dns2 (real csf install + canonical takeover) the classifier returnsAmbiguityConflictExternal. Same operator intent, different lattice path.internal/installer/restore/contract.md. Doc-only. Single file. 222 insertions.What changes
INV-AMD3-CONFLICT-EXTERNAL-CSF-NARROWG1/AmbiguityConflictExternalsplit entirely within Group 1; §5 precedence preservedWhat is NOT changed
internal/installer/restore/engine.go— untouched (code-A's scope, separate PR)internal/installer/restore/engine_test.go— untouched (same).github/workflows/*.yml— untouchedAuthorityNFTBanpathINV-PR26-NEW-MUTATION-SURFACES-BOUNDED— preserved (zero new mutation surfaces)INV-PR26-VERIFICATION-IS-PROOF-NOT-DECISION— unchangedINV-AMD2-EXPLICIT-INTENT-IS-NARROW— unchangedAuthoring discipline
Test plan
amendment-3-code-APR implementing the §63 + §64 lattice extension🤖 Generated with Claude Code