Skip to content

docs(adr): ADR-0028 — Principle II forbids network dependence, not availability - #144

Merged
mbeacom merged 1 commit into
mainfrom
mbeacom-adr-0028-network-denial-exemption
Aug 14, 2026
Merged

docs(adr): ADR-0028 — Principle II forbids network dependence, not availability#144
mbeacom merged 1 commit into
mainfrom
mbeacom-adr-0028-network-denial-exemption

Conversation

@mbeacom

@mbeacom mbeacom commented Aug 14, 2026

Copy link
Copy Markdown
Owner

What

Resolves an ambiguity in Constitution Principle II and records a single bounded exemption, unblocking feature 010's T093.

The finding

T093 discharges FR-050, whose second conjunct reads "network access is permitted only during dependency installation". That is false while bun test runs with ambient network, and it cannot be made true by effort: the suite contains the two-sided controls that prove the denial mechanism works, and a control that establishes denial cannot itself run under denial.

Wrapping it was attempted on both platforms and fails differently on each, which is what makes the obstruction structural rather than a macOS quirk:

Platform Result
macOS sandbox-exec denies loopback outright — 3 tests fail with Failed to start server
Linux unshare --net brings lo up so that failure does not occur — 11 fail instead, because the denial-proving tests must nest a sandbox inside the one already wrapping them

The real problem is that FR-050 is stricter than the law it cites. Principle II tests dependence in three places and availability in one:

Principle II text Tests
"MUST require no credentials, no running services, and no network access" dependence
"Network-dependent tests and runtime behavior are forbidden" dependence
"a change that makes any post-install gate … require … a network call is a defect" dependence
"the install exception is limited to bun install --frozen-lockfile" availability

bun test satisfies all three of the first kind — nothing in the suite reaches the network, and it passes with the network gone — and fails the fourth. FR-050 restated the principle using the fourth reading and presented it as a faithful derivation. So a task has been blocked by a feature requirement that overstates ratified law, with the record of that living in a task comment rather than a decision.

The decision

Principle II's operative test is dependence, not availability. A post-install step is compliant when it neither requires nor uses the network, whether or not one happens to be reachable. This changes no observable behavior — every gate that was green stays green, and no step gains permission to use a network it could not use before.

The bun test step of clean-clone-builds is recorded as the single authorized exemption, bounded by four conditions that must all hold or it lapses:

  1. Named where it occurs — an unwrapped step not recorded here is a defect, not an instance of this record
  2. Justified by the nesting obstruction, not convenience — if the denial-proving controls leave the suite, the exemption ends with them
  3. Every other post-install step stays wrapped; a second exemption requires its own record
  4. Ambient availability is permitted; use is not — a test that reaches the network remains a defect under Principle II's binding clauses

FR-050 is amended by reference, the same mechanism ADR-0014 used for ADR-0012 and ADR-0013. Its remainder — no credential, no running service, nothing required by build, test, or generator invocation — stands unchanged and unweakened.

Options recorded, including the one refused

Option D — wrap the step and delete the denial-proving controls is named in the record as considered and refused. It would satisfy the letter by removing the evidence that makes every other wrapped step meaningful, trading real assurance for a green checkbox. It is written down so a future reader can see it was rejected rather than overlooked.

Option B (fix FR-050 silently in the spec) was rejected because Principle II's fourth bullet genuinely supports the stricter reading — this is a choice between two live readings of ratified law, and resolving that inside a feature spec is how a constitutional interpretation gets made by whoever happened to be writing a requirement that day.

Option C (split T093) defers the decision and leaves the next feature citing Principle II with the same ambiguity and the same stall.

Verification

The 13-of-14 figure was counted from the workflow, not asserted. The clean-clone-builds job has 17 steps: 3 pre-install, 14 post-install, of which 13 reference run-network-denied.ts in their run command and exactly one does not — the bun test step this record names.

  • adr lint — 28 records, 0 errors, 0 warnings
  • adr queue — empty (this record is accepted, ratified by @mbeacom)

Follow-on

The four action items are tracked in the record and land in #98: amend FR-050 to cite this record, close T093 on the runner evidence, name the exemption in the workflow step, and state it as one step of fourteen wherever job coverage is described — never as "every step is denied".

…ailability

Feature 010's T093 could not be closed, and the reason was not the one it was
recorded under.

T093 discharges FR-050, whose second conjunct reads "network access is permitted
**only** during dependency installation". That is false while `bun test` runs
with ambient network, and it cannot be made true by effort: the suite contains
the two-sided controls that prove the denial mechanism works, and a control that
establishes denial cannot itself run under denial. Wrapping it was attempted on
both platforms and fails differently on each — macOS `sandbox-exec` denies
loopback (3 failures); Linux `unshare --net` brings `lo` up so that failure does
not occur and 11 fail instead, because the denial-proving tests must nest a
sandbox inside the one already wrapping them.

The finding is that FR-050 is stricter than the law it cites. Principle II tests
**dependence** in three places — "MUST require no ... network access",
"Network-dependent tests ... are forbidden", "a change that makes any post-install
gate ... require ... a network call is a defect" — and **availability** in one:
"the install exception is limited to `bun install --frozen-lockfile`". `bun test`
satisfies all three of the first kind and fails the fourth. FR-050 restated the
principle using the fourth reading and presented it as a faithful derivation, so
a task has been blocked by a feature requirement that overstates ratified law,
with the record of it living in a task comment.

This record resolves the reading — dependence is the operative test — and records
the `bun test` step as the single named exemption, bounded by four conditions:
it must be named where it occurs, justified by the nesting obstruction rather
than convenience, accompanied by every other post-install step remaining wrapped,
and it permits ambient availability but never use. FR-050 is amended by
reference, the mechanism ADR-0014 used for ADR-0012 and ADR-0013.

Option D — wrap the step and delete the denial-proving controls — is recorded as
considered and refused, because it would satisfy the letter by removing the
evidence that makes every other wrapped step meaningful.

The 13-of-14 figure was counted from the workflow, not asserted: the
`clean-clone-builds` job has 17 steps, 3 pre-install, 14 post-install, of which
13 reference `run-network-denied.ts` in their run command and exactly one does
not — the `bun test` step this record names.

`adr lint`: 28 records, 0 errors, 0 warnings. `adr queue`: empty.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Mark Beacom <m@beacom.dev>
Copilot AI balanced review requested due to automatic review settings August 14, 2026 02:31
@mbeacom
mbeacom merged commit eed4285 into main Aug 14, 2026
12 checks passed
@mbeacom
mbeacom deleted the mbeacom-adr-0028-network-denial-exemption branch August 14, 2026 02:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Records ADR-0028’s interpretation of Constitution Principle II and a bounded bun test exemption.

Changes:

  • Defines network dependence as the operative compliance test.
  • Documents the single exemption, constraints, alternatives, and follow-up work.
Suppressed comments (2)

docs/adr/0028-read-principle-ii-as-forbidding-network-dependence-and-exempt-the-step-that-proves-denial.md:87

  • This factual claim contradicts the control that motivates the ADR. PR #98's probe deliberately fetches its loopback listener and asserts the unsandboxed result is CONNECTED; this ADR also records that the full suite fails under both denial wrappers. Distinguish external-network dependence from the intentional hermetic loopback access instead of claiming that nothing reaches the network or that the suite passes with it gone.
Three statements test whether a step *depends on* the network. One tests whether
the network is *available to* it. `bun test` satisfies all three of the first
kind — nothing in the suite reaches the network, and it passes with the network
gone — and fails the fourth.

docs/adr/0028-read-principle-ii-as-forbidding-network-dependence-and-exempt-the-step-that-proves-denial.md:99

  • The named suite does not satisfy this operative test as written: PR #98's denial control intentionally makes an unsandboxed loopback request, while condition 4 later says any test that reaches the network is a defect. Define the rule in terms of external network/egress with an explicit hermetic-loopback allowance, or make that specific control access part of the exemption; otherwise the ADR immediately classifies its own justification as noncompliant.
**Principle II's operative test is dependence, not availability. A post-install
step is compliant when it neither requires nor uses the network, whether or not
one happens to be reachable. The `bun test` step of `clean-clone-builds` is
recorded as a named, bounded exemption from the availability reading.**

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +18 to +21
- type: path
pattern: "specs/**/spec.md"
- type: path
pattern: "specs/**/tasks.md"
mbeacom added a commit that referenced this pull request Aug 16, 2026
CI caught a real id collision that the local tree did not have: `main`
merged a different ADR-0028 (portable agent plugin) while this branch was
open, so `adr check` failed with `unique-id 0028 is used by multiple
records`. self-dogfood, clean-clone-builds and both node-smoke jobs went
red on it.

This is the risk flagged when 0028 was first scaffolded — the number had
already been used and reverted (#144/#145), so `adr new` offered it again
and a concurrent branch took it first. The corpus is right to fail closed
here; a duplicate id makes every `affects:` resolution ambiguous.

Renumbered highest-first through placeholders so 0028 -> 0029 could not
then be re-caught by the 0029 -> 0030 pass:

  0028 scope-backstage-publication...      -> 0029
  0029 keep-extension-surfaces...          -> 0030
  0030 publish-a-narrow-consumer-sdk...    -> 0031

Filenames, frontmatter ids, `# ADR-XXXX` headings, `relatesTo`, every
cross-link between the three, the ADR-0031 amendment note on ADR-0029,
and the ADR-0030 references in `scripts/check-deps.ts` and its test
(comment, violation reason string, and the describe block) all moved
together. Verified that no other record's number was touched: the only
ADR references remaining in the three files are 0003, 0007, 0010, 0012,
0013, 0014, 0016, 0019, 0020, 0025 plus the new 0029/0030/0031.

Ratification carries over unchanged — 0029 and 0030 remain accepted and
ratified by @mbeacom, 0031 remains proposed.

adr lint: 31 records, 0 errors, 0 warnings. typecheck clean, 2173 pass /
0 fail, check:deps ok. `adr check` over the branch diff now reports 0
changed-record errors, which is the failure CI reported.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Mark Beacom <m@beacom.dev>
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.

2 participants