Skip to content

sync: v17.0 catch-up — Phase 136 (core decoupling) + Phase 137 waves 1–4 (crosswake_sigra) — no publish - #41

Merged
szTheory merged 68 commits into
mainfrom
sync/main-v17.0-phase137-catchup
Jul 2, 2026
Merged

sync: v17.0 catch-up — Phase 136 (core decoupling) + Phase 137 waves 1–4 (crosswake_sigra) — no publish#41
szTheory merged 68 commits into
mainfrom
sync/main-v17.0-phase137-catchup

Conversation

@szTheory

@szTheory szTheory commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Scope

Boundary catch-up: local main is a clean superset of origin/main, 66 commits ahead, 0 divergence (fast-forwardable). Lands the v16.0 milestone-archival tail + all of v17.0 to date (Phase 136 complete + Phase 137 waves 1–4). Follows the established sync/main-* boundary-PR pattern (#28, #40) — merge commit, no squash, .planning/ included.

No hex.pm publish in this PR. This is repo hygiene + a sync to origin. Publishing crosswake_sigra is a separate deferred human gate (Plan 137-05); its release-please Release PR will open after this lands and stays unmerged.

Why

Get the repo into a clean state before continuing v17.0: land accumulated work to origin, get CI green, refresh stale GSD state, and update the user-facing changelog. See docs/MILESTONE-BOUNDARY-HYGIENE.md (added here) for the reusable ritual.

Shape

212 files across 66 commits (36 docs / 19 feat / 4 test / 3 fix / 2 refactor / 2 chore):

  • .planning/ — 139 files (milestone archival, v17.0 roadmap/requirements, phase 136/137 planning + summaries; already tracked on origin)
  • packages/crosswake_sigra/ — 35 files (new standalone Hex package; module names preserved = non-breaking)
  • lib/ — 9, test/ — 19 (D-4 Finding boundary refactor + sigra test migration)
  • .github/ — 1, script/ — 1 (crosswake_sigra release-please component + no-engine clean-room mode)
  • CHANGELOG.md + docs/ — 2 (Unreleased honesty pass + hygiene runbook)

Highlights

  • Phase 136 (Core Decoupling) — complete + verified: inverts the auth/notification coupling sites onto the runtime :companions registry (optional @behaviour callbacks + function_exported?/3). Non-breaking; adopter touch-point config :crosswake, :companions unchanged.
  • Phase 137 waves 1–4 (crosswake_sigra) — green: D-4 %Finding{axis: :auth} boundary end-to-end; mechanical extraction into packages/crosswake_sigra/; independent release-please component + CI publish pipeline wired; hex.publish --dry-run green.

Tests

  • Phase 136 full suite 1162/0; Phase 137 dress rehearsal core 1029/0 + package 137/0; crosswake_sigra hex.publish --dry-run green (correct name/version/files, test/ excluded). All local, --seed 0 deterministic.

Deferred / admin follow-ups (not in this PR)

  • No hex publish: the crosswake_sigra (0.1.0), and existing crosswake_rulestead/crosswake_rindle (chore(main): release crosswake_rulestead 0.1.0 #39/chore(main): release crosswake_rindle 0.1.0 #38) Release PRs remain open/deferred by design.
  • Admin (harness-blocked): provision BRANCH_PROTECTION_READ_TOKEN (stops the scheduled required-checks-audit self-paging); optionally register merge-blocking lanes green-first (DRY_RUN=0 script/register_required_checks.sh) — see 135-REQUIRED-CHECKS-REGISTRATION.md.
  • Phase 137 stays mid-flight at its wave-5 human publish gate; Phase 138 (crosswake_chimeway) is next.

🤖 Generated with Claude Code

szTheory and others added 30 commits June 30, 2026 09:57
PR #40 merged (main=029aa4a, origin at v16.0). STATE now records the completion
handoff: only remaining steps are (1) admin lane registration (human gate by design,
green-first) and (2) /gsd-complete-milestone v16.0. Audit already PASSED.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Archive ROADMAP/REQUIREMENTS/AUDIT + phase dirs (129-135) to milestones/;
collapse ROADMAP v16.0 to a one-line <details> entry; evolve PROJECT.md
(v16.0 → Validated, package-family Context + Key Decisions, next-milestone
goals) and STATE.md. Safety checkpoint before REQUIREMENTS.md removal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add v16.0 milestone section (what worked / inefficient / patterns / lessons)
and four new cross-milestone trend rows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Archived to .planning/milestones/v16.0-REQUIREMENTS.md; fresh REQUIREMENTS.md
will be created by the next milestone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…coupling

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add @callback forbidden_metadata_keys/0 :: [atom()]
- Add @callback denial_codes/0 :: [String.t()]
- Add @callback evaluate_auth/3 :: {:allow, map()} | {:deny, Denial.t()}
- Add @callback auth_authority?/0 :: boolean()
- Expand @optional_callbacks to full 5-entry keyword list
- Behaviour compiles clean with 11 declared callbacks (DECOUPLE-01..05)
- Add four new callback tuples: forbidden_metadata_keys/0, denial_codes/0,
  evaluate_auth/3, auth_authority?/0 (marked as Added in Phase 136 DECOUPLE)
- @expected_callbacks MapSet now freezes at 11 callbacks (was 7)
- All 7 tests pass; MapSet.equal? assertion holds at new 11-entry shape
- DECOUPLE-04: evaluate_auth/3 raising → rescued → :deny (fail-closed)
- DECOUPLE-01: zero companions → events/0 non-empty, reserved set empty
- DECOUPLE-04: multiple auth_authority?/0 companions → first-registered wins + conflict signal
- DECOUPLE-05: baseline_forbidden_metadata_keys/0 returns exactly 10 atoms
- DECOUPLE-05: forbidden-key set captured at attach time, not per-event (handler config key)
- All five tests are RED until Plans 02/03 land (expected Wave 0 state)
- Stub companions defined outside test module; reuses Application.put_env pattern from phase130
- Add 136-01-SUMMARY.md with coverage metadata and threat flags
- Update STATE.md: advance plan counter, record metrics, add decisions
- Wave 0 complete: 11-callback Companion behaviour + freeze test + 5 RED backstop tests
…ylist + cache forbidden set

- Replace static Sigra.Telemetry/Chimeway.Telemetry calls in build_reserved_events/0 with
  runtime Application.get_env(:crosswake, :companions, []) aggregation via function_exported?/3
- Add @baseline_forbidden_keys module attribute (10 atoms: access_token, refresh_token,
  id_token, authorization_code, token, session_ref, subject_ref, actor_id, ip, email)
- Expose public baseline_forbidden_metadata_keys/0 with semver contract docs
- Build merged forbidden-key MapSet once in attach_default_logger/1 (baseline + Threadline +
  companion keys) and pass as map config to :telemetry.attach_many handler closure
- Update __handle_event__/4 to read forbidden_keys from config map (Map.get, not Keyword.get)
- Remove all_forbidden_keys/0 (now replaced by attach-time-cached MapSet in handler config)
- Zero Companions.Sigra or Companions.Chimeway references remain in telemetry.ex (DECOUPLE-01)
…endent shape assertion

- Drop length(reserved_events) >= 24 and its stable_id_message block (D-136-D)
- Add shape assertion: each :reserved entry matches %{event: [_ | _], tier: :reserved,
  measurements: list, metadata: list} via match? with is_list guards (no magic numbers)
- Keep refute MapSet.member?(active_prefixes, event) no-overlap invariant unchanged
- Test now passes with zero companions registered (reserved set legitimately empty)
…-closed + rescue

- Remove alias Crosswake.Companions.Sigra.Evaluator (L9); keep Denial alias
- Inline auth_predicated?/1 helper with three-field nil-check (auth_min_level/
  requires_recent_auth/auth_posture) replacing Sigra.Evaluator.auth_predicated?/1
- Rewrite prepend_auth_evaluation_denials/4 third clause:
  * Predicate gate: non-auth routes return acc unchanged (no companion scan)
  * Registry auth_authority?/0 scan with function_exported?/3 guard
  * Zero-authority: deny with :dependency_missing (fail-closed; DECOUPLE-04)
  * Multiple authorities: first-registered used; emit
    [:crosswake, :companion, :auth_authority_conflict] telemetry (D-3)
  * evaluate_auth/3 wrapped in try/rescue; rescue -> :dependency_missing deny
  * {:allow, _} returns acc unchanged; {:deny, denial} passes Denial.t() through
- Fix backstop test 3 assertion: check absence of auth denials not decision.status
  (empty Target always produces compatibility denials; auth outcome is the invariant)
- Backstop tests 1+3 and phase130_fail_closed_contract_test all green
…time helpers

- Remove alias Crosswake.Companions.Sigra.Telemetry, as: SigraTelemetry (L16)
- Convert @auth_contract_truth module attribute to @auth_contract_truth_static map +
  def auth_contract_truth/0 runtime helper that reads :companions registry via
  denial_codes/0 callback (DECOUPLE-03 / T-136-03)
- Convert @notification_support_truth module attribute to @notification_support_truth_static
  map + def notification_support_truth/0 runtime helper
- Companion-sourced fields (event_names, metadata_keys, forbidden_metadata_keys,
  denial_codes, safe_detail_keys) are [] sentinels; callers fill via registry at runtime
- No Crosswake.Companions.Sigra or SigraTelemetry reference remains in non-comment lines
- mix compile --warnings-as-errors: 0 warnings; phase133 telemetry contract test: 8/8 pass
…with runtime lookups

- Replace Map.get/3 fallback defaults in phase_46_auth_findings/1 that called
  Crosswake.Companions.Sigra.DenialCodes.codes() and .allowed_detail_keys() eagerly
- denial_codes now obtained via Application.get_env(:crosswake, :companions) +
  function_exported?(mod, :denial_codes, 0) registry lookup (DECOUPLE-03 / T-136-04)
- safe_detail_keys defaults to [] (callers fill via registry; no static Sigra reference)
- No Crosswake.Companions.Sigra reference remains in non-comment lines of doctor.ex
- mix compile --warnings-as-errors: 0 warnings
- phase130 fail_closed test: 4/4 pass; phase133 telemetry contract test: 8/8 pass
…anned, scope exclusion

- Add Crosswake.Companions.Sigra and Crosswake.Companions.Chimeway to
  @extracted_companion_names (covers all child modules via prefix match)
- Replace exact-match guard (when parts in @banned_alias_parts) with
  unconditional match + Enum.any?(@banned_alias_parts, &List.starts_with?(parts, &1))
  in function body — Elixir when guards cannot call Enum.any?/List.starts_with?
- Update assert_no_static_refs!/0 scope to lib/**/*.ex minus
  lib/crosswake/companions/**/*.ex (list subtraction; Path.wildcard has no negative glob)
- Decouple policy/schema.ex from Crosswake.Companions.Sigra.Contracts alias:
  inline @mfa_level_vocabulary [:none, :password, :mfa, :phishing_resistant] as
  a module attribute; remove the static SigraContracts alias (Rule 2: missed coupling site)
- mix compile --warnings-as-errors passes; assert_no_static_refs!() returns :ok
…n test

- Update "A real Sigra-referencing core file" test description: Plans 02/03 removed
  the Sigra.Evaluator alias from route_gate.ex; test remains green (no alias = :ok)
- Invert L122-136: change "check_source/1 does NOT detect Sigra" from :ok to
  {:violation, _} — Sigra is now extracted/banned; child-module prefix detection proven
- Add scope-exclusion test: assert_no_static_refs!/0 returns :ok, proving
  lib/crosswake/companions/** is excluded from the walk (in-tree self-references not flagged)
- 13 tests, 0 failures
szTheory and others added 28 commits July 1, 2026 15:34
…er, VALIDATION nyquist sign-off, grep vacuity fix)
…ard base_details merge

- Add optional :code (String.t() | nil) and :details (map(), default %{}) to Finding struct
- Add :auth clause to finding_to_denial/2 returning :step_up_required with finding.code and finding.details
- Guard base_details/Map.merge block with cond so :auth passes details UNMERGED (audit fix ①)
- Extend compatibility_test.exs with three D-137-A/D-137-B behavior assertions
…ate Finding→Denial in RouteGate

- Update Companion.evaluate_auth/3 @callback return type from Denial.t() to Finding.t()
- Update @doc prose to state core translates Finding to Denial at RouteGate boundary (D-137-A)
- RouteGate accumulation now calls Compatibility.finding_to_denial(finding, route_id: route.id) on deny arm
- Sigra facade adds D-137-A shim: converts returned Denial to %Finding{axis: :auth} to satisfy callback contract
- phase46 auth-contract proof stays green end-to-end through RouteGate translation
…sed proof (D-137-D)

- Add Crosswake.TestSupport.StubSigraAbsentCompanion beside rulestead/rindle absent stubs
- companion_id/0 returns :sigra; validate_dependency/0 returns {:error, [Crosswake.Companions.Sigra]}
- auth_authority?/0 returns false — models absent engine with no auth authority
- Drives :dependency_missing fail-closed deny path for auth-predicated routes
- Core suite (excluding host/engine tags) stays green at 1165 tests, 0 failures
…al alias

- Replace Denial.new(...) in deny/4 with %Finding{axis: :auth, code:, message:, details: sanitized}
- DenialCodes.sanitize_details/1 still runs once at source (T-137-05 PII guard)
- finding.code always populated from caller-supplied dotted code (T-137-07 no-nil guard)
- @generic_message constant preserved as message (bypasses sanitize — PII guard)
- Replace alias Crosswake.Shell.Denial with alias Crosswake.Compatibility.Finding
- Update @SPEC evaluate_route_auth return type to {:deny, Finding.t()}
- Update phase54 test fixture: assert %Finding{axis: :auth} shape instead of denial.reason
…s guard preserved

- Replace alias Crosswake.Shell.Denial with alias Crosswake.Compatibility.Finding
- Change @SPEC evaluate_or_issue return type to {:deny, Finding.t()}
- Semantic match re-pointed from %Denial{reason: :step_up_required} to %Finding{axis: :auth}
- Catch-all deny arm changed from %Denial{} to %Finding{axis: :auth}
- issue_challenge/4 param renamed denial -> finding
- normalize_issue_result: host-error arm accepts {:error, %Finding{axis: :auth}} (Open Q1 resolved)
- normalize_issue_result: fallback constructs %Finding{axis: :auth, code: "projection_failed"}
- issue_attrs/4: param %Denial{} -> %Finding{axis: :auth}; finding.details["max_auth_age_seconds"]
  KEPT (T-137-06: dropping this silently removes the step-up max-age EoP guard)
- issue_attrs/4: route_denial_code uses finding.code instead of denial.code
…move Plan-01 shim

- step_up_plug.ex, step_up_on_mount.ex: post-ceremony deny arm migrated from
  %Denial{} to %Finding{axis: :auth} (ceremony now returns Finding end-to-end)
- step_up_plug.ex, step_up_on_mount.ex: issue_intent/1 else clause converts
  {:error, %Denial{}} -> {:error, %Finding{axis: :auth}} to match the new
  StepUpCeremony.normalize_issue_result/1 host contract (Open Q1 resolved)
- denied_path/1 in both adapters re-pointed from %Denial{} to %Finding{axis: :auth}
- handoff.ex: no changes — its %Denial{} arms are non-ceremony (RouteGate/SigraHandoff);
  stay as Denial per plan Task 3 guidance
- sigra.ex: remove Plan-01 Denial->Finding shim; evaluator emits Finding natively;
  finding passes through unchanged to RouteGate's finding_to_denial/2 translation
- sigra.ex: remove now-unused alias Crosswake.Compatibility.Finding
…uite green

- phase56: add alias Finding; migrate evaluator_result fixtures from Denial.new to
  %Finding{axis: :auth} (challengeable and non-challengeable arms)
- phase56: host_denial fixture changed to %Finding{axis: :auth}; {:deny, ^host_denial}
  assertion holds (normalize_issue_result passes Finding through unchanged)
- route_gate_test: add alias Finding; migrate direct Evaluator.evaluate_route_auth
  assertions from denial.reason == :step_up_required to %Finding{axis: :auth} match
- full core suite (--exclude requires_example_host --exclude engine_present):
  1165 tests, 0 failures (61 excluded)
- Denial alias kept in phase56 (still used in non-ceremony assertions that test
  Denial struct behavior directly)
…package, update core mix.exs

- Create packages/crosswake_sigra/ skeleton: mix.exs (@Version 0.1.0), config/config.exs, README.md, CHANGELOG.md, LICENSE, test/test_helper.exs, test/support/study_session_live.ex
- MOVE all 8 sigra sub-modules + facade from lib/ to packages/crosswake_sigra/lib/ (namespace Crosswake.Companions.Sigra.* preserved — non-breaking)
- Remove Crosswake.Companions.Sigra from core :companions env (Chimeway only remains)
- Add sigra to companions.test alias for dress-rehearsal lane (NOT as core dep — path dep would create circular dep)
- Remove Crosswake.Companions.Sigra.Telemetry from core docs groups_for_modules
- packages/crosswake_sigra compiles --warnings-as-errors; zero Crosswake.Shell.Denial refs in package lib/
- [Rule 1 - Bug] Fixed: removed sigra_dep() from core deps (circular dep: core -> sigra (path) -> core); dress rehearsal via companions.test alias matches rulestead/rindle pattern
- Renamed sigra companion unit tests (contracts, handoff, step_up, telemetry) to package
- Renamed phase54 session authority tests to package (6 tests)
- Created phase54 support truth test in package with Application.put_env setup
- Deleted core phase54_sigra_session_authority_test.exs (all 7 tests moved/split to package)
- Created phase56 package test (10 hermetic tests; fixed File.read! paths with ../../)
- Stripped core phase56 to @requires_example_host test only (host-DB integration)
- Renamed phase73 admin workflow proof test to package (all 9 tests; fixed examples/ paths)
- Self-referential "does not claim" guard maintained via concatenation/comment discipline
…re tests to package

- Add phase137_sigra_cleanroom_test.exs: non-vacuous clean-room proof registering sigra
  via put_env, driving RouteGate.evaluate/4, asserting :step_up_required not :dependency_missing
- Move 8 core proof/test files to crosswake_sigra package (compile-time or runtime sigra dep):
  route_gate_test, phase46/47/57/58/71, publish_readiness, operator_inspection
- Add phase55/phase47 package versions with inline stubs (StubRulesteadAbsent, StubRindleAbsent)
  replacing core test support modules unavailable in package load path
- Add put_env setup for phase71/chimeway tests needing sigra at runtime
- Strip core companions_test.exs, support_matrix_test.exs, doctor_test.exs to sentinel checks;
  non-vacuous assertion coverage lives in sigra package lane
- Update chimeway/resolver_test.exs: expect :dependency_missing (fail-closed) not :step_up_required
  when no auth-authority companion registered
- Regenerate phase52 JSON fixtures with sentinel output (denial_codes/safe_detail_keys as [])
- Add crosswake_sigra row to guides/companion_compatibility.md (phase132 drift test)
- Dress rehearsal: core 1029 tests 0 failures; package 137 tests 0 failures
- NO_ENGINE=1 set when $3/$4 are omitted, empty, or sentinel 'none'
- no-engine mode: deps patch emits duo (crosswake + PACKAGE only, no engine dep)
- no-engine smoke test: validate_dependency/0 returns :ok unconditionally (no engine-present assertion)
- no-engine config/runtime.exs: registers companion only (no engine config line)
- default engine path (rulestead/Rindle) unchanged — additive only
- invocation: verify_companion_cleanroom.sh crosswake_sigra <version> (no engine args)
…component

- add packages/crosswake_sigra block to release-please-config.json (elixir, separate-pull-requests)
- one-shot release-as: 0.1.0 with _TODO_release_as removal note (recipe Step 12f / Pitfall 6)
- extra-files: packages/crosswake_sigra/mix.exs + standard changelog-sections
- crosswake_sigra intentionally NOT in linked-versions lockstep group (D-8)
- add packages/crosswake_sigra: 0.1.0 to .release-please-manifest.json (6th key)
- add sigra_release_created/sigra_tag_name/sigra_version outputs (D-8 double-dash alias contract)
- add publish-hex-sigra job: needs release-please, gates on sigra_release_created (per-component)
  CROSSWAKE_RELEASE=1 env, checkout sigra_tag_name, working-dir packages/crosswake_sigra,
  dry-run then publish, Hex.pm propagation poll (T-137-14/15)
- add clean-room-proof-sigra job: needs [release-please, publish-hex-sigra], no-engine invocation
  verify_companion_cleanroom.sh crosswake_sigra VERSION (T-137-16)
- extend release-as-cleanup: add sigra_release_created to if:; add strip_release_as.py crosswake_sigra
  block (T-137-13 one-shot cleanup)
- extend release-failure-alert: add publish-hex-sigra + clean-room-proof-sigra to needs: and body
…A-03 over-claim

- STATE.md: reflect 137 waves 1-4 green + paused at wave 5 (human hex-publish gate);
  fix stale stopped_at/last_activity/widgets, DECOUPLE-03 resolved note, stale next-steps,
  drop malformed plan-metric rows from Deferred Items.
- REQUIREMENTS.md: SIGRA-03 [x]->[~] — CI pipeline + dry-run green, but the irreversible
  Hex publish is the deferred human gate (137-05) and has not run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…der [Unreleased]

crosswake_sigra extracted in-tree + dress-rehearsed + dry-run green but NOT published;
rulestead/rindle Release PRs open-unmerged; core decoupling is internal + non-breaking.
Published Hex truth stays 0.1.2 (no version heading cut).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reusable checklist for clean git/GSD/CI state + boundary sync PR before continuing work
(no hex publish). Consolidates worktree cleanup, STATE refresh, changelog honesty pass,
PR triage, boundary PR mechanics, and admin follow-ups.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ction

Phase 137-03 moved Sigra.{Handoff,Contracts,DenialCodes} out of core into
packages/crosswake_sigra, but examples/phoenix_host/.../saas_portal/handoff.ex still
calls them directly — so the example host's `mix compile --warnings-as-errors` (e2e-proof,
route-tour-proof, offline-sync-e2e lanes) failed with undefined-module warnings. Declare
crosswake_sigra as a path dep alongside rulestead/rindle, mirroring the adopter pattern.
Local example-host compile now clean; dress rehearsal excluded these lanes so it wasn't caught.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 137-03 moved the sigra-dependent auth proof tests (phase46/47/54/57/58, phase71
notification, phase73 auth-sensitive, sigra telemetry, operator_inspection, publish_readiness)
into packages/crosswake_sigra, but the dedicated core CI lanes still ran them from the old
core path -> 'did not match any directory/file'.

- phase71-proof.yml / phase73-proof.yml: run the (now package-only) proof from crosswake_sigra.
- phase58-proof.yml: split — core-side tests (support_matrix/doctor/companions/closeout_verify,
  phase55/56 which are requires_example_host-excluded here) stay in core; moved tests
  (phase54/57/58, sigra telemetry, operator_inspection, publish_readiness) run from the package.

Verified locally: package proofs 10+6+18+27 green; core-side parity 98 green. phase46 correctly
lives in the package (it aliases Sigra.Contracts at compile time — cannot stay in core).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@szTheory
szTheory merged commit 5083e79 into main Jul 2, 2026
73 checks passed
@szTheory
szTheory deleted the sync/main-v17.0-phase137-catchup branch July 2, 2026 12:35
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