Skip to content

docs: publish architectural design records#66

Open
bilby91 wants to merge 1 commit into
mainfrom
design/publish-architecture
Open

docs: publish architectural design records#66
bilby91 wants to merge 1 commit into
mainfrom
design/publish-architecture

Conversation

@bilby91
Copy link
Copy Markdown
Member

@bilby91 bilby91 commented May 16, 2026

Summary

Publishes the architectural design notes that have been internal-only since the repo started. They explain the choices behind the public API for contributors and embedders — not user-facing docs.

Six published records, indexed via design/README.md and linked from the top-level README:

  • resolved-config.md — the central data type
  • runtime.md — Runtime / Engine / Workspace layering
  • runtime-applecontainer.md — second backend over a Swift bridge
  • compose-native.md — runtime-agnostic compose orchestrator
  • features.md — Dev Container Features pipeline
  • structured-errors.md*devcontainer.Error surface

Internal planning material (milestone trackers, draft upstream-contribution plans, the superseded shell-out compose design) is kept under design/private/, which the new .gitignore rule excludes from the repo.

What's been scrubbed from the published docs

  • Internal product names (DAP) → replaced with generic phrasing (consumer, your application).
  • The PRD reference that broke standalone reading (§13) was replaced with the underlying point.

What remains: some shipping-plan vocabulary (milestone labels, "PR-X" references) is intact where it doesn't impede understanding. These are design records, not living documentation — the conversational language is part of how they read. The status legend in design/README.md describes the convention.

Test plan

  • .gitignore correctly excludes design/private/ while tracking the rest of design/.
  • grep -nE "\bDAP\b" design/*.md returns no matches.
  • All links in design/README.md resolve.
  • Top-level README's new ## Design section links into design/README.md.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation

    • Added comprehensive architectural design documentation covering the runtime abstraction layer, features infrastructure, native compose support, Apple container macOS backend, structured error handling, and configuration resolution.
    • Enhanced project documentation with a design directory guide.
  • Chores

    • Updated .gitignore for improved artifact management.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 16, 2026

📝 Walkthrough

Walkthrough

This PR adds comprehensive architectural design documentation to the devcontainer library. Seven new design specifications define core contracts for config resolution, runtime abstraction, features pipeline, compose orchestration, Apple container backend, and structured error handling. The documentation is introduced through a new design/ directory with its own README, and linked from the main project README.

Changes

Architectural Design Documentation

Layer / File(s) Summary
Directory setup and framing
.gitignore, README.md, design/README.md
Project files updated to introduce the design directory with a status-and-scope README explaining document purpose, relationship to code and external spec, included documents, and status legend.
ResolvedConfig specification
design/resolved-config.md
Public ResolvedConfig contract specifying config lifecycle (parse → merge → host-context resolve), top-level shape with stable DevcontainerID, sealed Source variants (image/build/compose), lifecycle command structures, feature representation, mount normalization, and M1 scope.
Runtime interface specification
design/runtime.md
Runtime layer between ResolvedConfig and container engines, defining the Runtime interface (build/pull/run/start/stop/remove/exec/inspect/logs/find-by-label), Workspace and Engine APIs, idempotent lifecycle phases via marker files, substitution context wiring for ${containerEnv:*}, and M2 ship scope.
Apple container runtime implementation
design/runtime-applecontainer.md
macOS Runtime backend using Apple's container stack with cgo-to-Swift bridge (libACBridge.dylib), mandatory daemon (container-apiserver) dependency, exact version pinning (0.12.x), platform constraints (darwin/arm64, macOS 15+, Swift 6), and M6 ship scope.
Features pipeline design
design/features.md
Features layer for M3, covering reference resolution (OCI/HTTPS/Local), DAG ordering with cycle detection, feature Dockerfile generation, devcontainer.metadata label format, on-disk cache with content-addressed keys and lockfiles, and pre-baked-image skip behavior via AlreadyInstalled.
Compose orchestration design
design/compose-native.md
Go-native compose orchestrator replacing docker compose shell-out, specifying compose subset, project naming (dc-<devcontainerId>), new runtime primitives (CreateNetwork/RemoveNetwork/CreateVolume/RemoveVolume/ListContainers), Up/Down algorithms with topo-sort and health gating, config-hash staleness policy, capability-flag pattern, and Apple backend implications with M7 scope.
Structured error handling
design/structured-errors.md
Structured error wrapper (*devcontainer.Error) with stable Code, Reason, Cause, and Context, StderrCarrier interface for subprocess stderr, classifier helpers for translating external/runtime errors to codes, and stepwise migration plan with testing patterns.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 Seven documents deep, the architecture's laid,
Config flows to Runtime, each layer well-weighed,
Features dance with Compose in a Go-native way,
While Apple's Swift bridge opens a new day—
Errors structured clean, from the root we declare! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'docs: publish architectural design records' directly and clearly summarizes the main change: publishing previously internal architectural design documents to the design/ directory with an index and README links.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch design/publish-architecture

Comment @coderabbitai help to get the list of available commands and usage tips.

Six design notes that explain *why* the public API looks the way it
does. Useful for contributors and embedders; not part of the user-
facing surface. Lives under design/, indexed via design/README.md
and linked from the top-level README.

Published records:
  - resolved-config.md  — the ResolvedConfig type and parse-merge-
    substitute pipeline.
  - runtime.md          — Runtime / Engine / Workspace boundaries.
  - runtime-applecontainer.md — Apple's `container` backend over a
    cgo + Swift bridge.
  - compose-native.md   — runtime-agnostic compose orchestrator.
  - features.md         — Dev Container Features pipeline.
  - structured-errors.md — *devcontainer.Error surface.

What's NOT in this commit (kept under design/private/, gitignored):
  - status.md — internal milestone tracker.
  - upstream-apple-container.md — planning doc for upstream
    contributions to apple/container.
  - compose.md — superseded by compose-native.md (kept for context).

.gitignore narrowed from `design/` to `design/private/` so the
published records can be tracked while the in-flight planning
material stays local.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bilby91 bilby91 force-pushed the design/publish-architecture branch from 19acad1 to 7067ada Compare May 16, 2026 04:16
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (16)
design/compose-native.md (4)

640-643: 💤 Low value

Add language specifier to JSON error example.

The error message at lines 640-643 is valid JSON and should be marked as such for proper syntax highlighting.

📝 Proposed fix
-   ```
+   ```json
    Error: failed to bootstrap container ... (cause: "VZErrorDomain
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/compose-native.md` around lines 640 - 643, The code fence containing
the JSON error example ("Error: failed to bootstrap container ... (cause:
\"VZErrorDomain Code=2 'The storage device attachment is invalid.'\")") is
missing a language specifier; update that triple-backtick fence to include
"json" (i.e., change ``` to ```json) so the JSON-like error is highlighted
correctly in the compose-native.md example block.

27-50: 💤 Low value

Consider adding language specifier to ASCII diagram code block.

The ASCII diagram is in a fenced code block without a language specifier. While not critical for ASCII art, adding text or plaintext would satisfy linting tools and improve consistency.

📝 Proposed fix
-```
+```text
 ┌──────────────────────────────────────────────────────────────────┐
 │ Engine (devcontainer pkg)                                        │
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/compose-native.md` around lines 27 - 50, Update the fenced ASCII
diagram code block (the block that starts with the box drawing characters and
the compose pkg / runtime diagram) to include a language specifier like "text"
or "plaintext" after the opening triple backticks so linters recognize it as
plain text; e.g., change the opening fence from ``` to ```text and keep the
diagram content unchanged.

291-339: 💤 Low value

Add language specifiers to algorithm pseudocode blocks.

The Up and Down algorithm descriptions (lines 291-339 and 343-358) use fenced code blocks without language specifiers. Consider using text or pseudocode to satisfy linting and improve rendering.

Also applies to: 343-358

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/compose-native.md` around lines 291 - 339, Update the fenced code
blocks that contain the Up and Down algorithm pseudocode so they include a
language specifier (e.g., replace ``` with ```text or ```pseudocode);
specifically target the block beginning with "Input: Plan {" (the Up algorithm
pseudocode) and the subsequent Down algorithm block so the linter and renderer
recognize them as pseudocode/text.

141-148: 💤 Low value

Add language specifiers to label example code blocks.

The label examples at lines 141-148 and 162-166 are in fenced code blocks without language specifiers. These appear to be configuration/label formats.

📝 Proposed fix

For the container labels block:

-```
+```yaml
 com.docker.compose.project        = <projectName>     # interop label

For the network/volume labels block:

-```
+```yaml
 com.docker.compose.project = <projectName>

Also applies to: 162-166

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/compose-native.md` around lines 141 - 148, The fenced code blocks
containing the example container labels and the network/volume labels should
include a language specifier for syntax highlighting; update both example blocks
shown in the diff (the "container labels" example with com.docker.compose.* and
dev.containers.* lines and the "network/volume labels" example) to use ```yaml
as the opening fence instead of a plain fence so readers get proper YAML
highlighting.
design/structured-errors.md (3)

187-193: ⚡ Quick win

Document that With() mutates the receiver.

The builder pattern here is clean for the common usage (chained immediately after New()), but the method should document that it mutates the receiver in place:

// With adds a Context entry and returns the receiver for chaining.
// It mutates the Error in place; the returned value points to the same instance.
func (e *Error) With(key string, val any) *Error {
    ...
}

This prevents surprises if someone tries to fork an Error by calling With() multiple times on the same base instance.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/structured-errors.md` around lines 187 - 193, Add a Go doc comment to
the With method on type Error that clearly states it mutates the receiver and
returns the same instance for chaining; update the comment above func (e *Error)
With(key string, val any) *Error to something like: "With adds a Context entry
and returns the receiver for chaining. It mutates the Error in place; the
returned value points to the same instance." so callers know not to expect a
copy when reusing a base Error.

153-153: 💤 Low value

Specify the exact Error() format string.

The comment indicates the format will be "<code>: <reason>", but consider documenting the exact implementation to ensure consistency:

func (e *Error) Error() string {
    return string(e.Code) + ": " + e.Reason
}

This makes it clear whether there are spaces around the colon, how Code is converted to string, and whether Cause/Context appear in the output.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/structured-errors.md` at line 153, Document and implement Error() for
the Error type to return the exact string format "code: reason" (use
string(e.Code) + ": " + e.Reason semantics) and explicitly state that neither
Cause nor Context are included in Error() output; update the comment for the
Error.Error() method to show that format and reference the Error type and its
fields Code, Reason, Cause, and Context so readers know how Code is converted
and what is omitted.

568-568: 💤 Low value

Optional: Hyphenate compound modifier.

For grammatical consistency, "Runtime-typed errors" should use a hyphen when the compound modifier precedes the noun:

-7. **Existing typed errors stay.** `config/errors.go` and
-   `runtime/errors.go` types continue to exist as Cause carriers.
-   Runtime typed errors gain `Stderr()` methods to satisfy
+   Runtime-typed errors gain `Stderr()` methods to satisfy

This is a minor stylistic point in a design document.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/structured-errors.md` at line 568, Change the phrase "Runtime typed
errors" to the hyphenated "Runtime-typed errors" in the sentence "Runtime typed
errors gain `Stderr()` methods to satisfy" so the compound modifier is
grammatically consistent; locate that exact phrase in the document and update it
to "Runtime-typed errors".
design/features.md (9)

302-306: ⚡ Quick win

Clarify mirror URL deduplication mechanism.

The spec states "content-addressed dedupes across mirror URLs" which is excellent, but the mechanism could be clearer. Currently:

  • index.json maps ref → digest
  • Cache entries are keyed by digest

So two refs (e.g., ghcr.io/org/feat:1 and docker.io/org/feat:1) pointing to the same content would:

  1. Both appear in index.json with different ref keys
  2. Both map to the same digest
  3. Share the same oci/sha256-<digest>/ directory

Please add a sentence confirming this is the intended deduplication behavior, as it's an important cache efficiency property.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/features.md` around lines 302 - 306, The spec should explicitly state
that deduplication across mirror URLs is achieved by mapping each mutable or
mirror ref in index.json to a single content digest and using that digest as the
cache key so multiple refs (e.g., ghcr.io/org/feat:1 and docker.io/org/feat:1)
that resolve to the same digest will each have separate entries in index.json
but point to and share the same on-disk cache directory (oci/sha256-<digest>/),
ensuring a single stored copy per content digest.

285-300: 💤 Low value

Add language identifier to code block.

The cache layout block is missing a language specifier.

📝 Suggested fix
-```
+```text
 features/
   oci/
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/features.md` around lines 285 - 300, The fenced code block showing the
cache layout (the triple-backtick block containing "features/ oci/
sha256-<digest>/ ... index.json") is missing a language specifier; update the
opening fence from ``` to ```text so the block is treated as plain text (leave
the content and closing fence unchanged).

212-224: 💤 Low value

Add language identifier to code block.

The build context layout block is missing a language specifier.

📝 Suggested fix
-```
+```text
 <engine-managed tmp dir>/
   Dockerfile                # the file above
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/features.md` around lines 212 - 224, The code block showing the build
context layout (starting with "<engine-managed tmp dir>/" and lines like
"Dockerfile" and "build-context/") lacks a language identifier; update the
opening fence from ``` to ```text (or another appropriate language) so the
snippet is rendered correctly and syntax/highlighting is consistent.

19-58: 💤 Low value

Add language identifier to code block.

The ASCII diagram code block is missing a language specifier.

📝 Suggested fix
-```
+```text
 devcontainer.json (features map)
         │
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/features.md` around lines 19 - 58, The fenced ASCII diagram block is
missing a language tag; update the code fence that wraps the diagram (the triple
backticks before "devcontainer.json (features map)") to include a language
identifier like text (i.e. change ``` to ```text) so the ASCII art renders
correctly and avoids markdown highlighting issues for the diagram shown in the
feature.Resolve / feature.Order / feature.GenerateDockerfile flow.

201-201: ⚡ Quick win

Specify where FEATURE_REF variable is defined.

The trap on line 201 references FEATURE_REF in the error message, but the script doesn't show where this variable is defined. Please clarify:

  • Is it injected by the generator as a literal string substitution?
  • Is it set in an environment file?
  • Should the example show this variable definition?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/features.md` at line 201, The trap message references FEATURE_REF but
the document doesn't define it; update the example around the trap (the trap
'rc=$?; ... FEATURE_REF ...' line) to either (a) state explicitly that
FEATURE_REF is a generator-substituted placeholder, (b) show a preceding example
variable definition (e.g., export FEATURE_REF="your-feature-name") or (c) note
it is expected from an environment file—choose one approach and add one clear
sentence and a sample definition so readers know where FEATURE_REF comes from.

352-352: 💤 Low value

Remove space in code span element.

There's an extra space inside the code span: >= should be >=.

📝 Suggested fix
-   version `>= ` requested via semver. Opt-in:
+   version `>=` requested via semver. Opt-in:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/features.md` at line 352, The code span contains an extra trailing
space: change the inline code element text from "`>= `" to "`>=`" so the semver
comparator has no trailing space; locate the occurrence of the code span "`>= `"
in the features.md content and remove the space inside the backticks (replace
"`>= `" with "`>=`").

148-149: ⚡ Quick win

Clarify installsAfter behavior for unlisted features.

The spec states installsAfter is a soft hint "if both listed," but doesn't specify what happens when a feature declares installsAfter for a feature that isn't in the user's configuration. Is this:

  • Silently ignored (safest)?
  • Treated as a warning?
  • An error?

Please add a sentence clarifying this edge case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/features.md` around lines 148 - 149, Add a single clarifying sentence
to the spec near the `installsAfter` description: state that `installsAfter` is
only effective when both features are present in the user's configuration, and
if a feature names an `installsAfter` target that is not listed it is ignored
(does not block installation); optionally note that implementations may emit a
non-fatal warning for missing targets. Ensure the sentence references
`installsAfter` and contrasts it with `dependsOn` for clarity.

274-278: ⚡ Quick win

Clarify "resolved digest" storage for HTTPS features.

The document states "we record the resolved digest on the metadata entry" for version matching. This is clear for OCI features (which have a manifest digest), but HTTPS features use "sha256 of body" as their cache key (§2, line 67).

Please clarify:

  • Is the HTTPS sha256 stored in the same ResolvedRef field as OCI digests?
  • Does StrictFeatureVersionMatch byte-level comparison work identically for both?
  • Should the metadata entry distinguish between OCI digest and HTTPS content hash?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/features.md` around lines 274 - 278, Update the design text to
explicitly state that for HTTPS features the sha256(body) is stored in the same
ResolvedRef field used for OCI manifest digests, that StrictFeatureVersionMatch
performs identical byte-level identity comparison for both OCI manifest digests
and HTTPS content hashes, and to add a short note about distinguishing the two
in metadata (either by a source/type prefix on ResolvedRef, e.g.
"oci:sha256:..." vs "https:sha256:...", or by adding a small discriminator
field) so downstream tooling can tell manifest digest vs content hash; reference
ResolvedRef, StrictFeatureVersionMatch and the metadata entry when making this
clarification.

239-239: ⚡ Quick win

Specify merge semantics for maps/objects.

The merge semantics state "later overrides earlier" for scalars and "concat + dedupe" for lists, but don't address maps/objects (e.g., containerEnv, customizations). Are these:

  • Shallow overridden (entire map replaced)?
  • Deep merged (keys merged recursively)?

Please add a sentence clarifying nested object behavior, as this is common in devcontainer.json (e.g., containerEnv: { KEY: value } layers).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/features.md` at line 239, The doc omits merge semantics for
maps/objects; add a clear sentence stating whether object/map fields are
shallow-overridden or deep-merged (and how conflicts are resolved), and give the
devcontainer-specific examples `containerEnv` and `customizations` to show
expected behavior (e.g., "maps are deep-merged recursively by key, with later
values overriding scalar leaves" or "maps are shallow-replaced: the later map
completely replaces the earlier"). Update the paragraph that currently documents
scalars and lists to include this single clarifying sentence and ensure it
mentions recursive key-merge behavior and conflict resolution rules.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@design/compose-native.md`:
- Line 92: Update the §2.1 in-scope table entry for
services.<name>.network_mode: service:<other> to reflect the Apple backend
limitation mentioned in probe R4 — change the description to indicate this is
"docker backend only" (or "Docker backend only; not supported on Apple backend")
so the table matches the probe text in §2.1 and R4; ensure any other references
in §2.1 that mention this feature are consistent with the updated phrasing.

In `@design/features.md`:
- Around line 362-369: Add a clarifying sentence that disambiguates the two
resolution layers: state that config-level resolution (e.g.,
devcontainer.Resolve) only parses the features map and intentionally leaves
per-feature fields like Metadata, Dir, ResolvedRef, and AlreadyInstalled unset,
while feature-level resolution (feature.Store.Resolve) performs the fetch and
populates those fields; also state that Engine.Up is responsible for invoking
feature.Store.Resolve for features not already installed. Reference the exact
names devcontainer.Resolve, feature.Store.Resolve, and Engine.Up in the sentence
to make the distinction clear.
- Around line 81-85: Update the "HTTPS mechanics" section to explicitly specify
the security and network policies for feature downloads: state that TLS
certificates must be validated against system/root CAs and explain whether/when
custom CA bundles are allowed, define redirect handling (follow or reject and a
max redirect depth), set a response body size limit and behavior on overflow,
document request timeouts (connect and overall) and retry/backoff policy, and
enumerate error handling semantics for network failures (which errors are
retriable vs fatal) and how EngineOptions.FeatureDownloadHeaders is applied;
include these details alongside the existing notes about filename validation,
sha256 caching, and streaming/extraction so implementers have a complete,
consistent spec.
- Around line 136-137: The doc is ambiguous about when enum/proposal validation
runs; update the text to state that enum validation occurs after feature
metadata is available (i.e., during feature.Store.Resolve() once
devcontainer-feature.json has been fetched and merged into Metadata), and that
Engine.Up will perform validation as a fallback for any features whose metadata
wasn't resolved earlier (for example when features are injected or mutated
late). Also explicitly document the pre-baked-image hot path behavior: if
features are not fetched because a pre-baked image is used, skip remote metadata
validation and either validate against embedded Metadata (if present) or treat
enums as unvalidated/default to safe behavior; reference
feature.Store.Resolve(), Resolve, Metadata, Engine.Up and the pre-baked-image
hot path in the updated prose so readers know where each validation step happens
and what to expect.
- Around line 175-178: The _REMOTE_USER_HOME value is being computed with whoami
while USER is set to root, so it captures root's home; change the logic that
writes to /tmp/dc-features/builtin.env to look up the home for the intended
target user (use the build ARG _DEV_CONTAINERS_IMAGE_USER or a default) instead
of whoami—either move the ARG _DEV_CONTAINERS_IMAGE_USER earlier so it’s
available in this RUN or defer writing _REMOTE_USER_HOME until after that ARG is
defined, and use getent passwd ${_DEV_CONTAINERS_IMAGE_USER:-root} to populate
_REMOTE_USER_HOME.

In `@design/resolved-config.md`:
- Around line 15-24: Add language identifiers to the two fenced code blocks that
currently use plain backticks so markdownlint stops failing: change the opening
fences for the ASCII diagram block (the box/arrow diagram around "files -> raw
-> merged -> resolved") and the one containing the expression "devcontainerId =
base32(sha256(localWorkspaceFolder + "\x00" + configPath))[:16]" to include a
language tag (e.g., use ```text) so the blocks are explicitly marked; update the
opening triple-backtick lines for those blocks in the document where the diagram
and the devcontainerId expression appear.

In `@design/runtime-applecontainer.md`:
- Around line 205-221: The docs list an InspectImage mapping for runtime.Runtime
but the declared Runtime interface in design/runtime.md does not include
InspectImage; update the contract so they match by either adding InspectImage to
the Runtime interface (and document expected signature/behavior consistent with
the "image service inspect" mapping and labels round-trip note) or remove the
InspectImage entry from design/runtime-applecontainer.md and any Apple-specific
mapping; ensure references to runtime.Runtime, InspectImage, and the image
service/labels behavior are updated accordingly.
- Around line 19-51: The fenced ASCII diagram block (starting with "Engine
(devcontainer pkg)" / the large box diagram) and the other unlabeled fenced
block later (the block covering the section that begins with
"container-apiserver (Apple's daemon; launchd LaunchAgent)" / lines ~258-267)
are missing a language identifier; update both triple-fenced blocks to use
```text so markdownlint passes and tooling renders them as plain text, leaving
the contents unchanged.
- Around line 161-163: The Package.swift manifest currently uses a wildcard
string with the exact requirement (e.g., exact: "0.12.x") which SwiftPM rejects;
update the dependency declaration in Package.swift to use a fully qualified
semantic version (for example change exact: "0.12.x" to exact: "0.12.3") so the
exact: requirement is a concrete version; ensure any other occurrences of exact:
with an x wildcard are replaced with the specific patch version and keep bump
policy (separate PRs + parity integration) unchanged.

In `@design/runtime.md`:
- Around line 17-42: The fenced ASCII architecture diagram in runtime.md lacks a
language token; update the opening code fence to include a language (e.g.,
change ``` to ```text) so the diagram block is recognized as plain text and
resolves markdownlint MD040 and editor rendering issues; locate the ASCII block
that starts with the "Caller (your application, CLI, tests, ...)" diagram and
add the language token to its opening fence.

---

Nitpick comments:
In `@design/compose-native.md`:
- Around line 640-643: The code fence containing the JSON error example ("Error:
failed to bootstrap container ... (cause: \"VZErrorDomain Code=2 'The storage
device attachment is invalid.'\")") is missing a language specifier; update that
triple-backtick fence to include "json" (i.e., change ``` to ```json) so the
JSON-like error is highlighted correctly in the compose-native.md example block.
- Around line 27-50: Update the fenced ASCII diagram code block (the block that
starts with the box drawing characters and the compose pkg / runtime diagram) to
include a language specifier like "text" or "plaintext" after the opening triple
backticks so linters recognize it as plain text; e.g., change the opening fence
from ``` to ```text and keep the diagram content unchanged.
- Around line 291-339: Update the fenced code blocks that contain the Up and
Down algorithm pseudocode so they include a language specifier (e.g., replace
``` with ```text or ```pseudocode); specifically target the block beginning with
"Input: Plan {" (the Up algorithm pseudocode) and the subsequent Down algorithm
block so the linter and renderer recognize them as pseudocode/text.
- Around line 141-148: The fenced code blocks containing the example container
labels and the network/volume labels should include a language specifier for
syntax highlighting; update both example blocks shown in the diff (the
"container labels" example with com.docker.compose.* and dev.containers.* lines
and the "network/volume labels" example) to use ```yaml as the opening fence
instead of a plain fence so readers get proper YAML highlighting.

In `@design/features.md`:
- Around line 302-306: The spec should explicitly state that deduplication
across mirror URLs is achieved by mapping each mutable or mirror ref in
index.json to a single content digest and using that digest as the cache key so
multiple refs (e.g., ghcr.io/org/feat:1 and docker.io/org/feat:1) that resolve
to the same digest will each have separate entries in index.json but point to
and share the same on-disk cache directory (oci/sha256-<digest>/), ensuring a
single stored copy per content digest.
- Around line 285-300: The fenced code block showing the cache layout (the
triple-backtick block containing "features/ oci/ sha256-<digest>/ ...
index.json") is missing a language specifier; update the opening fence from ```
to ```text so the block is treated as plain text (leave the content and closing
fence unchanged).
- Around line 212-224: The code block showing the build context layout (starting
with "<engine-managed tmp dir>/" and lines like "Dockerfile" and
"build-context/") lacks a language identifier; update the opening fence from ```
to ```text (or another appropriate language) so the snippet is rendered
correctly and syntax/highlighting is consistent.
- Around line 19-58: The fenced ASCII diagram block is missing a language tag;
update the code fence that wraps the diagram (the triple backticks before
"devcontainer.json (features map)") to include a language identifier like text
(i.e. change ``` to ```text) so the ASCII art renders correctly and avoids
markdown highlighting issues for the diagram shown in the feature.Resolve /
feature.Order / feature.GenerateDockerfile flow.
- Line 201: The trap message references FEATURE_REF but the document doesn't
define it; update the example around the trap (the trap 'rc=$?; ... FEATURE_REF
...' line) to either (a) state explicitly that FEATURE_REF is a
generator-substituted placeholder, (b) show a preceding example variable
definition (e.g., export FEATURE_REF="your-feature-name") or (c) note it is
expected from an environment file—choose one approach and add one clear sentence
and a sample definition so readers know where FEATURE_REF comes from.
- Line 352: The code span contains an extra trailing space: change the inline
code element text from "`>= `" to "`>=`" so the semver comparator has no
trailing space; locate the occurrence of the code span "`>= `" in the
features.md content and remove the space inside the backticks (replace "`>= `"
with "`>=`").
- Around line 148-149: Add a single clarifying sentence to the spec near the
`installsAfter` description: state that `installsAfter` is only effective when
both features are present in the user's configuration, and if a feature names an
`installsAfter` target that is not listed it is ignored (does not block
installation); optionally note that implementations may emit a non-fatal warning
for missing targets. Ensure the sentence references `installsAfter` and
contrasts it with `dependsOn` for clarity.
- Around line 274-278: Update the design text to explicitly state that for HTTPS
features the sha256(body) is stored in the same ResolvedRef field used for OCI
manifest digests, that StrictFeatureVersionMatch performs identical byte-level
identity comparison for both OCI manifest digests and HTTPS content hashes, and
to add a short note about distinguishing the two in metadata (either by a
source/type prefix on ResolvedRef, e.g. "oci:sha256:..." vs "https:sha256:...",
or by adding a small discriminator field) so downstream tooling can tell
manifest digest vs content hash; reference ResolvedRef,
StrictFeatureVersionMatch and the metadata entry when making this clarification.
- Line 239: The doc omits merge semantics for maps/objects; add a clear sentence
stating whether object/map fields are shallow-overridden or deep-merged (and how
conflicts are resolved), and give the devcontainer-specific examples
`containerEnv` and `customizations` to show expected behavior (e.g., "maps are
deep-merged recursively by key, with later values overriding scalar leaves" or
"maps are shallow-replaced: the later map completely replaces the earlier").
Update the paragraph that currently documents scalars and lists to include this
single clarifying sentence and ensure it mentions recursive key-merge behavior
and conflict resolution rules.

In `@design/structured-errors.md`:
- Around line 187-193: Add a Go doc comment to the With method on type Error
that clearly states it mutates the receiver and returns the same instance for
chaining; update the comment above func (e *Error) With(key string, val any)
*Error to something like: "With adds a Context entry and returns the receiver
for chaining. It mutates the Error in place; the returned value points to the
same instance." so callers know not to expect a copy when reusing a base Error.
- Line 153: Document and implement Error() for the Error type to return the
exact string format "code: reason" (use string(e.Code) + ": " + e.Reason
semantics) and explicitly state that neither Cause nor Context are included in
Error() output; update the comment for the Error.Error() method to show that
format and reference the Error type and its fields Code, Reason, Cause, and
Context so readers know how Code is converted and what is omitted.
- Line 568: Change the phrase "Runtime typed errors" to the hyphenated
"Runtime-typed errors" in the sentence "Runtime typed errors gain `Stderr()`
methods to satisfy" so the compound modifier is grammatically consistent; locate
that exact phrase in the document and update it to "Runtime-typed errors".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 95349023-cbcd-4ae7-9e87-51bb4bde8f32

📥 Commits

Reviewing files that changed from the base of the PR and between a888f7e and 7067ada.

📒 Files selected for processing (9)
  • .gitignore
  • README.md
  • design/README.md
  • design/compose-native.md
  • design/features.md
  • design/resolved-config.md
  • design/runtime-applecontainer.md
  • design/runtime.md
  • design/structured-errors.md

Comment thread design/compose-native.md
| `services.<name>.restart` | Passthrough to `RunSpec.RestartPolicy`. |
| `services.<name>.labels` | Merged with our project-scoping labels (§3.1). |
| `services.<name>.networks` (default network only) | Project gets one network (`<project>_default`); services join it. |
| `services.<name>.network_mode: service:<other>` | Single edge case; needed for sidecars sharing network namespace. |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update §2.1 in-scope table to reflect Apple backend limitation.

Line 822 in probe R4 states: "The §2.1 in-scope row for network_mode: service:<other> is updated to docker backend only." However, the actual table entry at line 92 remains unchanged and doesn't indicate this limitation. This creates an inconsistency between the probe findings and the in-scope feature list.

📝 Proposed fix
-| `services.<name>.network_mode: service:<other>` | Single edge case; needed for sidecars sharing network namespace. |
+| `services.<name>.network_mode: service:<other>` | Single edge case; needed for sidecars sharing network namespace. **Docker backend only** — Apple's VM-per-container model cannot share namespaces (see §11.3 R4). |

Also applies to: 818-822

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/compose-native.md` at line 92, Update the §2.1 in-scope table entry
for services.<name>.network_mode: service:<other> to reflect the Apple backend
limitation mentioned in probe R4 — change the description to indicate this is
"docker backend only" (or "Docker backend only; not supported on Apple backend")
so the table matches the probe text in §2.1 and R4; ensure any other references
in §2.1 that mention this feature are consistent with the updated phrasing.

Comment thread design/features.md
Comment on lines +81 to +85
**HTTPS mechanics:** GET the URL, validate filename matches
`^devcontainer-feature-[A-Za-z0-9_-]+\.tgz$`, stream body to disk, extract.
Cache key is the sha256 of the response body so the same content at two
URLs dedupes. Custom headers (auth) supplied by callers via
`EngineOptions.FeatureDownloadHeaders map[string]string`.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Specify HTTPS security requirements.

The HTTPS download mechanism mentions custom headers for auth but does not specify critical security measures:

  • TLS certificate validation policy
  • HTTP redirect handling (follow/reject, max depth)
  • Response size limits to prevent DoS
  • Request timeout configuration
  • Error handling for network failures

These should be documented to ensure consistent, secure implementations across the codebase.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/features.md` around lines 81 - 85, Update the "HTTPS mechanics"
section to explicitly specify the security and network policies for feature
downloads: state that TLS certificates must be validated against system/root CAs
and explain whether/when custom CA bundles are allowed, define redirect handling
(follow or reject and a max redirect depth), set a response body size limit and
behavior on overflow, document request timeouts (connect and overall) and
retry/backoff policy, and enumerate error handling semantics for network
failures (which errors are retriable vs fatal) and how
EngineOptions.FeatureDownloadHeaders is applied; include these details alongside
the existing notes about filename validation, sha256 caching, and
streaming/extraction so implementers have a complete, consistent spec.

Comment thread design/features.md
Comment on lines +136 to +137
`install.sh`). Rejecting typos before image build is worth the small
duplication.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Clarify when enum validation occurs.

The statement "We validate enum/proposals at parse time" appears inconsistent with §10 (line 364) which states that Resolve leaves Metadata empty. Enum values are defined in devcontainer-feature.json metadata, which must be fetched before validation can occur.

Please clarify:

  • Does "parse time" mean during feature.Store.Resolve() (after fetch)?
  • Or does this validation actually occur later in Engine.Up?
  • How does this interact with the "pre-baked-image hot path" where features aren't fetched?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/features.md` around lines 136 - 137, The doc is ambiguous about when
enum/proposal validation runs; update the text to state that enum validation
occurs after feature metadata is available (i.e., during feature.Store.Resolve()
once devcontainer-feature.json has been fetched and merged into Metadata), and
that Engine.Up will perform validation as a fallback for any features whose
metadata wasn't resolved earlier (for example when features are injected or
mutated late). Also explicitly document the pre-baked-image hot path behavior:
if features are not fetched because a pre-baked image is used, skip remote
metadata validation and either validate against embedded Metadata (if present)
or treat enums as unvalidated/default to safe behavior; reference
feature.Store.Resolve(), Resolve, Metadata, Engine.Up and the pre-baked-image
hot path in the updated prose so readers know where each validation step happens
and what to expect.

Comment thread design/features.md
Comment on lines +175 to +178
echo "_CONTAINER_USER_HOME=$(getent passwd root | cut -d: -f6)" \
>> /tmp/dc-features/builtin.env && \
echo "_REMOTE_USER_HOME=$(getent passwd $(whoami) | cut -d: -f6)" \
>> /tmp/dc-features/builtin.env
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

_REMOTE_USER_HOME logic captures root's home, not the remote user's.

Line 168 sets USER root, so the $(whoami) command on line 177 will return root, not the intended remote user. This means _REMOTE_USER_HOME will be set to root's home directory, which is incorrect.

The intent appears to be capturing the home directory of the final container user (specified via _DEV_CONTAINERS_IMAGE_USER on line 192-193). Consider using that ARG value to look up the home directory, or document if there's a different intended behavior.

🔧 Possible fix approach
# Instead of whoami (which is root at this point), use the target user
RUN \
  echo "_CONTAINER_USER_HOME=$(getent passwd root | cut -d: -f6)" \
    >> /tmp/dc-features/builtin.env && \
  echo "_REMOTE_USER_HOME=$(getent passwd ${_DEV_CONTAINERS_IMAGE_USER:-root} | cut -d: -f6)" \
    >> /tmp/dc-features/builtin.env

However, this requires _DEV_CONTAINERS_IMAGE_USER to be available at that RUN layer. The current template defines it as an ARG on line 192, which is after this RUN. The ARG would need to be moved earlier, or the builtin.env generation deferred.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/features.md` around lines 175 - 178, The _REMOTE_USER_HOME value is
being computed with whoami while USER is set to root, so it captures root's
home; change the logic that writes to /tmp/dc-features/builtin.env to look up
the home for the intended target user (use the build ARG
_DEV_CONTAINERS_IMAGE_USER or a default) instead of whoami—either move the ARG
_DEV_CONTAINERS_IMAGE_USER earlier so it’s available in this RUN or defer
writing _REMOTE_USER_HOME until after that ARG is defined, and use getent passwd
${_DEV_CONTAINERS_IMAGE_USER:-root} to populate _REMOTE_USER_HOME.

Comment thread design/features.md
Comment on lines +362 to +369
full DAG.** `Resolve` parses the features map, applies
`overrideFeatureInstallOrder`, merges user options with what's
defaultable without fetching; leaves `Metadata`, `Dir`, `ResolvedRef`
empty and `AlreadyInstalled` false. `Engine.Up` reads the base
image's `devcontainer.metadata` label, marks `AlreadyInstalled` for
matching features, and fetches only the rest — preserving the consumer's
pre-baked-image hot path. M1's stubbed `WarnUnsupportedFeatureField`
warning goes away in PR6.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Disambiguate "Resolve" operations.

Decision #5 describes a split between "Resolve populates partial Features" and "Engine.Up does fetch + full DAG," stating that Resolve "leaves Metadata, Dir, ResolvedRef empty."

This conflicts with §3 (lines 97-111) where feature.Store.Resolve() returns *Resolved with these fields populated. The apparent resolution:

  • Config-level Resolve (e.g., devcontainer.Resolve()) parses the features map but doesn't call feature.Store.Resolve() yet
  • Feature-level feature.Store.Resolve() does the actual fetch and returns full metadata
  • Engine.Up calls feature.Store.Resolve() for features not already installed

Please add a clarifying sentence distinguishing these two "Resolve" operations by name/layer to prevent implementation confusion. For example: "Config resolution (devcontainer.Resolve) leaves feature metadata unpopulated; feature resolution (feature.Store.Resolve) fetches and populates it; Engine.Up orchestrates the latter."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/features.md` around lines 362 - 369, Add a clarifying sentence that
disambiguates the two resolution layers: state that config-level resolution
(e.g., devcontainer.Resolve) only parses the features map and intentionally
leaves per-feature fields like Metadata, Dir, ResolvedRef, and AlreadyInstalled
unset, while feature-level resolution (feature.Store.Resolve) performs the fetch
and populates those fields; also state that Engine.Up is responsible for
invoking feature.Store.Resolve for features not already installed. Reference the
exact names devcontainer.Resolve, feature.Store.Resolve, and Engine.Up in the
sentence to make the distinction clear.

Comment thread design/resolved-config.md
Comment on lines +15 to +24
```
┌─────────┐ parse ┌─────────┐ merge ┌─────────┐ substitute ┌──────────┐
│ files │ ───────▶ │ raw │ ───────▶ │ merged │ ───────────▶ │ resolved │
└─────────┘ └─────────┘ └─────────┘ └──────────┘
*.json, one Go raw + host vars
JSONC struct per image label filled in;
file metadata + container vars
feature may remain
metadata
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language identifiers to fenced code blocks.

Line 15 and Line 306 use fenced blocks without a language tag, which will keep markdownlint failing and reduce render/tooling quality.

Suggested doc fix
-```
+```text
 ┌─────────┐  parse   ┌─────────┐  merge   ┌─────────┐  substitute  ┌──────────┐
 │  files  │ ───────▶ │   raw   │ ───────▶ │ merged  │ ───────────▶ │ resolved │
 └─────────┘          └─────────┘          └─────────┘              └──────────┘
   *.json,             one Go               raw +                    host vars
   JSONC               struct per           image label              filled in;
                       file                 metadata +               container vars
                                            feature                  may remain
                                            metadata
-```
+```

-```
+```text
 devcontainerId = base32(sha256(localWorkspaceFolder + "\x00" + configPath))[:16]
-```
+```

Also applies to: 306-308

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 15-15: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/resolved-config.md` around lines 15 - 24, Add language identifiers to
the two fenced code blocks that currently use plain backticks so markdownlint
stops failing: change the opening fences for the ASCII diagram block (the
box/arrow diagram around "files -> raw -> merged -> resolved") and the one
containing the expression "devcontainerId = base32(sha256(localWorkspaceFolder +
"\x00" + configPath))[:16]" to include a language tag (e.g., use ```text) so the
blocks are explicitly marked; update the opening triple-backtick lines for those
blocks in the document where the diagram and the devcontainerId expression
appear.

Comment on lines +19 to +51
```
┌──────────────────────────────────────────────────────────────────┐
│ Engine (devcontainer pkg) │
│ selects runtime.Runtime impl by EngineOptions │
└──────────────────────────────────────────────────────────────────┘
┌─────────────────────────────▼────────────────────────────────────┐
│ Runtime interface (runtime pkg) │
│ unchanged — both DockerRuntime and AppleContainerRuntime │
│ satisfy it; ComposeRuntime sub-interface is Docker-only │
└─────────────────────────────┬────────────────────────────────────┘
┌─────────────────────────────▼────────────────────────────────────┐
│ runtime/applecontainer (Go, build-tagged darwin && arm64) │
│ thin cgo wrapper; marshals options to JSON, calls @_cdecl │
│ exports, decodes responses, owns the handle table for │
│ cancellation and streams. │
└─────────────────────────────┬────────────────────────────────────┘
│ cgo
┌─────────────────────────────▼────────────────────────────────────┐
│ libACBridge.dylib (Swift, this repo's applecontainer-bridge/) │
│ imports apple/container's ContainerAPIClient + supporting │
│ modules; wraps async APIs as fire-and-forget @_cdecl funcs; │
│ pipes for high-throughput streams (exec stdio, logs, build). │
└─────────────────────────────┬────────────────────────────────────┘
│ XPC (mach service)
┌─────────────────────────────▼────────────────────────────────────┐
│ container-apiserver (Apple's daemon; launchd LaunchAgent) │
│ owns VMs (Virtualization.framework), virtiofs, image cache, │
│ networks, persistent state. Installed via `brew install │
│ container`. Started via `container system start`. │
└──────────────────────────────────────────────────────────────────┘
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language identifiers to unlabeled fenced code blocks.

Line 19 and Line 258 use unlabeled fences. Adding text keeps markdownlint clean and improves readability/tool support.

Also applies to: 258-267

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 19-19: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/runtime-applecontainer.md` around lines 19 - 51, The fenced ASCII
diagram block (starting with "Engine (devcontainer pkg)" / the large box
diagram) and the other unlabeled fenced block later (the block covering the
section that begins with "container-apiserver (Apple's daemon; launchd
LaunchAgent)" / lines ~258-267) are missing a language identifier; update both
triple-fenced blocks to use ```text so markdownlint passes and tooling renders
them as plain text, leaving the contents unchanged.

Comment on lines +161 to +163
**Rule:** `Package.swift` uses `.package(url: ..., exact: "0.12.x")`.
Bumps are their own PRs, gated by re-running the parity integration
suite (PR-H) against the new version. We do NOT use `from:` or `branch:`.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does Swift Package Manager allow wildcard values like "0.12.x" with .package(..., exact: "..."), or does exact require a full semantic version such as "0.12.3"?

💡 Result:

Swift Package Manager does not support wildcard values like "0.12.x" with the.exact requirement [1][2]. The.exact requirement expects a specific, fully qualified semantic version (e.g., "0.12.3") [1][2]. If you need to specify a range of versions rather than a single exact version, you should use other dependency requirements, such as: -.upToNextMajor(from:): Allows the package manager to select versions starting from the specified minimum up to, but not including, the next major version (e.g., "1.2.3" allows "1.2.4", "1.3.0", etc., but not "2.0.0") [1][3]. - Range operators: You can use Swift range syntax to define specific bounds, such as "1.2.3"..<"1.2.6" [1]. Using.exact is generally discouraged by Apple because it can lead to dependency graph conflicts when multiple packages depend on the same library [1][2]. Using version ranges is the recommended approach to provide flexibility while maintaining compatibility [1][3].

Citations:


Use a concrete semantic version for SwiftPM exact: pins.

Line 161 uses exact: "0.12.x", but Swift Package Manager requires a fully qualified version (e.g., 0.12.3) with the exact requirement; wildcards like 0.12.x are not supported and will cause an invalid manifest.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/runtime-applecontainer.md` around lines 161 - 163, The Package.swift
manifest currently uses a wildcard string with the exact requirement (e.g.,
exact: "0.12.x") which SwiftPM rejects; update the dependency declaration in
Package.swift to use a fully qualified semantic version (for example change
exact: "0.12.x" to exact: "0.12.3") so the exact: requirement is a concrete
version; ensure any other occurrences of exact: with an x wildcard are replaced
with the specific patch version and keep bump policy (separate PRs + parity
integration) unchanged.

Comment on lines +205 to +221
Every method on `runtime.Runtime` (runtime/runtime.go:83-129) is
reachable through Apple's stack. Direct mapping:

| `Runtime` method | Apple API | Bridge shape | Notes |
| ----------------------- | -------------------------------------------------- | ---------------------------- | ----- |
| `BuildImage` | `ContainerBuild` (BuildKit gRPC) | callback stream for progress | Builder runs in a separate VM; clear error if not started. Heaviest PR (PR-G). |
| `PullImage` | `ImagePull` via images service | callback stream for progress | low risk |
| `RunContainer` | `ContainerClient.create` + create-not-start path | sync request/reply | Mounts, env, labels, runArgs map cleanly. Verify UID semantics (§11). |
| `StartContainer` | `ContainerClient.start` | sync | low risk |
| `StopContainer` | `ContainerClient.stop` | sync | Timeout maps directly. |
| `RemoveContainer` | `ContainerClient.delete` / `kill` | sync | Force + remove-volumes flags. |
| `ExecContainer` | `ContainerExec` flow with `ProcessIO` | pipe fds + callback | Hardest. TTY mode supported by `config.terminal`. Cancellation via Task. |
| `InspectContainer` | `ContainerClient.get` / `inspect` | sync, JSON response | Confirm Created/StartedAt/ExitCode/FinishedAt all present. |
| `InspectImage` | image service `inspect` | sync, JSON response | Labels round-trip — load-bearing for the `devcontainer.metadata` fast path. |
| `ContainerLogs` | `ContainerLogs` flow | pipe fd | Follow + non-follow. |
| `FindContainerByLabel` | `ContainerClient.list` + client-side label filter | sync | If Apple adds server-side filtering, switch. |
| `ComposeRuntime` (sub) | not implemented | type assertion fails | See §9. |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Align Runtime method mapping with the declared Runtime interface.

This section maps an InspectImage method, but the Runtime interface described in design/runtime.md does not declare InspectImage. Please reconcile the docs so backend implementation scope matches the shared contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/runtime-applecontainer.md` around lines 205 - 221, The docs list an
InspectImage mapping for runtime.Runtime but the declared Runtime interface in
design/runtime.md does not include InspectImage; update the contract so they
match by either adding InspectImage to the Runtime interface (and document
expected signature/behavior consistent with the "image service inspect" mapping
and labels round-trip note) or remove the InspectImage entry from
design/runtime-applecontainer.md and any Apple-specific mapping; ensure
references to runtime.Runtime, InspectImage, and the image service/labels
behavior are updated accordingly.

Comment thread design/runtime.md
Comment on lines +17 to +42
```
┌──────────────────────────────────────────────────────────────────┐
│ Caller (your application, CLI, tests, ...) │
│ eng.Up(ctx, UpOptions{...}) → *Workspace │
└──────────────────────────────────────────────────────────────────┘
┌─────────────────────────────▼────────────────────────────────────┐
│ Engine (devcontainer pkg) │
│ - resolves config (M1) │
│ - builds image (M3) │
│ - drives Runtime to create + start │
│ - runs lifecycle phases with idempotency markers │
│ - manages container-context Substituter │
│ - emits Events │
└──────────────────────────────────────────────────────────────────┘
┌─────────────────────────────▼────────────────────────────────────┐
│ Runtime interface (runtime pkg) │
│ container primitives only — no devcontainer-spec semantics │
└──────────────────────────────────────────────────────────────────┘
┌─────────────────────────────▼────────────────────────────────────┐
│ DockerRuntime (runtime/docker) │
│ uses the Docker Engine API Go SDK │
└──────────────────────────────────────────────────────────────────┘
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Specify a language for the architecture diagram code fence.

Line 17 has a fenced block without a language token; adding text will resolve markdownlint MD040 and improve editor rendering.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design/runtime.md` around lines 17 - 42, The fenced ASCII architecture
diagram in runtime.md lacks a language token; update the opening code fence to
include a language (e.g., change ``` to ```text) so the diagram block is
recognized as plain text and resolves markdownlint MD040 and editor rendering
issues; locate the ASCII block that starts with the "Caller (your application,
CLI, tests, ...)" diagram and add the language token to its opening fence.

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