Conversation
Distill the credential-broker design from sandboxd/vm-anthropic source material into a first-class architecture doc. Covers: - Two-planes-of-identity argument: network-bound egress identity vs scoped-JWT resource authorization (sandbox-security-teardown.md §2.6). - Broker contract: JWT validation, upstream signing (SigV4 / x-api-key), filestore CRUD semantics, TLS origination. - Deployment topology matrix per L2 runtime tier (Docker variants, Firecracker/CH with vsock channel). - Vsock-shim pattern: preserve localhost ergonomics on microVM tiers without baking vsock awareness into callers. - Multi-tenancy posture: shared broker vs broker-per-VM vs per-VM with delegated STS; vsock CID as unforgeable tenant attribution. - filesystem_id as a first-class secret-scope dimension. - Open questions tagged for Phase 4 lockdown (issuer of scoped JWT identified as the gating decision). Source: sandboxd/vm-anthropic/credential-broker-spec.md and sandbox-security-docs.zip (sandbox-security-teardown.md, vm-internal-channels.md). Fills Tier-1 gap #1 from the plan at ~/.claude/plans/users-nick-open-computer-use-sandboxd-v-eventual-allen.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace LICENSE with Functional Source License v1.1 + Apache 2.0 Future
License (FSL-1.1-Apache-2.0). Each release automatically converts to
Apache-2.0 two years after publication under the Grant of Future License
clause. Use, modification, forking, internal self-hosting, and
redistribution remain permitted; offering a hosted or embedded competing
service requires a separate commercial agreement.
Past releases keep their BUSL-1.1 terms via the LICENSE file frozen at
each tag — git history is unchanged. CHANGELOG records the transition;
the migration commit is the boundary between BUSL and FSL releases.
Scope:
- LICENSE — replaced with FSL-1.1-Apache-2.0 text.
- NOTICE — updated multi-license model description; GitHub URL aligned
to Wide-Moat org.
- README.md — license badge + License section updated.
- CLAUDE.md — License Headers section now requires
SPDX-License-Identifier: FSL-1.1-Apache-2.0 for new core files.
- CONTRIBUTING.md — contributor license terms updated; removed obsolete
BSL Change-Date release-process section, replaced with FSL Apache
conversion note (no per-release LICENSE edit needed under FSL).
- SPDX find-replace across 176 source files (Python / shell / YAML /
TOML / TypeScript / JavaScript / JSON / HTML / Dockerfile / Helm
templates / Markdown). 186 files now carry the FSL SPDX tag.
- package.json — license field.
- THIRD-PARTY-LICENSES.md — own-source-code license reference.
- helm/computer-use-server/{README,templates/NOTES.txt} — license
reference.
- computer-use-server/cli-defaults/{opencode.json, codex.json,
README.md} — _spdx JSON field.
- tests/test-docker-image.sh — assertion updated.
- tests/test_codex_toml_converter.py — fixture values updated.
- CHANGELOG.md — new Unreleased entry documenting the migration.
Skills under skills/public/{describe-image,sub-agent}/ retain MIT.
Third-party skills retain their own LICENSE.txt. Loki/Tempo/Grafana (and
any future AGPL-3.0 deps run as separate services with stable APIs)
remain compatible with FSL-1.1-Apache-2.0 distribution — documented in
the forthcoming docs/architecture/manifesto/05-licensing-posture.md.
Verification:
- grep "BUSL-1.1" outside CHANGELOG / docs/future-architecture / .venv
/ .planning / node_modules returns no source-file hits.
- tests/test-project-structure.sh: 24/24 PASS.
Part of next/v1 Layer 0 scaffolding (PR #1 of 4). Follow-ups:
docs/architecture/ scaffolding + CLAUDE.md sections (PR #2),
documentation linters (PR #3), CI security/test gates + CODEOWNERS
(PR #4).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Catch up with main: pulls in observed execution/egress/secrets axes + DN-1 design note (PR #130). No conflicts expected — both branches only touch docs/future-architecture/ in non-overlapping files. next/v1 continues as the long-lived architecture branch; main is not modified by this merge.
Without this file CodeRabbit auto-reviews only PRs targeting the repo's default branch (main) and skips PRs against next/v1 with the message: "Auto reviews are disabled on base/target branches other than the default branch". next/v1 is the long-lived enterprise-architecture branch; we will land many sub-PRs against it over months. Manual @coderabbitai review per PR is impractical. reviews.auto_review.base_branches now lists both main and next/v1. Profile set to chill (less noise on the architecture work). Drafts not auto-reviewed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chore(license): migrate BUSL-1.1 → FSL-1.1-Apache-2.0
chore(ci): enable CodeRabbit auto-review on next/v1 PRs
…sections (#134) * docs(architecture): scaffold next/v1 architecture tree + CLAUDE.md sections Layer 0 step 2: stub-only scaffolding for docs/architecture/ and seven new sections in CLAUDE.md governing all architecture work on next/v1. Pacing rule (locked): no bulk-generation. Each future architecture artifact appears one PR at a time after discussion. status:stub / status:tbd are first-class states. See docs/architecture/PROCESS.md. Created stubs only — no real content, just front-matter + 1-line purpose. The tree grows per PROCESS.md. - README.md (navigator: what's here, what's NOT here yet, reading order) - MANIFESTO.md (stub — planned sections listed, no content yet) - glossary.md (stub — empty terms list) - PROCESS.md (draft — 3-step playbooks: component / ADR / NFR / dependency / TBD) - adr/README.md + adr/0000-template.md (Nygard format, status flow, hard cap 200 lines, when-to-write-an-ADR test) - components/0000-template.md (fixed section order, hard cap 600 lines) - manifesto/, compliance/, diagrams/ as .gitkeep-only empty dirs Every file carries the mandatory front-matter (status, last-reviewed, owner, applies-to). Linters in PR #3 will enforce this in CI. Added under a new H1 "Architecture work on next/v1": 1. Architecture decisions — pre-read MANIFESTO.md; deviations require an ADR. 2. Architecture content routing — 10-step decision tree ("where does this paragraph go?") with 30-second placement rule. 3. Diagrams — Mermaid first; D2/PlantUML when needed; ASCII forbidden in docs/architecture/; PNG only for external-UI screenshots. 4. Dependency policy — license gate, supply-chain gate, bundled vs not-bundled, enterprise-grade heuristic, first-class reject reasons. 5. Testing & QA discipline — top-3 CI gates a bank auditor opens first (secrets / SAST+SCA / signed SBOM+SLSA-3), full rule set, doc linter list, code-review discipline. 6. v1 non-goals — skill registry / hosted models / admin UI / our own SaaS are explicitly out; each gets a clean abstraction boundary. 7. Documentation discipline — front-matter rules, hard caps per doc type, banned vocabulary + phrases, English-only, no emoji. These sections are the contract the AI assistant operates under on next/v1. They do not constrain quick fixes or PoC work on main. The License Headers section still references BUSL-1.1 in this commit; PR #132 (license migration BUSL → FSL) updates it. After both land on next/v1 the file is consistent. Part of next/v1 Layer 0 scaffolding (PR #2 of 4). Follow-ups: doc linters (PR #3), CI security/test gates + CODEOWNERS (PR #4). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): address CodeRabbit review (SPDX headers + ADR Status + glossary stub) CodeRabbit flagged 10 inline issues on PR #134. All addressed: 1. **Missing SPDX/copyright headers (8 files).** Added the mandatory `<!-- SPDX-License-Identifier: FSL-1.1-Apache-2.0 -->` + `<!-- Copyright (c) 2025 Open Computer Use Contributors -->` as the first two lines of: - docs/architecture/README.md - docs/architecture/MANIFESTO.md - docs/architecture/glossary.md - docs/architecture/PROCESS.md - docs/architecture/adr/README.md - docs/architecture/adr/0000-template.md - docs/architecture/components/0000-template.md Matches the project's CLAUDE.md "License Headers" rule. The headers sit above the YAML front-matter, in HTML-comment form (the convention used by other Markdown files in docs/future-architecture/ and docs/operating/). 2. **glossary.md `## Terms` stub heading removed.** Documentation discipline rule: "No stub headings. Write the content or remove the heading." The intent ("terms added when first used in ≥ 2 docs") moved into the body prose. Glossary now has no H2 sections until real terms land. 3. **ADR template missing `## Status` section.** The Nygard format requires Status / Context / Decision / Consequences / Alternatives, per CLAUDE.md. Status was only in YAML front-matter; added a `## Status` section at the top with the lifecycle values and a note that the section mirrors the front-matter field. No other PR feedback to address. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): drop forward reference to components/00-overview.md CodeRabbit follow-up finding on PR #134. The README's reading order listed "The component diagram in components/00-overview.md (when it lands)" — a forward reference to a non-existent document, which violates the documentation-discipline rule "No forward references." Replaced with a single line that says ADRs and component specs are not yet populated and points at PROCESS.md for how they will land. * docs(architecture): add one-sentence purpose line to ADR + component templates CodeRabbit follow-up finding on PR #134 (adr/0000-template.md:17). Documentation discipline rule from CLAUDE.md: "First line after front-matter: one sentence stating purpose and audience. No preamble." Both 0000-template.md files began with their H1 immediately after front-matter, skipping the purpose line. Added one sentence to each naming the document type and audience. The 5 non-template scaffolding files (README, MANIFESTO, glossary, PROCESS, adr/README) already carry a purpose-line. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…+ Versioning (#135) Pure structural refactor. No new rules, no removed rules — just better grouping and a few stale references corrected. - **New section `## Branches and scope` at the top.** Explains the difference between `main` (PoC / current production) and `next/v1` (long-lived enterprise architecture). Mentions that a future PR will add a separate "# Architecture work on next/v1" section with rules scoped to that branch. - **Reorganized as `# Global rules (apply to every branch)`.** Same rules; clearer group heading. - **`## Project Structure` updated**: added `settings-wrapper/`, `helm/`, `vendor/`, `docs/architecture/`, `docs/future-architecture/`. Switched from bullet list to table for readability. - **`## Versioning` updated**: example version bumped from the stale `v0.8.X.Y` to the current `v0.9.X.Y`. Added a line noting that `next/v1` will define its own versioning scheme in an ADR; until then no tagged releases on that branch. - **Section titles normalized** to sentence case ("Building the Docker image", "npm packages layout", "Project structure"). - License Headers rules (already FSL after PR #132). - Building / Testing / npm-layout rules — same. - All wording about FSL-1.1-Apache-2.0, English-only, SPDX headers, etc. The `# Architecture work on next/v1` section lands in PR #134 (docs/architecture scaffolding). Keeping the structural refactor separate makes both PRs reviewable: this PR shows the reorganization diff cleanly; PR #134 shows the new sections cleanly. After both merge the file reads top-to-bottom: Branches+Scope → Global rules → Architecture work. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
) * chore(ci): add documentation linters + fix BUSL leak in openwebui tool Layer 0 sub-PR #3 of 4. Adds the documentation-linter stack defined in CLAUDE.md "Testing & QA discipline" → "Documentation linter" subsection. ## Linters introduced | Gate | Tool | What it catches | |---|---|---| | Style | markdownlint | base Markdown style; long-line check disabled (tables) | | Prose | vale | banned vocabulary, banned phrases, marketing-tone tells | | Links | lychee | broken internal links; forward references = block | | Size | wc-budget.sh | ADR ≤ 200, component spec ≤ 600, MANIFESTO ≤ 400 | | Slop | ai-slop-detector.sh | TOC in short docs, reflexive Conclusion sections, stub headings | | Diagrams | ascii-diagram-detector.sh | Unicode box-drawing in docs/architecture/ | | Front-matter | front-matter-validator.sh | mandatory status / last-reviewed / owner / applies-to | ## Banned vocabulary list CLAUDE.md lists 14 banned adjectives ("comprehensive", "robust", "seamless", "powerful", "best-in-class", "industry-leading", "elegant", "battle-tested", plus 4 additions: "cutting-edge", "next-generation", "state-of-the-art", "world-class"). All grep-checkable; case-insensitive. ## Banned phrases list 12 phrases including "It's worth noting that…", "In this section we will…", "This document will…", "Going forward…", "Please note…", "Happy coding", "In today's fast-paced", "delve into". Regex-based with word-boundary anchors so technical contexts ("forward references", "going forward into the merge") don't false-positive. ## Self-test scripts/docs-lint/test-linters.sh runs intentional-fail fixtures through each detection rule. 8/8 PASS locally. The CI workflow runs this as the first job — if any detection rule loses bite, CI fails before the rule is evaluated against real docs. ## CI orchestration .github/workflows/docs-lint.yml runs 8 jobs in parallel on every PR that touches docs/architecture/, CLAUDE.md, README.md, CONTRIBUTING.md, or the linter configs themselves. Triggered on PR and on push to next/v1. ## BUSL leak fix PR #132 missed `openwebui/tools/computer_use_tools.py:1` during the SPDX find-replace (suspected: the file was created via an Open WebUI filter-tool export rather than the standard source path, but the SPDX header line itself was still BUSL-1.1). Caught by the gsd-verifier pass on the plan's P-02 check. Fixed by changing the SPDX-License-Identifier to FSL-1.1-Apache-2.0; matches the rest of the repo. ## Out of scope here CI security gates (gitleaks, Semgrep, Trivy, Cosign, SBOM/SLSA), CODEOWNERS, branch protection, conventional-commits enforcement — these land in PR #4 of the Layer 0 plan. Verification: - `bash scripts/docs-lint/test-linters.sh` → 8 passed, 0 failed. - All 4 detector scripts run cleanly against current `next/v1` content ("OK" or "OK (no files to scan)"). - `git grep "SPDX-License-Identifier: BUSL-1.1"` outside CHANGELOG and docs/future-architecture returns zero. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(ci): scope markdownlint to docs/architecture/ + fix lychee inputs Two CI failures on docs-lint workflow for PR #136: 1. **markdownlint** failed on pre-existing style issues in top-level CLAUDE.md (1 finding: MD032 blanks-around-lists) and README.md (4 findings: MD028, MD034, MD031 x2). These are global rules-area docs that were authored before this lint stack landed and aren't the target of the architecture linter. Scope markdownlint to `docs/architecture/**/*.md` only. Bringing the top-level docs into compliance is a separate cleanup task; this PR is the linter itself, not a project-wide style overhaul. 2. **lychee** failed with "required arguments were not provided: <inputs>...". The `include = [...]` key in lychee.toml is not a real lychee config key — inputs are positional CLI args. Moved the glob into the workflow `args:` and removed the dead key from lychee.toml. Added `--offline` so the gate only checks internal / forward-reference link integrity (external HTTP checks are rate-limit surfaces and not what the forward-reference rule protects against). Verification: workflow YAML parses; the same docs/architecture/**/*.md glob is used by both markdownlint and lychee jobs for consistency. * fix(ci): lychee — failIfEmpty:false on empty docs trees PR #136 itself doesn't add files under docs/architecture/ (the scaffolding lives in PR #134). The glob expanded to zero files and the action default failIfEmpty:true treated empty-result as a CI failure. The gate exists to catch broken internal links when docs/architecture/ has content; an empty result on this branch is a non-event. Other docs-lint jobs (front-matter, wc-budget, ai-slop, ascii-diagram) already emit 'OK (no files to scan)' on empty trees — match that. * fix(ci): markdownlint — disable MD022, scope MD003 to ATX, drop MD033 After PR #134 scaffolding landed on next/v1, markdownlint started flagging 47 false-positives across the new template / README files. Three rules were misfiring: - MD003 (heading-style): the linter auto-detected setext style from a coincidental line in the file and then flagged every ATX heading. Pin style=atx explicitly. - MD022 (blanks-around-headings): the linter parsed the YAML front-matter closing '---' as a setext H2 underline, then demanded blank lines around the preceding 'status: proposed' line (which is YAML, not a heading). Disabled — false positive specific to our front-matter shape. - MD033 (no-inline-html): the templates contain angle-bracket placeholders ('# ADR-NNNN: <title>', '<verb>', '<object>', '<alternative>', '<name>') that markdownlint reads as inline HTML tags. Allow-list approach didn't scale; placeholder leakage into real ADRs is caught by ai-slop-detector and human review anyway. Disabled. Net effect: markdownlint still enforces the genuine style rules (list spacing, fenced-block spacing, no-bare-urls, etc.) but no longer trips on front-matter parsing artifacts or template placeholders. * fix(ci): markdownlint — disable MD003 entirely (front-matter parsing) After scoping MD003 to style:atx, markdownlint still flagged 7 files with the inverse error: 'Expected: atx; Actual: setext'. Root cause: markdownlint-cli2 doesn't understand YAML front-matter and parses the closing '---' delimiter at line 5 of every architecture doc as a setext H2 underline. That makes line 5 a 'heading', and the linter then claims the file's heading style is setext, so every subsequent ATX heading is 'wrong style'. Front-matter is mandatory in docs/architecture/ (enforced by front-matter-validator.sh), so we can't drop the delimiter. The cli2 default does not strip front-matter pre-parse. Net: MD003 can never work for our docs as-is, so disable it. Heading-style consistency in practice is enforced by: - The component-spec template ('Purpose / Boundaries / Invariants / Failure modes / Operational concerns / Open questions' — all ATX). - The ADR template (Status / Context / Decision / etc — all ATX). - Documentation-discipline review. No ATX-vs-setext mixing has been observed; the protection MD003 gave us was an illusion fighting the front-matter parser. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes Layer 0 of the next/v1 enterprise architecture bootstrap. Lands the
top-3 CI gates a bank auditor opens first, plus the supporting CODEOWNERS,
issue templates, SECURITY.md and gitleaks config.
## What's in
- `.github/workflows/security.yml` — secrets (gitleaks + trufflehog),
SAST (semgrep), SCA (trivy CRITICAL blocking + HIGH informational),
IaC (checkov on helm), conventional-commits PR-title gate.
- `.github/workflows/supply-chain.yml` — SBOM (syft) + Cosign keyless
signature + in-toto SBOM attestations (SPDX + CycloneDX) + cosign
verify-attestation self-check, gated by `environment: production`.
- `.github/security-exceptions.yml` — schema for 14-day HIGH exceptions.
- `.github/CODEOWNERS` — review routing covering Dockerfile,
docker-compose, supply-chain entry points (requirements.txt,
package.json), helm/, computer-use-server/, all build/release/codeql
workflows, .gitleaks.toml, SECURITY.md, ISSUE_TEMPLATE/, CHANGELOG.md.
- `.github/ISSUE_TEMPLATE/{adr,bug,component,dependency,nfr}-proposal.md`
+ `config.yml` — proposal chooser, blank issues off, security-advisory
stop banner on bug-report, Fulcio-identity + maintainer health fields
on dependency-proposal.
- `.gitleaks.toml` — allowlist for documented placeholders and minified
bundles; unsafe stopwords removed.
- `SECURITY.md` — private vulnerability reporting, 30-day SLA for
Critical-with-active-exploitation, 90-day SLA for other Critical/High.
- Deleted `.github/SECURITY.md` (duplicate with contradictory policy).
## Hardening
- Every third-party action pinned to 40-char commit SHA.
- Every container image pinned to `name:tag@sha256:<digest>`.
- `persist-credentials: false` on every actions/checkout call.
- Two-source gitleaks pattern: PR head as scan target, base-ref
.gitleaks.toml fetched via `gh api` (with bootstrap fallback to
upstream defaults when base lacks the file). Closes the fork-PR
config-injection bypass.
- supply-chain workflow_dispatch.inputs.image_ref locked to
`ghcr.io/${owner}/*` prefix + character whitelist (closes identity-
laundering through arbitrary image signing).
- Anchored `--certificate-identity-regexp` on cosign verify.
- Docker container runs: `--read-only`, non-root user, `:ro` mounts.
- Trivy `limit-severities-for-sarif: true` (works around
aquasecurity/trivy-action#309).
- SLSA-3 provenance job removed — its `digest: ""` violated the
generator's contract. Re-added in a follow-up release workflow that
colocates build/push and provenance generation.
## Verified
All 8 checks pass on commit 64c1963 (CodeRabbit, IaC checkov, SAST
semgrep, SCA trivy filesystem, Trivy, conventional-commits, secrets
gitleaks, secrets trufflehog). Local semgrep against both workflows: 0
findings. Local gitleaks against full history (508 commits): no leaks.
Independent gsd-code-reviewer pass surfaced 9 HIGH + 9 MED + 1 LOW
beyond the CodeRabbit set — all addressed in this PR.
Post-merge gsd-code-reviewer pass on PR #137 commit 64c1963 surfaced three real defects that PR #137 missed. Two were active bypasses; one was a guaranteed first-real-release failure. ## HIGH - H-1 gitleaks bootstrap-fallback was the bypass it was meant to prevent. Without --config, gitleaks v8.30.1 autoloads /repo/.gitleaks.toml from the PR head per its documented config precedence. A fork PR shipping a permissive allowlist would silently win. Fix: always pass --config; when the base ref has no real file, write a useDefault stub. - H-2 supply-chain.yml signed the wrong tag. build.yml strips the leading v via type=match,pattern=v(.*),group=1, but supply-chain.yml kept the v in the image ref. Fix: tag=${REF_NAME#v}. - H-3 CycloneDX attestation was created but never verified before the job exited green. Fix: mirror cosign verify-attestation --type cyclonedx after the spdxjson one. ## MED + LOW - Trivy CRITICAL pass ignore-unfixed=false (force exception ledger entries for un-patched CRITICALs). - CODEOWNERS dual-team on /.github/dependabot.yml, /.gitleaks.toml, /SECURITY.md. - Dropped dead helm/open-computer-use/values.example.yaml allowlist. - Narrowed workflow_dispatch cert-identity regex to refs/tags/v* or refs/heads/(main|next/v1). - Added p/dockerfile + p/github-actions to semgrep config. - Defence-in-depth .. segment check on image_ref. - Regex-escape REF_NAME and REPO_FOR_VERIFY before interpolation into cert-identity anchor. - Bug-report template Browser qualifier widened to Open WebUI / Computer Use UI. - gh api uses .content // empty to handle directory listings cleanly. - SECURITY.md back-port window softened to two most recent minors at maintainer discretion. CI green (8/8). CodeRabbit auto-review: No actionable comments.
* chore(ci): exclude main-line legacy from Layer 0 SAST gate ADR-0001 records the policy: `.semgrepignore` enumerates main-line legacy paths that v1 GA does not ship (Dockerfile, computer-use-server, openwebui, settings-wrapper, cron, cleanup, bundled skills). Every new-architecture component PR removes the corresponding path in the same commit. PROCESS.md "Adding a component" gains step 4 to enforce that inheritance. Layer 0 verifier on `next/v1` HEAD = 13f724e flagged the SAST gate red on 37 findings in legacy code (root containers, wildcard CORS, md5 cache keys, stdlib XML parsing, dynamic urllib). The legacy code is not refactored on next/v1 — it is replaced from scratch in Layer 6+. The exclusion list shrinks monotonically; new code is never excluded. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(docs): remove LAYER-0-VERIFICATION.md This file was not in the architecture plan and does not fit any content-routing tree branch in CLAUDE.md. Verifier output is an ephemeral process artifact — it belongs in the PR description (where the verdict and evidence are already captured) or a tracked issue, not as a committed snapshot that drifts the moment the next pass runs. ADR-0001 already encodes the policy that resolved the gate-row-0 issue the verifier flagged; the snapshot is redundant. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(ci): extend .semgrepignore to cover missed legacy paths PR #139 shipped the initial exclusion list but missed three legacy areas the SAST gate scans: .github/workflows/release-chart.yml, skills/examples/, and tests/. All three are main-line PoC code slated for replacement in Layer 6+. The amendment lands them under the same ADR-0001 policy with no change to the decision or alternatives. Discovered by the third verifier pass on commit 709db53. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(ci): address CodeRabbit nits on .semgrepignore - Anchor /tests/ to repo root so future components' nested tests/ directories are not silently skipped by SAST. - Reword the skills/ comment so it matches the actual entries: three specific public subtrees plus the whole examples tree, not a blanket "skills/public/" claim. Both raised on PR #140 review. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(docs-lint): add architecture-tree whitelist linter Each file under docs/architecture/ must match an entry in the per- directory whitelist. Anything else fails CI with a hint pointing at PROCESS.md and the content-routing tree in CLAUDE.md. This catches the LAYER-0-VERIFICATION.md class of drift before it lands: scratch notes, AI snapshots, screenshots in diagrams/, files at the wrong level, etc. When a PR legitimately needs a new file kind, it updates ALLOWED in architecture-tree-whitelist.sh in the same commit, with the tightest pattern that fits the use case. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(docs-lint): segment-aware glob matching in tree whitelist CodeRabbit caught that fnmatch.fnmatchcase treats `/` as a normal character. With the original matcher, a pattern like `compliance/*-mapping.md` would silently accept `compliance/sub/evil-mapping.md`. Replace the matcher with one that splits both sides on `/`, requires equal depth, and applies fnmatch per segment — so `*` can never cross a directory boundary. Self-test gains a dedicated nested-path denial fixture (`compliance/sub/x-mapping.md`) plus a positive legitimate fixture (`compliance/soc2-mapping.md`) so future regressions back to plain fnmatch fail loudly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rtifact) (#143) * docs(architecture): land manifesto §01 audience-and-buyer (Layer 1) First content-bearing artifact of Layer 1 on next/v1. 54 lines, in budget. Decisions captured in §01 (per research synthesis in docs/future-architecture/research/SUMMARY-manifesto-01.md): - Audience framed as capability ceiling = tier-1-bank-grade, primary commercial focus = tier-1 US/EU banks as trust anchor, but the same artifact serves any organisation that wants in-perimeter agentic AI. - Wide-Moat sells an ecosystem subscription plus enablement and certification, not a single component. The repository is one component of that ecosystem. - Three coexisting personas inside the customer: business users, agents themselves, builder/platform engineers (the enablement target). - Solo enthusiast is a downstream consequence of FSL, not a co-equal persona; contribution channels named. - Buyer chain has four parallel veto-bearing functions; TPRM is the top deal-killer in 2026 driven by NYDFS, FDIC FIL-44-2025, OCC Bulletin 2025-17, and DORA Articles 28-30. SR 26-2 (17 Apr 2026) shifts the veto path from MRM to TPRM/operational-risk/cyber. - Why-now uses post-Omnibus EU AI Act dates: Annex III standalone 2 Dec 2027, product-embedded 2 Aug 2028. - Positioning thesis stakes four clauses (in-perimeter incl. agent loop, model-neutral by MCP, compliance evidence as first-class build artifact, FSL anti-SaaS with Additional Permissions instrument). UiPath (5 May 2026) and Anthropic (19 May 2026) shipped partial in-perimeter answers; in-perimeter alone is necessary but no longer sufficient. Eight research-buffer files land alongside as input evidence: - bank-buyer.md, enthusiast-audience.md, widemoat-thesis-advisor.md (initial gsd-research briefs) - proof-uipath-anthropic-2026-05.md (primary-source verification of the shock events with URLs) - proof-anthropic-sdk-license.md (Anthropic open vs closed components: srt Apache-2.0, Claude Code binary closed, MCP tunnel proxy closed) - proof-anthropic-sandbox-runtime-vs-ours.md (verdict: adopt selectively as BoM dep for in-microVM secondary defence, not a competitor) - advisor-fsl-internal-use.md (Option 3: stock FSL + published LICENSE-ADDITIONAL-PERMISSIONS.md, draft text included) - SUMMARY-manifesto-01.md (conflicts resolved, decisions taken) Plan and memory updates queued for post-merge follow-up (EU AI Act dates, new thesis in widemoat memory, regulator triad memory, Wide-Moat scope clarification memory). Local docs-lint runs PASS: wc-budget, front-matter-validator, ai-slop-detector, ascii-diagram-detector, architecture-tree-whitelist. Vale banned-vocab/phrase check deferred to CI. * docs(architecture): address gsd-code-reviewer Critical findings on §01 Code review by gsd-code-reviewer (REVIEW-pr-143.md, 2 Critical / 7 Warning / 6 Info, verdict: ship with notes) flagged two pre-merge blockers plus reconciliation issues with the research buffer. This commit addresses both Criticals and four of the Warnings; remaining Info and Warning items are queued as post-merge follow-up per the review's verdict. Critical fixes: - CR-01: dropped FDIC FIL-44-2025 and OCC Bulletin 2025-17 citations from the buyer-chain paragraph. Neither identifier was verified in the research buffer (only NYDFS 21 Oct 2025, DORA Art. 28-30, and SR 26-2 are cited with primary-source backing). Bank Legal would dereference both on first read and find no source; safer to remove until a proof-fdic-occ-2025.md buffer lands in a follow-up PR. - CR-02: reworded "published LICENSE-ADDITIONAL-PERMISSIONS.md instrument" to "planned" with explicit tracking-issue link (arch/additional-permissions-instrument) and pointer to the draft in advisor-fsl-internal-use.md. The instrument exists in draft only; calling it "published" was a forward-reference violation per CLAUDE.md doc-discipline. Warning fixes: - WR-02: added the four 2026 closing use-cases (KYC/AML, IT helpdesk, dev productivity, compliance evidence) to the Audience block per SUMMARY-manifesto-01.md Decision #4. §01 had silently dropped them post-synthesis; restored. - WR-04: trimmed the eight-component enumeration in the commercial-model paragraph to one sentence. Component detail belongs in §06 or component-spec index, not Audience. - WR-05: added the Apache-2.0-conversion qualifier ("during the FSL term... each release converting to Apache 2.0 two years after publication") to the Wide-Moat self-imposed SaaS prohibition. Without the qualifier the claim read as absolute and would not survive Legal review. - WR-06: split agents out of the persona-numbered-list into a separate paragraph framed as architectural concern, not buyer. Personas list now contains only humans (business users + builder engineers). Queued for post-merge follow-up (per review verdict): - WR-01: rephrase "four-clause" to avoid overload with adjacent counts. - WR-03 + WR-07: reconcile SUMMARY-manifesto-01.md line counts and Open Question 4 swap with the shipped §01. - IN-01: add hedge marker to "CAIO function exists at every tier-1" (uncited assumption). - IN-02 + IN-03: stylistic refinements on veto-power phrasing and 65-word sentence split. - IN-04: convert Open Question slug placeholders to clickable issue links once issues are filed. - IN-05: verify post-merge update list still accurate. - IN-06: add SPDX license headers to six research-buffer files on next touch (not blocker; research-buffer discipline is lower than canonical architecture). File grew from 54 to 55 lines after the use-case addition; still well within 80-line section practical cap. All five local linters PASS (wc-budget, front-matter-validator, ai-slop-detector, ascii-diagram-detector, architecture-tree-whitelist). * docs(architecture): fix lychee forward-ref failure on §01 CI docs-lint / lychee step failed on PR #143 with one broken link: [ERROR] manifesto/05-licensing-posture.md | Cannot find file CLAUDE.md doc-discipline rule is intentional: "No forward references. Don't link to docs that don't exist." Lychee gate enforces this with no exclude-path overrides for in-Manifesto cross-refs (and we should not loosen the gate). §01 had two clickable forward-refs to ./05-licensing-posture.md. Replaced both with plain-text §05 references that carry tracking-issue slugs (arch/manifesto-05-licensing-posture, arch/additional-permissions-instrument). Removed the inline link to ./../../future-architecture/research/advisor-fsl-internal-use.md in the FSL paragraph for the same reason — the path resolves on disk but points into the research buffer (CLAUDE.md doc-discipline: architecture docs should not link into the buffer; the buffer links INTO architecture on synthesis, not the other way around). When §05 lands in a later PR, that PR converts the plain-text §05 references back to clickable links in the same commit. File still 55 lines. All five local linters PASS. * docs(architecture): fix CodeRabbit Minor finding in REVIEW-pr-143.md CodeRabbit caught an internal inconsistency in our gsd-code-reviewer output: IN-06 heading said "Two research-buffer files" but the list enumerated six. Updated the heading to match the listed set (six). The seven CodeRabbit Critical comments on this PR are all false positives from the known BUSL-1.1 -> FSL-1.1-Apache-2.0 stale-cache trap (PR #132 migrated the licence; CodeRabbit's coding-guideline DB still references BUSL-1.1; per memory project_next_v1_layer_0_status: "do NOT flip headers"). Ignoring those seven; not changing any SPDX header.
…ng them (#144) Research cycles surface architectural primitives Wide-Moat will need (evidence-as-code bundle, ModelProvider abstraction, kill switch SLA, replay bundles, DORA RoI fields, MCP allow-list, etc.). Without a discipline for capturing them, primitives stay buried in research-buffer files and get lost on the next cycle. Three changes: 1. `docs/architecture/PROCESS.md` — new section "Capturing primitives discovered during research" with the one-line-per-entry format and the two drain directions (resolve into NFR/principle/spec, or escalate to GitHub issue). 2. `docs/architecture/primitives-backlog.md` — initial backlog with 16 entries surfaced during Layer 1 §01 research (PR #143). Each entry names: primitive, purpose, source research-file, target section/spec. File carries the same front-matter + SPDX header discipline as the rest of the architecture tree. 3. `scripts/docs-lint/architecture-tree-whitelist.sh` — add `primitives-backlog.md` to the top-level whitelist. Self-test (10/10) still passes. Backlog shrinks monotonically — entries delete in the PR that lands their destination artifact (NFR catalogue, principle list, component spec, BoM row, or tracking issue). Local docs-lint runs PASS: wc-budget, front-matter, ai-slop, ascii, architecture-tree-whitelist + self-test.
Post-merge follow-up #6 from PR #143 backlog. Applies the remaining Warning and Info fixes from REVIEW-pr-143.md (gsd-code-reviewer output) that were not blocking but deferred for a single tidy-up PR. Changes to docs/architecture/manifesto/01-audience-and-buyer.md (57 lines, still under the 80-line section cap): - WR-01: rephrased the four-clause thesis to drop the bare "four-clause" shorthand that competed with adjacent counts (four buyer chains, four forcing functions, four compliance certifications). The Positioning paragraph now reads "intersection of model-neutrality, source availability, fully in-perimeter execution, per-release compliance evidence" — same semantics, no overloaded count. - IN-01: added an explicit hedge marker on the CAIO-function-exists claim ("the function is assumed to exist... uncited assumption — see Open Question 1"). The claim was carried forward from bank-buyer.md where it was already labelled uncited. - IN-02: rephrased "four parallel chains, each with veto power" to "each chain holds at least one veto, and the gatekeeper chain contains four independent vetoes" — removes the ambiguity flagged by the reviewer. - IN-03: split the 65-word TPRM sentence into two sentences (regulator triad / consequence) for grep-ability. Changes to docs/future-architecture/research/SUMMARY-manifesto-01.md: - WR-03: line-count claim updated from "76 lines" (draft) to "57 lines shipped after pre-merge tightening". - WR-07: added an Open-Question-reconciliation paragraph noting the swap from FedRAMP-v1-or-v2 to ModelProvider-scope and the added fifth Additional-Permissions-edge-cases question. - IN-05: the "Required plan + memory updates" block converted from "queued" to "completed" with one-line status per item (all four items applied during this same follow-up cycle: plan-file dates, widemoat thesis memory, layer-0 status memory entry, new regulator-triad memory). Changes to six research-buffer files (IN-06): Added the standard two-line SPDX/copyright header to bank-buyer.md, enthusiast-audience.md, widemoat-thesis-advisor.md, proof-uipath-anthropic-2026-05.md, proof-anthropic-sdk-license.md, advisor-fsl-internal-use.md. They were the six research files that landed in PR #143 without headers; SUMMARY-manifesto-01.md and 01-audience-and-buyer.md already carried them. Not addressed (intentionally deferred): - IN-04 (Open Question slugs → clickable issue links): the GitHub issues do not exist yet. Conversion to clickable links happens when the issues are filed (separate PR or inline with the §05 / §02 PRs that consume the answers). Local docs-lint runs PASS: wc-budget (57), front-matter, ai-slop, ascii, architecture-tree-whitelist. Vale + lychee defer to CI.
…2) (#146) * docs(architecture): manifesto §02 non-functional requirements (Layer 2) §02 catalogues 142 NFR rows across 9 ISO/IEC 25010:2023 categories with hybrid Compliance + Cost sections. Each row carries a measurable target, verification, and source — no aspirational prose. Three trust planes locked in: - inbound: Ed25519 JWT on WebSocket bound to container_name - data access: scoped JWT through credential broker bound to filesystem_id - egress: network-bound, single path through MITM-proxy Tier-aware design preserves one-click solo install: - default tier: Apache-2.0 + TCP + single docker-compose up - bank tier: HSM-signed Merkle audit, FIPS image variant, mTLS substrate Standing rules respected: - zero refs to sandboxd/, process_api_re, "reverse-engineered", "Anthropic-observed", or sysbox (security-policy) - 259 lines (under the 400-line MANIFESTO/sub-doc cap) - gitignored-ref-detector passes on §02 Adds support tooling: - scripts/docs-lint/gitignored-ref-detector.sh — fails CI when any doc under docs/architecture/ or docs/future-architecture/ cites a path that is in .gitignore (reader from a clean clone sees a dead link) - .gitignore — translations (*-ru.md) marked disposable Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(docs-lint): correct header comment in gitignored-ref-detector to match implementation CodeRabbit caught that the "Allowed exceptions" header listed four cases (`.planning/`, URLs, `docs/`, code-span heuristic) but the script body only implemented two (URLs + absolute non-repo paths + a system-path heuristic). Rewrites the comment block to describe what is actually filtered out vs what is intentionally left to `git check-ignore`. No behaviour change. Honest documentation only. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(gitignore): extend research-buffer exclusions for Layer 3 tooling Adds ADVISOR-, NYQUIST-AUDIT-, PATTERN-MAP-, and layer*.md patterns. Layer 3 introduced three new review-tooling shapes (gsd-advisor-researcher, gsd-nyquist-auditor, gsd-pattern-mapper) on top of the §02 set (REVIEW, CROSS-REVIEW, PLAN-CHECK, SUMMARY, CONTRADICTION-CHECK). The buffer files cite gitignored paths and carry phrases we keep out of committed prose. Canonical work lives in docs/architecture/; these stay local. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): manifesto Layer 3 trust boundaries (draft) Lands docs/architecture/02-trust-boundaries.md (226 lines) and the canonical trust-zone diagram at docs/architecture/diagrams/02-trust-boundaries.mmd. Five drawn zones: Control plane / Credential broker / Compute plane / Egress trust-edge / Audit pipeline. Eleven external actors. Eight content-keyed data classes mapped to NYDFS, GLBA, SEC, GDPR, EU AI Act, PCI DSS. T0-T5 tenant-isolation menu. Three egress modes (transparent / MITM / DLP-ICAP). Workload-identity floor minimal vs full-capability. Signer-identity-per-boundary table (§8.1) covering egress JWT, internal RPC, broker scoped-JWT, MITM cert, Merkle head, image admission. Encryption matrix and regulator citation map verbatim per §02 NFR anchors. Closes follow-up #71 (transport variants documented in §7). Goes through six review passes: gsd-code-reviewer, gsd-advisor-researcher cross-review, gsd-plan-checker, gsd-advisor-researcher on three structural decisions, gsd-nyquist-auditor gap audit, gsd-pattern-mapper. Re-review verdict READY-TO-COMMIT: all 5 blockers RESOLVED, all 5 cross-review CRs RESOLVED, advisor PKI table verified, all 11 Nyquist gaps closed. Open Questions tracked in §13 with five entries (placeholder GH-issue slugs land as real URLs in a follow-up PR before draft → proposed). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(docs-lint): allow top-level numbered cross-cutting artifacts Adds `[0-9][0-9]-*.md` pattern to ALLOWED for files at docs/architecture/ root. Layer 3 (02-trust-boundaries.md) is the first such file; future Layer 4 (C4 Context) and Layer 5 (deployment topologies) follow the same shape. Per PROCESS.md, cross-cutting artifacts cited by every component spec live at the top level rather than under manifesto/ or components/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): shrink Layer 3 inline mermaid to honour ≤15-line cap CodeRabbit flagged the §5 inline mermaid as 17 lines (fences + init directive + 15 content), exceeding the CLAUDE.md ≤15-line cap. Drops the init directive (elk renderer still applied via the canonical .mmd source) and shortens four arrow labels. Block now 16 lines total (2 fences + 14 mermaid). Canonical diagram at docs/architecture/diagrams/02-trust-boundaries.mmd unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): drop "bank" wrapper words from Layer 3 prose Removes four "bank"/"bank-reviewer" occurrences from §1 + §11 prose where they were marketing wrappers, not load-bearing referents. The audience stays the same (regulator-reviewer + self-hosting developer per §01); the prose just doesn't keep saying "bank" in front of it. Keeps one mention as "(CFR-cited financial-institution rules)" in §6 retention column — that one is the actual CFR referent, not a wrapper word. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): cut AI-slop from Layer 3 prose User flagged residual slop. Sweep removed: - self-referential meta-noise about line caps and CI conventions in §1 - triple "It does NOT restate / NOT describe / NOT carry" formulation in §1 - "no phone-home, no license-check, no telemetry" no-no-no pattern in §1 - "Each is a place where our code runs and where a reviewer can point and ask" preamble in §2 - "the contract is ready when X lands" hedge in §2 - repeated "External actors appear on the diagram but are not zones we own" preamble in §3 (already in §1) - repeated "Layer 3 names the isolation tiers we ship" preamble in §4 - "(including elk-renderer init directive, 11 actors, and the optional-marking dashed strokes)" list-of-three slop in §5 - duplicate "Optional configurations" paragraph in §5 - "binding artifact for the contract" pompous in §6 - "the minimal-config shape is honest about not being a compliance posture" hedge in §6 - "Both NFRs hold in spirit on both shelves; the substrate differs" hedge in §8 (replaced with what actually happens) - "the signer's key custody and rotation are properties of that boundary, not a separate zone" design-defence in §8.1 - "The full matrix lives in the canonical encryption table here; component specs cite this matrix and never restate it" cite-rules in §9 - duplicate substrate-specific TLS paragraph in §9 (already in §2) - "robust(ness) appears verbatim... preserved against banned-vocab list" meta-noise in §11 - "useful as background while the buffer is migrated" framing in §12 Layer 3 down to 211 lines from 225. Inline mermaid 16 lines including fences. Zero "bank" / "hardened" wrapper words. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): drop LLM/S3 from External actors; clarify Control plane is not a model proxy User flagged that LLM upstream as a named External actor with a ModelProvider abstraction contract overstates what we own. Outbound traffic from the sandbox or Control plane to an LLM endpoint, a customer MCP server, or a customer object store is just traffic through the Egress trust-edge — the egress policy decides where it can go, the credential broker decides which scoped token reaches it. None of these are zones with a contract we hold at the boundary. Removed from §3: LLM upstream row, Customer object store row. Both fold into "endpoints behind the egress policy" framing added at the top of §3. Reworded §2 Control plane row: dropped "LLM-upstream proxy (we proxy, we do not host)" phrasing that read like we host a model proxy. Replaced with "outbound to LLM and any other upstream goes through Egress trust-edge like any other request; the Control plane is not a model proxy". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): cut second-pass slop from Layer 3 + add TTL to diagram labels Removed 6 more slop patterns user flagged: - preamble "Names the trust zones, the data classifications, ..." list-of-five - §1 first paragraph "Layer 3 is the zoning map: what zones exist, ..." duplicate - triple "X stay in Y; X' stay in Y'; X'' stay in Y''" parallelism in §1 - list-of-six "LLM hosting, chat UI, the caller of ..." in §1 scope sentence - "Five zones appear as subgraphs on the canonical diagram" preamble in §2 - "These are the only systems with which we hold a published contract" pompous framing in §3 - "(elk renderer, 11 external actors, optional-marking dashed strokes...)" internal-kitchen list in §5 - "the inverse mapping (our class → customer class) is what the contract binds" pompous in §6 Diagram label fix from v3 reviewer: appended TTLs to two boundary edges so the §5 inline mermaid is self-sufficient without cross-checking §8.1: - "Ed25519 JWT" → "Ed25519 JWT (session ≤4h + RPC ≤60min)" - "scoped JWT" → "scoped JWT (≤15min)" Reconciled §1 / §3 contradiction (v3 reviewer Focus 2): §1 scope sentence now says "Everything else is either an external actor (§3) or an outbound endpoint behind the egress policy"; LLM endpoints stay outside §3 per explicit user direction. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(docs-lint): extend ai-slop-detector with 6 new pattern classes User flagged that the slop seen in Layer 3 should be caught by the linter on every future PR, not relied on for manual sweeps. Adds six new checks: - 6. Self-referential CI / doc-rules meta-noise: "kept within the X budget", "≤N-line form", "CLAUDE.md rules/conventions/budget", "backticks preserve … against banned-vocab". Reader does not need rules-about-itself; rules live in CLAUDE.md. - 7. Hedge / pompous phrasing: "holds in spirit", "honest about (not) being", "the binding artifact for the contract", "is what the contract binds". - 8. Boastful "is the only X and …" superlative without measurable referent. - 9. Triple-parallel "X verbs in Y; X' verbs in Y'; X'' verbs in Y''" construction (the verb appearing three times in one semicoloned line). - 10. Triple-negation "It does not X. It does not Y. It does not Z." - 11. List-of-three "(no X, no Y, no Z)" parenthetical construction. All patterns observed in Layer 3 drafts before manual cleanup; none should have reached the doc in the first place. Linter would have caught them. Tested: passes on Layer 3 (zero hits); existing pre-existing failure on adr/0001-layer-0-gate-legacy-exclusion.md "Amendments" stub heading is not new. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): drop prompt-redaction + Merkle-signing claims from Layer 3 scope User flagged two scope grabs we should not be making: 1. Prompt-redaction is not our zone. AI-guardrail policy (PII masking, prompt-injection detection, content filtering) is the customer's AI gateway responsibility — LiteLLM, Lakera, Lasso, in-perimeter model with its own guardrails, customer's own redactor service. We route the traffic and audit the egress event; what the gateway does with the prompt is its contract, not ours. §6 paragraph rewritten; §2 Egress trust-edge row updated; NFR-COMP-26 flagged for revisit in §02. 2. Merkle-head signing is not ours either. We submit audit batches to a transparency log of the customer's choice (public Sigstore Rekor, customer-private Rekor, customer-operated CT log). The log operator signs the Merkle head; we sign only the submission envelope (envelope auth, not log integrity). §8.1 signer row reframed; §10 paragraph updated; NFR-SEC-03 flagged for revisit in §02 to match this split. Both NFRs in §02 need a follow-up rev to match (separate PR). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): name scope ownership per NFR — DELIVER vs ENABLE vs REVISIT User flagged that several §02 rows tighten the platform's responsibility in ways Layer 3 has already corrected (prompt-redaction, Merkle-head signing). Adds a Scope-ownership section to §02 that classifies every row as one of three: - DELIVER: we ship the code, we are accountable for the measurable target. Sandbox escape, egress proxy, credential broker, audit pipeline, RTO/RPO of our planes, encryption defaults. - ENABLE: we publish the contract / telemetry / integration point; the customer is the principal and owns the policy/content. DORA major- incident timeline, NYDFS § 500.17, IdP posture (relying-party). - REVISIT: claims more than our scope or names a customer-side responsibility (AI gateway / data-controller / regulator-facing process). Eight current rows listed by ID with the corrected position: NFR-FS-03 (LLM cache), NFR-REL-04 (LLM failover), NFR-SEC-21 (model-level threats), NFR-COMP-09 (PMS Art. 72 is deployer), NFR-COMP-10 (DPIA is data controller), NFR-COMP-14 (model accuracy), NFR-COMP-18 (42001 binds the deployer), NFR-COMP-25 (ZDR is customer contract), NFR-COMP-26 (prompt redaction is AI gateway), NFR-SEC-03 Merkle-head wording (tx-log signs the head, not us). REVISIT rows keep their IDs and current wording in §02 until the next revision; Layer 3 already takes the corrected position. Layer 3 §1 now links the Scope-ownership section so the row-by-row decision is reachable in one hop. §02 grew 33 lines (246 → 279); Layer 3 grew 2 lines (209 → 211). Both under cap. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): citation map indicative-not-verbatim; drop legacy buffer refs; NFR-IDs as links User flagged that the §11 "Reviewers copy this into their workpapers; section / control IDs are verbatim, not paraphrased" claim is the dangerous bit, not prose slop. A doc that invites verbatim regulator-citation reuse without a verification trail and then carries misattributed citations becomes an audit liability the moment a reviewer copies a cell. §11 reframed: "Mapping is indicative, not verbatim. Verify every cell against the source text before reproducing in an audit workpaper. Layer 3 does not represent these citations as audit evidence by itself." Inline a list of confirmed defects tracked at `arch/regulator-citations-verify-pass`: - DORA Art. 12 is backup / restoration / recovery, not retention. 10-year retention floor lives in SEC 17a-4 / FCA SYSC 9 / EU AI Act Art. 19(1). - DORA Art. 9 is "Protection and prevention". ICT-risk framework is Art. 6; detection / logging is Art. 10. - NYDFS § 500.7 is access privileges (PAM, least privilege, JIT). Segmentation is not a § 500.7 requirement. - DORA Art. 28(2)(c) "location of processing" likely lives in Art. 30 key contractual provisions; source-check pending. - CRI Profile v2 column was lifting CSF 1.1 subcategory codes (PR.PT-N, DE.DP-N) which were restructured in CSF 2.0; CRI Profile uses its own diagnostic-statement numbers. Whole CRI column removed pending source pass. §12 "See also" section listing legacy buffer files dropped — legacy doc references in a canonical artifact are an antipattern. NFR-IDs converted to markdown links pointing at manifesto/02-nfrs.md. Reader clicks to land on §02; Ctrl+F finds the row. 64 NFR-ID occurrences linked. A per-ID anchor pass is a separate task (would need anchor headings or HTML anchors in §02 tables). Doc preamble after front-matter dropped (user flagged it as boilerplate the reader does not need). §11 verbatim/copy-into-workpapers self-praise removed. §11 inline `robust(ness)` linter-comment removed. Line count 207 / 600. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(docs-lint): catch verbatim-citation claims + 'is the only' superlatives User flagged citation-map "verbatim / copy into workpapers" claim as the dangerous slop pattern that pure-prose tools miss. Adds two more checks: - 12. "Reviewers copy this … workpapers" / "verbatim, not paraphrased" pompous audit-evidence framing. A draft doc cannot represent itself as a verbatim regulator-citation source. - 13. "is the only X" / "is unique among/in X" superlatives without a measurable referent (CLAUDE.md "no adjectives without measurable referent"). Both observed in Layer 3 v1 before cleanup; both should not have reached the doc. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): collapse double blank line in Layer 3 (markdownlint MD012) Trailing empty line left after removing the `robust(ness)` linter-comment created two consecutive blanks before §12 heading. Markdownlint MD012 caught it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): consolidated tree sweep — slop / consistency / scope fixes Cross-reviewer triangulation (code-reviewer FLAG, plan-checker ON-TRACK, pattern-mapper 3 top-risk) converged on this fix batch. §02 NFRs: - drop default-tier vs bank-tier framing in NFR-SEC-03 / COMP-07 / COMP-15 (was contradicting §01 "one product, not a tiered SKU"); rewrite as configuration-conditional on HSM-rooted custody per NFR-FLEX-04 - flip NFR-FLEX-15 egress default to transparent pass-through (was MITM; contradicted the one-click solo-install invariant); DLP-ICAP demoted to a configuration of the MITM mode, not a third mode - replace the §02 embedded trust-zone diagram with a link to the Layer 3 canonical (single source of truth) - rename data-plane → Compute plane, egress-proxy / egress gateway → Egress trust-edge across all NFR rows - drop tech-brand parentheticals from NFR-PERF-03 / NFR-SEC-02 / NFR-SEC-25 / NFR-SEC-28 / NFR-FLEX-03 / NFR-COMP-29 (brand picks belong in component specs, not portability-NFR rows; vendor lists kept only in NFR-FLEX-01/04/13 where the matrix IS the testable property) - strip self-referential CI / doc-rules meta-noise from the intro Layer 3 trust-boundaries: - fix four forward references (§12.4/5, components/<egress-proxy>.md, "Layer 7", MANIFESTO non-goals) - drop T4 / T5 isolation tiers (no named workload) into open question 1 - collapse egress posture from three modes to two; DLP-ICAP is an MITM configuration - reconcile §3 actor table with diagram: LLM / object-store drawn for orientation only; SIEM / KMS marked optional - shrink §9 encryption matrix to a single-sentence invariant citing NFR-SEC-37; per-boundary table moves to component specs - shrink §8.1 signer-identity table to a single paragraph; per-boundary table moves with the PKI decision - strip remaining tech names from prose (SIEM brand list, PKI tool shortlist, vendor lists) Diagram: - remove vendor lists from external-actor labels (LLM upstream / SIEM / outbound proxy / DLP-ICAP / KMS / transparency log) - LLM upstream + customer object store reclassified as `endpoint` nodes (dashed grey) to match prose "drawn for orientation, not actors" Glossary: - backfill 10 entries for terms used in ≥ 2 architecture docs (Control plane / Compute plane / Egress trust-edge / Credential broker / Audit pipeline / Capability shelf / Isolation tier T0-T3 / Egress posture / Egress JWT / OCSF / Transparency log / Compute-time metering) Primitives backlog: - prune 8 drained primitives that landed in §02 NFR rows (kill switch / replay bundle / tamper-evident audit / WORM retention / BYOK / SPIFFE / MITM egress / MCP allow-list) - remove Anthropic-srt entry — internal-research reference must not load- bear in the canonical tree - drop "first FSL adopter" superlative - record drained-list at the file end as audit trail ADR-0001: - fix Amendments stub heading (ai-slop-detector hit on every prior run) Linter: - ai-slop-detector check 14 — block internal research-artifact phrasing (anthropic srt / sandbox-runtime / sandboxd paths / reverse-engineering wording) from leaking into the architecture set Out of scope (deferred): ADR stubs for PKI / FIPS / k8s-distros / licence- allowlist are per-plan on-demand artifacts, not bulk-generated stubs; the open-question slugs in Layer 3 §12 + §02 stay as bare slugs until the TBD-to-issue batch lands. Layer 3.5 §03 non-negotiables slot decision also deferred. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): v2 review follow-ups — collateral cleanup Eleven small fixes surfaced by gsd-code-reviewer v2 + gsd-plan-checker v2 + gsd-pattern-mapper v2 after the consolidated batch landed. Each fix ≤ 5 lines; CI green locally before push. §02 NFRs: - drop NFR-SEC-03 from REVISIT bullet list — already reframed earlier in same batch (NEW-01) - §02 "Five zones meet around the Compute plane: ... Compute plane, ..." duplicate listing → "Five zones interact" (NEW-03) - drop LiteLLM / Lakera vendor names from REVISIT bullets NFR-REL-04 + NFR-COMP-26 — same vendor names were stripped from Layer 3 last batch but resurfaced here (NEW-04) - capitalise "egress trust-edge" → "Egress trust-edge" in NFR-FS-03 REVISIT bullet (plan-v2-1) - NFR-FLEX-10: bare "compute" → "Compute plane" (plan-v2-2) - NFR-PERF-07/08/09 brand-baked IDs (runc / gVisor / kata-fc) rewritten as substrate-named: container-substrate / user-space-kernel substrate / microVM substrate (pattern-v2-R3) — symmetric to NFR-SEC-02 brand- agnostic rewrite from prior batch Layer 3 trust-boundaries: - §2 over-claim "every inter-zone arrow is encrypted" → align with NFR-SEC-37 wording (carve-outs named) (NEW-06) - §10 "to be revisited in §02 to match this split" — stale, §02 now matches (NEW-02) Glossary: - Transparency log entry: drop "Sigstore Rekor" vendor brand → vendor- neutral wording (NEW-05); the term itself was held vendor-neutral in Layer 3 prose, glossary entry shouldn't reintroduce the brand - Compute plane entry: drop "formerly named data-plane" hedge — §02 rename is complete, hedge no longer needed (pattern-v2-R1) Diagram: - CPROXY (customer outbound proxy) and SOAR reclassified ext → extOpt (dashed border) to match the prose "(optional)" label in Layer 3 §3 actor table (pattern-v2 diagram dashes) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 3 v3 — close 5 contradictions before proposed User-flagged before draft → proposed transition. Each item was a real contradiction or ambiguity inside the canonical doc, not a stylistic one. 1. Retention floor — §6 REGULATED-AUDIT row cited "DORA Art. 12(2) 10 yr for critical functions" as the retention basis. §11 had already documented that DORA Art. 12 is backup/restoration, NOT retention; the 10-year floor lives in SEC 17a-4 / FCA SYSC 9 / EU AI Act Art. 19(1). §10 prose said "7-year minimum (NFR-COMP-01)" without naming the "10y configurable" half. Three numbers, one defective citation. Now: §6 cell + §10 prose both say "7 y default / 10 y configurable per NFR-COMP-01; 10 y floor from SEC 17a-4 / FCA SYSC 9 / EU AI Act Art. 19(1)". Single machine-enforced retention statement. 2. Revoke ≤5 min vs in-flight TTL ≤4 h — §7 said "IdP unreachable → in-flight sessions continue until TTL expiry"; §8 declared revoke latency target ≤5 min. Read together those promise that revoke holds during an IdP outage even though the only named mechanism is re-authentication. Made the revoke mechanism explicit: kill-switch maintains a Control-plane session denylist checked on every Compute RPC + every Egress request via the broker token; revoke is independent of IdP reachability, NFR-SEC-04 ≤5 min and NFR-SEC-01 ≤30 s kill-switch share the denylist. IdP participates in token issue, not in revoke. 3. T1 namespace + shared kernel for agent-execution — §4 placed T1 (namespace + netpolicy, shared kernel) under "non-NPI workloads", which is a data-classification argument, not a sandbox-escape argument. For LLM-issued tool calls / code, the attack surface is the container boundary regardless of data class. Added a "Multi-tenant agent-execution invariant" paragraph under §4: multi-tenant agent execution requires microVM substrate (the full-capability shelf); T1 namespace remains valid only for single-tenant agent execution or for multi-tenant workloads that do not execute LLM-issued code. 4. Token-name taxonomy — §5 diagram and §02 token TTL taxonomy used different spellings for the same three classes ("session JWT" vs "Egress JWT"; "RPC token" vs "Generic internal token"). Now: the canonical class names live in §8 + §02, the §5 diagram + canonical .mmd both use the same canonical names, and §8 carries a one-line diagram-label retirement note for the old wording. 5. Mermaid convention encoding — the §5 inline block declared "solid = always, dashed = optional" but did not encode it (all default solid), while the canonical .mmd does encode it. Now: caption says the convention applies in the canonical file, the inline block is a simplified overview that does not encode dashed-vs-solid, and the reader is pointed at the canonical file or §3 actor table for the optional reading. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(gitignore): extend research-buffer ignore pattern to CONSOLIDATED-* Sibling review artefacts (REVIEW-*, PLAN-CHECK-*, PATTERN-MAP-*) are already ignored under docs/future-architecture/research/. The CONSOLIDATED-* family (multi-reviewer synthesis docs the architect-loop produces between review passes) belongs to the same working buffer and gets the same treatment. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): mark REVISIT NFR rows informational / non-gating CodeRabbit Major: REVISIT bullets de-scope NFR-FS-03 / REL-04 / SEC-21 / COMP-09/10/14/18/25/26, but the rows themselves sit in the catalogue tables with active-looking Target columns. A CI gate or verifier that walks §02 row-by-row would enforce a Target the bullets explicitly de-scoped — contradiction between the gating mechanism and the prose. Fix: - §"Scope ownership" intro now states explicitly that REVISIT rows are informational / non-gating until re-cut; CI gates, release acceptance, compliance attestations, and verifier passes MUST NOT enforce a REVISIT row's Target. - Each of the 9 affected rows carries an inline **[REVISIT — non-gating]** prefix in its Scenario cell, so a gate-author walking the table cannot miss the deferral. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 3 — close peer-review findings M1 / M2 / M3 / m6 Peer review on PR #147 surfaced four substantive items. Each was a real defect verifiable against the doc itself; all closed in this commit. M1 (inline mermaid §5 — content defect): - Edge "CP → VM" was labelled "Egress JWT (≤4h) + Generic internal (≤60min)". Per §8 token taxonomy + canonical .mmd, Generic internal token rides Control plane ↔ broker ↔ audit (host-side), NOT CP → Compute plane. Label now reads "Egress JWT (≤4h)" — matches §8 + canonical .mmd line 51. M3 (§1 prose stale): - Said "the §02 catalogue still carries the old wording … until its next revision". §02 was updated in this same PR (NFR rows marked [REVISIT — non-gating] + enforcement-status block). Rewritten to reflect actual state: "§02 marks each REVISIT row inline as [REVISIT — non-gating] so CI and verifier passes do not enforce it; the substantive re-cut lands in a follow-up PR." Also: §"Scope-ownership" → §"Scope ownership" (heading spelling match). m6 (§2 zone 1 prose semantic): - Said "Outbound to LLM and any other upstream goes through the Egress trust-edge like any other request" while drawn from Control plane. Control plane never originates upstream traffic — only Compute plane does. Rewritten: "Holds no outbound path to upstream; all upstream traffic originates in the Compute plane and traverses the Egress trust-edge." M2 (link-cap structural): - §2 zone table carried 30+ NFR cross-doc links inline (5+ per zone). CLAUDE.md doc-discipline: "one outbound link cap: ≤ 3 cross-doc links per H2 section". Restructured: each zone row keeps a single primary NFR-anchor link; the rest move to a consolidated "Secondary NFR anchors per zone" footer immediately below the table. Same pattern for §8: tables carry bare NFR-ID text in §02-anchor column, single consolidated link-footer below. Reader still has every cross-reference; ≤3-per-H2 rule no longer broken across the doc. NOT changed: - m1 (inline mermaid 16 lines fence-inclusive) — wc-budget.sh counts content-only; CI passes; trace agreed with peer. - m7 (§11 retrospective-defects prose) — user explicitly requested this audit trail earlier in the PR session. Sweeping it to a one-liner loses the *why* the verification pass exists. Kept as-is. - m5 (PR title contains "manifesto") — accepted artefact, will use cleaner naming for next top-level cross-cutting PR (Layer 4 C4 Context). - n1 / n2 / n3 — all cosmetic; defer. PR description (m4) will be updated outside the commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): align canonical mmd with §3 actor table + §2/§8.1 wording Cross-check after peer-batch surfaced three diagram-vs-doc deltas: 1. IdP: was :::ext (solid border = required). §3 actor table now says "required on full shelf" — minimal-capability solo install runs without IdP. Reclassed :::extOpt (dashed) to match. 2. Credential broker node label: "no master key full-capability" parsed poorly. §8.1 + zone 2 wording is "delegated STS on full shelf" (host-local on minimal, delegated STS on full). Relabeled to match. 3. Egress proxy node label carried "NFR-SEC-08 MCP allow-list" — the only NFR-ID embedded in a node label across the whole diagram. Replaced with role wording "MCP allow-list enforcement". NFR-IDs live in §02 + §-anchor tables in the prose, not in diagram nodes. No edge changes; classDef set unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 3 — paper-cut polish before merge Sweep after the prior batch landed: remove rudiments and meta-comments. §11 Regulator citation map: - Drop the 5 "Confirmed defects from a prior pass" prose bullets — the defects they listed were already fixed in the table itself in earlier passes (DORA Art. 12 → 19(1); NYDFS § 500.7 → § 500.5; CRI Profile column removed entirely). The bullets paraphrased the table state from three revisions ago. CLAUDE.md "If a paragraph paraphrases the data, delete it." Tracking slug `arch/regulator-citations-verify-pass` stays in the preamble; full defect list lives in git history. - Row "Audit pipeline → SIEM" cell: drop trailing "not DORA Art. 12" — without the prose bullets above it, the negation has no context; rewritten as "(retention floor cited from SEC 17a-4 / FCA SYSC 9, see §10)". - Rows "Credential broker" / "Compute plane" EU AI Act cells: drop defensive "(direct Art. 15 wording)" parentheticals — leftovers from earlier vale-lint battle over banned-vocab escapes. The Art. 15(4) wording stands on its own. - Drop "(subpoint TBD)" from "Art. 28 ICT third-party general" — TBD without a tracking slug is just noise. - Preamble: "before reproducing in an audit workpaper" → "before reuse" (overkill phrasing). §6 REGULATED-AUDIT row: - Retention-floor cell collapsed from long inline explainer to "7 y default / 10 y configurable (see §10)". The full citation (SEC 17a-4 / FCA SYSC 9 / EU AI Act Art. 19(1)) already lives in §10 NFR-COMP-01 anchor. §2 footer Compute plane: - "Performance targets … live in component specs, not as zone properties." → "live in component specs." Drop the meta-justification by negation. §8: - Drop the "diagram-label note" about the older "session JWT" / "RPC token" retired wording. That was about a rev that already shipped; reader of current doc does not need the history. §12 item 5: - Drop hedge "when one of the candidate paths reaches a decision point" — the per-boundary signer table lands with the ADR, no need to qualify when that happens. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): align Layer 3 canonical diagram with §7 / §8 Five gaps caught before draft→proposed transition, all in the canonical .mmd (doc body unchanged): 1. Add ORCH→BR edge with Generic internal token label (host-side RPC, session policy + scope, TTL ≤60 min). §8 token taxonomy lists three token classes; without this edge the third class was invisible and the broker looked free-standing despite §8 stating "Control plane ↔ broker ↔ audit, host-side." 2. Add two dashed revoke edges ORCH-.->VM and ORCH-.->PROXY with NFR-SEC-04 ≤5 min label. §7 fixed revoke-independent-of-IdP via Control plane denylist checked on every Compute-plane RPC and Egress request; this control channel was missing from the canon entirely. 3. Symmetrise PROXY→LLM and PROXY→OBJ labels — both now read "strict TLS validation / broker-issued credential / fail-closed". Previous asymmetry ("fail-closed" only on LLM, "broker-issued token" only on OBJ) misrepresented that both upstreams use broker-issued credentials. 4. Drop "per DoD ZTRA" claim from palette comment — DoD ZTRA v2.0 does not normatively define red/amber/green/blue subgraph palette. Honest label is "project convention". Avoids the same overclaim §11 flags for regulatory citations. 5. Remove `defaultRenderer: elk` from init. GitHub-native mermaid renderer and many CI/Mintlify pipelines silently fall back to dagre when the elk plugin is absent, producing inconsistent layouts across audiences. Dagre default is stable everywhere. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): disambiguate Layer 3 revoke mechanism on egress path The §7 sentence "denylist checked on every Compute-plane RPC and on every Egress trust-edge request via the Credential broker token" was grammatically ambiguous between two designs: (a) direct denylist push to the Egress trust-edge, (b) indirect revoke via Credential broker scoped-JWT non-reissue. The previous .mmd encoded (a) with a dashed ORCH→PROXY edge; the rest of the architecture only works under (b): - §8 sets broker scoped-JWT TTL ≤15 min — the short TTL exists for revoke-via-non-reissue, otherwise it is unmotivated cost. - §2 zone 4 keeps the Egress trust-edge intentionally dumb (single egress, MCP allow-list, no policy state); direct denylist would add control-plane coupling for no extra coverage. - PROXY → LLM / OBJ edges already carry "broker-issued credential"; revoke through credential non-reissue uses the same channel. Two changes, no semantic drift: 1. .mmd — remove the dashed ORCH→PROXY edge. Compute plane keeps its direct denylist edge because the Egress JWT TTL (≤4 h) makes indirect-revoke too slow for that path. 2. §7 prose — split the sentence: Compute plane is checked directly; Egress trust-edge revoke is "indirect via Credential broker scoped-JWT non-reissue, TTL ≤15 min caps propagation on that path." Anchor the TTL bound to NFR-SEC-29. Add an explicit note that the NFR-SEC-01 ≤30 s p99 SLA is the Compute-plane stop bound, not the upstream-credential revoke bound. Kill switch SLA is not added to the diagram label: trust-boundary diagrams show which-channel-carries-what, not timing budgets per channel. The two SLAs (NFR-SEC-04 ≤5 min revoke, NFR-SEC-01 ≤30 s kill switch) both live on the same ORCH→VM edge; loading both onto one arrow degrades readability. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 3 close-out — wire §12 + §11 to real issues, draft → proposed Pre-merge close-out for PR #147. Two changes, one status transition: 1. §12 open questions — replace 5 `arch/*` placeholder slugs with real GitHub issue URLs (#148 cross-tenant isolation grading, #149 metadata- only gate, #150 SIEM-bridge transport + backpressure, #151 transparency-log publishing path, #152 PKI tool pick + signer-identity table). Drop the "Real GitHub issue URLs replace the slugs before draft → proposed" footer line. 2. §11 — replace `arch/regulator-citations-verify-pass` with #153. Cell-by-cell source verification scheduled as a follow-up batch with other REVISIT slots; not gating Layer 3 draft → proposed. 3. Internal references — §4 footer ([#148]) and §8.1 PKI pointer ([#152]) updated to match. `grep arch/` returns zero matches. 4. Front-matter — status: draft → proposed. last-reviewed: 2026-05-25. Layer 3 is now the second Manifesto artifact at proposed (after §02 NFRs) and is the source of truth for trust zones, isolation tiers, egress posture, audit-pipeline pluggability, and the token taxonomy. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…163) * arch(next/v1): §02 add "Sandbox tier — workload-driven selection" sub-section (E1) Adds the workload-trust-profile axis as a first-class §02 concept ahead of the catalogue rows that reference it. Three named profiles: - trusted_operator (solo / dev) → runc - internal_workforce (vetted employees) → gVisor (v1 hardened default) - untrusted (unknown actors) → microVM (post-v1, #161; not deployable v1 GA) Cites Anthropic Self-Hosted Sandboxes (May 2026) as the published multi-provider precedent. Forward-links NFR-SEC-38/39 (enforceability, landing in the next commit) and AP-13 (anti-pattern, landing with the row edits). * arch(next/v1): §02 reframe tier rows; add NFR-SEC-38/39; AP-13; drop tech-name leaks Row edits (E2-E11) + new rows (N1/N2) + new anti-pattern (AP-13): - E2 NFR-PERF-03: cold-start target generalised to hardened tier; per-tier baselines in PERF-07/08/09. - E3 NFR-PERF-09: explicitly gated on microVM tier shipping (#161); not enforced in v1. - E4 NFR-SEC-02: dropped "microVM-default" framing; gVisor v1 hardened default; microVM hardware-virt post-v1; tier-appropriate escape resistance with seccomp BPF + Landlock + cap-drop in every tier. - E5 NFR-SEC-29: broker binding substrate matches tier (loopback/UDS on runc and gVisor; vsock CID + JWT scope on microVM post-v1). - E6 NFR-SEC-35: KVM precondition limited to microVM tier; Helm pre-install probe ≤2 s with clear error on KVM-absent host; CI test on KVM-absent runner. - E7 NFR-FLEX-02: runtime ladder reframed (runc + gVisor v1; microVM post-v1, Firecracker named as example, Kata as one packaging option). - E8 NFR-FLEX-06: same egress invariant qualified by microVM tier ship. - E9 NFR-FLEX-09: dropped Kata+RKE2 / bare-VM Firecracker tech names. - E10 AP-13 (new): picking sandbox tier by data classification is forbidden; trust profile picks tier, data class governs custody / retention / residency. Backed by vale lint rule landing in next commit. - E11: pruned remaining "minimal-capability shelf" / "full-capability shelf" occurrences inside §02 (NFR-SEC-03 only). - E12: Open Question 5 parenthetical clarifies microVM is post-v1. New rows: - NFR-SEC-38: workload-trust profile declaration is a deployment-time invariant; mismatch is admission-time hard error; untrusted profile is NOT deployable in v1 GA (admission rejects with pointer to #161). - NFR-SEC-39: tier-downgrade alarm via audit event `config.trust_profile.downgraded`; SIEM-bridge HIGH; SOAR webhook ≤30s. Both new rows ship as commitments; implementation lands when control-plane code exists. * arch(next/v1): vale rule AP-13 — block "(NPI|RESTRICTED|CONFIDENTIAL) → microVM" phrasing Enforces §02 anti-pattern AP-13 at the prose level: data classification does not pick the sandbox substrate. Trust profile picks the tier; data class governs custody / retention / residency. Standalone file rather than appended to banned-phrases.yml because vale existence rules share message/level per-file; AP-13 needs its own message pointing the author to the §02 anchor. * arch(next/v1): Layer 3 shelf→tier rename; multi-tenant invariant in trust-profile terms (L1-L14) Aligns Layer 3 with the §02 workload-trust-driven tier model. - L1: §2 Compute plane row reframed in tier terms (runc / gVisor / microVM) with forward link to the new §02 "Sandbox tier" sub-section. - L3: §4 multi-tenant invariant rewritten in trust-profile terms — bare runc multi-tenant forbidden; gVisor as v1 default; microVM post-v1. - L4: T0 tier-table label "single-tenant minimal-capability" → "solo / dev / single-operator". - L5, L11, L13, L14: shelf → tier renames in §3, §6, §8, §9, §10, §12 (key custody, audit sink, signer narrative, Open question 4). - L6, L7, L8: §3 actor-table "Optional?" cells use tier names instead of shelf labels. - L9: §6 data-class-gating sentence reframed — trust profile picks the tier; data class still picks BYOK + customer-managed audit sink. AP-13 is the load-bearing forbidder of data-class-driven substrate selection. - L10: §8 table column headers renamed (Solo / dev tier vs Hardened tier and above). - L12: §8.1 signer paragraph renamed to tier vocabulary. last-reviewed bumped to 2026-05-27. * arch(next/v1): drop competitor-listing slop from §02 sandbox-tier sub-section The "Anthropic Self-Hosted Sandboxes — Cloudflare microVM, Daytona container, Modal gVisor, Vercel container" line was AI-slop preamble citing a competitor product launch as if it justified our design. §02 is a normative NFR catalogue, not a press-release. Evidence stays in the RESEARCH artifact. * arch(next/v1): slop sweep on §02 sub-section + tier NFR rows + Layer 3 invariant Removes self-praise, forward-references, and duplication introduced by the prior commits in this PR: - §02 sub-section gVisor row drops "Production precedent at AI scale: OpenAI, Modal, Anthropic, Google App Engine" — competitor listing in a normative NFR catalogue is marketing, not requirement. - §02 sub-section drops "Honest v1 deployability" header + the re-articulation paragraph (the table already says what the trust profile is and what tier it maps to). - §02 sub-section drops forward references to NFR-SEC-38/39 + AP-13 — reader sees those below; preamble pointing forward is slop. - NFR-SEC-02 drops "Runtime brand pick within a tier is a component-spec decision" — already covered by NFR-FLEX-02. - NFR-SEC-38 / NFR-SEC-39 row cells compressed; same load-bearing content. - AP-13 drops "Enforced at the prose level by a vale rule on ..." — anti-pattern is normative, the implementation note belongs in the vale rule itself. - Layer 3 §2 Compute plane row drops "(see ...)" preamble before the §02 link. - Layer 3 §4 multi-tenant invariant drops v1/post-v1 narrative — that already lives in §02 + §2 zone table. * arch(next/v1): fix CRIT F-01 self-contradiction + WARN F-02 matrix count + INFO F-05 back-link Code-review findings from REVIEW-PR-163-code.md: - F-01 (CRIT): Layer 3 §6 line 110 was internally contradictory — it asserted "CONFIDENTIAL+ workloads require the hardened tier (gVisor)..." (the data-class→tier mapping AP-13 forbids) and immediately added "Tier selection is workload-trust-driven, not data-class-driven (forbidden by AP-13)". Rewritten so data class drives custody / audit sink / residency obligations and trust profile drives the tier. - F-02 (WARN): NFR-SEC-38 admission-matrix count "6 valid v1 + 3 rejected v1" was ambiguous. Now spells out: 6 cells valid by pairing rules (3 require post-v1 microVM); 3 cells rejected by pairing; v1 GA deployable = 3; v1 GA rejected = 6 (3 pairing + 3 microVM-not-shipped). - F-05 (INFO): NFR-SEC-38 had no back-link to AP-13; added one clause. * arch(next/v1): plan-check WARN fixes — restore #161 link + AP-13 concrete example Plan-check findings from PLAN-CHECK-PR-163.md: - PC-1 (WARN): Layer 3 §4 multi-tenant invariant lost the direct #161 link in the slop sweep; reader now needs §02→sub-section→#161 (2 hops). Restored one inline [#161]. - PC-2 (WARN): AP-13 example was dropped in the slop sweep; without it the anti-pattern is abstract. Added the minimal concrete form ("NPI → microVM" / "PUBLIC → runc") that names the forbidden phrasing without re-introducing the long description.
…lit (#157) Absorb two egress contract primitives from sandboxd research dump (sandboxd/sandbox-egress-architecture.md) that are not yet named in §7: 1. Structured deny header (`x-deny-reason`) on blocked egress so audit and SOAR can classify outcomes without free-text log parsing. 2. Two-tier block discipline — SNI pre-filter for unallowed destinations (cheaper, lower forensic value) vs L7 inspection for allowed destinations (richer, more expensive). Both are contract-level claims about Egress trust-edge behavior, not implementation details; Envoy/Cilium/ext_proc wiring remains a component-spec concern when the egress-proxy spec opens. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…strate + operator-auth canon (#164) Cross-document consistency sweep of the canonical architecture set. T-01 — shelf/tier terminology fork. The minimal↔full config axis was named "Capability shelf" (glossary, C4, diagrams) but "solo / dev tier" / "hardened tier and above" (02-trust-boundaries §3/§8/§9/§10), with no doc bridging the two and "hardened tier" defined nowhere. Rename the key-custody-axis usages to "minimal shelf" / "full shelf" (glossary is the authority); reserve "tier" for the runtime ladder and T0–T3. Add a `## Sandbox tier` glossary entry for the runc/gVisor/microVM axis (previously defined only in §02) and cross-link all three axes as orthogonal. The §8 table header had also conflated the shelf with the runtime ("Hardened tier and above (v1 gVisor; microVM post-v1)") — split. T-02 — full-shelf substrate contradiction. glossary said "microVM on the full-capability shelf" and the trust-zone diagram drew "microVM full", but the NFRs and §2 say microVM is post-v1 and gVisor is the v1 hardened default. Fix glossary + .mmd to "gVisor full (microVM post-v1)". T-03 — operator-auth on the minimal shelf. PR #155 introduced a "host-rooted local credential" operator path in the C4 doc to close the no-IdP-on-minimal gap, but left it contradicting the canonical operator row, NFR-SEC-09, and NFR-COMP-29, and the term was undefined. Land the two-clause operator-auth in the canon: trust-boundaries §3 actor row, NFR-SEC-09, NFR-COMP-29, and a glossary definition under Capability shelf. The C4 row is now backed. Minor: NFR-REL-02 "Data-plane" → "Compute-plane" (single divergent label); README stale "empty" status cells for manifesto/ + components/ → "partial". Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(architecture): manifesto Layer 4 — C4 Context (draft) Layer 4 of the next/v1 manifesto stack, following §01 audience-and-buyer (PR #143), §02 NFRs (PR #146), and §02 trust-boundaries (PR #147). One canonical Mermaid + one ≤80-line doc, per the plan's "intentionally minimal" framing. Scope: - 03-c4-context.md (54 lines) — purpose / inside-the-box / diagram reference / external actor table with required-vs-optional column / scope-out / open questions. - diagrams/c4-context.mmd (44 lines) — flowchart LR + project palette (red/amber/green/blue), same engine as 02-trust-boundaries.mmd. Convention: solid = required, dashed = optional configuration. Five research agents (competitor format sweep, legacy mine, OCU value articulation, OCU-vs-Wide-Moat boundary, diagram-format advisor) synthesised in docs/future-architecture/research/SUMMARY-layer4.md. Key agreed decisions: - OCU is the central box; Wide-Moat is mentioned once as the opinionated bundle that ships OCU + peers (n8n, Open WebUI) as one curated stack but is not required for OCU to be useful. - Siblings are an open class: any MCP-speaking peer is a first-class integration; REST is a fallback. n8n and Open WebUI are examples in the bundle, not the definition of "sibling." - The §02 §3 actor table stays the single source of truth — Layer 4 cross-references it instead of duplicating, then adds an "optionality" column the actor table did not need at Layer 3. - LLM upstream is NOT a separate actor on Layer 4 — it is one of the MCP-speaking peers (model-neutral by construction). Customer object store is not an actor either — §02 line 45 already classifies it as an outbound endpoint behind the egress policy, not a contract-bearing actor. No backport to §02 §3 needed. - Preamble framing (Why OCU): practitioner-first value-creation ("build automations once, delegate, scale across a team without leaving the safety boundary"), with model-neutrality via MCP as the integration property. Not TPRM-first, not moat-intersection. Diagram engine: plain Mermaid flowchart with the project palette verbatim from 02-trust-boundaries.mmd. Rejected alternatives: Mermaid C4Context (upstream-experimental, palette divergence), C4-PlantUML (no GitHub-native render). Open question §6 #1 (Wide-Moat bundling status for n8n + Open WebUI on next/v1) tracked at #154. The integration shape is locked here; the packaging decision is not Layer 4's job. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): apply Layer 4 review batch (13 fixes from 4 reviewers) Four reviewers (gsd-code-reviewer, gsd-plan-checker, cross-architectural coherence, competitor comparison) converged on one load-bearing defect plus 12 follow-ups. Verdict matrix: 2 Error / 4 Warning / 7 Info. Errors (block merge): 1. LLM upstream as inbound MCP peer — three reviewers caught it. §02 trust-boundaries:45 explicitly classifies LLM upstream as an outbound endpoint behind the egress policy ("not actors against our contracts"), and 02-trust-boundaries.mmd:13 draws it as a separate outbound node. Listing it inside the inbound PEER node label put two opposing semantics on the same name. Fix: drop "LLM upstream" from the PEER node label and from the §4 actor-row example list. The §41 paragraph remains the canonical mention. 2. AI-guardrail anchor pointed at §02 §6 (Data classification taxonomy); the ownership statement lives in §02 §2 zone 4 / §7. Repointed to §2 zone 4 so the link lands where the claim actually lives. Warnings: 3. SIEM edge was solid in c4-context.mmd:35, but SIEM is :::extOpt (dashed-border optional). Layer 4's own header convention says "solid border = required; dashed border = optional configuration". The Layer 3 diagram already draws it dashed. Fixed. 4. "Layer 6" forward references in three places (doc §2 / §3 + diagram BOX node). Layer 6 does not exist as an artifact. Reworded to "Internal decomposition is out of scope at this layer" + dropped the pointer line from the diagram BOX node. 5. BOX node carried three lines of internal description that duplicated §1 prose. Collapsed to a single role-line "Open Computer Use / in-perimeter agent-execution platform". 6. §1 first sentence opened with value-prop voice ("users build automations once, delegate them to agents..."). Replaced with a scope declaration; the practitioner framing remains in §01 audience-and-buyer where it belongs. Info / polish: 7. Palette claim in §3 named all four colors (red / amber / green / blue) but the diagram only uses red + green. Weakened claim to "red-untrusted / green-trusted convention; amber and blue from the trust-boundary diagram do not apply at the Context level". 8. Added solo-install callout in §3: "the solid / dashed split makes the one-click solo-install path visible at a glance". 9. SIEM Role cell rephrased to "OCSF v1.x event bridge consumed by the customer's SIEM" for voice consistency with other customer-* rows. 10. Dropped repetitive `02-trust-boundaries.md §3` link from each actor row (the preamble already pins the actor table to §02 §3). Renamed column to "NFR anchor"; em-dash where no NFR anchor exists. 11. Operator edge in diagram now labelled `PAM-JIT SAML attr / NFR-COMP-29` matching 02-trust-boundaries.mmd:47. 12. PEER edge label simplified to `MCP authz spec / audience-validated` matching the Layer 3 wording. 13. Added compliance pointer after the actor table: "Regulator citations and measurable targets for each row land in manifesto/02-nfrs.md". 14. Added footnote tracing master-plan `agent user` → folded behind `MCP-speaking peer` (humans drive OCU only through an MCP-speaking peer; direct human-to-OCU UI is a v1 non-goal). Length 58 lines (≤80 budget). Banned vocab grep clean. ai-slop-detector OK. No new ASCII diagrams. Glossary additions (MCP-speaking peer, REST fallback, Wide-Moat opinionated bundle) and a few cross-doc reconciliations (NFR-FLEX-14 vs REST fallback wording, Layer 3 SOAR edge dashed-vs-solid) deliberately deferred to a follow-up PR — not Layer 4 scope. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): layer 4 v2-review batch (W-01 + 3 polish) W-01 — IdP optionality row: rewrite to two-clause form mirroring SIEM ("optional on minimal shelf (local auth fallback) — required on full-capability shelf"); resolves doc/diagram mismatch where doc said "required on full shelf" but .mmd drew IDP dashed. I-01 — Trim .mmd palette comment: list only colors actually used at Context level (red, green); amber/blue carve-out already explained in §3 prose. I-03 — Bind "regulated-enterprise" term once in §1 (CLAUDE.md default audience term) so a cold reader knows what flavor of customer "customer's existing IdP" means. I-05 — Drop "Master-plan agent user" phrasing (term not defined anywhere in architecture tree); rewrite as plain "humans drive OCU only through an MCP-speaking peer" sentence. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(architecture): layer 4 review batch — reconcile operator-auth + dashed-border convention Follow-up to W-01, which fixed the IdP row's optionality but left two internal contradictions the prior fix surfaced. R-01 — Operator-auth path on the minimal shelf. The Operator row was required everywhere via a "SAML-asserted attribute", but W-01 made the IdP optional on the minimal shelf — leaving the required operator with no SAML issuer, and the implied "local auth fallback" forbidden by NFR-FLEX-03 (no in-house user table). Give the Operator row the two-clause form: host-rooted local credential on the minimal shelf, short-lived SAML-asserted attribute on the full shelf. Drop the undefined "local auth fallback" phrase from the IdP row; the operator-credential story now lives on the row that owns it. R-02 — Dashed-border convention vs IdP. The §3 convention read "every dashed-border actor is opt-in for the full-capability shelf", but IdP is dashed yet required on the full shelf. Rebind the convention to the real axis: solid = present on the minimal shelf; dashed = not on the minimal shelf by default. Per-actor optionality stays in the §4 table. IdP and SOAR edges switched to dashed to match their dashed nodes; OPER edge label de-SAML'd to match the dual-credential row. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(architecture): Layer 5 — bounded contexts (draft) DDD strategic decomposition. Two core subdomains (Agent Execution & Sandbox Lifecycle; Compliance Evidence & Audit Lineage), two supporting (Tenancy & Isolation; Operator Access), four generic (Identity, Secrets, Policy, Model access). Distinguishes bounded context from trust zone; maps the five Layer 3 zones onto the two core contexts. Context map names the Published Language (OCSF), Conformist (MCP, ModelProvider), and ACL (generic integrations) relationships. Feeds Layer 6 C4 Container. Open questions tracked at #165, #166. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 5 review batch — fix model-edge canon contradiction Address gsd-code-reviewer findings on PR #167: - CR-01 + WR-01: §3 no longer claims all four generic contexts are Layer 3 §3 actors. Only IdP and KMS are §3 actors; Model access is an outbound endpoint behind the egress policy ("not an actor against our contracts"); Policy evaluation is not drawn in Layer 3, introduced here. - §4 context map reroutes the Model edge through the Egress trust-edge, matching the Layer 3 invariant that upstream traffic originates in the Compute plane and traverses the egress edge — never a direct context edge. - WR-02: expand "ACL" to "Anti-corruption layer" in diagram labels; add Bounded context, Anti-corruption layer, Published Language to glossary. - WR-03: align "OCSF events" → "OCSF event" across both diagrams; note §2 shows only the core-to-core edge. - WR-04: fix CLAUDE.md anchor to #v1-non-goals-locked-early. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 5 GSD-review batch — DDD rigor + goal-backward gaps Address gsd-plan-checker (3 blockers) and gsd-advisor (1 blocker, 4 warnings): - ModelProvider relabelled Conformist → Anti-corruption layer (self-authored adapter exists to absorb provider swaps — the defining ACL property; was internally inconsistent with the identical IdP/Secrets/Policy treatment). - Dropped the Egress trust-edge node from the §4 context map (a trust zone is not a context-map node); Model edge now direct AEX→MOD ACL, egress traversal stated in prose with the Layer 3 link. - OCSF core↔core boundary relabelled Open Host Service + Published Language (fan-in from four zones, fan-out to multiple SIEMs); added the no-shared-identifier invariant so PL does not degrade into a shared kernel. - Operator Access and Tenancy: value axes rewritten to name a real owned model (PAM-JIT contract; T0–T3 selection logic) instead of "cross-cutting property", resolving the build-but-undrawn incoherence. Operator drawn in §4 as Customer/Supplier; §5 questions reframed from existence to refinement. - Policy ACL consumer named: Egress trust-edge (MCP allow-list) + Credential broker (token scoping); SIEM/SOAR/transparency-log drawn as downstream consumers; proxy/ICAP noted as egress configs, not new contexts. - Compliance Evidence core-ness re-grounded on lineage/replay domain depth, not OCSF (generic) or TPRM (go-to-market). - §3 adds the linguistic-test defense for the four-zones-into-one merge; broker and workload-trust grading raised as Open Questions (#168, #169). - glossary: add Open Host Service, Customer/Supplier. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): reword shared-kernel invariant to clear ai-slop detector "the only thing that crosses" tripped the boastful-superlative pattern; restate as "share the OCSF event and nothing else" — same invariant, no superlative framing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 5 bounded contexts — draft → proposed User sign-off after full GSD review chain (code-review + plan-check + DDD advisor). CI green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: add slop-pattern rules + doc-slop-reviewer agent; apply to Layer 5 Structural AI-slop kept slipping past the word-level linter (negative-framing headings, redundant purpose lines, define-by-negation, repeated nouns). Codify the structural patterns and add a reusable reviewer. - CLAUDE.md "Documentation discipline" gains a "Slop patterns" subsection: headings name content (never "Why X is not Y"), purpose line states purpose once, no throat-clearing tails, no hedge-restatement, no rule-of-three padding, no define-by-negation, no forced symmetry. With before/after examples. - .claude/agents/doc-slop-reviewer.md: read-only reviewer for the structural tells regex cannot catch. Spawn on every new/edited doc before merge. - Layer 5 04-bounded-contexts.md, first doc through the new gate: - §1 heading "Why this layer is not the trust-zone layer" → "Context layer vs trust zones". - purpose line: drop the audience-restating second clause and the "before any component exists" tail. - §2 Tenancy cell: "selection model; a model with its own logic, not a mere deployment flag" → "selection logic" (dropped the repeated "model" that also collided with the LLM "Model access" context, and the negation). - §2 Operator cell: "specific to us, not a differentiator" → positive form. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ose tells (#170) * docs(architecture): slop sweep — clear negative-framing headings + prose tells Apply the new CLAUDE.md "Slop patterns" rules across the merged canon (found by the doc-slop-reviewer sweep; 0 blockers, structural warnings): - Negative-framing / question headings → noun phrases: README "What's here"/"What's NOT here yet" → "Contents"/"Not yet present"; PROCESS "What this file is not" → "Scope boundary" (negation list folded into one sentence); adr/README "When to write an ADR (vs. inline note)" → "ADR threshold". - 01-audience: drop the "security, compliance, and operational scale we know" adjective-triple + "we know" hedge; keep the tier-1-ceiling rationale. - 02-nfrs: drop the defensive tail "not contradictions". - adr/0001: drop the "replaced from scratch" restatement (already stated in Context); fold the rewrite-timing into the rejection clause. - adr/0000-template: "Neutral but worth noting:" → "Neutral:" (the template was seeding the banned hedge). - 03-c4-context: drop the second "visible at a glance" restatement. "## Why now" in 01-audience kept — recognized positioning-section label, body is dated fact; a noun-phrase rewrite reads worse. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): rename README heading to avoid TOC-detector collision "## Contents" matched the ai-slop-detector TOC regex (treats a literal "Contents" heading as a table of contents in a short doc). The section is a file inventory, not a TOC → "## Files in this directory". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#172) * docs(architecture): scope OCU correctly — loop and model are external, not ours The canon conflated OCU (the component we design: MCP server + sandbox executor) with the Wide-Moat bundle (Open WebUI + n8n + LiteLLM + OCU + …). The agent loop and model access live in the bundle / calling client, not in OCU. This produced a direct contradiction: CLAUDE.md called OCU a "multi-provider proxy" while glossary/Layer 3 say the Control plane "is not a model proxy". Bring every OCU doc to the correct state: - CLAUDE.md v1-non-goals: OCU does not host/select/proxy an LLM and does not run the loop; an LLM is one allow-listed egress endpoint; the loop and model choice live in the calling client. Drops "ModelProvider" + "multi-provider proxy" (the contradiction). - 04-bounded-contexts: delete the "Model access" generic context (node, table row, ACL edge, ModelProvider paragraph) — OCU has no model-integration slice; an LLM is egress, not a context. Reword "agent loop" → "agent-issued tool-calls/code" where it implied OCU drives the loop. Drop bare-"model" DDD-sense (use domain/language). - 03-c4-context: OCU is the tool-execution boundary; the calling client runs the loop and owns the model; hosted LLM/model-selection/loop are scope-out. - 01-audience-and-buyer: keep the bundle moat thesis but attribute "loop included" + "model-neutrality" to sibling bundle components; OCU contributes the sandbox + audit lineage. Drop "ModelProvider" from OCU's contract list. - 02-nfrs: re-cut NFR-FLEX-01 (provider-switch → endpoints-are-egress-config), NFR-FLEX-14 (MCP server to the client, not "to upstream LLM"), NFR-COST-02 (LLM-overhead → egress-edge overhead). - primitives-backlog: drop the ModelProvider primitive (it was a loop/ generation concern, not OCU's). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: ignore COMPETITOR-/PLAN-/RESEARCH- research-buffer files Extends the existing docs/future-architecture/research/ ignore patterns to the three new buffer files, keeping the working buffer out of git per the котлован rule (it stays a local scratch area until Layer 13 migration). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): apply GSD review batch to OCU scope-fix Address scope-consistency + code reviewers on PR #172: - c4-context.mmd: BOX label "in-perimeter agent-execution platform" → "tool-execution platform" — it lagged the same doc's "tool-execution" prose and the loop-is-external correction (the one artifact the prior commit missed). - 02-nfrs NFR-COMP-25: drop the dangling "(NFR-FLEX-01)" ZDR pointer — the rewritten NFR-FLEX-01 no longer carries the ZDR-posture clause; state it inline instead. - primitives-backlog: log the ModelProvider removal under a new "Removed as out-of-scope (2026-05-30)" section so the audit trail records why the entry vanished (scope-correction, not promotion). - last-reviewed bumped to 2026-05-30 on the five edited docs that lagged (03-c4-context, PROCESS, primitives-backlog, 01-audience, 02-nfrs). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): rephrase 03-c4 §1 opening off "OCU is…" scope-restatement CodeRabbit (Minor): the Purpose-section opener "Open Computer Use (OCU) is …" restates project scope, which CLAUDE.md bans. Lead with purpose+audience (names the external boundaries, for architects/security engineers), then the scope description — no "X is a…" opening, no "Purpose:" throat-clearing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): drop redundant "not in OCU" restatements The loop-is-external point was stated three times; twice is noise. Keep the load-bearing statements (the §4 prose in Layer 5, the "runs the loop" label on the MCP-caller node, the Layer 4 scope-out) and cut the duplicate negations: - 03-c4 §2: drop "not the LLM loop" tail (the guest agent is already defined as the in-sandbox executor). - 04-bc §3: drop "the agent loop and model choice live in the calling client, not in OCU" tail ("not a context we model" already carries it; §4 states the loop location once). - 04-bc §4: trim the trailing "not in OCU" (the sentence already names the MCP caller as where the loop runs). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…le (#177) * docs(architecture): reconcile credential model — strict Anthropic style The canon carried an internally-contradictory credential model: most rows said "broker issues a scoped-JWT into the guest, guest presents it" while NFR-SEC-30 already said "broker terminates outbound TLS". The guest-token framing was never the intent. Converge everything to the strict model confirmed against Anthropic's process_api / egress design: - The guest holds NO upstream credential. It sends an unauthenticated request; the Egress trust-edge attaches the upstream authorization on the outbound leg, fetched from host-side Credential custody. - "Credential broker" → "Credential custody" (host-side store, rotation, delegated STS). Injection folds into the Egress trust-edge. Custody has no guest-facing interface. - Token taxonomy: the guest holds only the Session JWT (session identity, ≤4h, CP→guest). The ≤15min lease is held by the edge (custody credential lease), never the guest. "Egress JWT" → "Session JWT" everywhere. - Injection requires the edge to originate the upstream connection (L7 / MITM mode); transparent pass-through cannot inject. Cert-pinning / client-mTLS / DPoP upstreams tracked at #176. Touches: NFR-SEC-23/25/27/29/30/31 + token taxonomy + SEC-10/11 rename; Layer 3 §2/§3/§5 diagram/§7 revoke/§8/§11; Layer 4 §2/§4; Layer 5 zone names + context-map vocab + open question; glossary entries. The five containers do not change — custody and edge stay two boxes (custody ≠ enforcement). Layer 6 (PR #173) reconciled separately on its branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): soften §8 token-table cross-claim (RC-01) Scope-consistency review (6/6 PASS, 2 nits): the §8 table claimed to match the NFR token table "verbatim", but the two now differ in column header (Consumer vs Holder) after the rewrite. Claim the three classes / scopes / TTLs match, not the literal layout. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): drop negative-restatement (doc-slop-reviewer) Three spots stated the "guest holds no upstream credential" invariant two or three times in one passage. Keep the single load-bearing negative, drop the restatements: custody glossary ("custody issues no token to the guest"), egress-edge fail-closed ("never bypassed"), token-table ("not anything the guest holds —"). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): clarify revoke timeline ≤1/≤5/≤15 (CodeRabbit) The rewrite left two revoke numbers reading as a conflict (≤5 min propagation vs ≤15 min lease survival). State the three bounds smallest-first: custody revokes the lease ≤1 min (NFR-SEC-29); denylist propagates ≤5 min (NFR-SEC-04); a non-revoked lease self-expires at its ≤15 min TTL. An explicit revoke cuts upstream access within ≤5 min — the 15-min TTL is only the ceiling for a session never revoked. Resolves both CodeRabbit nits. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): clarify token rotation, injection mode, revoke SLAs - NFR-SEC-10: the ≤4h is a per-token TTL, not a session cap. While a session is active the Control plane rotates the token before expiry (a stolen token dies in ≤4h); session length is not bounded by the TTL. A long human session (multi-hour investigation) is not interrupted. Drop the undefined "session-max"; a hard session cap, if any, is a policy tracked at #178. - NFR-SEC-29 (CodeRabbit): ≤1 min revocation is custody-internal — a tighter subset of the ≤5 min platform-wide target (NFR-SEC-04). State the relation. - Layer 3 zone 4 (CodeRabbit): qualify that upstream-auth injection is MITM-inspecting mode only; transparent pass-through cannot inject (§7). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): anchor session limits to regulators; demote token TTL The ≤4h session-JWT TTL was an unsourced number that conflated three distinct limits. Research (PCI-DSS 4.0, NIST SP 800-63B-4) separates them; we align to AAL3 (privileged automation in a bank perimeter): - NFR-SEC-10: session JWT TTL ≤4h → ≤60min, reframed as an anti-replay window (engineering bound, no regulatory citation), rotated while the session runs. - NFR-SEC-40 (new): idle / inactivity timeout ≤15min — PCI-DSS 4.0 Req 8.2.8 + NIST 800-63B-4 §2.3.3 (AAL3). This is the number a bank auditor looks for. - NFR-SEC-41 (new): absolute session lifetime ≤12h — NIST 800-63B-4 §2.3.3 (AAL3 SHALL). Default off on the minimal shelf, customer-tunable on the full shelf. Closes #178 with a sourced number instead of "if any". Token TTL ≠ idle ≠ absolute: the token rotates under both session limits; session length is bounded by SEC-40/41, not by the token TTL. Updated token taxonomy table, Layer 3 §5/§8 + diagram, glossary Session JWT entry. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): cut IdP-independence restatement (doc-slop-reviewer) §7 revoke paragraph stated IdP-independence three times. Keep the opening claim and the closing rationale ("that is why ≤5 min revoke holds even during an IdP outage"); drop the bare middle restatement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): generalize MCP allow-list → egress allow-list "MCP allow-list" mixed abstraction levels — it named a private case (one destination type) where the general control (egress allow-list, deny-by- default) was never stated. An MCP server, LLM API, object store, or internal API is one allow-listed destination, not its own enforcement mechanism. - NFR-SEC-08: "MCP allow-list enforcement" → "Egress allow-list" (customer declares reachable destinations; deny-by-default; destination type is not a separate control). - Layer 3 zone 4 + .mmd: same generalization. How a corporate environment authors these egress rules (rule format / standard) is deferred to the egress-proxy component spec + a separate research pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): finish MCP allow-list → egress allow-list (2 stragglers) bounded-contexts §3 and the §02 long-form-scenario list still named the private case. Generalize both. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): fix two more abstraction-substitution defects + skill supply-chain NFR Abstraction-substitution sweep (the MCP-allow-list defect class) found two more embarrassing instances; both fixed: - NFR-SEC-17 named "Egress posture (sandbox trust tier)" — but it is the enforcement mechanism of the NFR-SEC-08 allow-list, and "Egress posture" collides with the glossary/NFR-FLEX-15 term (transparent vs MITM). Renamed to "Egress allow-list enforcement mechanism" + cross-link SEC-08↔SEC-17. - NFR-SEC-05 named "MITM-friendly egress" — but it anchors the whole Egress zone and MITM is the opt-in mode, not the default. Renamed "Single forward-proxy egress (customer-CA injectable; MITM-inspecting opt-in)". - primitives-backlog: same two renames. Also: NFR-SEC-42 (new, v2/tbd) — skill-registry supply chain (author-uploaded, server-signed, provenance-tracked, signature-verified at attach), pairs with SkillProvider NFR-SEC-24; tracks #179. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): drop last 'MCP allow-list' straggler in PROCESS.md example Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…/operator split (#189) * docs(architecture): Layer 3 — Storage broker zone + Control-plane MCP/operator split Verified against the rclone-filestore binary (Go, anthropic.filestore.v1alpha Connect-RPC): the guest's mutable user-data mount is served by a host-side storage broker that holds the storage-backend credential; the guest holds only a session-scoped handle (filesystem_id). That credential class is distinct from the LLM-egress credential injected at the Egress trust-edge from Credential custody, and the inbound mount path is distinct from the outbound egress path. - Storage broker drawn as a 6th trust zone (was 5): host-side, guest-facing mount interface, governs the inbound data path; distinct from Credential custody (no guest interface, outbound-only). NFR-SEC-25/23 reconciled — the storage-backend credential is held by the Storage broker, not custody. - Control plane stated as one zone with two interfaces — agent-facing MCP and operator/lifecycle; the kill-switch is reachable only on the operator interface, never over MCP. The two-container split is a Layer 6 concern. - New §7.1 separates the two guest-data paths (mount-in vs egress-out). - Token taxonomy gains the storage-mount handle (four classes); synced between 02-trust-boundaries §8 and manifesto/02-nfrs §Token TTL taxonomy. - Zone count synced across 02-trust-boundaries, 03-c4-context, 04-bounded- contexts, glossary, 02-nfrs (six zones; five collapse into Agent Execution). Skill-mount classes (public read-only / user mutable) are deferred to the SkillProvider ADR (post-v1, NFR-SEC-24/42), not drawn here. Image signing / digest-pin remains a forward NFR (#180), not asserted as observed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Storage broker — file-RPC + broker-signs + allow-list-only egress Advisor + binary/competitor research resolved how the broker's backend leg reaches the object store without the SigV4-vs-proxy conflict the user flagged: - Guest speaks a file-operation interface to the broker, NOT the object-store protocol. The broker is the object-store client and signs its own backend requests, so no middlebox ever rewrites a request signature. (Anthropic's rclone-filestore is a custom anthropic.filestore.v1alpha Connect-RPC fork, not a stock S3 mount; Daytona runs the same runner-is-S3-client shape.) - The broker's backend leg traverses the Egress trust-edge in allow-list-only mode (no TLS termination), so the signature stays intact while all outbound still passes the single audited egress (NFR-SEC-16). A direct broker→backend dial bypassing the edge is forbidden. - Content inspection / DLP runs at the broker on plaintext, before signing — not at the edge, which sees only ciphertext on this leg. - Backend credential is STS-scoped per session to the prefix the filesystem_id names, held by the broker, never the guest. Fixed the .mmd PROXY→OBJ edge (was mislabeled with the LLM custody-injection semantics; the object-store leg is the broker's, broker-signed, allow-list-only). Reconciled docs/future-architecture/architecture/06-storage.md: removed the STS-token-in-guest / stock-rclone-as-target drift; stock rclone→S3 is now labeled interim-PoC-only, broker model is the target. The allow-list-only egress routing of the broker's backend leg is OUR design choice, not observed Anthropic behavior (their broker→cloud controls were not in the sources). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Move research notes that belong in the local working buffer out of the tracked tree (gitignore + git rm); the canonical architecture under docs/architecture/ is the deliverable. Competitor, market, and audience research stays tracked. The research/ directory is not ignored wholesale — only the local-buffer files, by glob. - Tidy the future-architecture design docs: drop stale source-citations and third-party internal identifiers, link only to surviving files, and state each design fact directly. Technical content is unchanged. - Add two doc-discipline rules to CLAUDE.md: state the result rather than the process that produced it, and let each fact live in one place. - Untrack two working-buffer files that predate the local-only ignore rules. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-43 (#190) The control / exec channel stays off any network the guest can reach: the host opens it and the guest listens, over vsock (microVM) or a host-side unix socket (gVisor / runc); a TCP listener rejects loopback and own-interface sources so guest code cannot dial the supervisor through its own stack. Every host-facing call carries an identity the host derives itself — hypervisor context id, kernel peer credentials of the per-session sandbox principal, or a per-session socket path the guest cannot enumerate — never an identity the guest supplies. A guest-out reverse dial to a host-side bridge is a fallback only where a host-reachable guest listener is unavailable; that bridge holds no credential, runs unprivileged and syscall-confined, and authenticates before any privileged action. Lands as the §4 invariant in 02-trust-boundaries and NFR-SEC-43. Honest residual: shared-kernel tiers share the host kernel, so escape surface and DoS containment are weaker than the microVM's hypervisor boundary — microVM stays the isolation ceiling. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#196) * docs(architecture): Layer 7 — STRIDE threat model on the container DFD STRIDE-per-element over the Layer 6 DFD (7 containers, 2 data stores, 4 external actors, 11 boundary flows). The in-sandbox process is the primary adversary, so the high-value rows weight the sandbox's outbound and host-facing edges. Each threat resolves to a canon NFR or routes to a tracked open hole; severity is qualitative Likelihood x Impact. The twenty OPEN/residual rows map to existing security issues (#149, #176, #181-188); the snapshot-at-rest and guest-self-audit gaps surface as OPEN, not silently mitigated. The machine-checkable Threagile layer is deferred to #194; a LINDDUN privacy pass to #195. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 7 review fixes — CI slop, cross-layer NFR, open-question routing - Rephrase two "is the only" superlatives the slop detector flagged (P6-T1, P6-E1). - P5-D1: credit NFR-SEC-14 for the per-container PID ceiling it already mandates; narrow the #188 residual to disk quota + deterministic OOM scoping. - Route four edge-integrity open questions to issues: edge binary/config attestation, no-credential-in-response, MITM-plaintext zeroization (#197), and transparent-mode SNI/Host consistency (#198). - P3-I1: drop the out-of-scope NFR-SEC-32 citation (it disclaims guest-VM memory, not host custody-process memory). - P2-S2: name the gateway's generic internal token class (NFR-SEC-23). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(architecture): NFR-SEC-44..60 — close Layer 7 open holes Adds 17 security NFRs adjudicated from the Layer 7 STRIDE residuals (the OPEN holes and the PARTIAL residual tails). Each row is the measurable control for a threat the model left uncovered. Cheap fixes (close a tracked hole with a bounded control): - SEC-44 snapshot-token-exclusion (#184), SEC-45 operator-action-audit (#186), SEC-46 resource-exhaustion-containment (#188), SEC-51 mcp-param-schema, SEC-52 cp-split-reachability, SEC-53 gateway-conn-ceiling. New cross-component controls: - SEC-47 guest-self-audit (#181), SEC-48 trusted-time (#185), SEC-49 per-action-authz (#187), SEC-50 mtls-upstreams (#176), SEC-54 mount-erase-order, SEC-55 killswitch-under-dos, SEC-56 audit-ingest-fairness. Accept-with-tier (a measurable tier target plus a named, formally accepted residual): - SEC-57 egress-exfil-tripwire (#182), SEC-58 side-channel (#183), SEC-59 host-custody-memory (host-foothold only), SEC-60 minimal-storage-floor. Threat-model anchor repointing (the live rows citing "none") lands with the model restructure, not here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): NFR review fixes — SEC-44 timing, SEC-45/39 cross-ref, measurability Applies the duplication / contradiction / slop review findings: - SEC-44: the ≤1 min revoke bound applied to all token classes was wrong for the Session JWT (host-side JWT revoke is ≤5 min per SEC-04). Restate: the pre-snapshot JWT is invalid at resume by construction; only the custody/ storage lease carries the ≤1 min (SEC-29) replay bound. - SEC-45 ⊃ SEC-39: add a bidirectional cross-reference so the operator-action audit set and the tier-downgrade alarm do not read as duplicate controls. - SEC-46: bind the "≤10% degradation" target to a named SLI (p99-latency regression vs the NFR-PERF baseline). - SEC-58: drop the "documented in datasheet" clause from the Target (a deliverable, not a measurable bar). - SEC-57: drop "zero reliance on payload inspection" from the Target (a design constraint already stated in the Scenario). - SEC-56 / SEC-49: add one disambiguating clause each (vs SEC-46 data-plane limits; vs SEC-51 structural validation). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): SEC-44 — clean-before-stop primary; fix SEC-38/39 source refs A snapshot image is a verbatim copy of guest RAM + disk, so a secret live at snapshot time is frozen into a file that can be copied and booted where the resume hook never runs. Host-side revocation makes such a token useless but not absent from the image — two different controls the prior text conflated. Flip SEC-44's primacy: the load-bearing, testable control is that no session-scoped secret is present at snapshot-create time (image taken at minimal-init, session material hot-swapped at restore; verified by offline extraction finding none). Resume-side re-auth + VMGenID reseed + N-fork uniqueness become defence-in-depth. Public anchors: Firecracker snapshot docs, VMGenID spec, arXiv 2102.12892, NIST SP 800-190 §4.5. Also fix the SEC-38/SEC-39 Source cells: "this PR" was a placeholder that broke once #163 merged; repoint to #163 (their origin). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(architecture): NFR-SEC-61..72 — sandbox lifecycle hardening Twelve NFRs closing the lifecycle gaps surfaced alongside the SEC-44 rewrite. They cluster on three transitions the model under-specified: snapshot/resume, crash, and warm-pool reuse — and on the container tiers, which get no VM-death scrub for free. - SEC-61 snapshot-artifact-confidentiality (encrypt+authenticate the image) - SEC-62 single-resume / N-fork uniqueness - SEC-63 resume-clock-correction (correct CLOCK_REALTIME before TTL checks) - SEC-64 no-cross-session-cache-residue - SEC-65 container-tier-teardown-order (host-driven finalizer for runc/gVisor) - SEC-66 pre-freeze-buffer-zeroize - SEC-67 crash-state-sanitize - SEC-68 single-use-guest (a guest that ran a session is destroyed, not pooled) - SEC-69 claim-time-reauth (warm-pool claim re-derives identity) - SEC-70 clean-before-pool - SEC-71 guest-identity-regen (boot_id/machine-id on boot-from-snapshot) - SEC-72 lifecycle-audit-events (audit per security-bearing transition) Public anchors only (Firecracker snapshot/clone docs, VMGenID spec, arXiv 2102.12892, NIST SP 800-190 §4.5); the rest labelled OUR-DESIGN. Threat-model M-3 expansion lands separately, on the restructured model (#199). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): apply quad-review fixes to the lifecycle NFRs Blockers: - SEC-65: replace phantom token names ("egress JWT", "broker lease") with canon — session JWT, custody credential lease, network-bound egress route (NFR-SEC-27); the §8 taxonomy has no egress JWT. - SEC-62: cut the N-fork invariant it restated from SEC-44; carry only the single-restore guard and point to SEC-44 for fork uniqueness. - SEC-47: replace the undefined "tier-2+" with the named gVisor/microVM tiers. Cross-layer / dedup: - SEC-50: state it is MITM-mode only (§7) — transparent pass-through cannot attach an upstream credential. - SEC-64: name the boundary vs SEC-54 (persistent substrate) and SEC-13 (DEK). - SEC-71: name the fork-uniqueness family (SEC-44 token/nonce/RNG, SEC-62 single-restore, SEC-71 guest unique IDs). - SEC-72/SEC-45: split the audit set by initiator (operator → SEC-45, system lifecycle → SEC-72) so the two fixtures neither overlap nor gap. - SEC-70: re-point the warm-pool pairing (pre-claim vs claim-time vs single-use). Slop: - SEC-65: ordering property kept, the six-step arrow list demoted to a gloss. - SEC-46: drop the per-breach audit clause (SEC-72 owns it). - SEC-44: drop the "(defence-in-depth, not the proof)" hedge. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(architecture): Layer 7 — actor model + two-tier threat table Restructure 06-threat-model.md so the STRIDE findings read as a curated security artifact rather than one 79-row table, following the CNCF / Microsoft-TMT / OWASP convention. - §1 declares three threat actors (A1 in-sandbox guest = primary adversary, A2 external caller, A3 host-foothold) once; rows reference them by ID. An A3 threat is conditional on a prior escape (derives from NFR-SEC-02) or sits behind the trusted-host assumption, not a guest-isolation failure. - §2 element×STRIDE applicability is the completeness proof. - §3 Live threats carries only OPEN/PARTIAL, split by actor: §3.1 reachable by the guest (the primary adversary), §3.2 reachable only off a host foothold or external position. - §4 Covered threats lists MITIGATED as a terse ID→controlling-NFR receipt. - Drop the L and I columns; Rating already encodes Likelihood × Impact. No threat content changed; rows are reclassified by actor and regrouped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): re-anchor threat-model rows to SEC-44..72; honest residual register After the lifecycle NFRs landed (#200/#201), 20 live rows that read "no canon NFR" now have a committed control. Re-anchor each from `none` to its NFR and move it OPEN→PARTIAL — the control is specified, not yet built, so it is not MITIGATED. - §3: 20 rows re-anchored (snapshot→SEC-44/61/66, guest-audit→SEC-47, trusted-time→SEC-48/63, operator-audit→SEC-45, resource→SEC-46/53, exfil→SEC-57, per-action→SEC-49, mTLS→SEC-50, side-channel→SEC-58); residual restated as "committed, implementation pending". Only P1-I1 (#149) stays genuinely OPEN — no NFR yet. - §5: residual register reworked — one truly-uncovered row plus a theme→controlling-NFR table, so the picture reads "control specified, not built" rather than "uncovered". - diagram: split the OPEN node into OPEN (P1-I1 only) and a committed-NFR-pending node. - slop: drop the "PRIMARY ADVERSARY" caps tags (the §3.1 heading already establishes A1 as primary); collapse the §1 STRIDE-applicability stack that restated the §2 table to a pointer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): fix #199 review findings — mitigation/anchor consistency Cross-layer + defect review of the re-anchored model found the bulk re-anchor updated Anchor/Residual/Status but left the Mitigation cell stale on 11 rows, and overlooked two more-precise NFRs. - B1: reword the Mitigation cell on 11 rows from "no NFR / not yet canon" to "NFR-SEC-NN specifies the control; implementation pending" (P5-I1, P4-D1, P7-S1, P7-R2, P3-R1, P7-T2, P7-T3, P1-E2, P3-E1, P5-T1, P5-D1). - B2: re-anchor P2-E1 → SEC-52 (CI IaC gateway↛operator assertion, the exact control its residual said was missing) and P2-D1 → SEC-55 (kill-switch ≤30s under control-plane DoS). - C1: §5 theme table — add the missing rows (P2-T2/P5-R1 to trusted-time, P2-R2 to operator-audit, the full #188/#150 DoS set to resource). - C2: diagram PEND node — add #148/#150. - C3: P1-D1 — add SEC-53 (per-caller connection ceiling). - S1: §5 wording "by their controlling NFR" → "grouped by theme". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(architecture): drop "commitment / lands-with" self-narration from NFRs and threat model A control row states a property, not a roadmap. Remove the "Commitment; implementation lands with <X> code" tails (NFR-SEC-38/39) and reword the threat-model residual/mitigation cells from "is committed by NFR-NN but not yet implemented" to "specified by NFR-NN". The PARTIAL status already carries "not built"; the prose no longer restates it. Kept: "events committed locally" in the durable-bus mitigation (a transactional term, not narration). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): collapse double-space left by the narration strip (SEC-38/39) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…aps (#203) * docs(architecture): NFR-SEC-73..77 + amendments — close the 8 reference-coverage gaps Reference review (Anthropic-first) of the threat model surfaced eight controls a mature sandbox runtime carries that ours did not name. This adds them and re-anchors the affected threat rows; after it, no threat row is genuinely open. New NFRs: - SEC-73 downloadable axis — storage authz gains a third axis {scope, intent, downloadable}; a non-downloadable object is readable in-session but yields no egress-eligible artifact, and the tag denies at the edge. - SEC-74 exec-channel stdout/stderr bound (framed transport + byte counter + truncation marker). - SEC-75 host-side env/argv secret-scrub at spawn (allowlist env, never secrets on argv). - SEC-76 reject-non-host-source at the broker/control listener + broker-per-tenant for multi-tenant (accept-time enforcement of SEC-43). - SEC-77 supervisor-death → VM-death (microVM tier; container tiers accept the routed-orphan residual closed by the SEC-65 finalizer). Amendments: SEC-46 (broker max-object/message/mandatory-chunk, closes P4-T1/P4-D1), SEC-12 (pin control/broker endpoints host-side, proxy resolver sole egress authority), SEC-51 (bound + id-minimize MCP error/discovery, closes P1-I1 / #149 — the last open threat row). Layer 3 §2 zone 3 gains the downloadable-axis sentence. Threat model: P1-I1 OPEN→PARTIAL, new P5-I4 (spawn-time secret leak), and SEC-73/74/76 anchors added to the affected P4/P6/P2/P5 rows. §5 residual register and the overlay diagram updated — zero OPEN rows remain. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): #203 review nits — tighten SEC-74 anchor, single-theme P6-I1 - P2-D1: drop the loose SEC-74 cite (its vector is session-create flood, not stdout amplification); SEC-74 stays on P5-D1, the exec-channel row. - §5 register: P6-I1 lists once under Content-blind egress (its primary SEC-57 theme); the SEC-73 strengthening is already noted in its §3 row. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… + embeddable UI (#213) Measurable NFRs the file surface and its embeddable UI need, that the per-sandbox rows did not cover: - NFR-SEC-78: north-side inbound byte path (per-request body ceiling, pre-buffer reject, per-caller rate) — distinct from per-sandbox SEC-46. - NFR-SEC-79: OCSF File System Activity audit on both broker faces, fail-closed. - NFR-SEC-80: pre-extraction archive validation (decompression bomb, path traversal, symlink escape, entry-count). - NFR-SEC-81: content classification on ingest (classify-and-record default + per-scope policy-deny). - NFR-SEC-82: embeddable-UI authentication (signed short-TTL OIDC embed token, cross-origin without re-login). - NFR-SEC-83: iframe-embedding headers (CSP frame-ancestors allowlist). - NFR-SEC-84: first-party session cookie + CSRF for the embedded UI. Extend NFR-SEC-49 with the three-value intent enum (read/write/preview); align NFR-SEC-73 and trust-boundaries zone-3; reword NFR-IC-02 to scope the UI non-goal to the operator/control-plane console (data-plane preview/render UI is in scope per NFR-SEC-82). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… serves its own SPA) (#214) Add a Data-plane client actor to the C4 Context: it reaches OCU's own authenticated SPA — file preview and artifact render — plus the headless upload/list/download API. Bytes flow client↔OCU directly, never relayed through a peer and never reaching the object store. The SPA is embeddable cross-origin in a calling peer (NFR-SEC-82/83). Rendering this data-plane surface is OCU's, not the calling client's. Scope the UI non-goal to the operator/control-plane console; the data-plane preview/render SPA is in scope. Browser/terminal live-view (CDP/ttyd) is v2, deferred under #210 and host-proxied per NFR-SEC-43 when taken up; the machine-facing PTY+CDP WebSocket (NFR-IC-03) stays v1 machine-to-machine. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-language (#216) The file/artifact + SPA/preview surface stays inside the Agent Execution bounded context: it shares the session aggregate root and introduces a delivery sub-language, not a new context. Extend the Storage-broker sub-language clause with the north-face terms (artifact, preview, embed-token, downloadable) and mark SPA-render as a generic component the broker gates, not a built capability. No new context, no table row, no diagram change, no ADR — mirrors the C4 verdict (broker north face; SPA is a component, not a separate container). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lient) (#215) The Storage broker is one object-store client with two faces: the guest mount (south, filesystem_id-scoped file operations) and the data-plane client face (north — OCU's authenticated SPA, the file/artifact API upload/list/download, and preview-render). Both run as components inside the one broker container, not a separate one. Both faces share the one backend credential and the one egress backend leg; the broker is the only object-store client (NFR-SEC-25), so one consistency view covers both and the downloadable axis (NFR-SEC-73) resolves at read on either face. The north face verifies the embed token and sets a first-party session (NFR-SEC-82, NFR-SEC-83). Neither guest nor data-plane client holds a backend credential. The §4 boundary row carries the data-plane client → broker (north) edge, inbound and caller-side: host-side caller to host-side broker, so the host-dials-guest invariant (NFR-SEC-43) is unaffected. The container diagram keeps the data-plane client as an external actor and the north face as a face of the broker container — no eighth container. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#219) L6 (#215) gave the Storage broker a north face — OCU's authenticated SPA plus the file/artifact API — reached by a new external actor (the data-plane client) over a new boundary flow. The threat model covered the broker's south mount (F7) and backend leg (F10) but not this surface. Add six STRIDE rows on the north face (P4-S3/T3/I3/D3/R2/E3, flow F12, actor E5 data-plane client, A2-class): - S: embed-token replay/forgery + clickjack→session-fixation (SEC-82/83) - T: CSRF on the SameSite=None cookie-bound API + token-in-URL leak (SEC-84) - I: cross-filesystem_id read / preview-render leak / non-downloadable bytes to browser (SEC-49/73/83) - D: inbound byte-path + UI-face flood, archive-bomb on ingest (SEC-78/80) - R: north-face file-activity attribution (SEC-79 fail-closed) - E: intent/downloadable bypass + artifact-id traversal via the HTTP API (SEC-49/73/80) Update §1 (twelve flows, five actors) and §2 (E5 actor, F12 flow, P4 north-face sub-element) to match. §5 residual register: extend the exhaustion / per-action-authz / downloadable themes, add three north-face theme rows (file-activity attribution #181; embeddable-UI auth #217; preview-render parser isolation #218). Two new gaps with no prior issue get tracking issues #217 (embed-token replay-binding) and #218 (preview-render parser isolation). §7 unchanged. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-78/79 (#220) The C4 layers (03/04/05), Layer 5 bounded contexts, and the Layer 7 threat model all name the north-side file-artifact actor "Data-plane client". NFR-SEC-78/79 still carried the older "File-client" term. Align the two NFR rows to the one name; no semantic change. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ts (#204) * docs(architecture): Layer 8 — contract-surface overview (08-contracts.md) Maps every boundary that carries a wire contract to its format and to OCU's role (define / conform / relying-party), with the versioning policy and the Layer 7 mitigations each contract must carry. The inventory is the ten internal boundaries from Layer 6 §4 plus the external actors from Layer 4 §4. Five external surfaces are integration contracts OCU conforms to (MCP authz, SAML/OIDC, PKCS#11/KMIP, chained-proxy, ICAP), consistent with the Layer 5 context map; the rest OCU defines. Four formats cover the defined surfaces: MCP JSON-Schema for the agent edge, OpenAPI 3.1 for inbound REST, Protobuf/gRPC for internal RPC, AsyncAPI 3.0 over the OCSF Published Language for audit fan-in. Versioning is additive-only; breaking changes take a major version with a deprecation header (NFR-IC-04) for OCU-defined surfaces, and the MCP edge uses date-revision negotiation as its compatibility signal. Executable schema files, mock servers, and the SkillProvider contract are deferred. diagrams/08-contracts.mmd overlays the format on each container crossing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): correct MCP dialect default + split run-on sentence The MCP §2 bullet wrongly implied the 2025-06-18 revision pins no dialect. The revision defaults embedded tool schemas to JSON Schema 2020-12 and lets `$schema` declare an alternative; correct the bullet to state default + override, and recast the OpenAPI bullet's one-dialect note on that basis. Split the §4 versioning run-on into shorter sentences for readability. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): correct exec/mount formats + transport-fence split The exec/PTY+CDP channel is a single bidirectional WebSocket per session carrying tagged-JSON control frames and raw binary stdio frames, not a unary gRPC call — aligned with NFR-IC-03. The file-operation mount is an HTTP+JSON mount config (filesystem_id, broker-signed lease) over a FUSE/virtio-fs/9p substrate, not gRPC — aligned with NFR-SEC-25. gRPC is scoped to the unary internal RPC legs (session set-up, lease pull); §2 names WebSocket as the fifth format. Add the transport-vs-direction split: the transport substrate (TCP/UDS/vsock; FUSE/virtio-fs/9p) is a deployment-overlay and component-spec choice, not a contract (NFR-SEC-26/25); the contract fixes channel direction — control/exec host-dialled with non-host peers rejected (NFR-SEC-43), outbound guest-out under egress policy (NFR-SEC-27). Fix the audience-authz citation to trust-boundaries §8 (Workload-identity floor), the canonical home of token-class material, not §3. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Layer-8 schema drafts + contracts-lint gate Add the five OCU-defined contract schemas the overview maps to, drafted against the wire sources and bounded by the NFRs: - contracts/mcp/2025-06-18/ocu-constraints.schema.json — MCP conform profile (pins the revision, layers OCU bounds; defines no MCP types). - contracts/exec/exec-channel.schema.json — exec/PTY WebSocket envelope; CreateProcess, the server/client message union, capability negotiation. - contracts/storage/mount-config.schema.json — mount config; a guest config carries no broker lease by construction. - contracts/storage/file-ops.schema.json — file-op names; bodies tbd. - contracts/audit/audit-fanin.asyncapi.yaml — OCSF fan-in over a durable bus; compute-metering and saturation payloads tbd (#150). Unsourced numeric bounds are x-ocu-default annotations the operator retunes within the NFR-SEC-46/51 floor, not frozen contract values. Add .github/workflows/contracts-lint.yml: ajv 2020-12 meta-validation, asyncapi validate, and a provenance guard, triggered on contracts/**. Update 08-contracts.md: §5 lists the drafted schemas by real path and keeps openapi/proto, the transparency-log envelope, and mock servers as not-built; fix the §3 audience citation to trust-boundaries §3, the SOAR webhook anchor to NFR-COMP-27, and scope the gRPC claim to the unary session/lease legs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci(contracts): ajv --strict=false so spec-legal vendor keywords pass ajv strict mode rejected the x-ocu-* vendor extensions and the $comment-* convention, which JSON Schema 2020-12 permits as unknown keywords. Validate against the meta-schema without keyword-policing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(contracts): exec frame union, provenance, TBD links — final review pass A multi-lens adversarial review surfaced one correctness defect and four cleanups, all confirmed: - exec-channel: TraceEvent is a valid frame in both directions, so it appears in both the server and client message sets. The top-level oneOf then rejected every TraceEvent frame (matches two branches). Switch to anyOf — frame direction is a transport property, not an envelope distinction, so the envelope asserts no mutual exclusivity the wire does not have. - exec-channel: reword the V2-payload open question from "is observed" to "is the expected payload" — state the fact, not a derivation. - contracts-lint: extend the provenance guard to catch `anthropic` and `observed`. - 08-contracts.md: link every open question and not-built artifact to a tracking issue (#151, #158, #205-#209); no bare placeholders remain. - audit AsyncAPI: drop the restated "TTL <=15 min" from a channel summary; the NFR-SEC-29 anchor already owns the value. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(contracts): CodeRabbit review — enforce tools-only, mount scope XOR, u64 maximum, pin CI tools - mcp profile: capabilities now additionalProperties:false — rejects every non-tools capability (sampling, experimental, …), not just a four-key denylist; the documented tools-only surface is now enforced. - mount-config: a mount is scoped by filesystem_id XOR memory_store_id (oneOf), so a memory-backed mount no longer has to invent a filesystem id; the RW `mounts` array pins writes:true to mirror readonly_mounts' writes:false. - exec-channel: memory_limit_bytes drops the 2^64-1 JSON-number maximum (a validator rounds it past the IEEE-754 safe-integer range); the u64 domain is enforced by the wire type, documented in $comment. - contracts-lint: pin ajv-cli@5.0.0 and @asyncapi/cli@6.0.0 for deterministic runs (keep --spec=draft2020 — ajv-cli@5 defaults to draft-07 and errors without it). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 8 — north-face file/artifact contract surface The contracts predated the file-surface stack (#213/#214/#215/#216/#219). Add the Storage broker north face — the data-plane client HTTP API and embeddable SPA — alongside the existing south-face mount and file-op RPC. New schema contracts/storage/file-artifact-api.schema.json: - operation set (upload/listFiles/getManifest/download/downloadArchive/ previewRender/delete) mapped to the PoC route shape; per-operation bodies left tbd, like the south face — no invented wire bodies - three-axis authz reuse (scope/intent/downloadable, NFR-SEC-49/73) - embed-token verify contract (peer mints, north verifies, exp ≤120s, NFR-SEC-82); first-party cookie + CSRF + CSP envelope (NFR-SEC-83/84) - inbound byte ceiling (NFR-SEC-78), archive validation (NFR-SEC-80), content classification (NFR-SEC-81) as x-ocu-default, not frozen - OCSF File System Activity event (class_uid 1001, NFR-SEC-79) - embed-token binding (#217) and preview-render parser isolation (#218) carried as tracked tbd items; opaque object id, list pagination, resumable upload, and share-by-link are not modelled (not sourced) 08-contracts.md: §1 north-face surface row, §2 OpenAPI-3.1 note, §3 seven contract-enforced north-face mitigation rows (SEC-78/79/80/81/82/83/84), §5 the new schema file. Diagram: data-plane client actor + north-face edge. Stays v1alpha — bodies tbd and open issues mean beta would overclaim stability; the storage set bumps together when sourced (NFR-IC-04). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 8 — fleet-audit fixes across the contract set A per-contract fleet audit (one auditor per file + cross-contract link check, each finding adversarially verified with quoted evidence) caught unsourced concrete values that earlier reviews missed — mostly in the pre-existing schemas, not the new north-face file. BLOCKs (invented values with no source / NFR figure): - file-ops: drop "~4MB / 128M" chunk constants (NFR-SEC-46 states no figure) and the "opaque pagination cursor" hint (no source; the north face already refuses one); soften the chunk-model assertion to what NFR-SEC-46 carries - mount-config: mark the unsourced `source` field x-ocu-tbd (not frozen) - exec-channel: drop the concrete algorithm name — accept_zstd/supports_zstd → accept_compression/supports_compression as negotiation flags, algorithm pinned to a new x-ocu-open-questions entry FLAGs: - mount-config: rename ca_cert → ca_cert_pem to match the sourced wire name (and its `required` entry) - audit-fanin: storageBrokerAudit channel names both broker faces (NFR-SEC-79) - 08-contracts.md: getMetadata → getManifest (the sourced op name) - unify schema $id authority host to schemas.open-computer-use.dev NITs: Signal bound cites NFR-SEC-51 (input validation) not SEC-46; MCP missing-header fallback qualifier made exact; audit envelope maxLength fields annotated x-ocu-design (NFR-SEC-51-derived, not frozen). ajv 2020-12 compile green on all five schemas; AsyncAPI valid; provenance clean. The new file-artifact-api.schema.json passed the audit unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 8 — restore sourced storage shapes, cover gaps A fleet restore/gap pass (grounded in a sanitized field-name brief, never provenance) recovered storage shapes the earlier audit had wrongly dropped as "invented" — they are real field/message shapes, the audit agents just could not see the source. file-ops (south face, broker RPC): - promote ReadFileRequest_Range (ranged read offset/length), ListDirectoryRecursiveCursor (opaque pagination cursor), FileUploadRequest_Params (chunked chunk/numChunks) from prose hints to real $defs, wired into the request envelope as op-gated carriers - add SizeLimits $def: RPC message ceiling (~4 MiB default), read-chunk default (128 MiB), broker max-file-size (tbd, server policy), per-mount VFS cache ceiling (1 GiB, owner is mount-config) — figures are x-ocu-default, not frozen consts - AuthorizationMetadata noted at request field 4/5 - add getFileMetadata + listFiles as distinct ops; honest tbd hints for fileDownload / importFiles / importZip / migrateFilesystem / removeFilesystem mount-config: - per-mount cache_duration_s with role-directional defaults (uploads 1s, tool_results 3s, transcripts 10s, outputs 3600s) - MountRole enum + role↔RW binding (uploads/tool_results/transcripts RO, outputs RW), host-enforced; crypt modelled off (isolation by scope) ajv 2020-12 green on all three storage schemas; no dangling $refs; south/north names stay distinct; provenance clean (field names only). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 8 — contracts/ navigator README + §5 count fix Add contracts/README.md: per-file surface/format/validator table, how to read a schema, the x-ocu-* annotation conventions (sourced vs design vs default vs tbd), and the change/versioning pointer. Closes the navigation gap — 08-contracts.md is the surface map, this is the reader's guide. Fix §5: six schema files drafted (storage carries three), not five; link the new README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): close inter-layer seams for the file-surface thread An inter-layer cross-review (vertical L2→L8 seams + horizontal cross-doc links, every finding adversarially verified) found the file/artifact surface landed L4→L8 but never reached L3, plus contract/diagram/glossary seams. L3 trust-boundaries (the BLOCK): the Storage broker had only its south face. Add the north data-plane face — §2 zone 3 names two faces, the embed-token → first-party-session crossing, archive-validation + content-classification on ingest (SEC-78/79/80/81/82/83), and the per-tenant broker rule (SEC-76); §3 gains a Data-plane client external-actor row; §7.1 notes the non-guest north path (host-side caller↔broker, NFR-SEC-43 unaffected); the zone-3 secondary-anchor line carries the north-face NFRs. L8 §3: add the Three-axis authz (SEC-49) and Downloadable-at-read (SEC-73) mitigation rows — the controlling NFRs of threat rows P4-I3/P4-E3 were unrepresented. Audit fan-in: the FileSystemActivity message gains the NFR-SEC-79 required-field overlay (filesystem_id/intent/downloadable) so the mandated field set is pinned on both faces, not deferred to the bare OCSF class; the message summary names both faces. L7 diagram: add the data-plane client (north face / F12) and the P4 north-face STRIDE cluster + #217/#218. L7 §1: the data-store, IdP/SOAR, and F-number elements are named STRIDE elements, not nodes on c4-container.mmd — wording corrected to not over-claim the diagram. L6 §3: add NFR-SEC-83 to the broker NFR-anchor column (prose already cited it). glossary: add Data-plane client, South/north face, Downloadable, Embed token; extend Storage broker with the two-face model. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 8 — reconcile mount-config drift vs the real surface A drift-reconcile pass (research the underfilled provisioning fields, adjudicate the design-added ones, adversarially verified) cleaned the mount-config against the real guest-mount surface. INCLUDE — the one genuinely-missing in-scope field: - backend_cache_ttl: a config-level broker-side cache window, distinct from the per-mount cache_duration_s; added to ProvisionMountConfig only (broker-side, not the guest variant), x-ocu-tbd pending unit/scope confirmation. DROP — design-adds that are derivable-inside or redundant: - source: not on the wire; the broker derives the backend source path from filesystem_id + the mount's directional intent. Least-data (NFR-SEC-25) — a derivable value the guest cannot be trusted to set is not a wire field. Documented in the MountBase $comment. - (no schema change for fuse_mounts / readonly_dev_start_index: the RO/RW split they encode is already carried, more cleanly, by mounts[]/readonly_mounts[] + the writes boolean.) REFRAME — provenance honesty: - role / MountRole: the role NAMES are the directional-window vocabulary, but role-as-a-stored-field is an OCU design construct, not a sourced provisioning field. Comments corrected (were "Sourced role set"). OUT-OF-SCOPE (not added; tracked separately): resolv_conf / etc_hosts belong to the guest network/init surface (Compute plane), not the file-mount contract; mount_model_tools / mount_rclone_tools belong to the SkillProvider surface (v1 non-goal). No §5 not-built line added without a real tracking issue. ajv 2020-12 green; provenance clean; field names only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 8 — drop the MountRole field (derivable, not sourced) role / MountRole was an OCU design construct, not a provisioning-struct field: the real surface carries RW/RO structurally (the readonly_mounts split) and the freshness window as cache_duration_s itself, with no role field. role only duplicated values already carried by writes + cache_duration_s, bound by two if/then constraints — redundant and unsourced. Drop the role property, its $def, and the role→writes allOf blocks; remove it from required. RW/RO stays in writes + the mounts/readonly_mounts split; the directional window stays in cache_duration_s. The role names survive as the cache-window vocabulary. Same least-data reasoning that dropped `source` (NFR-SEC-25): a value the broker derives is not a wire field. ajv 2020-12 green; provenance clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 8 — fix RW-enforcement symmetry + role-comment wording Final review (post role/source drop) flagged two consequences of dropping role: - ProvisionMountConfig.mounts items were a bare MountBase $ref with no writes:const:true, so a provisioning RW-array entry could carry writes:false — contradicting the structural-split invariant the prose asserts. Mirror the GuestMountConfig.mounts constraint: writes:const:true on the provisioning RW array too. Now both variants pin writes:true on mounts[] and false on readonly_mounts[]. - $comment-no-role narrated drafting history ("an earlier draft carried ... it was dropped") — a process-narration tell. Reworded to a present-tense design record that keeps the rejection rationale without the history clause. ajv 2020-12 green; provenance clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): Layer 8 — require x_deny_reason on a deny outcome CodeRabbit: the FileActivityEvent outcome description says "a deny carries the structured deny-reason" but the schema only required disposition_id, so a deny with no reason validated — text and schema disagreed. Add an if/then: when disposition_id is "deny", x_deny_reason is required. allow outcomes unchanged. ajv 2020-12 green; verified deny-without-reason now rejected, deny-with-reason and allow accepted. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rs (#221) * docs(architecture): Layer 10 — component specs for the seven containers Add a spec per Layer 6 container under components/, plus the directory index (00-overview) and a glossary entry for the Generic internal token. Each spec follows the fixed section order (Purpose, Boundaries, Invariants, Failure modes, Operational concerns, Open questions) and adds only the intra-container design the layer docs do not already own: - 01 MCP gateway, 02 Control/operator API, 03 Credential custody, 04 Storage broker, 05 Session sandbox, 06 Egress trust-edge, 07 Audit pipeline. Failure-mode rows trace to the Layer 7 STRIDE rows and repeat each row's controlling NFR; every container's PARTIAL rows have a home. Invariants are stated test-enforceably against a real NFR anchor. Build-vs-buy (storage engine) and runtime-tier remain future ADRs — the specs name them by role and carry them as open decisions. The 04 two-face split is an inline component diagram; the broker mount-remanence row anchors to NFR-SEC-54/13/64 (erase-before-reuse, per-session DEK, cache residue). 00-overview records the spec slot, status, and bound contracts per container; ADR cells stay empty until Layer 9 produces them. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): fix L10 CI — trailing newlines + drop superlative markdownlint MD047 on four specs (missing final newline) and the AI-slop superlative rule on the sandbox egress-route line ("is the only path"). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): drop residual superlative in 05 sandbox flow table CodeRabbit flagged 'the one outbound network leg' in the edge-flow row; the direction is already carried by the 'guest -> edge' column. The measurable referent (sole egress, invariant 4) stays in the rationale cell. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(architecture): manifesto §05 — licensing posture (FSL + dep gate + reject table) Adds the licensing-posture manifesto doc that CLAUDE.md already references for the Bill of Materials and the rejection table. States the FSL-1.1 terms and the per-release two-year Apache-2.0 conversion, the licence + supply-chain gates a dependency passes, the bundled-vs-not-bundled rule, and the seven rejected dependencies with the path taken instead. The Bill of Materials table is not pre-populated: a row lands when the ADR or component spec that adopts a dependency lands, so the bundled call is made with the rationale that needs it. This unblocks the licence-evidence the L9 ADR backlog cites. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): drop process-narration in §05 reject-table preamble doc-slop-reviewer flagged 'Licence facts were checked … on 2026-06-01' as narrating the authoring step rather than stating a property. The forward constraint (the adopting ADR re-verifies before citing a row) carries the load; the snapshot date does not. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The data-plane UI discovers its views from a session-scoped descriptor list rather than a hardcoded tab set, so the deferred live-session views (browser, terminal, #210) are additive entries, not a breaking change. v1 returns one descriptor (files); the endpoint returns three when #210 lands and an old shell renders the subset it recognizes. Per-surface authentication (no panel-wide credential) and a host-side-only descriptor entry.url (NFR-SEC-43) close the PoC's single-chat_id and direct-guest-reachability weaknesses. Indexed in adr/README. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ratifies the workload-trust selection axis the §02 NFRs already encode and closes the v1/post-v1 cut: tier is selected by workload_trust_profile (runc for trusted_operator, gVisor for internal_workforce), microVM deferred post-v1, never by data classification (AP-13). The ADR references NFR-SEC-02/38/39 rather than restating them. As the adopting ADR for runc and gVisor, both enter the §05 Bill of Materials as bundled (Apache-2.0). Enterprise audit sinks/alarms stay opt-in for the solo default; the local audit emit is mandatory in code. Sets components/05 adr:[0003], links 00-overview and the ADR index. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eep (#230) * docs(lint): gate 'bank' as audience framing + sweep canon to 'regulated enterprise' The 'bank only as a named example, default term regulated enterprise' rule lived only in prose, so every new doc re-introduced bank-as-framing and it was caught by eye, not CI. Adds an ai-slop-detector check (#15) that flags framing tells (the bank's, targets banks, bank-required/grade, bank InfoSec/ CISO/reviewer) while allowlisting the tier-1 US/EU bank named example, with a self-test fixture pair. Sweeps the existing framing hits to 'regulated enterprise': CLAUDE.md (targets banks; bank auditor), PROCESS.md, ADR-0003, manifesto/05. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(lint): OIDC-only identity surface — gate SAML + sweep canon OCU's identity surface is OIDC; a SAML-only customer IdP federates in through Dex or Keycloak, never an OCU SAML endpoint. The rule lived nowhere, so SAML kept appearing as a co-equal platform surface. Adds ai-slop-detector check #16 (SAML asserted as a surface fails; a federation/fallback clause passes) with a self-test fixture pair, and sweeps the 9 canon mentions: NFR-SEC-09, NFR-FLEX-03, NFR-COMP-29, and the 02/03/04/08/primitives docs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(architecture): ADR-0004 — operator authentication substrate Closes the operator-auth needs-ADR in component 02: minimal shelf = host-rooted local credential + signature-verified signed-webhook; full shelf = OCU as relying-party to the customer IdP (OIDC+SCIM, PAM-JIT) + SPIFFE SVID for SOAR. Drops dual-control and break-glass — the kill switch is already the single-operator emergency path and NFR-SEC-45 already carries accountability; multi-party approval is a post-v1 policy seam (#225). License: relying-party, nothing bundled (Teleport AGPL / Boundary BUSL rejected). Sets component 02 adr:[0004] and the ADR index row. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): drop 'only' superlative in ADR-0004 context AI-slop detector flags 'is the only / unique' without a measurable referent. 'the privileged plane' carries the same meaning; the reachability claims (kill switch, denylist, tier admission) are the referent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): ADR-0004 — 'bank' framing → regulated enterprise Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): ADR-0004 — OIDC-only, SAML via federation only Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… SDS (#231) Excise the Credential custody service from the canon. Egress credential delivery rides Envoy SDS + credential_injector: a static file on the solo shelf, a customer-provided SDS-compatible store on the enterprise shelf. OCU stores, mints, and rotates nothing; the source owns the lifecycle. The NFR-SEC-23 invariant holds — the upstream secret never enters the guest; it is attached only at the egress boundary. Trust zones 6 -> 5, containers 7 -> 6: the Egress trust-edge carries the boundary-injection property. The bespoke F8 lease-pull protocol, the STS delegator, and the OCU-enforced TTL/revoke bounds are removed. - ADR-0005: egress credential delivery decision (replaces the F8/STS draft) - delete components/03 credential-custody; rewrite components/06 egress edge - 05 container, 02 trust-boundaries (+ .mmd), 06 threat-model: drop P3/D1/F8, renumber zones/containers/flows - 08 contracts: drop lease-pull row (#205 re-scoped to session set-up) - 02-nfrs: reframe SEC-23/25/27/29/31/59 to the SDS source; SEC-45/48/49/50/65/77 - BoM: add Envoy (Apache-2.0); diagrams c4-container/threat-model/contracts - deferred: credential_injector/OAuth2 maturity caveat (components/06 open question) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(architecture): ADR-0006 — egress forward-proxy substrate Closes the forward-proxy half of egress open-Q#2: one Apache-2.0/MIT/BSD forward proxy (Envoy lead candidate) scoped to the v1 deny-by-default floor — allow-list on resolved-IP+SNI, proxy-owned resolver with the mandatory deny-set, x-deny-reason, one ext_authz seam (static allow-list default, OPA deferred), a per-upstream-leg origination hook. No CA/SDS/ICAP/xDS on the transparent default path. MITM-termination is a separate deferred ADR. Adds Envoy to the §05 Bill of Materials (Apache-2.0, bundled); sets component 06 adr:[0006] and narrows its open-Q#2 to MITM-termination only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(architecture): ADR-0006 — 'bank' framing → regulated enterprise Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Comment retired during the initial-public-release history consolidation. |
…rotocol-broker (#234) Select the egress credential-attachment mechanism by upstream: edge-inject (fixed-client bearer, e.g. an LLM API) or protocol-broker (high-value scoped-by-rights credential, e.g. a PAT or object store). v1 ships edge-inject only; the protocol-broker mechanism is the existing Storage-broker zone, deferred for other upstreams. Egress posture becomes a ladder by need (deny-all / transparent pass-through / egress-wide bump / external SDS source) rather than a two-mode switch. Bump is the default only when an upstream credential is configured, so the one-click solo path holds at every rung; the per-deployment CA is auto-generated and its public certificate auto-injected into the sandbox trust store at start. The bump substrate is the Envoy data plane plus a self-hosted SDS minting service for per-SNI leaves; a config-time-enumerable allow-list uses pre-minted leaves over a file SDS source instead. mitmproxy/Squid are rejected-as-default for dropping the Envoy data plane. Injection is gated on a scoped credential the request presents, never on network origin (tightens P6-E2). The guest holds no long-lived upstream secret but may carry a short-lived session-scoped handle (corrects the prior categorical "guest holds nothing"). Propagated across §7, NFRs (FLEX-15, SEC-05/17/23/27/37/50/57/73), the threat model, component-06, glossary, c4 container/context, contracts, the trust-zone and threat-model diagrams, ADR-0005/0006 forward-refs, and the BoM. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Closing: this PR's diff is the entire next/v1 branch against main (274 files, +8769/-1959), not the single credential-broker doc the title describes — it was opened with the wrong base/head. The credential-broker design it intended to distill is now superseded by merged ADR-0005 (egress credential delivery) and ADR-0007 (egress auth mechanism), which fold custody into the egress-edge + storage-broker and remove the standalone custody process (threat-model: P3/D1 removed by ADR-0005). Not mergeable and not current. |
|
Reopened — closed prematurely before the author reviewed it. No action taken; left for the author to decide. |
…se (#236) Three-lens review fixes (the bounded, uncontested ones): - components/00-overview.md — the index showed component-02 bound ADRs as "—", but its spec front-matter is `adr: [0004]`; the index now cites ADR-0004. - components/04-storage-broker.md — the `contract:` front-matter listed only mount-config, but the spec binds three storage contracts (mount-config, file-ops, file-artifact-api), all present; the field now lists all three. - 02-trust-boundaries.md — drop the "(consolidated to satisfy the CLAUDE.md ≤ 3-links rule)" parenthetical; the section shows the consolidation, the reason is not a fact about the content. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Closing: the diff is the entire next/v1 branch against main (274 files, +8769/-1959), not the single credential-broker doc the title describes — wrong base/head. The credential-broker design it intended to distill is superseded by merged ADR-0005 and ADR-0007 (custody folds into the egress-edge + storage-broker; threat-model records P3/D1 as removed by ADR-0005). Not mergeable, not current. |
Description retired during the initial-public-release history consolidation. The canonical content lives in docs/architecture/ at the current tip.