Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .specify/feature.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"feature_directory": "specs/003-dependency-policy-ci"
"feature_directory": "specs/004-macos12-macports-support"
}
34 changes: 34 additions & 0 deletions specs/004-macos12-macports-support/checklists/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Specification Quality Checklist: macOS 12 MacPorts Support

**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2026-08-03
**Feature**: [spec.md](../spec.md)

## Content Quality

- [x] No implementation details (languages, frameworks, APIs)
- [x] Focused on user value and business needs
- [x] Written for non-technical stakeholders
- [x] All mandatory sections completed

## Requirement Completeness

- [x] No [NEEDS CLARIFICATION] markers remain
- [x] Requirements are testable and unambiguous
- [x] Success criteria are measurable
- [x] Success criteria are technology-agnostic (no implementation details)
- [x] All acceptance scenarios are defined
- [x] Edge cases are identified
- [x] Scope is clearly bounded
- [x] Dependencies and assumptions identified

## Feature Readiness

- [x] All functional requirements have clear acceptance criteria
- [x] User scenarios cover primary flows
- [x] Feature meets measurable outcomes defined in Success Criteria
- [x] No implementation details leak into specification

## Notes

- Validation passed on 2026-08-03. The specification is ready for `$speckit-plan`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Contract: macOS Target Selection

## Purpose

The macOS dependency installer must classify the host before dependency preflight so Monterey receives the
legacy MacPorts-aware path and newer macOS releases keep their existing behavior.

## Inputs

- macOS product version.
- Machine architecture.
- Machine role selected during chezmoi initialization.
- Dependency-management enabled/disabled choice.
- Presence and discoverability of the MacPorts `port` command when the selected source requires MacPorts.

## Ordered behavior

1. If dependency management is disabled, exit successfully before package-manager checks, network access,
installation, or state writes.
2. Detect macOS major version and CPU architecture.
3. If the major version is `12`, classify the target as Monterey legacy macOS and set the package-management
path to MacPorts-aware.
4. If the major version is newer and already supported by the repository, retain the existing macOS path.
5. If the architecture is not `x86_64` or `aarch64`, return `target-unsupported` before mutation.
6. Apply workstation/server role filtering before resolving dependency sources.
7. When at least one selected source requires MacPorts, validate `port` availability before preflight.
8. Return a structured diagnostic that includes macOS release category, architecture, role, selected package
path, and next action whenever target selection blocks setup.

## Result classes

| Result | Meaning | Mutation allowed |
|---|---|---|
| `target-selected` | A supported macOS target and role were selected. | Not yet; proceed to preflight |
| `disabled` | Dependency management is disabled. | No mutation; successful exit |
| `prerequisite-blocked` | Monterey selected a MacPorts-required path but `port` is missing, hidden, or unusable. | No |
| `target-unsupported` | macOS version or architecture has no declared handling. | No |

## Safety invariants

- Do not use Homebrew as an implicit fallback on Monterey.
- Do not route newer macOS releases into the Monterey path by accident.
- Do not mutate dependencies or machine-local state until target selection and prerequisites succeed.
- Do not install MacPorts automatically; provide documented user action instead.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Contract: Monterey Dependency Reconciliation

## Purpose

Monterey dependency reconciliation extends the existing policy model with MacPorts-aware prerequisites and
conflict diagnostics while preserving official artifact compatibility and user-owned software.

## Inputs

- Selected macOS target from the macOS target-selection contract.
- Valid dependency compatibility manifest.
- Role-filtered managed dependency list.
- Active executable/font state, including candidate duplicate paths.
- MacPorts prerequisite state when a selected dependency source requires it.
- Machine-local retain override state.

## Ordered behavior

1. Select each applicable dependency source from the manifest.
2. Prefer a declared official artifact when it is compatible with Monterey and checksum-verifiable.
3. Use a MacPorts native package only when the manifest explicitly declares a MacPorts source for that
dependency and target.
4. If a MacPorts source is selected, verify the MacPorts prerequisite before package or artifact preflight.
5. Observe active installations and classify each active path as managed user-local, MacPorts, Homebrew,
manual, font registry, absent, or unknown.
6. Report active Homebrew/manual conflicts when they affect compatibility; do not remove them automatically.
7. Preflight every selected artifact/package and collect all failures before mutation.
8. Apply changes in manifest order only after the complete applicable preflight succeeds.
9. Verify the active executable version or font asset after each change.
10. On success, report compatible or explicitly unsupported status according to retained-version state.

## Required diagnostics

Every blocked Monterey diagnostic includes:

```text
Dependency: <name or prerequisite>
Expected: <declared version, package, or prerequisite>
Observed: <observed version/path/state>
Target: macOS 12 Monterey/<architecture>/<role>/<package-management-path>
Next action: <safe user action>
```

Mixed-manager diagnostics additionally include the active path and the selected package-management path so
users can understand whether Homebrew, MacPorts, a managed artifact, or a manual binary is currently taking
precedence.

## Safety invariants

- Never silently substitute Homebrew for MacPorts on Monterey.
- Never silently substitute a different package or artifact version.
- Never remove Homebrew, MacPorts, or manual installations outside explicitly managed locations.
- Never install workstation-only GUI terminals or fonts for the server role.
- Never claim Monterey compatibility until every applicable active dependency is verified or a documented
unsupported-retain state exists.
121 changes: 121 additions & 0 deletions specs/004-macos12-macports-support/data-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Data Model: macOS 12 MacPorts Support

## MacOSTarget

The normalized macOS machine identity used before dependency resolution.

| Field | Type | Rules |
|---|---|---|
| `os` | literal | Always `darwin` for this feature. |
| `majorVersion` | integer | `12` selects the Monterey legacy path; newer supported versions retain existing behavior. |
| `releaseName` | enum | `monterey` when `majorVersion` is `12`; otherwise `newer-macos` for this feature's regression scope. |
| `arch` | enum | `x86_64` or `aarch64`; unknown architecture is blocked before mutation. |
| `role` | enum | `workstation` or `server`; role filters dependencies before preflight. |
| `packageFamily` | enum | `macports` for Monterey when native package management is required; existing macOS family for newer releases. |

Validation rules:

- macOS 12 must not be routed through the newer macOS package-management path by default.
- Newer macOS must not enter the Monterey path unless explicitly selected by a documented override.
- Unknown macOS major version or CPU architecture must produce an actionable blocked diagnostic rather than
guessing.

## LegacyPackagePrerequisite

The prerequisite state for Monterey package-management operations.

| Field | Type | Rules |
|---|---|---|
| `manager` | literal | `macports`. |
| `command` | string | `port`. |
| `expectedPrefix` | path | Default expected prefix is `/opt/local`. |
| `status` | enum | `available`, `missing`, `not-on-path`, `unusable`. |
| `observedPath` | path/null | The discovered `port` executable path when present. |
| `observedVersion` | string/null | Result of a version probe when available. |
| `nextAction` | string | English instruction for installing, opening a new shell, or fixing PATH. |

Validation rules:

- A missing or unusable prerequisite blocks before dependency preflight and mutation.
- The diagnostic must identify the selected package-management path and the next action.
- The prerequisite record must not imply that Homebrew is an acceptable Monterey fallback.

## DependencySourceSelection

The selected source for a managed dependency on a specific Monterey target.

| Field | Type | Rules |
|---|---|---|
| `dependencyId` | string | Must match an existing managed dependency ID. |
| `target` | MacOSTarget | Monterey target plus role and architecture. |
| `strategy` | enum | `official-artifact`, `native-package`, or `platform-exception`. |
| `manager` | enum/null | `macports` only when `strategy` is `native-package`; null for official artifacts. |
| `version` | string | Exact declared compatible version; never `latest`. |
| `verification` | object | Executable version probe or font hash requirements from the dependency policy. |
| `requiresPrerequisite` | boolean | True when the selected source needs MacPorts before mutation. |

Validation rules:

- Official artifacts remain valid on Monterey only when their declared archive and member are compatible with
the target architecture and checksum verification passes.
- Native MacPorts package selections require an exact compatible package declaration and an available
MacPorts prerequisite.
- A dependency may not silently switch to an undeclared source or version.

## ActiveMacOSInstallation

The active executable or asset observed on the Monterey machine.

| Field | Type | Rules |
|---|---|---|
| `dependencyId` | string | Managed dependency identity. |
| `activePath` | path/null | First executable or asset selected by the active environment. |
| `sourceClass` | enum | `managed-user-local`, `macports`, `homebrew`, `manual`, `font-registry`, `absent`, `unknown`. |
| `observedVersion` | string/null | Parsed executable version or verified font asset identity. |
| `comparison` | enum | `missing`, `equal`, `older`, `newer`, `unparseable`, `incompatible`. |
| `duplicates` | list | Additional candidate paths or assets; informational only. |

Validation rules:

- Competing Homebrew or manual installations are never automatically removed.
- A duplicate candidate must be reported when it affects active compatibility.
- A successful run verifies the active installation after mutation or confirms it was already compatible.

## MontereyDiagnostic

The user-facing and evidence-facing result for a blocked, compatible, unsupported, or partial Monterey run.

| Field | Type | Rules |
|---|---|---|
| `result` | enum | `compatible`, `prerequisite-blocked`, `preflight-blocked`, `target-unsupported`, `interaction-required`, `partial-failure`, `unsupported`. |
| `dependencyId` | string/null | Required for dependency-specific failures. |
| `expected` | string | Expected version, package path, or prerequisite. |
| `observed` | string | Observed version, path, missing state, or failure reason. |
| `target` | MacOSTarget | Exact macOS release category, architecture, role, and package-management path. |
| `nextAction` | string | Safe action the user can perform. |

Validation rules:

- `prerequisite-blocked`, `preflight-blocked`, `target-unsupported`, and `interaction-required` happen before
dependency mutation.
- Partial failure reports changed, failed, and pending dependencies plus safe removal guidance.
- Compatible results require every role-applicable dependency to be verified.

## State Transitions

```text
detect macOS major version and architecture
-> if macOS 12: select Monterey legacy path
-> if newer macOS: retain existing macOS path
-> filter dependencies by role
-> resolve source selection for each applicable dependency
-> if any selected source requires MacPorts: validate MacPorts prerequisite
-> missing/unusable: PREREQUISITE_BLOCKED, no mutation
-> observe active installations and duplicates
-> preflight selected artifacts/packages
-> any failure: PREFLIGHT_BLOCKED, no mutation
-> apply changes in dependency order
-> verify active result after each change
-> failure: PARTIAL_FAILURE
-> all verified: COMPATIBLE
```
131 changes: 131 additions & 0 deletions specs/004-macos12-macports-support/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Implementation Plan: macOS 12 MacPorts Support

**Branch**: `004-macos12-macports-support` | **Date**: 2026-08-03 | **Spec**: [spec.md](./spec.md)

**Input**: Feature specification from `/specs/004-macos12-macports-support/spec.md`

## Summary

Add a Monterey-specific macOS dependency path for Mac mini systems that treats Homebrew as unsuitable
for macOS 12 while preserving the current macOS behavior for newer releases. The implementation will
keep checksum-verified official artifacts as the preferred source when they remain compatible on
Monterey, introduce MacPorts-aware target selection and prerequisite diagnostics for legacy macOS, add
MacPorts PATH awareness, extend fixtures for blocked and mixed-manager states, and document real Mac
mini validation without claiming unperformed platform verification.

## Technical Context

**Language/Version**: chezmoi templates; POSIX `sh`; YAML dependency data; Markdown documentation;
PowerShell and shell-based policy tests where existing test harnesses require them
**Primary Dependencies**: chezmoi template data/functions, macOS `sw_vers` and `uname`, MacPorts `port`,
existing official upstream release artifacts, POSIX archive/hash utilities, dependency-policy fixtures
**Storage**: committed `.chezmoidata/dependencies.yaml`; generated shell configuration templates;
machine-local dependency state under `${XDG_STATE_HOME:-$HOME/.local/state}`; committed evidence notes
**Testing**: static/template checks on the development host; macOS installer fixtures for Monterey and
newer macOS target selection; existing dependency-policy tests; real-machine validation on a macOS 12
Monterey Mac mini when available
**Target Platform**: macOS 12 Monterey x86_64 and arm64 Mac mini workstation/server roles, with regression
coverage for existing newer macOS x86_64 and arm64 targets
**Project Type**: cross-platform dotfiles and dependency bootstrap scripts
**Performance Goals**: second apply performs no dependency mutation; prerequisite failure stops before
network or installation work; target detection completes before dependency preflight
**Constraints**: official artifact compatibility remains preferred, MacPorts is a legacy macOS path rather
than the new default for every macOS release, no silent version substitution, no automatic removal of
Homebrew/manual installations, no GUI/font installation for server role, English-only repository content
**Scale/Scope**: existing eight managed dependencies, one additional legacy macOS version category,
two macOS CPU architectures, two roles, existing macOS installer and shared POSIX reconciliation logic

## Constitution Check

*GATE: Passed before Phase 0 and re-checked after Phase 1.*

| Principle | Design evidence | Result |
|---|---|---|
| Cross-Platform Consistency | Monterey uses the same declared dependency policy and compatibility reporting model while adding a legacy macOS target-selection branch. | Pass |
| One-Command, Repeatable Setup | Missing MacPorts prerequisites block before mutation; successful second applies are no-ops; PATH updates must be duplicate-safe. | Pass |
| Native Package Management First | MacPorts becomes the appropriate supported manager for legacy macOS, while official artifacts remain allowed when native packages cannot provide the required compatible version. | Pass |
| Pinned Critical Tool Versions | Monterey must not accept undeclared replacement versions and must verify active versions/assets before reporting compatibility. | Pass |
| Workstation and Server Separation | WezTerm and font handling remain workstation-only on Monterey; server role keeps CLI-only behavior. | Pass |
| English Repository Content | All planned specs, diagnostics, tests, and docs are English. | Pass |
| Platform-Specific Verification | Fixture coverage is required for macOS target-selection behavior; real Mac mini evidence is recorded as verified or explicitly deferred. | Pass |

Post-design re-check: the research decisions, data model, contracts, and quickstart preserve every gate.
No constitution exception is required.

## Project Structure

### Documentation (this feature)

```text
specs/004-macos12-macports-support/
|-- plan.md
|-- research.md
|-- data-model.md
|-- quickstart.md
|-- contracts/
| |-- macos-target-selection.md
| `-- monterey-reconciliation.md
`-- tasks.md # Created later by $speckit-tasks
```

### Source Code (repository root)

```text
.chezmoidata/
`-- dependencies.yaml # Extend target/source declarations only if Monterey needs source-specific overrides

.chezmoitemplates/
|-- dependency-policy-posix.sh.tmpl # Shared preflight/reconciliation support for any MacPorts native-package entries
`-- nushell-config.nu # Add MacPorts executable paths without duplicating entries

run_onchange_before_10-install-packages-darwin.sh.tmpl
# Detect macOS major version and select legacy/newer macOS package family

README.md # Document Monterey prerequisite, setup path, and troubleshooting

tests/dependency-policy/
|-- test-darwin-dependency-install.sh # Add Monterey and mixed-manager fixtures
|-- README.md # Record fixture coverage and real-machine boundary
`-- evidence/
`-- macos.md # Record Monterey Mac mini verification or explicit deferral
```

**Structure Decision**: Keep the repository's existing dotfiles layout. Add Monterey-aware behavior to the
macOS entrypoint and shared POSIX policy logic instead of creating a separate installer. Use the existing
manifest and fixture directories so Monterey support is reviewed alongside current dependency-policy
coverage.

## Implementation Phases

### Phase A - Target selection and source policy

1. Classify macOS 12 as `darwin-monterey` plus architecture and role while leaving newer macOS targets on
the existing path.
2. Select MacPorts as the legacy macOS package-management family for Monterey prerequisite diagnostics and
any exact native package entries.
3. Continue selecting official artifacts for Monterey when the declared artifact is compatible and
checksum-verifiable.
4. Fail before mutation when MacPorts is required but `port` is missing, not discoverable, or not usable.

### Phase B - Reconciliation, PATH, and diagnostics

1. Add MacPorts-aware native package preflight and install behavior only for manifest entries that declare
a MacPorts package source.
2. Add `/opt/local/bin` and `/opt/local/sbin` as macOS candidate paths without creating duplicates or
demoting the managed user-local bin directory.
3. Extend blocked diagnostics with selected package-management path, missing prerequisite, active path, and
next action.
4. Preserve user-owned Homebrew and manual installations: report conflicts, never remove them automatically.

### Phase C - Fixtures, evidence, and docs

1. Add macOS fixture scenarios for Monterey Intel/arm64, missing MacPorts, MacPorts not on PATH,
Homebrew-plus-MacPorts conflict, dependency management disabled, workstation, and server roles.
2. Re-run existing dependency-policy checks and confirm newer macOS x86_64/arm64 behavior remains unchanged.
3. Update README setup/troubleshooting sections with Monterey-specific prerequisites and validation steps.
4. Record real Mac mini validation in `tests/dependency-policy/evidence/macos.md`, or explicitly mark it
deferred with commands the user can run on the Monterey machine.

## Complexity Tracking

No constitution violations require justification.
Loading