Ctrl K
ComunidadGuías…

project/spec/conformance.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
version: 1
product: Artifact Server
updated: "2026-08-26"
evidence_root: "../.."

source:
  product_spec: artifact-server-product-spec.html
  supporting_spec: artifact-server-product-spec.md
  administration_spec: single-application-administration-spec.md
  mcp_spec: artifact-server-mcp-baseline.md
  plannotator_spec: plannotator-artifact-server-integration-spec.md

# A deployment can be advertised as supported only when every requirement that
# names that deployment is verified with evidence from that deployment.
deployment_sets:
  all: &all
    [local, single_server, kubernetes, cloudflare, aws, gcp]
  external_storage: &external_storage
    [single_server, kubernetes, cloudflare, aws, gcp]
  replicated: &replicated
    [kubernetes, cloudflare, aws, gcp]
  hosted: &hosted
    [cloudflare]
  direct_clouds: &direct_clouds
    [aws, gcp]
  plannotator_capable: &plannotator_capable
    [single_server, kubernetes, cloudflare, aws, gcp]

allowed_statuses:
  - specified
  - implementing
  - behavior_verified
  - verified
  - blocked
  - not_applicable

status_contract:
  specified: The behavior and tests are defined, but no implementation proof is claimed.
  implementing: Implementation work has started, but proof is incomplete.
  behavior_verified: At least one applicable deployment has passing behavior-test evidence, but full proof is incomplete.
  verified: Every applicable deployment has passing behavior and failure-test evidence.
  blocked: Work cannot proceed until the recorded blocker is resolved.
  not_applicable: The requirement was retained for traceability but has a recorded reason it does not apply.

evidence_contract:
  required_fields: [deployment, tests, result, run, recorded_at]
  allowed_results: [pass, fail]
  note: A verified requirement must cover its behavior and failure test on every applicable deployment with passing evidence.

allowed_kinds:
  - behavior
  - constraint
  - security
  - deployment
  - release_gate
  - exclusion

allowed_modules:
  - product-core
  - project-core
  - artifact-core
  - manifest
  - publishing
  - blob-storage
  - content-delivery
  - authorization
  - comparison
  - git-history
  - web-application
  - http-api
  - mcp
  - cli
  - agent-skills
  - artifact-comments
  - agent-dispatch
  - agent-bridge
  - agent-presence
  - local-workspace
  - kanban
  - plannotator-integration
  - database-adapters
  - deployment
  - operations
  - hosted-policy

required_source_sections:
  top: [PRD-001, PRD-002]
  product: [PRD-003]
  artifact: [PRJ-001, PRJ-002, PRJ-003, PRJ-004, ART-001, ART-002, ART-003, ART-004, ART-005, ART-008]
  experience: [CNT-001, CNT-002, VER-001, DIF-001, GIT-001]
  sharing: [AUTH-001, AUTH-002, AUTH-003, AUTH-004, AUTH-018]
  plannotator: [PLN-001, PLN-002, PLN-003, PLN-004, PLN-005, PLN-017]
  architecture: [ARC-001, ARC-002, ARC-006, PUB-001, CNT-003]
  mcp: [MCP-001, MCP-002, CLI-001, SKL-001]
  deployment: [DEP-001, DEP-002, DEP-003, DEP-004]
  safety: [SEC-001, SEC-002, SEC-003, SEC-004]
  scope: [SCP-001, SCP-002, SCP-003]
  implementation: [REL-001, REL-002, REL-003, REL-004]
  decisions: [GATE-001, GATE-002, GATE-003]

requirements:
  - id: PRD-001
    kind: behavior
    behavior: Artifact Server stores and serves finished client-side sites and arbitrary individual files.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: top}
    acceptance:
      behavior: {id: PRD-001-B, description: "Publish and open both a complete client-side site and one ordinary file."}
      failure: {id: PRD-001-F, description: "Reject input that is neither a valid file nor a valid finished client-side directory without creating an artifact."}
    deployments: *all
    status: specified
    depends_on: []
    evidence: []

  - id: PRD-002
    kind: exclusion
    behavior: Artifact Server does not build source code, install packages, run an artifact backend, perform server-side rendering, or convert uploaded media.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: top}
    acceptance:
      behavior: {id: PRD-002-B, description: "Serve already-finished files without starting an artifact-specific runtime or conversion job."}
      failure: {id: PRD-002-F, description: "Publishing source that requires Node.js, Python, a database, a server function, or a conversion step does not cause the server to execute it."}
    deployments: *all
    status: specified
    depends_on: []
    evidence: []

  - id: PRD-003
    kind: behavior
    behavior: The normal workflow publishes, opens, compares, and shares a project artifact without creating a separate hosting deployment for that artifact.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: product}
    acceptance:
      behavior: {id: PRD-003-B, description: "Complete publish, open, compare, and visibility operations against one stable artifact identity."}
      failure: {id: PRD-003-F, description: "Repeating the workflow does not create an unrelated deployment, project, or artifact identity."}
    deployments: *all
    status: specified
    depends_on: [ART-001, VER-001, DIF-001]
    evidence: []

  - id: PRJ-001
    kind: behavior
    behavior: One installation represents one person, team, or company and contains projects; a new installation creates one default project without adding an organization switcher or Artifact Store object.
    owner: project-core
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: PRJ-001-B, description: "Start a new local and team installation, observe one stable default project, create another project, and list both within the same installation."}
      failure: {id: PRJ-001-F, description: "A caller cannot create or select an organization, Artifact Store, Namespace, or project belonging to another installation."}
    deployments: *all
    status: implementing
    proof_gap: The current local test proves one default project, creation of a second project, and foreign-project rejection, but it does not start a team deployment or probe organization, Artifact Store, and Namespace creation and selection surfaces.
    depends_on: [AUTH-001]
    evidence: []

  - id: PRJ-002
    kind: security
    behavior: Every artifact belongs to exactly one project, and project scope is enforced by repositories, uploads, idempotency, browser sessions, HTTP, MCP, audit, backup, and restore.
    owner: project-core
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: PRJ-002-B, description: "Publish, list, read, compare, restore, change, audit, back up, and restore artifacts inside their named projects through HTTP and MCP."}
      failure: {id: PRJ-002-F, description: "Cross-project and cross-installation artifact, version, upload, key, idempotency, content-session, list, search, audit, backup, and restore attempts fail without revealing which identifier exists."}
    deployments: *all
    status: implementing
    proof_gap: The current local test covers selected HTTP upload, list, read, comparison, mutation, and audit boundaries; it does not prove the complete HTTP and MCP matrix or the named key, idempotency, content-session, search, backup, and restore boundaries.
    depends_on: [PRJ-001, AUTH-008]
    evidence: []

  - id: PRJ-003
    kind: behavior
    behavior: Projects use installation membership and have no separate member list or access-control list; archiving stops new artifacts and versions while preserving existing reads and immutable history.
    owner: project-core
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: PRJ-003-B, description: "Read account-required artifacts through installation membership, archive a project, retain existing reads and comparisons, and reject new artifacts and versions."}
      failure: {id: PRJ-003-F, description: "Project creation cannot add a hidden member list or ACL, and archive cannot delete, retarget, or alter an existing artifact, version, link, manifest, or action record."}
    deployments: *all
    status: implementing
    proof_gap: The archive test uses a public artifact and proves write rejection plus retained reads, but it does not prove installation-membership access, absence of a project ACL, retained comparisons, or unchanged links, manifests, and action records.
    depends_on: [PRJ-001, AUTH-001, VER-001]
    evidence: []

  - id: PRJ-004
    kind: release_gate
    behavior: Existing installations migrate every artifact into one default project without changing any existing identity, version bytes, link target, action record, or authorization outcome.
    owner: database-adapters
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: PRJ-004-B, description: "Upgrade populated SQLite and Postgres installations and verify preserved installation, artifact, version, manifest, content, action, visibility, tag, and link values under the default project."}
      failure: {id: PRJ-004-F, description: "Interrupted, repeated, partially applied, and rolled-back migrations cannot duplicate projects, orphan artifacts, change IDs, lose bytes, or widen access."}
    deployments: *all
    status: implementing
    proof_gap: The acceptance-ID test exercises a populated SQLite migration and repeat startup only; the combined SQLite and Postgres preservation matrix plus interrupted, partially applied, and rolled-back migration proof is not attached to these IDs.
    depends_on: [PRJ-001, PRJ-002]
    evidence: []

  - id: PRD-004
    kind: constraint
    behavior: Browser, HTTP, MCP, CLI, and Plannotator entry points use the same product and authorization services.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: PRD-004-B, description: "Run the same publish and authorization conformance cases through browser, HTTP, and MCP entry points."}
      failure: {id: PRD-004-F, description: "An operation forbidden through one interface is not permitted through another interface."}
    deployments: *all
    status: specified
    depends_on: [AUTH-008, MCP-009]
    evidence: []

  - id: ART-001
    kind: behavior
    behavior: An artifact has one stable identity across every intentional publish.
    owner: artifact-core
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: ART-001-B, description: "Publish two versions and confirm that the artifact ID remains stable while version IDs differ."}
      failure: {id: ART-001-F, description: "A new version cannot change or reuse another artifact's identity."}
    deployments: *all
    status: behavior_verified
    depends_on: []
    evidence:
      - deployment: local
        tests: [ART-001-B]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: ART-002
    kind: behavior
    behavior: An artifact records its project, name, access setting, current version, creation time, and deletion state.
    owner: artifact-core
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: ART-002-B, description: "Create an artifact in a project and retrieve every required field with stable types and values."}
      failure: {id: ART-002-F, description: "Reject creation when required project or artifact data is missing or refers to another project or installation."}
    deployments: *all
    status: behavior_verified
    depends_on: [PRJ-002, ART-001]
    evidence:
      - deployment: local
        tests: [ART-002-B]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: ART-003
    kind: behavior
    behavior: A saved version records a unique ID, artifact ID, number, canonical manifest digest, entry file, routing mode, publisher, and creation time.
    owner: artifact-core
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: ART-003-B, description: "Publish a version and retrieve all required version fields and their referenced artifact."}
      failure: {id: ART-003-F, description: "Reject a version whose artifact, manifest, entry file, publisher, or routing mode is invalid."}
    deployments: *all
    status: behavior_verified
    depends_on: [ART-001, MAN-001]
    evidence:
      - deployment: local
        tests: [ART-003-B]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: ART-004
    kind: behavior
    behavior: Every saved version is immutable after its database commit.
    owner: artifact-core
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: ART-004-B, description: "Read a committed version repeatedly and confirm that its manifest and file fingerprints never change."}
      failure: {id: ART-004-F, description: "Reject attempts to edit a committed version or replace any referenced blob."}
    deployments: *all
    status: behavior_verified
    depends_on: [PUB-005]
    evidence:
      - deployment: local
        tests: [ART-004-B, ART-004-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: ART-005
    kind: behavior
    behavior: Restoring an earlier version changes only the artifact's current-version pointer and records the action.
    owner: artifact-core
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: ART-005-B, description: "Restore an earlier version and confirm that existing version IDs, manifests, and files remain unchanged."}
      failure: {id: ART-005-F, description: "Reject restoring a version from another artifact or installation."}
    deployments: *all
    status: behavior_verified
    depends_on: [ART-004, AUD-001]
    evidence:
      - deployment: local
        tests: [ART-005-B, ART-005-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: ART-006
    kind: behavior
    behavior: Deleting an artifact creates a tombstone and stops every application and content link without deleting individual versions immediately.
    owner: artifact-core
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: ART-006-B, description: "Delete an artifact and confirm that all stable and exact-version links stop serving while its tombstone remains."}
      failure: {id: ART-006-F, description: "A deleted artifact cannot be reopened through a cached application authorization or direct origin request."}
    deployments: *all
    status: behavior_verified
    depends_on: [ART-004, AUTH-017]
    evidence:
      - deployment: local
        tests: [ART-006-B, ART-006-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: ART-007
    kind: constraint
    behavior: Automatic version expiry and individual committed-version deletion are not supported in the initial product.
    owner: artifact-core
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: ART-007-B, description: "Confirm that a committed version remains addressable until its artifact is tombstoned under explicit policy."}
      failure: {id: ART-007-F, description: "No API, UI, MCP tool, or cleanup worker can delete one committed version independently."}
    deployments: *all
    status: behavior_verified
    depends_on: [ART-004]
    evidence:
      - deployment: local
        tests: [ART-007-B]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: ART-008
    kind: behavior
    behavior: An artifact has zero to 20 normalized, unique tags. Tags belong to the artifact rather than one version, remain through publish, restore, and tombstone operations, and support exact normalized filtering by any selected tag.
    owner: artifact-core
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: ART-008-B, description: "Create tags through inline and staged publication, replace them atomically, filter by one or more exact normalized tags with any-tag matching, and confirm they remain through publish, restore, and tombstone operations."}
      failure: {id: ART-008-F, description: "Reject empty, overlong, control-character, and oversized tag sets plus conflicting retries without changing stored tags or action history."}
    deployments: *all
    status: behavior_verified
    depends_on: [ART-001, ART-005, ART-006, AUD-001]
    evidence:
      - deployment: local
        tests: [ART-008-B, ART-008-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: ART-009
    kind: behavior
    behavior: Project artifact search runs before pagination and returns artifacts whose normalized name contains the normalized search text or whose tags contain that exact normalized text, while a Review keeps its exact selected preview when it is outside the result set.
    owner: artifact-core
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: ART-009-B, description: "Search a project by case- and whitespace-normalized artifact-name substring and exact normalized tag, including an artifact absent from the loaded catalog page, while the selected Review preview remains unchanged."}
      failure: {id: ART-009-F, description: "A partial tag, another project, or a nonmatching name is not returned, and an empty result cannot replace the selected Review artifact or version."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local HTTP and browser evidence proves project-wide search and preview preservation. Equivalent evidence for each team deployment remains unrecorded.
    depends_on: [ART-002, ART-008, PRJ-002]
    evidence:
      - deployment: local
        tests: [ART-009-B, ART-009-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-25T19:14:39.424Z"
      - deployment: local
        tests: [ART-009-B, ART-009-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-25T19:16:53.330Z"

  - id: ART-010
    kind: behavior
    behavior: Review offers a confirmed Make current action for a historical version, submits the expected current-version ID, reports conflicts without moving the pointer, and keeps the reviewer on the exact selected version after success or conflict.
    owner: artifact-core
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: ART-010-B, description: "Confirm Make current for a historical version, observe only the current pointer move, and remain on the exact historical Review URL and preview."}
      failure: {id: ART-010-F, description: "Publish concurrently after confirmation opens; Make current fails with a conflict, refreshes pointer state, and neither changes the concurrent current version nor navigates the reviewer."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local browser evidence proves conflict-safe Make current behavior and exact Review preservation. Equivalent evidence for each team deployment remains unrecorded.
    depends_on: [ART-004, ART-005, CMT-016]
    evidence:
      - deployment: local
        tests: [ART-010-B, ART-010-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-25T19:16:53.330Z"

  - id: ART-011
    kind: behavior
    behavior: The Review catalog shows exact comment totals and can filter artifacts by comment presence or order them by newest and most commented before pagination.
    owner: artifact-core
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: ART-011-B, description: "Show exact per-artifact comment totals, filter the complete project catalog to artifacts with or without comments, and page a deterministic most-commented ordering."}
      failure: {id: ART-011-F, description: "Reject a cursor from another ordering, preserve the selected Review when filtering hides it, and never reduce filtering or sorting to the artifacts already loaded in the browser."}
    deployments: *all
    status: implementing
    proof_gap: Local SQLite and browser behavior plus provider-specific D1 and Postgres query paths must pass before this requirement can be marked verified.
    depends_on: [ART-002, ART-009, CMT-001]
    evidence: []

  - id: MAN-001
    kind: behavior
    behavior: A canonical manifest contains a sorted list of normalized paths, fingerprints, sizes, media types, disposition, entry file, routing mode, and serving metadata.
    owner: manifest
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: MAN-001-B, description: "Build the same manifest from equivalent directory walks and obtain identical canonical bytes and digest."}
      failure: {id: MAN-001-F, description: "Reject a manifest with duplicate paths, missing fields, nondeterministic ordering, or an absent entry file."}
    deployments: *all
    status: implementing
    proof_gap: The current test compares manifest digests and path ordering, but it does not compare canonical manifest bytes or cover every missing-field and nondeterministic-ordering failure named by the acceptance tests.
    depends_on: []
    evidence: []

  - id: MAN-002
    kind: behavior
    behavior: Each file entry records normalized path, byte length, media type, SHA-256 fingerprint, and file disposition.
    owner: manifest
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: MAN-002-B, description: "Publish representative files and confirm each manifest entry matches the exact stored bytes and serving metadata."}
      failure: {id: MAN-002-F, description: "Reject a claimed size or fingerprint that differs from the uploaded bytes."}
    deployments: *all
    status: implementing
    proof_gap: The complete-site test confirms stored bytes and selected response headers, but it does not inspect every committed manifest-entry field; the size and fingerprint rejection path is proved under PUB-003 rather than MAN-002-F.
    depends_on: [MAN-001]
    evidence: []

  - id: MAN-003
    kind: security
    behavior: Manifest paths are normalized, relative POSIX paths.
    owner: manifest
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: MAN-003-B, description: "Publish nested portable paths and serve every file only at its normalized manifest location."}
      failure: {id: MAN-003-F, description: "Reject absolute paths, dot segments, empty segments, backslashes, NUL bytes, .git components, reserved .artifactserver metadata components, and encoded separators."}
    deployments: *all
    status: behavior_verified
    depends_on: []
    evidence:
      - deployment: local
        tests: [MAN-003-B, MAN-003-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: MAN-004
    kind: security
    behavior: Publishing rejects symlinks, devices, sockets, and other special filesystem entries.
    owner: manifest
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: MAN-004-B, description: "Publish a directory containing only regular files and directories."}
      failure: {id: MAN-004-F, description: "Attempt every supported special-file type and confirm that the publish fails before a version is committed."}
    deployments: *all
    status: specified
    depends_on: [MAN-003]
    evidence: []

  - id: MAN-005
    kind: security
    behavior: Publishing rejects path collisions after case folding or Unicode normalization.
    owner: manifest
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: MAN-005-B, description: "Publish distinct normalized names that remain distinct on every supported storage system."}
      failure: {id: MAN-005-F, description: "Reject case-only and normalization-equivalent path pairs before storing the version."}
    deployments: *all
    status: implementing
    proof_gap: MAN-005-F proves local rejection of case-only and normalization-equivalent collisions, but no behavior test publishes distinct normalized names across every supported storage system.
    depends_on: [MAN-003]
    evidence:
      - deployment: local
        tests: [MAN-005-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: MAN-006
    kind: security
    behavior: Content requests resolve only through the committed manifest and never by joining an untrusted path to a storage directory.
    owner: manifest
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: MAN-006-B, description: "Serve every committed file through its manifest entry."}
      failure: {id: MAN-006-F, description: "Traversal, alternate encoding, storage-key, and unlisted-file requests never read bytes outside the manifest."}
    deployments: *all
    status: behavior_verified
    depends_on: [MAN-001, MAN-003]
    evidence:
      - deployment: local
        tests: [MAN-006-B]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: PUB-001
    kind: behavior
    behavior: Publishing starts with an expiring upload record and a unique staging location bound to the principal and installation.
    owner: publishing
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: PUB-001-B, description: "Create an upload and verify its principal, installation, unique staging location, and expiration."}
      failure: {id: PUB-001-F, description: "Another principal or installation cannot read, append, commit, or renew the staged upload."}
    deployments: *all
    status: behavior_verified
    depends_on: [AUTH-008]
    evidence:
      - deployment: local
        tests: [PUB-001-B, PUB-001-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: PUB-002
    kind: behavior
    behavior: Public clients publish one actual file or finished directory through a file-upload transport. JSON and MCP schemas do not accept raw source strings or base64-wrapped file contents.
    owner: publishing
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: PUB-002-B, description: "Publish one ordinary file and one large multi-file fixture through the advertised upload plan without asking the user for a manifest, fingerprint, upload ID, or size threshold."}
      failure: {id: PUB-002-F, description: "Reject raw source strings, base64-wrapped file contents, and oversized MCP payloads with instructions for the supported file-upload path."}
    deployments: *all
    status: behavior_verified
    depends_on: [PUB-001]
    evidence:
      - deployment: local
        tests: [PUB-002-B, PUB-002-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: PUB-003
    kind: security
    behavior: The server verifies every staged file's size and SHA-256 fingerprint before committing the version.
    owner: publishing
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: PUB-003-B, description: "Commit correctly sized and hashed staged files and retrieve matching manifest entries."}
      failure: {id: PUB-003-F, description: "Reject missing, truncated, oversized, or hash-mismatched files without creating a version."}
    deployments: *all
    status: behavior_verified
    depends_on: [PUB-001, MAN-002]
    evidence:
      - deployment: local
        tests: [PUB-003-B, PUB-003-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: PUB-004
    kind: behavior
    behavior: Verified files become immutable content-addressed blobs written without overwriting an existing blob.
    owner: blob-storage
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: PUB-004-B, description: "Publish identical file bytes from several versions and confirm that they resolve to the same immutable fingerprint object."}
      failure: {id: PUB-004-F, description: "A conflicting write to an existing fingerprint cannot replace or corrupt the stored bytes."}
    deployments: *all
    status: behavior_verified
    depends_on: [PUB-003]
    evidence:
      - deployment: local
        tests: [PUB-004-B, PUB-004-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: PUB-005
    kind: behavior
    behavior: One database transaction creates the version, manifest entries, idempotency result, action record, and conditional current-version update after blobs are durable.
    owner: publishing
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: PUB-005-B, description: "Commit a publish and observe all database records and the current pointer together after every blob exists."}
      failure: {id: PUB-005-F, description: "Inject failures before and during the transaction and confirm that no partial visible version or dangling current pointer exists."}
    deployments: *all
    status: specified
    depends_on: [PUB-004, MAN-001, AUD-001]
    evidence: []

  - id: PUB-006
    kind: behavior
    behavior: Retrying the same publish with the same idempotency key and input digest returns the original result.
    owner: publishing
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: PUB-006-B, description: "Lose the first response, retry with the same key and input, and receive the original artifact and version IDs."}
      failure: {id: PUB-006-F, description: "Reusing an idempotency key with different input is rejected and creates no new version."}
    deployments: *all
    status: behavior_verified
    depends_on: [PUB-005]
    evidence:
      - deployment: local
        tests: [PUB-006-B, PUB-006-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: PUB-007
    kind: behavior
    behavior: A new idempotency key creates a new version even when its canonical manifest matches an earlier version.
    owner: publishing
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: PUB-007-B, description: "Intentionally publish identical input with a new key and receive a distinct version ID and number."}
      failure: {id: PUB-007-F, description: "The intentional identical publish does not mutate or alias the earlier version record."}
    deployments: *all
    status: behavior_verified
    depends_on: [PUB-006]
    evidence:
      - deployment: local
        tests: [PUB-007-B]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: PUB-008
    kind: behavior
    behavior: A publish that changes the current pointer states the version it started from and conflicts if the pointer moved first.
    owner: publishing
    source: {file: artifact-server-product-spec.html, anchor: artifact}
    acceptance:
      behavior: {id: PUB-008-B, description: "Publish from the actual current version and atomically advance the pointer."}
      failure: {id: PUB-008-F, description: "Race two publishes from the same version and confirm that the loser reports the actual current version without overwriting it."}
    deployments: *all
    status: behavior_verified
    depends_on: [PUB-005]
    evidence:
      - deployment: local
        tests: [PUB-008-B, PUB-008-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: PUB-009
    kind: behavior
    behavior: The first release deletes expired uncommitted staging uploads but does not garbage-collect committed or orphaned blobs.
    owner: operations
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: PUB-009-B, description: "Expire abandoned staging records and confirm that their staging bytes are removed."}
      failure: {id: PUB-009-F, description: "Cleanup cannot delete a blob referenced by a committed version or one involved in a concurrent commit."}
    deployments: *all
    status: behavior_verified
    depends_on: [PUB-005]
    evidence:
      - deployment: local
        tests: [PUB-009-B]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"
      - deployment: cloudflare
        tests: [PUB-009-B]
        result: pass
        run: project/evidence/cloudflare-phase11-qualification.json
        recorded_at: "2026-08-16T17:44:26Z"
      - deployment: aws
        tests: [PUB-009-B]
        result: pass
        run: project/evidence/aws-phase11-qualification.json
        recorded_at: "2026-08-16T03:24:47Z"
      - deployment: gcp
        tests: [PUB-009-B]
        result: pass
        run: project/evidence/gcp-phase11-qualification.json
        recorded_at: "2026-08-16T14:36:48Z"

  - id: PUB-010
    kind: security
    behavior: A local publishing client may read a user-selected path with its operating-system permissions, rejects unsafe file types and paths, and immediately uploads bytes; HTTP and MCP never receive the client path.
    owner: publishing
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: PUB-010-B, description: "Publish a regular local file through the client and confirm that later source changes do not change the saved version."}
      failure: {id: PUB-010-F, description: "Reject symlinks, special files, forbidden manifest paths, and paths inaccessible to the client's operating-system identity before creating an upload."}
    deployments: [local, single_server]
    status: specified
    depends_on: [MAN-004, PUB-001]
    evidence: []

  - id: PUB-011
    kind: security
    behavior: A remote server accepts uploaded bytes and never accepts a client filesystem path or fetches an arbitrary source URL.
    owner: publishing
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: PUB-011-B, description: "Publish remote input only through a server-issued file-upload plan."}
      failure: {id: PUB-011-F, description: "Reject client paths and arbitrary URLs, including private-network and cloud-metadata targets."}
    deployments: *external_storage
    status: behavior_verified
    depends_on: [PUB-001]
    evidence:
      - deployment: single_server
        tests: [PUB-011-B, PUB-011-F]
        result: pass
        run: project/evidence/external-storage-runtime.json
        recorded_at: "2026-08-17T03:08:19.183Z"

  - id: PUB-012
    kind: security
    behavior: A file publishing client uses its own authenticated server profile and follows short-lived upload instructions without copying MCP credentials into the CLI; any temporary upload address is scoped to the declared upload and file and remains an internal redacted transfer detail.
    owner: publishing
    source: {file: phase-10-cli-auth-and-remote-publishing.md, anchor: publication-path}
    acceptance:
      behavior: {id: PUB-012-B, description: "Publish one file and one finished directory through a verified remote profile, reuse that profile after a server restart, and return browser links without exposing credentials or transfer details."}
      failure: {id: PUB-012-F, description: "Reject an invalid remote credential without saving a profile, reject an exact-origin mismatch before publication, and retain the profile when secure credential deletion cannot be completed."}
    deployments: *all
    status: behavior_verified
    depends_on: [PUB-001, PUB-002, PUB-003]
    evidence:
      - deployment: local
        tests: [PUB-012-B, PUB-012-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: PUB-013
    kind: behavior
    behavior: Every successful publication returns a durable exact-version review link, a stable current-version artifact link, and an immutable raw version link; MCP identifies the authenticated full-screen review link as the primary user handoff.
    owner: publishing
    source: {file: artifact-server-product-spec.html, anchor: experience}
    acceptance:
      behavior: {id: PUB-013-B, description: "Publish through HTTP, CLI, and MCP, receive the same three link roles, open the review URL directly in the exact version's full-screen Review, and observe MCP text and instructions leading with that review URL."}
      failure: {id: PUB-013-F, description: "A review URL cannot follow the moving current pointer, omit focus view, contain a bootstrap token or credential, replace the immutable raw URL, or leave an agent to infer which link to share first."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local HTTP, CLI, MCP, and browser checks pass. Equivalent publication and handoff evidence has not yet been recorded for every team deployment.
    depends_on: [PUB-002, VER-001, MCP-003]
    evidence:
      - deployment: local
        tests: [PUB-013-B, PUB-013-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-25T17:51:55.551Z"
      - deployment: local
        tests: [PUB-013-B, PUB-013-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-25T17:52:50.473Z"

  - id: CLI-001
    kind: security
    behavior: The Artifact Server CLI keeps profiles by exact server origin and account; remote interactive login uses browser authorization and operating-system credential storage, local mode uses private user-only state without visible secrets, and CI uses scoped service credentials from its secret manager.
    owner: cli
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: CLI-001-B, description: "Log in, inspect status, renew, log out, and switch exact-origin profiles on a browser-authorized server; use local automatic authentication and a CI service credential through their documented paths."}
      failure: {id: CLI-001-F, description: "Credentials never appear in startup output, command output, project files, shell arguments, logs, traces, support bundles, or another origin's profile, and revoked or mismatched credentials fail closed."}
    deployments: *all
    status: implementing
    proof_gap: The OAuth acceptance-ID test proves browser PKCE, refresh, status, and revocation, but not the local automatic-authentication and CI paths or every credential-leak surface named by CLI-001-F.
    depends_on: [AUTH-009, AUTH-017]
    evidence: []

  - id: CLI-002
    kind: behavior
    behavior: artifactserver publish accepts one local file or finished directory and completes validation, hashing, upload, safe retry, commit, and structured result as one user-visible operation through the same application services and authorization used by HTTP and MCP.
    owner: cli
    source: {file: phase-10-cli-auth-and-remote-publishing.md, anchor: publication-path}
    acceptance:
      behavior: {id: CLI-002-B, description: "Publish one file and one finished directory through a remote profile and receive structured project, artifact, exact version, and browser-link results."}
      failure: {id: CLI-002-F, description: "Invalid credentials, an exact-origin mismatch, and an unavailable credential store fail without saving an invalid profile, crossing server origins, deleting a recoverable profile, or exposing a secret."}
    deployments: *all
    status: behavior_verified
    depends_on: [PUB-002, PUB-006, PUB-008, PUB-010, PUB-012, CLI-001]
    evidence:
      - deployment: local
        tests: [CLI-002-B, CLI-002-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: CLI-003
    kind: behavior
    behavior: artifactserver publish persists one private operation identity before network mutation, reuses it after lost responses and process restarts, and reconciles the original commit result without creating a duplicate artifact or version.
    owner: cli
    source: {file: phase-10-cli-auth-and-remote-publishing.md, anchor: publication-path}
    acceptance:
      behavior: {id: CLI-003-B, description: "Commit a publication, lose the response, restart the CLI process, retry the same command, receive the replayed original result, and observe exactly one artifact and version."}
      failure: {id: CLI-003-F, description: "A changed input or target, corrupt pending record, concurrent operation, or different server cannot reuse or replace a pending identity and cannot create a duplicate while the earlier result is unresolved."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local real-process and real-HTTP proof covers a dropped commit response, restart recovery, changed-input refusal, and duplicate prevention. Equivalent recovery evidence is not yet attached for every team deployment.
    depends_on: [CLI-002, PUB-006, PUB-008]
    evidence:
      - deployment: local
        tests: [CLI-003-B, CLI-003-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-25T18:29:58.000Z"

  - id: AUD-001
    kind: security
    behavior: Every publish, restore, access change, connection change, and deletion records the responsible effective principal and human authorizer when present.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: AUD-001-B, description: "Perform every mutation, including comment creates, replies, edits, resolves, reopens, and deletes, through human and agent principals and inspect complete immutable action records."}
      failure: {id: AUD-001-F, description: "A mutation cannot commit without a valid actor and action record."}
    deployments: *all
    status: specified
    depends_on: []
    evidence: []

  - id: CNT-001
    kind: behavior
    behavior: HTML and complete client-side directories open in the browser without rebuilding their files.
    owner: content-delivery
    source: {file: artifact-server-product-spec.html, anchor: experience}
    acceptance:
      behavior: {id: CNT-001-B, description: "Open plain HTML, a multi-page site, and compiled React, Vue, and Svelte fixtures from their published entry files."}
      failure: {id: CNT-001-F, description: "No request starts a build, package installation, source transform, or artifact-specific server process."}
    deployments: *all
    status: specified
    depends_on: [ART-003, MAN-001]
    evidence: []

  - id: CNT-002
    kind: behavior
    behavior: Images and PDFs display through browser-native behavior; audio and video use browser playback; unknown, ZIP, and office files download safely; text-like files are served as text without a custom renderer.
    owner: content-delivery
    source: {file: artifact-server-product-spec.html, anchor: experience}
    acceptance:
      behavior: {id: CNT-002-B, description: "Exercise image, PDF, audio, video, text, Markdown, JSON, source, ZIP, office, and unknown-file fixtures and verify the declared native or download behavior."}
      failure: {id: CNT-002-F, description: "A misleading filename or media type cannot cause active content to be served with an unsafe disposition or sniffed type."}
    deployments: *all
    status: behavior_verified
    depends_on: [CNT-008]
    evidence:
      - deployment: local
        tests: [CNT-002-B, CNT-002-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: CNT-003
    kind: security
    behavior: The application origin and published content use separate registrable domains on hosted and external-storage deployments.
    owner: content-delivery
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: CNT-003-B, description: "Confirm that application and content origins have different registrable domains and cookies do not cross the boundary."}
      failure: {id: CNT-003-F, description: "Deployment validation rejects an external-storage domain configuration that would make artifact JavaScript same-site with the application."}
    deployments: *external_storage
    status: specified
    depends_on: []
    evidence: []

  - id: CNT-004
    kind: security
    behavior: Every saved version has its own immutable content origin, including an isolated localhost hostname in local mode.
    owner: content-delivery
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: CNT-004-B, description: "Publish two versions and confirm that they receive different origins and continue serving their exact files."}
      failure: {id: CNT-004-F, description: "One version cannot read origin storage, cookies, caches, or service-worker control belonging to another version or the application."}
    deployments: *all
    status: specified
    depends_on: [ART-004]
    evidence: []

  - id: CNT-005
    kind: behavior
    behavior: Root-relative URLs remain inside the exact version origin.
    owner: content-delivery
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: CNT-005-B, description: "Open a site whose HTML, CSS, and JavaScript use root-relative assets and confirm that every request resolves within that version."}
      failure: {id: CNT-005-F, description: "A root-relative asset cannot resolve against the application origin, another version, or another artifact."}
    deployments: *all
    status: behavior_verified
    depends_on: [CNT-004]
    evidence:
      - deployment: local
        tests: [CNT-005-B]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: CNT-006
    kind: security
    behavior: A service worker installed by one version cannot control another version or the application.
    owner: content-delivery
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: CNT-006-B, description: "Install a service worker in one fixture version and confirm that its scope is limited to that version origin."}
      failure: {id: CNT-006-F, description: "Attempts to register a scope for the application or another version do not gain control."}
    deployments: *all
    status: specified
    depends_on: [CNT-004]
    evidence: []

  - id: CNT-007
    kind: behavior
    behavior: Static routing returns 404 for a missing path; SPA routing returns the entry HTML only for a missing browser navigation while missing assets still return 404.
    owner: content-delivery
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: CNT-007-B, description: "Run static and SPA fixtures through navigation and missing-asset cases and observe the declared routing."}
      failure: {id: CNT-007-F, description: "Missing JavaScript, stylesheets, images, fonts, and data never receive the SPA entry HTML."}
    deployments: *all
    status: behavior_verified
    depends_on: [MAN-001]
    evidence:
      - deployment: local
        tests: [CNT-007-B, CNT-007-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"
      - deployment: aws
        tests: [CNT-007-B, CNT-007-F]
        result: pass
        run: project/evidence/aws-phase11-qualification.json
        recorded_at: "2026-08-16T03:24:47Z"
      - deployment: gcp
        tests: [CNT-007-B, CNT-007-F]
        result: pass
        run: project/evidence/gcp-phase11-qualification.json
        recorded_at: "2026-08-16T14:36:48Z"
      - deployment: cloudflare
        tests: [CNT-007-B, CNT-007-F]
        result: pass
        run: project/evidence/cloudflare-phase11-content.json
        recorded_at: "2026-08-16T17:44:26.049Z"

  - id: CNT-008
    kind: security
    behavior: Published responses use explicit media type, X-Content-Type-Options nosniff, stable ETag, safe Content-Disposition, GET and HEAD semantics, and byte ranges where applicable.
    owner: content-delivery
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: CNT-008-B, description: "Verify headers, conditional requests, HEAD, and media range requests for the content fixture suite."}
      failure: {id: CNT-008-F, description: "Unsupported methods, malformed ranges, misleading extensions, and active unknown files do not bypass safe serving rules."}
    deployments: *all
    status: implementing
    proof_gap: The acceptance-ID and live-cloud probes prove range, conditional, and HEAD behavior, but they do not cover the complete content fixture's media type, nosniff, disposition, unsupported-method, misleading-extension, and active-unknown-file matrix.
    depends_on: [MAN-002]
    evidence: []

  - id: CNT-009
    kind: constraint
    behavior: Artifact Server does not copy or rewrite scripts, styles, fonts, images, or data loaded by a published site from other origins; normal browser and network rules apply.
    owner: content-delivery
    source: {file: artifact-server-product-spec.html, anchor: experience}
    acceptance:
      behavior: {id: CNT-009-B, description: "Load a permitted external dependency from the artifact origin without changing its URL or bytes."}
      failure: {id: CNT-009-F, description: "A blocked external dependency remains blocked and is not silently proxied or copied by Artifact Server."}
    deployments: *all
    status: specified
    depends_on: []
    evidence: []

  - id: VER-001
    kind: behavior
    behavior: Each intentional publish creates a new immutable version, the stable artifact link opens the current version, and an exact version link never changes.
    owner: artifact-core
    source: {file: artifact-server-product-spec.html, anchor: experience}
    acceptance:
      behavior: {id: VER-001-B, description: "Publish two versions and confirm current-link movement, fixed exact-version links, and unmodified earlier bytes."}
      failure: {id: VER-001-F, description: "Current-link changes cannot alter an exact version's origin, manifest, or files."}
    deployments: *all
    status: behavior_verified
    depends_on: [ART-001, ART-004, CNT-004]
    evidence:
      - deployment: local
        tests: [VER-001-B, VER-001-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: DIF-001
    kind: behavior
    behavior: Comparisons use canonical manifests and do not require Git.
    owner: comparison
    source: {file: artifact-server-product-spec.html, anchor: experience}
    acceptance:
      behavior: {id: DIF-001-B, description: "Disable Git and compare two versions from primary records and blobs."}
      failure: {id: DIF-001-F, description: "A missing or failed Git provider does not remove, change, or block comparison results."}
    deployments: *all
    status: behavior_verified
    depends_on: [MAN-001, VER-001]
    evidence:
      - deployment: local
        tests: [DIF-001-B]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: DIF-002
    kind: behavior
    behavior: Manifest comparison reports files added, removed, and changed by normalized path.
    owner: comparison
    source: {file: artifact-server-product-spec.html, anchor: experience}
    acceptance:
      behavior: {id: DIF-002-B, description: "Compare a fixture containing one added, one removed, one unchanged, and one changed file and verify the result."}
      failure: {id: DIF-002-F, description: "Path encoding and normalization differences cannot hide or invent file changes."}
    deployments: *all
    status: behavior_verified
    depends_on: [DIF-001]
    evidence:
      - deployment: local
        tests: [DIF-002-B, DIF-002-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: DIF-003
    kind: behavior
    behavior: A rename is reported only when one removed path and one added path have the same fingerprint.
    owner: comparison
    source: {file: artifact-server-product-spec.html, anchor: experience}
    acceptance:
      behavior: {id: DIF-003-B, description: "Move unchanged bytes to a new path and report the change as a rename."}
      failure: {id: DIF-003-F, description: "Changed bytes or ambiguous same-fingerprint candidates are not reported as a certain rename."}
    deployments: *all
    status: behavior_verified
    depends_on: [DIF-002]
    evidence:
      - deployment: local
        tests: [DIF-003-B, DIF-003-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: DIF-004
    kind: behavior
    behavior: Bounded text files receive a line comparison; binary files report old and new size and fingerprint with links to both exact versions.
    owner: comparison
    source: {file: artifact-server-product-spec.html, anchor: experience}
    acceptance:
      behavior: {id: DIF-004-B, description: "Compare bounded text and representative binary fixtures and verify their different result shapes."}
      failure: {id: DIF-004-F, description: "Oversized, invalidly encoded, or binary input cannot exhaust the text-diff path or be misrepresented as a text diff."}
    deployments: *all
    status: behavior_verified
    depends_on: [DIF-002, CNT-008]
    evidence:
      - deployment: local
        tests: [DIF-004-B, DIF-004-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: DIF-005
    kind: exclusion
    behavior: The first release has no specialized image, PDF, audio, video, or archive comparison engine.
    owner: comparison
    source: {file: artifact-server-product-spec.html, anchor: scope}
    acceptance:
      behavior: {id: DIF-005-B, description: "Binary comparison returns metadata and exact-version links only."}
      failure: {id: DIF-005-F, description: "No interface claims or invokes specialized binary analysis or conversion."}
    deployments: *all
    status: behavior_verified
    depends_on: [DIF-004]
    evidence:
      - deployment: local
        tests: [DIF-005-B, DIF-005-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: GIT-001
    kind: constraint
    behavior: Git handoff is optional, private, disabled by default, and selected by explicit installation configuration; there is no automatic provider selection.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: experience}
    acceptance:
      behavior: {id: GIT-001-B, description: "Run with the provider variable absent and set to off; observe the disabled capability shape, identical artifact behavior, and no Git implementation load or provider request."}
      failure: {id: GIT-001-F, description: "Missing, invalid, or inaccessible optional Git configuration cannot prevent the server from starting, publishing, opening, or comparing, and cannot trigger automatic provider selection."}
    deployments: *all
    status: implementing
    proof_gap: Provider-off behavior, explicit configuration, and fail-open application startup are implemented for Node and Workers runtimes. The complete no-load/no-call and malformed-configuration acceptance matrix across every deployment remains unproved.
    depends_on: [DIF-001]
    evidence: []

  - id: GIT-002
    kind: behavior
    behavior: Optional Git receives an asynchronous private copy only after the primary version is durable, with at most one commit mapped to each saved version.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: GIT-002-B, description: "Publish with Git enabled and confirm the browser link works before or independently of the recorded Git commit."}
      failure: {id: GIT-002-F, description: "Retry and worker failures cannot create conflicting version-to-commit mappings or change the primary version."}
    deployments: *all
    status: implementing
    proof_gap: SQLite, Postgres, and D1 atomically enqueue provider-neutral mirror jobs after primary publication, and deterministic mapping adoption prevents duplicate version commits across retries and restarts. Concurrent multi-worker convergence and the complete cross-deployment persistence matrix remain unproved.
    depends_on: [PUB-005]
    evidence: []

  - id: GIT-003
    kind: behavior
    behavior: Git failure never blocks, deletes, or makes unavailable a primary saved version and is retried separately.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GIT-003-B, description: "Disable the configured Git provider during publish and confirm the version opens and the copy can retry later."}
      failure: {id: GIT-003-F, description: "Git errors cannot roll back or corrupt the committed database and blob records."}
    deployments: *all
    status: implementing
    proof_gap: Provider failures and logical budget exhaustion are isolated from primary publication and delivery, with durable retry and restart recovery proved on the local runtime. Sustained outage, database rollback, and all-deployment hostile recovery remain unproved.
    depends_on: [GIT-002]
    evidence: []

  - id: GIT-004
    kind: behavior
    behavior: Files outside deterministic per-file and per-version copy limits remain only in primary blob storage while the Git manifest records their paths, media types, sizes, and fingerprints; each job snapshots the limits that define its retry-stable commit.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: GIT-004-B, description: "Publish above and below the configured per-file and per-version Git copy limits and verify deterministic copied-file and pointer representation across a retry and configuration change."}
      failure: {id: GIT-004-F, description: "Excluded bytes cannot be silently omitted without path, media type, size, and fingerprint metadata, and a retry cannot change a commit because current limits differ from the job snapshot."}
    deployments: *all
    status: implementing
    proof_gap: Mirror jobs snapshot copy limits, produce deterministic copied files and pointer metadata, and preserve the representation across a retry. Configuration changes after enqueue, maximum manifest size, and full adapter coverage remain unproved.
    depends_on: [GIT-002]
    evidence: []

  - id: GIT-005
    kind: security
    behavior: Public artifact access never grants Git access or exposes earlier versions through a Git remote.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: GIT-005-B, description: "Make an artifact public and confirm that only its current content path is available without authentication."}
      failure: {id: GIT-005-F, description: "Probe Git protocols, repository paths, commit IDs, and earlier versions from a public session and receive no access."}
    deployments: *all
    status: implementing
    proof_gap: Authenticated, short-lived clone credentials are scoped to one provisioned repository and public-link sessions are rejected. The complete Git-protocol, timing, log-redaction, and earlier-version probe matrix remains unproved.
    depends_on: [GIT-001, AUTH-004]
    evidence: []

  - id: GIT-006
    kind: deployment
    behavior: The first managed Git handoff provider is Cloudflare Artifacts; additional provider names are not accepted or advertised until their adapters independently pass the common provider suite.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: GIT-006-B, description: "Run the Git provider conformance suite against every advertised provider for its deployment."}
      failure: {id: GIT-006-F, description: "A deployment cannot advertise optional Git until its provider passes persistence, retry, upgrade, backup, and isolation tests."}
    deployments: *all
    status: implementing
    proof_gap: Cloudflare Artifacts is the only accepted provider. The Node REST product path passed live availability, estimate, project enablement, backfill, two-version mirroring, read-only clone, disablement, artifact deletion, and cleanup; the remote Workers-binding path passed isolated live creation, deterministic commit, token, smart-HTTP, read, and cleanup qualification. Upgrade, backup, and the complete common provider suite remain unproved.
    depends_on: [GIT-003]
    evidence: []

  - id: GIT-007
    kind: release_gate
    behavior: Cloudflare Artifacts ships only as an explicit off-by-default provider and remains non-authoritative while availability, pricing, limits, retry behavior, retention, regional behavior, Git compatibility, and production support are verified.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GIT-007-B, description: "Record verified Cloudflare Artifacts behavior and pass the optional Git provider suite without making it authoritative."}
      failure: {id: GIT-007-F, description: "Every deployment remains complete and supported with Cloudflare Artifacts disabled or unavailable."}
    deployments: *all
    status: implementing
    proof_gap: The provider remains explicit, private, off by default, and non-authoritative; checked-in evidence records successful isolated REST, Workers-binding, and bounded product-lifecycle qualification. Pricing, quota pressure, retention, regional behavior, sustained outage recovery, and Cloudflare production-support posture remain operator considerations rather than fully proved release evidence.
    depends_on: [GIT-006]
    evidence: []

  - id: GIT-008
    kind: behavior
    behavior: Enabling Git handoff for a project with existing versions asynchronously backfills every unmapped version in that project in bounded, resumable, oldest-first order per artifact without delaying primary traffic or copying another project.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: GIT-008-B, description: "Enable one project after several versions exist and observe complete ordered repository history while new publishes continue and an unselected project remains untouched."}
      failure: {id: GIT-008-F, description: "Crash and restart project reconciliation and race it with a new publish without losing a version, duplicating a commit mapping, exhausting foreground work, copying another project, or changing primary data."}
    deployments: *all
    status: implementing
    proof_gap: Project enablement inserts bounded oldest-first jobs for existing versions, leaves other projects untouched, and resumes a failed mirror after restart without a duplicate mapping. Crash timing, foreground-work bounds, and complete SQLite/Postgres/D1 concurrency coverage remain unproved.
    depends_on: [GIT-002, GIT-007]
    evidence: []

  - id: GIT-009
    kind: behavior
    behavior: Disabling Git handoff for a project or provider stops applicable mirror work without deleting remote data or durable state; deletion work stays durable, re-enabling the same project and provider resumes, and changing provider location requires an explicit migration.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: GIT-009-B, description: "Disable one project during backfill and the provider while idle, publish and delete while off, verify applicable calls stop and durable state remains, then re-enable the same project and provider and complete missing mirror and deletion work without duplicate commits."}
      failure: {id: GIT-009-F, description: "A policy or configuration change cannot silently delete remote repositories, discard queued deletion work, or write persisted coordinates through a different provider, account, or namespace; an unsupported replacement reports migration-required while core behavior continues."}
    deployments: *all
    status: implementing
    proof_gap: Project disablement preserves repositories and durable mappings, same-provider re-enable resumes work, artifact deletion queues repository deletion, and provider identity changes fail as migration-required. Provider-wide disablement during deletion and the complete cross-deployment lifecycle matrix remain unproved.
    depends_on: [GIT-008]
    evidence: []

  - id: GIT-010
    kind: behavior
    behavior: Authenticated capability discovery separately reports provider availability, bounded limits and accounting, and each project's effective Git state without secrets, and optional Git health never controls application readiness.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: GIT-010-B, description: "Observe provider disabled, checking, available, degraded, misconfigured, and migration-required plus project disabled, waiting, backfilling, ready, degraded, and budget-limited through HTTP and MCP discovery with matching shapes."}
      failure: {id: GIT-010-F, description: "Provider credentials, credential-bearing remotes, queue internals, or raw provider errors cannot appear in capability output, and no optional Git state can make readiness fail."}
    deployments: *all
    status: implementing
    proof_gap: Node and Workers runtimes expose secret-free provider and project states through authenticated HTTP and MCP without joining readiness; SQLite, Postgres, and D1 persist provider identity, and both Cloudflare control planes passed live qualification. The complete state-transition, redaction, and cross-deployment readiness matrix remains unproved.
    depends_on: [GIT-001, GIT-003]
    evidence: []

  - id: GIT-011
    kind: security
    behavior: Permanent removal of an installation's Git repositories requires an operator-only plan/apply command with exact installation confirmation; it is bounded and resumable and cannot delete primary data or the provider namespace.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: GIT-011-B, description: "Plan with no provider writes, apply with exact installation confirmation, interrupt the purge, and resume until every persisted repository is confirmed absent."}
      failure: {id: GIT-011-F, description: "Reject a wrong confirmation or mismatched provider, never expose a purge through HTTP or MCP, and never delete primary artifacts, versions, blobs, backups, or the Cloudflare namespace."}
    deployments: *all
    status: implementing
    proof_gap: Compact and external-storage operator commands provide read-only plans, exact installation and provider confirmation, bounded resumable deletion, and focused proof that planning makes no provider call and a partial purge resumes. The transient D1 operator path is typechecked but has not run against a dedicated live qualification database, and complete primary-data and backup invariance remain unproved.
    depends_on: [GIT-006, GIT-009]
    evidence: []

  - id: GIT-012
    kind: behavior
    behavior: Provider availability and data selection are separate; configuration alone creates no repository or history job, every project has one off-by-default Git history setting, and an authorized project manager may enable one project only after reviewing and confirming an on-demand planning estimate.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: GIT-012-B, description: "Configure Cloudflare Artifacts with existing projects and observe zero copies, then read, estimate, enable, repeat, and disable one project through authorized, naturally idempotent HTTP and MCP operations with matching results while another and every newly created project remain disabled."}
      failure: {id: GIT-012-F, description: "A missing estimate confirmation, unconfigured or invalid provider, unauthorized caller, project request, path, hostname, or ambient credential cannot enable a project or change another project's setting."}
    deployments: *all
    status: implementing
    proof_gap: The real project setting, estimate confirmation, repository mirroring, and disablement are implemented through the Projects UI, authenticated HTTP, and MCP over SQLite, Postgres, and D1. The complete authorization, natural-idempotency, hostile-input, and cross-deployment parity matrix remains unproved.
    depends_on: [GIT-001, GIT-008, AUTH-001, PRD-004, MCP-008, MCP-009]
    evidence: []

  - id: GIT-013
    kind: security
    behavior: Each Artifact Server installation environment uses one exclusive persisted Cloudflare account and namespace identity; the adapter is namespace-scoped, exposes no namespace or account-wide deletion, and live tests use a dedicated bounded run-manifest cleanup boundary.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: GIT-013-B, description: "Run the bounded Node REST and remote Workers-binding suites in an artifact-server-test- namespace with unique run-prefixed repositories, a separate token, explicit opt-in, and resumable manifest-only cleanup."}
      failure: {id: GIT-013-F, description: "A request-selected namespace, changed persisted location, wrong namespace prefix, missing opt-in, exceeded test bound, failed teardown, or cleanup manifest cannot cause writes or deletion in another namespace, another run, or the account at large."}
    deployments: *all
    status: implementing
    proof_gap: SQLite, Postgres, and D1 persist immutable provider identity; both provider adapters are namespace scoped; and bounded REST and Workers-binding runs used unique repository prefixes and left the dedicated qualification namespace empty without deleting it. Wrong-prefix refusal, interrupted live cleanup recovery, and the complete isolation matrix remain unproved.
    depends_on: [GIT-006, GIT-009, GIT-011]
    evidence: []

  - id: GIT-014
    kind: constraint
    behavior: Git handoff shows an on-demand planning estimate of repository, version, operation, copied-byte, and pointer-byte impact before project enablement; deterministic copy limits and an optional atomically reserved logical copied-byte budget bound provider work without changing primary behavior.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: GIT-014-B, description: "Confirm a current-inventory planning estimate labeled as non-billing guidance, race mirror workers at the configured budget, observe no overshoot and budget-limited, then increase capacity or delete repositories and resume."}
      failure: {id: GIT-014-F, description: "Concurrent workers, retries, a lowered budget, provider pricing drift, or a hard provider limit cannot silently exceed configured logical capacity, rewrite mapped commits, block readiness, or change a saved primary version."}
    deployments: *all
    status: implementing
    proof_gap: SQLite, Postgres, and D1 compute planning estimates, snapshot deterministic copy bounds, atomically reserve logical copied bytes, expose budget-limited, and can resume after an explicit budget increase. Multi-worker race proof, lowered-budget behavior, provider-pricing drift, and complete deployment coverage remain unproved.
    depends_on: [GIT-004, GIT-012]
    evidence: []

  - id: AUTH-001
    kind: behavior
    behavior: A standalone installation represents one person, team, or company and has no public self-sign-up or organization switcher; all projects use that installation membership group.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: sharing}
    acceptance:
      behavior: {id: AUTH-001-B, description: "Admit users through installation administration and confirm that each belongs to the one installation group."}
      failure: {id: AUTH-001-F, description: "An unaffiliated user cannot self-register, discover another organization, or switch the installation context."}
    deployments: *all
    status: behavior_verified
    depends_on: []
    evidence:
      - deployment: local
        tests: [AUTH-001-B, AUTH-001-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: AUTH-002
    kind: behavior
    behavior: Account required is the default read setting and permits every admitted standalone installation member to read the artifact.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: sharing}
    acceptance:
      behavior: {id: AUTH-002-B, description: "Create an artifact and confirm that admitted members can read it while unauthenticated and outside users cannot."}
      failure: {id: AUTH-002-F, description: "An account-required link, asset, or exact-version address cannot be read without an authorized content session."}
    deployments: *all
    status: behavior_verified
    depends_on: [AUTH-001]
    evidence:
      - deployment: local
        tests: [AUTH-002-B, AUTH-002-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: AUTH-003
    kind: behavior
    behavior: Public link removes sign-in only for people who can reach the server and have the unpredictable link; it does not create a tunnel or alter network reachability.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: sharing}
    acceptance:
      behavior: {id: AUTH-003-B, description: "Open a public current-version link without an account from a network that can reach the installation."}
      failure: {id: AUTH-003-F, description: "Enabling a public link does not open firewall rules, create a tunnel, expose an unreachable server, or make the link enumerable."}
    deployments: *all
    status: specified
    depends_on: [CNT-004]
    evidence: []

  - id: AUTH-004
    kind: security
    behavior: A public link opens only the current version; version lists, comparisons, earlier versions, mutations, and Git remain account-required.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: sharing}
    acceptance:
      behavior: {id: AUTH-004-B, description: "Open the public current version and confirm that no authenticated history or mutation surface is exposed."}
      failure: {id: AUTH-004-F, description: "Probe earlier version hosts, comparison endpoints, mutation routes, and Git using only public access and receive no access."}
    deployments: *all
    status: behavior_verified
    depends_on: [AUTH-003]
    evidence:
      - deployment: local
        tests: [AUTH-004-B]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: AUTH-005
    kind: behavior
    behavior: Public links are unlisted and send X-Robots-Tag noindex, nofollow, but the product states that these are not access control and links can be redistributed.
    owner: web-application
    source: {file: artifact-server-product-spec.html, anchor: sharing}
    acceptance:
      behavior: {id: AUTH-005-B, description: "Inspect a public response and the visibility UI for the indexing header and redistribution warning."}
      failure: {id: AUTH-005-F, description: "No product copy or authorization check treats robots directives or URL secrecy as a security boundary."}
    deployments: *all
    status: specified
    depends_on: [AUTH-003]
    evidence: []

  - id: AUTH-006
    kind: behavior
    behavior: Administrators can disable public links for an installation.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: sharing}
    acceptance:
      behavior: {id: AUTH-006-B, description: "Disable public links and confirm that new and existing artifacts cannot be made or remain publicly readable under server policy."}
      failure: {id: AUTH-006-F, description: "Members, agents, API keys, and Plannotator cannot bypass the administrator's public-link policy."}
    deployments: *all
    status: specified
    depends_on: [AUTH-003]
    evidence: []

  - id: AUTH-007
    kind: behavior
    behavior: Changing public content to account required stops new public origin requests, purges supported caches, and warns that downloaded or externally cached copies cannot be recalled.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: AUTH-007-B, description: "Change a public artifact to account required and verify origin denial, configured purge, and the product warning."}
      failure: {id: AUTH-007-F, description: "A stale public cache key cannot obtain a fresh origin response after the change, and the interface never promises recall of external copies."}
    deployments: *all
    status: specified
    depends_on: [AUTH-003]
    evidence: []

  - id: AUTH-008
    kind: security
    behavior: Every admitted human member can manage artifacts in the installation's projects; service principals act only within explicit capabilities.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: sharing}
    acceptance:
      behavior: {id: AUTH-008-B, description: "Confirm that admitted human members can read, publish, restore, change visibility, tag, and delete project artifacts."}
      failure: {id: AUTH-008-F, description: "Reject service principals that lack the explicit capability required for the requested read or mutation."}
    deployments: *all
    status: behavior_verified
    depends_on: [AUTH-001]
    evidence:
      - deployment: local
        tests: [AUTH-008-B, AUTH-008-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: AUTH-009
    kind: security
    behavior: An API key belongs to one named user or service principal and installation, has explicit capabilities, expiration, rotation, and revocation, and never falls through to another credential parser.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: AUTH-009-B, description: "Issue, constrain, rotate, expire, and revoke human and service API keys; rotation preserves the effective principal and original authorizer while replacing only the credential."}
      failure: {id: AUTH-009-F, description: "Cross-installation, over-scoped, expired, revoked, replaced, malformed, and JWT-like API keys are rejected without parser confusion."}
    deployments: *external_storage
    status: behavior_verified
    depends_on: [AUTH-008]
    evidence:
      - deployment: single_server
        tests: [AUTH-009-B, AUTH-009-F]
        result: pass
        run: project/evidence/external-storage-runtime.json
        recorded_at: "2026-08-27T05:26:19.095Z"

  - id: AUTH-010
    kind: security
    behavior: Application cookies are host-only and never scoped to the content domain.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: AUTH-010-B, description: "Sign in and confirm that application cookies are sent only to the application host."}
      failure: {id: AUTH-010-F, description: "Artifact origins, sibling versions, and content JavaScript cannot receive or read an application cookie."}
    deployments: *all
    status: behavior_verified
    depends_on: [CNT-003, CNT-004]
    evidence:
      - deployment: local
        tests: [AUTH-010-B, AUTH-010-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: AUTH-011
    kind: security
    behavior: Cookie-authenticated application mutations require CSRF protection, trusted Origin, and valid Fetch Metadata and reject content origins.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: AUTH-011-B, description: "Submit a valid same-origin mutation with the required CSRF and Fetch Metadata signals."}
      failure: {id: AUTH-011-F, description: "Reject cross-origin forms, fetches, frames, missing or stale CSRF tokens, hostile origins, and invalid Fetch Metadata."}
    deployments: *all
    status: behavior_verified
    depends_on: [AUTH-010]
    evidence:
      - deployment: local
        tests: [AUTH-011-B, AUTH-011-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: AUTH-012
    kind: security
    behavior: The application grants no credentialed CORS access to content origins.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: AUTH-012-B, description: "Confirm that documented public API CORS behavior does not include artifact content credentials."}
      failure: {id: AUTH-012-F, description: "Preflight and direct credentialed requests from every artifact origin fail closed."}
    deployments: *all
    status: behavior_verified
    depends_on: [CNT-004]
    evidence:
      - deployment: local
        tests: [AUTH-012-B, AUTH-012-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: AUTH-013
    kind: security
    behavior: OAuth callbacks, browser login, MCP authorization, artifact metadata, and mutations remain on the application origin; version origins are read-only.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: AUTH-013-B, description: "Enumerate application and content routes and confirm the required separation."}
      failure: {id: AUTH-013-F, description: "No content host exposes login callback, OAuth, metadata mutation, administration, or MCP endpoints."}
    deployments: *all
    status: specified
    depends_on: [CNT-003, CNT-004]
    evidence: []

  - id: AUTH-014
    kind: security
    behavior: Opening account-required content uses a short-lived, single-use bootstrap token bound to one viewer, artifact, version, and content hostname.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: AUTH-014-B, description: "Authorize one exact version and exchange its bootstrap token once on the bound content host."}
      failure: {id: AUTH-014-F, description: "Reject replay, expiry, another viewer, another version, another host, tampering, and use before application authorization."}
    deployments: *all
    status: behavior_verified
    depends_on: [AUTH-002, CNT-004]
    evidence:
      - deployment: local
        tests: [AUTH-014-B]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: AUTH-015
    kind: security
    behavior: The bootstrap exchange creates a HttpOnly, host-only, read-only content session valid only for GET and HEAD on one immutable version origin. HTTPS origins require Secure; loopback HTTP uses the browser-compatible host-only exception.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: AUTH-015-B, description: "Load account-required HTML and all relative assets through the clean URL using the version-scoped content session."}
      failure: {id: AUTH-015-F, description: "The session cannot write, access another version, survive beyond expiry, cross hosts, or expose its value to artifact JavaScript."}
    deployments: *all
    status: behavior_verified
    depends_on: [AUTH-014]
    evidence:
      - deployment: local
        tests: [AUTH-015-B, AUTH-015-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: AUTH-016
    kind: security
    behavior: Account-required content is not stored in a shared CDN cache; the current public version may use immutable CDN caching.
    owner: content-delivery
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: AUTH-016-B, description: "Inspect cache behavior for private and public fixtures and observe private no-store or private handling and immutable public keys."}
      failure: {id: AUTH-016-F, description: "An unauthenticated viewer cannot receive private bytes from a shared cache populated by another viewer."}
    deployments: *external_storage
    status: specified
    depends_on: [AUTH-015]
    evidence: []

  - id: AUTH-017
    kind: security
    behavior: The installed identity is derived from trusted authentication and routing; untrusted request input cannot select a tenant or storage boundary.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: AUTH-017-B, description: "Authenticate each installation and confirm that database, blob, cache, job, backup, and restore operations receive its trusted scope."}
      failure: {id: AUTH-017-F, description: "Header, query, body, path, token, cache-key, and job-payload tampering cannot select another installation."}
    deployments: *replicated
    status: specified
    depends_on: []
    evidence: []

  - id: AUTH-018
    kind: security
    behavior: Installation administrators can page through every active public-link artifact across all projects and make one bounded selection account-required through the normal optimistic, idempotent, audited visibility operation with explicit partial-failure retry.
    owner: web-application
    source: {file: artifact-server-product-spec.html, anchor: sharing}
    acceptance:
      behavior: {id: AUTH-018-B, description: "Page across projects, inspect project, artifact, current-version and public-URL context, make one or up to 100 selected links private, retry stale items, and observe one normal visibility action per successful item plus denial of new public origin bytes."}
      failure: {id: AUTH-018-F, description: "Deny non-administrators and oversized or duplicate bulk requests, preserve per-item stale-version protection, report partial failures without rolling back successful items, and never promise recall of downloaded or external cached copies."}
    deployments: *all
    status: behavior_verified
    depends_on: [AUTH-007, AUTH-008, AUD-001]
    evidence:
      - deployment: local
        tests: [AUTH-018-B, AUTH-018-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:20:00Z"

  - id: AUTH-019
    kind: behavior
    behavior: A deployment configured with a generic OIDC issuer completes browser login through discovery, authorization code with PKCE and nonce, id_token verification, and normal admission, on every deployment kind.
    owner: authorization
    source: {file: oidc-interactive-login-spec.md, anchor: conformance}
    acceptance:
      behavior: {id: AUTH-019-B, description: "Sign in against a real stub OIDC provider; an admitted member gets a session, the bootstrap administrator is admitted on first contact, display name and issuer-qualified binding are recorded, and a second login reuses the binding."}
      failure: {id: AUTH-019-F, description: "An unadmitted verified identity, an unverified email, and a missing email are refused without creating members or sessions."}
    deployments: *all
    status: behavior_verified
    depends_on: [AUTH-001, AUTH-010]
    evidence:
      - deployment: local
        tests: [AUTH-019-B, AUTH-019-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T15:31:35.706Z"

  - id: AUTH-020
    kind: security
    behavior: The OIDC callback fails closed on every token-validation defect.
    owner: authorization
    source: {file: oidc-interactive-login-spec.md, anchor: conformance}
    acceptance:
      behavior: {id: AUTH-020-B, description: "Valid logins succeed under a thirty-second clock skew, and a returnTo that only becomes scheme-relative after path normalization still lands on an application path."}
      failure: {id: AUTH-020-F, description: "Wrong signature, wrong issuer, wrong audience, expired token, replayed or unknown state, expired attempt, wrong nonce, and a callback presented without the handshake cookie minted at /auth/login are each refused; no session or member is created; codes and tokens never appear in logs."}
    deployments: *all
    status: behavior_verified
    depends_on: [AUTH-019]
    evidence:
      - deployment: local
        tests: [AUTH-020-B, AUTH-020-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T15:31:35.706Z"

  - id: AUTH-021
    kind: constraint
    behavior: OIDC configuration is all-or-nothing, mutually exclusive with WorkOS, and issuer and endpoint URLs obey the HTTPS rules.
    owner: authorization
    source: {file: oidc-interactive-login-spec.md, anchor: conformance}
    acceptance:
      behavior: {id: AUTH-021-B, description: "A complete OIDC configuration boots and reports the oidc interactive identity provider; an application layer constructed without either provider keeps interactive login unavailable, while private-team process startup separately obeys AUTH-025."}
      failure: {id: AUTH-021-F, description: "Partial OIDC configuration, any WorkOS variable configured beside any OIDC variable, a non-HTTPS non-local issuer, and discovery documents with a mismatched issuer or a credentialed or fragmented endpoint URL each fail startup or login without weakening the running server."}
    deployments: *all
    status: behavior_verified
    depends_on: [AUTH-019]
    evidence:
      - deployment: local
        tests: [AUTH-021-B, AUTH-021-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T15:31:35.706Z"

  - id: AUTH-022
    kind: constraint
    behavior: In-process authentication caching is a bounded-staleness optimization only; successful session and managed-key checks may be cached for at most 30 seconds in a bounded store, entries never outlive the credential's own expiry, failures are never cached, and same-process logout, key revocation, key rotation, and member deactivation evict immediately, so a credential revoked on another replica authenticates for at most 30 more seconds.
    owner: authorization
    source: {file: decisions/0004-installation-identity-and-login.md, anchor: consequences}
    acceptance:
      behavior: {id: AUTH-022-B, description: "Warm a session check, revoke the session directly in shared storage as another replica would, observe the warmed check keep succeeding inside the 30-second bound, observe refusal once the bound passes, and observe same-process logout refuse immediately without waiting out the bound."}
      failure: {id: AUTH-022-F, description: "A warmed session check cannot outlive the session's absolute expiry inside the cache window, and a session refused by storage is not cached and stays refused."}
    deployments: *all
    status: behavior_verified
    depends_on: [AUTH-008]
    evidence:
      - deployment: local
        tests: [AUTH-022-B, AUTH-022-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-23T23:32:33Z"

  - id: AUTH-023
    kind: behavior
    behavior: A fresh browser profile on a direct local installation establishes a normal application session for the stable local administrator without a sign-in step, copied credential, or credential-bearing URL.
    owner: authorization
    source: {file: local-owner-and-private-team-access-spec.md, anchor: conformance-requirements}
    acceptance:
      behavior: {id: AUTH-023-B, description: "Open the compiled application and the Vite development origin in separate fresh browser profiles, receive separate normal sessions for the same stable local administrator, and recover once after cookie clearing and session expiry without showing sign-in."}
      failure: {id: AUTH-023-F, description: "Local bootstrap never exposes a session, browser-bootstrap credential, or development-proxy credential in a URL, history entry, Referrer header, browser storage, startup output, log, trace, support manifest, or diagnostic response."}
    deployments: [local]
    status: implementing
    proof_gap: The local HTTP acceptance test proves stable same-owner sessions, cookie-only authority, recovery, and the absence of credentials in the exchange response, while the browser suite proves a fresh compiled application session and cookie-clearing recovery. A separately recorded Vite-origin fresh-profile run and the complete URL, history, referrer, startup-output, log, trace, support-manifest, and diagnostic leak scan remain unproved.
    depends_on: [AUTH-010, AUTH-011]
    evidence: []

  - id: AUTH-024
    kind: security
    behavior: Local-owner session authority is available only through the explicit exact-loopback runtime boundary or its credentialed loopback development proxy and never through a remote, forwarded, or ambiguous request.
    owner: authorization
    source: {file: local-owner-and-private-team-access-spec.md, anchor: conformance-requirements}
    acceptance:
      behavior: {id: AUTH-024-B, description: "Start the direct local runtime on an exact loopback address and establish an owner session through a same-origin request and through the current run's credentialed loopback Vite proxy."}
      failure: {id: AUTH-024-F, description: "Refuse non-loopback binds, loopback DNS aliases, remote origins, missing or conflicting Fetch Metadata, forwarded identity headers, private-team mode, and missing, stale, or forged development-proxy credentials without creating a member or session."}
    deployments: [local]
    status: implementing
    proof_gap: The local acceptance test proves exact-loopback binding, same-origin Fetch Metadata, forwarded-header refusal, hostile Origin and Host refusal, and a valid or forged development-proxy credential. Conflicting Fetch Metadata, a credential from a prior development run, and the packaged boundary matrix remain unproved.
    depends_on: [AUTH-023]
    evidence: []

  - id: AUTH-025
    kind: constraint
    behavior: Private-team entry points require exactly one configured browser identity provider and accept neither a local browser-bootstrap credential nor the legacy installation bearer as HTTP API or MCP request authority.
    owner: authorization
    source: {file: local-owner-and-private-team-access-spec.md, anchor: conformance-requirements}
    acceptance:
      behavior: {id: AUTH-025-B, description: "Start compact and external-storage team runtimes with one complete OIDC or WorkOS configuration, bootstrap the configured administrator through that provider, and authenticate non-browser clients only with managed keys or a compatible external OAuth verifier."}
      failure: {id: AUTH-025-F, description: "Missing or multiple identity providers, a configured local bootstrap credential, the local-owner session route, the generated compact bootstrap credential, and the legacy installation bearer each fail startup or authentication without granting request authority."}
    deployments: [single_server, kubernetes]
    status: implementing
    proof_gap: The Node runtime test proves provider discovery, missing-provider startup refusal, local-owner route absence, managed-key authority, and legacy-bearer refusal in private-team mode, and the real Keycloak suite proves the OIDC round trip. Compact Compose, external-storage Compose, and Kubernetes startup plus the compatible external OAuth verifier matrix remain unproved.
    depends_on: [AUTH-009, AUTH-019, AUTH-021]
    evidence: []

  - id: AUTH-026
    kind: behavior
    behavior: The management application discovers a non-secret access-mode contract and follows one bounded local-owner session flow or the configured private-team sign-in flow, with mode-correct expiry, logout, denial, and recovery behavior.
    owner: web-application
    source: {file: local-owner-and-private-team-access-spec.md, anchor: conformance-requirements}
    acceptance:
      behavior: {id: AUTH-026-B, description: "Load authenticated, unauthenticated, expired, and deep-linked browser states in each mode; local owner recovers once without sign-in, while private team offers the configured provider, returns safely after login, and logs out to the signed-out state."}
      failure: {id: AUTH-026-F, description: "The public context reveals no issuer, client, bootstrap email, member state, or credential; local failures do not loop or offer provider login; team denial, deactivation, and provider failure create no session and never offer local login."}
    deployments: [local, single_server, kubernetes]
    status: implementing
    proof_gap: The browser suite proves local-owner bootstrap, deep-link loading, cookie-clearing recovery, and no logout affordance, while the HTTP suite proves the non-secret private-team context and refusal of local bootstrap. Complete private-team browser expiry, logout, denial, deactivation, provider-failure recovery, and replicated-deployment runs remain unproved.
    depends_on: [AUTH-023, AUTH-024, AUTH-025]
    evidence: []

  - id: AUTH-027
    kind: security
    behavior: Deactivating a member stops that member's provider login, application sessions, and member-owned API keys immediately in the handling process and within the documented authentication-cache bound on every other replica, while preserving durable attributed records.
    owner: authorization
    source: {file: local-owner-and-private-team-access-spec.md, anchor: conformance-requirements}
    acceptance:
      behavior: {id: AUTH-027-B, description: "Authenticate one member through the identity provider, an existing application session, and a member-owned managed key; deactivate the member; observe immediate same-process refusal and cross-replica refusal within the cache bound while the member's artifacts, actions, comments, and attribution remain."}
      failure: {id: AUTH-027-F, description: "A deactivated member cannot create a new provider binding or session, renew an existing session, use a member-owned key, or regain access through stale cached authority after the bound; unrelated service principals and durable attributed records are not removed."}
    deployments: [single_server, kubernetes]
    status: implementing
    proof_gap: The local acceptance tests prove immediate refusal of a deactivated member's session and member-owned key, preserve the installation service principal, and bound a warmed cross-process session decision through the authentication cache. Provider relogin, cross-replica managed-key expiry, and explicit preservation checks for every attributed record remain unproved.
    depends_on: [AUTH-008, AUTH-009, AUTH-022, AUTH-025]
    evidence: []

  - id: AUTH-028
    kind: constraint
    behavior: Membership administration cannot deactivate the member represented by the current human session or leave an installation without at least one active administrator; local-owner mode cannot deactivate its stable local administrator.
    owner: authorization
    source: {file: local-owner-and-private-team-access-spec.md, anchor: conformance-requirements}
    acceptance:
      behavior: {id: AUTH-028-B, description: "Admit a second administrator and have that administrator deactivate the first non-current administrator while another active administrator remains."}
      failure: {id: AUTH-028-F, description: "Refuse current-member deactivation, last-administrator deactivation, concurrent attempts that would remove all administrators, and local-owner administrator deactivation without changing membership, sessions, or audit state."}
    deployments: [local, single_server, kubernetes]
    status: implementing
    proof_gap: The local tests prove current-member and stable local-owner refusal, last-administrator refusal, and deactivation by a replacement administrator while another administrator remains. The concurrent last-administrator race and the complete replicated-deployment matrix remain unproved.
    depends_on: [AUTH-001, AUTH-023, AUTH-025]
    evidence: []

  - id: SEC-001
    kind: security
    behavior: Published websites are treated as untrusted arbitrary browser JavaScript.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: SEC-001-B, description: "Run the malicious-artifact fixture without compromising normal rendering or the application."}
      failure: {id: SEC-001-F, description: "Forms, fetches, frames, service workers, cross-origin requests, navigation, and storage attacks cannot obtain application authority."}
    deployments: *all
    status: specified
    depends_on: [CNT-004, AUTH-010, AUTH-011, AUTH-012, AUTH-013]
    evidence: []

  - id: SEC-002
    kind: security
    behavior: Every product database, blob, cache, background-job, backup, and restore operation is tenant-scoped and has a cross-tenant hostile test.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: SEC-002-B, description: "Run the storage and operation conformance suite under two installations and observe strict isolation."}
      failure: {id: SEC-002-F, description: "Remove, alter, or forge tenant scope at each boundary and confirm fail-closed behavior."}
    deployments: *replicated
    status: specified
    depends_on: [AUTH-017]
    evidence: []

  - id: SEC-003
    kind: constraint
    behavior: Administrators control login, public-link policy, accepted file types, size and rate limits, retention, and network rules for their installation.
    owner: operations
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: SEC-003-B, description: "Change each documented server policy and verify enforcement through browser, HTTP, MCP, and Plannotator paths."}
      failure: {id: SEC-003-F, description: "No non-administrator or alternate interface can override installation policy."}
    deployments: *all
    status: specified
    depends_on: [PRD-004]
    evidence: []

  - id: SEC-004
    kind: security
    behavior: Backups, restores, deletion, cleanup, and upgrades preserve referential integrity and cannot expose or lose another installation's data.
    owner: operations
    source: {file: artifact-server-product-spec.html, anchor: safety}
    acceptance:
      behavior: {id: SEC-004-B, description: "Exercise each lifecycle operation with two installations and run the blob-reference integrity check afterward."}
      failure: {id: SEC-004-F, description: "Interrupted, replayed, partial, cross-tenant, and stale lifecycle operations fail without exposing or losing committed versions."}
    deployments: *external_storage
    status: specified
    depends_on: [SEC-002, OPS-003]
    evidence: []

  - id: MCP-001
    kind: behavior
    behavior: Remote MCP uses HTTP POST at /mcp; normal results are JSON and request-scoped server-sent events are reserved for useful progress.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-001-B, description: "Call discovery and representative tools through POST /mcp and receive conforming JSON or request-scoped progress."}
      failure: {id: MCP-001-F, description: "GET and DELETE /mcp return 405, and a request cannot create a permanent event stream or sticky session."}
    deployments: *all
    status: behavior_verified
    depends_on: []
    evidence:
      - deployment: local
        tests: [MCP-001-B, MCP-001-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: MCP-002
    kind: constraint
    behavior: The primary MCP path implements revision 2026-07-28 with the official TypeScript SDK version 2 and keeps every request independent.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-002-B, description: "Pass protocol conformance using the pinned revision and SDK without initialization, MCP session IDs, or load-balancer affinity."}
      failure: {id: MCP-002-F, description: "A client cannot require undocumented session state, sticky routing, or an older protocol on the primary path."}
    deployments: *all
    status: behavior_verified
    depends_on: [MCP-001]
    evidence:
      - deployment: local
        tests: [MCP-002-B, MCP-002-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: MCP-003
    kind: behavior
    behavior: server/discover reports supported protocol versions and instructions; tools/list and resources/templates/list report the catalog; artifact_capabilities reports deployment-specific workflow, limits, and sharing modes.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-003-B, description: "Discover each deployment, list its tools and resources, then call artifact_capabilities and confirm that all returned behavior and limits match the installation."}
      failure: {id: MCP-003-F, description: "Disabled, unsupported, or policy-forbidden methods are not advertised as available."}
    deployments: *all
    status: behavior_verified
    depends_on: [MCP-002, SEC-003]
    evidence:
      - deployment: local
        tests: [MCP-003-B, MCP-003-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: MCP-004
    kind: constraint
    behavior: Subscriptions and subscriptions/listen are rejected until the deployment has a real shared event service.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-004-B, description: "Discover a deployment without an event service and observe no subscription capability."}
      failure: {id: MCP-004-F, description: "Subscription attempts receive a stable unsupported response and allocate no permanent connection state."}
    deployments: *all
    status: behavior_verified
    depends_on: [MCP-003]
    evidence:
      - deployment: local
        tests: [MCP-004-B, MCP-004-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: MCP-005
    kind: constraint
    behavior: The official SDK serves required 2025-era clients through a stateless compatibility path while the primary 2026-07-28 request family remains unchanged.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-005-B, description: "Complete an exact 2025-06-18 initialization and tool call alongside the pinned modern conformance suite using the same authenticated product services."}
      failure: {id: MCP-005-F, description: "Compatibility cannot create session IDs, sticky routing, GET streams, DELETE session operations, replay state, different credentials, or altered modern endpoint behavior."}
    deployments: *all
    status: behavior_verified
    depends_on: [MCP-002]
    evidence:
      - deployment: local
        tests: [MCP-005-B, MCP-005-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: MCP-006
    kind: behavior
    behavior: The initial MCP surface supports capabilities, list, get, open, upload creation, upload commit, visibility, tags, version list, diff, restore, and delete. It has no local-path, raw-text, base64, or inline-content publishing tool.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-006-B, description: "Execute every documented tool against its supported fixture and compare the result with the HTTP behavior."}
      failure: {id: MCP-006-F, description: "Each tool rejects invalid input, unsupported capability, wrong installation, wrong artifact, and insufficient permission through the shared authorization layer."}
    deployments: *all
    status: behavior_verified
    depends_on: [PRD-004, MCP-003]
    evidence:
      - deployment: local
        tests: [MCP-006-B, MCP-006-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: MCP-007
    kind: behavior
    behavior: MCP carries instructions, file metadata, and bounded results while file bytes and complete directories use the server's upload plan.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-007-B, description: "Publish one small file and one large complete site from filesystem inputs while the client selects the advertised upload transport."}
      failure: {id: MCP-007-F, description: "Raw content and oversized MCP input are rejected before memory or message limits are exceeded and return the supported upload path."}
    deployments: *all
    status: behavior_verified
    depends_on: [MCP-003, PUB-002]
    evidence:
      - deployment: local
        tests: [MCP-007-B, MCP-007-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: MCP-008
    kind: behavior
    behavior: Every durable MCP mutation includes an application idempotency key; mutations of an existing artifact also include the current version the caller started from. Upload creation is disposable staging and creating a new artifact has no prior version.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-008-B, description: "Lose and retry an MCP write and receive the original result without duplicating or overwriting work."}
      failure: {id: MCP-008-F, description: "Missing, reused-with-different-input, and stale write controls are rejected through the same publishing rules as HTTP."}
    deployments: *all
    status: behavior_verified
    depends_on: [PUB-006, PUB-008]
    evidence:
      - deployment: local
        tests: [MCP-008-B, MCP-008-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: MCP-009
    kind: security
    behavior: MCP tool handlers use the same membership, capability, visibility, tenant, and mutation authorization layer as browser and HTTP operations.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-009-B, description: "Run the complete authorization matrix through MCP and HTTP and obtain equivalent outcomes."}
      failure: {id: MCP-009-F, description: "MCP cannot list, read, publish, restore, change visibility, or delete beyond the caller's normal authority."}
    deployments: *all
    status: implementing
    proof_gap: The current test proves read-only listing, publication denial, and one foreign-installation list denial; it does not run the complete browser, HTTP, and MCP authorization matrix or every listed MCP mutation denial.
    depends_on: [AUTH-008]
    evidence: []

  - id: MCP-010
    kind: security
    behavior: Hosted remote MCP advertises protected-resource metadata, challenges unauthenticated clients, and uses WorkOS AuthKit for browser approval and resource-bound credentials.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-010-B, description: "Add only the hosted /mcp URL in supported clients and complete discovery, browser approval, callback, token use, refresh, revoke, and reconnect."}
      failure: {id: MCP-010-F, description: "Missing, wrong-issuer, wrong-audience, expired, revoked, malformed, and web-session tokens are rejected with correct challenge behavior."}
    deployments: *hosted
    status: implementing
    proof_gap: Live staging covers selected WorkOS and named-client flows, but the complete supported-client discovery, callback, refresh, revoke, reconnect, and hostile-token matrix is not attached as MCP-010 behavior and failure evidence.
    depends_on: [MCP-001, AUTH-017]
    evidence: []

  - id: MCP-011
    kind: security
    behavior: Hosted MCP tokens are verified for signature, allowed algorithm, exact issuer, exact /mcp audience, expiry, and subject using rotation-safe cached keys. The exact resource-bound audience grants MCP access; WorkOS does not issue a separate product scope.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-011-B, description: "Verify valid tokens before and after signing-key rotation and map them to an internal provider-neutral principal."}
      failure: {id: MCP-011-F, description: "Reject algorithm confusion, unknown keys, multiple-resource confusion, missing subject, invalid time, issuer, or audience."}
    deployments: *hosted
    status: implementing
    proof_gap: Local verifier tests cover selected issuer, audience, expiry, and key failures, but there is no hosted MCP-011 run that includes signing-key rotation and the complete algorithm, key, resource, subject, time, issuer, and audience hostile matrix.
    depends_on: [MCP-010]
    evidence: []

  - id: MCP-012
    kind: security
    behavior: WorkOS owns hosted authorization, consent, codes, client registration, access credentials, refresh, and revocation; bearer credentials never reach storage, workers, sites, files, or logs.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-012-B, description: "Trace a hosted authorization and tool call and confirm that Artifact Server receives only the bearer at its verification boundary and emits a redacted internal principal."}
      failure: {id: MCP-012-F, description: "Authorization codes, refresh tokens, cookies, ID tokens, bearer values, and credential-bearing URLs never appear downstream or in logs."}
    deployments: *hosted
    status: implementing
    proof_gap: The live authorization record proves selected grant flows, but no MCP-012 trace demonstrates that every listed credential form is absent from storage, Worker, content, file, and log boundaries.
    depends_on: [MCP-011]
    evidence: []

  - id: MCP-013
    kind: behavior
    behavior: Local mode connects through artifactserver connect and a stdio bridge without browser OAuth or a human-visible secret; self-hosted mode uses browser OAuth when compatible authorization is configured and otherwise uses administration-issued scoped API keys. A generic OIDC issuer is compatible authorization when it signs verifiable access-token JWTs, binds the exact <origin>/mcp audience, and offers a client registration path its clients can use; the installation registers that client and never runs an authorization server of its own.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-013-B, description: "Connect locally through the stdio bridge with no visible credential, connect to a private OAuth server through browser approval including a generic OIDC issuer whose access token names the exact /mcp resource, and connect to a no-OAuth server using an administration-issued revocable API key."}
      failure: {id: MCP-013-F, description: "Startup logs, diagnostics, project files, generic OIDC ID tokens, browser login cookies, and wrong-resource tokens cannot expose or substitute for a valid MCP credential."}
    deployments: [local, single_server, kubernetes, aws, gcp]
    status: implementing
    proof_gap: Local stdio, API-key, and generic OIDC access-token paths are implemented and covered by the local conformance suite and the real Keycloak harness, but the combined private OAuth, no-OAuth, local, wrong-credential, and credential-leak matrix has no deployment-specific MCP-013 evidence. The Keycloak harness obtains its MCP access tokens through the password grant; no MCP client has yet completed browser approval (authorization code with S256 PKCE, client registration, and the RFC 8707 resource parameter) against a generic OIDC issuer, so the browser-approval half of MCP-013-B is unproved for OIDC.
    depends_on: [AUTH-009]
    evidence: []

  - id: MCP-014
    kind: release_gate
    behavior: Embedded Better Auth MCP OAuth is optional and unsupported until its beta path passes security, client compatibility, migration, durable-state, revocation, and recovery tests.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: MCP-014-B, description: "Pass the full hosted hostile and client matrix using the embedded provider before advertising it."}
      failure: {id: MCP-014-F, description: "Self-hosted deployments remain usable through API keys and compatible external issuers when embedded OAuth is absent."}
    deployments: [single_server, kubernetes, aws, gcp]
    status: specified
    depends_on: [MCP-010, MCP-013]
    evidence: []

  - id: MCP-015
    kind: behavior
    behavior: artifact_get returns the current exact full-screen Review address, and artifact_open returns the selected exact full-screen Review address beside the raw immutable content address; agents prefer Review for human handoff and never label raw content as Review. Only a local helper opens an address on the local computer, while remote servers return addresses.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-015-B, description: "Read and open local and remote artifacts and confirm that the correct client computer receives an exact full-screen Review address and a separately named raw content address for the authoritative current or selected version."}
      failure: {id: MCP-015-F, description: "Review addresses contain no bootstrap credential, raw content addresses are never described as Review, and a remote server never attempts to start a browser on the server machine or opens an artifact from a guessed server."}
    deployments: *all
    status: behavior_verified
    depends_on: [MCP-006, SKL-004]
    evidence:
      - deployment: local
        tests: [MCP-015-B, MCP-015-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-30T17:56:35.366Z"

  - id: MCP-016
    kind: release_gate
    behavior: The supported local MCP path is install Artifact Server, run artifactserver connect, and use the selected AI client without browser sign-in, Docker, a visible token, copied key, or startup-log inspection.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-016-B, description: "From a clean local package, connect Codex, Claude Code, Cursor, and VS Code through artifactserver connect, complete discovery and representative tool calls, restart, reconnect, disconnect, and run doctor."}
      failure: {id: MCP-016-F, description: "Multiple-client ambiguity asks for a choice, stale or corrupt registration produces a useful diagnosis, and no command output, log, project file, process argument, or diagnostic bundle exposes the internal local credential."}
    deployments: [local]
    status: implementing
    proof_gap: Adapter and packaged-bridge tests exist, but clean real-host connect, representative use, restart, reconnect, disconnect, doctor, stale-state, and credential-leak proof is not complete for all four named clients.
    depends_on: [MCP-002, MCP-009, MCP-013, OPS-008]
    evidence: []

  - id: MCP-017
    kind: release_gate
    behavior: The supported hosted interactive MCP path is add or select the exact /mcp address, complete browser sign-in and approval, and return to a connected client with automatic credential renewal.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-017-B, description: "In every advertised remote client, add only the server address and pass discovery, browser approval, callback, tool use, renewal after access-token expiry, revoke, disconnect, and reconnect from fresh and stale client state."}
      failure: {id: MCP-017-F, description: "Wrong issuer, audience, callback, network boundary, revoked grant, stale registration, and unadmitted user fail clearly without accepting a browser cookie or changing firewall or VPN access."}
    deployments: *hosted
    status: specified
    depends_on: [MCP-010, MCP-011, MCP-012]
    evidence: []

  - id: MCP-018
    kind: release_gate
    behavior: Self-hosted fallback and unattended MCP access use scoped user or service API keys issued through an administration interface or administrator CLI and stored through the client or deployment secret manager.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-018-B, description: "Issue, enter or inject, use, rotate, and revoke user and service keys through the supported administration and secret-storage paths on each applicable deployment."}
      failure: {id: MCP-018-F, description: "Keys never appear in startup logs, ordinary diagnostics, generated shell history, project configuration, artifact content, MCP results, or traces, and revoked or over-scoped keys fail closed."}
    deployments: *all
    status: specified
    depends_on: [AUTH-009, MCP-009, OPS-008]
    evidence: []

  - id: MCP-019
    kind: release_gate
    behavior: Every advertised MCP client has a native one-click installation where supported or one copyable command or configuration otherwise, plus tested upgrade, disconnect, stale-state recovery, and reauthorization instructions.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: MCP-019-B, description: "Install and exercise the release path in current supported Codex, Claude Code, Cursor, and VS Code hosts and record the exact host versions and connection method."}
      failure: {id: MCP-019-F, description: "A host with missing transport, protocol, authorization, installation, upgrade, or stale-state evidence is omitted from the supported-client list rather than inferred to work."}
    deployments: *all
    status: specified
    depends_on: [MCP-016, MCP-017, MCP-018]
    evidence: []

  - id: MCP-020
    kind: security
    behavior: Local MCP connect and disconnect preflight client and private registration state, journal every intended client change before mutation, resume forward or roll back after interruption, and refuse to overwrite independently changed client configuration.
    owner: mcp
    source: {file: artifact-server-mcp-baseline.md, anchor: transactional-client-onboarding}
    acceptance:
      behavior: {id: MCP-020-B, description: "Interrupt onboarding after the client mutation, restart the process, resume from the private journal, and finish with one exact client registration and no pending journal."}
      failure: {id: MCP-020-F, description: "A failed client mutation rolls back cleanly, while an independently changed client or private registration state is preserved, blocks recovery, and retains the journal without being overwritten."}
    deployments: [local]
    status: behavior_verified
    proof_gap: Real-process adapter proof covers native-client interruption, rollback, and conflict preservation. Current released Codex, Claude Code, Cursor, and VS Code host versions still require the full MCP-016 and MCP-019 qualification matrix.
    depends_on: [MCP-016, MCP-019]
    evidence:
      - deployment: local
        tests: [MCP-020-B, MCP-020-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-25T18:29:58.000Z"

  - id: SKL-001
    kind: behavior
    behavior: Artifact Server ships one portable artifact-server skill that routes routine artifact work and explicit server-operation work to separate internal references.
    owner: agent-skills
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: SKL-001-B, description: "Install the one skill and route realistic artifact, review, project, and explicit server-operation requests to the correct internal reference."}
      failure: {id: SKL-001-F, description: "Routine artifact requests do not load server-operation instructions, implicit infrastructure work does not proceed, and adjacent non-artifact requests do not activate the skill."}
    deployments: *all
    status: implementing
    proof_gap: The unified skill and routing references are present, but there is no independent install, route-selection, non-activation, and adjacent-request evidence across supported agents.
    depends_on: [MCP-003]
    evidence: []

  - id: SKL-002
    kind: security
    behavior: The artifact route can publish, update, open, share, list, and compare using normal user permissions, routes local-file operations through the CLI and server-only operations through MCP or CLI, and does not load or gain server-operation instructions or credentials.
    owner: agent-skills
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: SKL-002-B, description: "Complete local-file publishing through the CLI and every server-only routine artifact task through MCP and CLI with equivalent product results."}
      failure: {id: SKL-002-F, description: "Routine artifact requests never gain administrator commands or credentials, and an infrastructure request must route through the explicit server-operation path."}
    deployments: *all
    status: implementing
    proof_gap: Skill files and forward tests cover selected publishing paths, but no SKL-002 run exercises every routine operation through MCP and CLI equivalently plus an infrastructure-request denial on each applicable deployment.
    depends_on: [SKL-001, MCP-009, CLI-002, ARC-006]
    evidence: []

  - id: SKL-003
    kind: security
    behavior: The artifact-server skill loads its server-operation reference only for explicit administrator work, requires administrator access, shows the proposed change, uses the selected native adapter, and verifies health afterward.
    owner: agent-skills
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: SKL-003-B, description: "Plan, apply, and verify representative install, upgrade, backup, restore, inspect, and repair work on each supported target."}
      failure: {id: SKL-003-F, description: "Non-administrators, implicit requests, unsupported targets, and failed health checks cannot silently apply or report success."}
    deployments: *all
    status: specified
    depends_on: [SKL-001, OPS-001]
    evidence: []

  - id: SKL-004
    kind: behavior
    behavior: The artifact route resolves the server from explicit request, artifact reference, current conversation, project default, then user default, and asks rather than guessing when ambiguity remains.
    owner: agent-skills
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: SKL-004-B, description: "Exercise every precedence source and confirm that an artifact reference includes server address, artifact ID, and exact version ID when needed."}
      failure: {id: SKL-004-F, description: "Ambiguous, missing, conflicting, and stale targets prompt for a choice and perform no read, publish, or open operation."}
    deployments: *all
    status: implementing
    proof_gap: Target-resolution logic is documented and partially tested, but the complete precedence, artifact-reference, ambiguity, conflict, missing, and stale-target matrix has no SKL-004 evidence.
    depends_on: [SKL-002]
    evidence: []

  - id: SKL-005
    kind: security
    behavior: Project configuration may name a non-secret default server or profile, while MCP credentials remain in the MCP client and CLI credentials remain in the operating-system credential store or another documented secure user-local store.
    owner: agent-skills
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: SKL-005-B, description: "Resolve a project default from .artifactserver.json and route an MCP or CLI operation while each adapter retrieves its own credential from user-local secure state."}
      failure: {id: SKL-005-F, description: "Skills never write bearer tokens, API keys, cookies, infrastructure credentials, or private server credentials into the project."}
    deployments: *all
    status: implementing
    proof_gap: Non-secret configuration and secure credential boundaries exist, but no SKL-005 acceptance run covers project defaults and verifies absence of every named credential type across MCP and CLI adapters.
    depends_on: [SKL-004]
    evidence: []

  - id: SKL-006
    kind: deployment
    behavior: The Artifact Server skill uses the open Agent Skills folder format, lives in the official repository, is versioned with server releases, and is tested for activation, route selection, non-activation, output, compatibility, and old-server behavior.
    owner: agent-skills
    source: {file: artifact-server-product-spec.html, anchor: mcp}
    acceptance:
      behavior: {id: SKL-006-B, description: "Validate, package, install, and run the release-matched Artifact Server skill in supported clients and publish its distribution metadata."}
      failure: {id: SKL-006-F, description: "Incompatible server versions produce a clear refusal or supported fallback rather than incorrect tool calls."}
    deployments: *all
    status: implementing
    proof_gap: Format, validation, and repository forward-test records exist for the unified skill, but released distribution metadata, supported-client installation, release matching, old-server behavior, and route-selection evidence remain incomplete.
    depends_on: [SKL-001, MCP-003]
    evidence: []

  - id: CMT-001
    kind: behavior
    behavior: A comment thread is created on one exact saved version and continues to reference that version after later publishes and restores.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-001-B, description: "Create a thread on one saved version, publish and restore other versions, and observe the thread still naming its original artifact and version."}
      failure: {id: CMT-001-F, description: "Publishing a second version and restoring the first change nothing on a thread made on the first; a thread on a nonexistent version is rejected."}
    deployments: *all
    status: behavior_verified
    depends_on: [ART-004, VER-001]
    evidence:
      - deployment: local
        tests: [CMT-001-B, CMT-001-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T09:21:52.377Z"

  - id: CMT-002
    kind: behavior
    behavior: A thread may name one manifest entry path inside its version, and the path is validated against that version's manifest.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-002-B, description: "Create a thread on one manifest entry path and read the same path back on the stored thread."}
      failure: {id: CMT-002-F, description: "A path that is not in that version's manifest is rejected as an invalid comment and creates no thread."}
    deployments: *all
    status: behavior_verified
    depends_on: [CMT-001, MAN-001]
    evidence:
      - deployment: local
        tests: [CMT-002-B, CMT-002-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T09:21:52.377Z"

  - id: CMT-003
    kind: behavior
    behavior: A comment anchor is opaque client-owned data of bounded size, and a top-level point must carry x and y between 0 and 1.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-003-B, description: "Store anchors of several shapes up to the documented size limit and read each one back byte for byte."}
      failure: {id: CMT-003-F, description: "An oversize anchor and an out-of-range point are rejected while an otherwise valid anchor is stored unchanged."}
    deployments: *all
    status: behavior_verified
    depends_on: [CMT-001]
    evidence:
      - deployment: local
        tests: [CMT-003-B, CMT-003-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T09:21:52.377Z"

  - id: CMT-004
    kind: behavior
    behavior: Replies are one level deep and are accepted only on open threads.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-004-B, description: "Reply to an open thread, list the thread with its replies, and observe that a reply has no replies of its own."}
      failure: {id: CMT-004-F, description: "A reply to a resolved thread is refused, and a concurrent resolve and reply never leaves a reply on a resolved thread."}
    deployments: *all
    status: behavior_verified
    depends_on: [CMT-001]
    evidence:
      - deployment: local
        tests: [CMT-004-B, CMT-004-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T09:21:52.377Z"

  - id: CMT-005
    kind: behavior
    behavior: Resolve and reopen are the same state change on a thread, and both record who changed the state and when.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-005-B, description: "Resolve and reopen one thread through the same operation and inspect the recorded actor and time for each change."}
      failure: {id: CMT-005-F, description: "An invalid state value is rejected, and a resolved thread lists as resolved from every backend."}
    deployments: *all
    status: behavior_verified
    depends_on: [CMT-001]
    evidence:
      - deployment: local
        tests: [CMT-005-B, CMT-005-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T09:21:52.377Z"

  - id: CMT-006
    kind: security
    behavior: Reading comments requires artifact read authority, and comments never appear on the content origin or through a public link.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-006-B, description: "Read threads and replies as an admitted member of the owning installation through the application origin only."}
      failure: {id: CMT-006-F, description: "A public-link viewer and an anonymous request are denied, and no content-domain route returns comment data."}
    deployments: *all
    status: behavior_verified
    depends_on: [CMT-001, AUTH-008]
    evidence:
      - deployment: local
        tests: [CMT-006-B, CMT-006-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T09:21:52.377Z"

  - id: CMT-007
    kind: security
    behavior: Creating threads, replies, resolves, and reopens requires a direct human member or a service principal holding the comment-write capability.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-007-B, description: "Write comments as an admitted human member and as a service key that holds the comment-write capability."}
      failure: {id: CMT-007-F, description: "A key that holds only artifact read authority is denied every comment mutation."}
    deployments: *all
    status: behavior_verified
    depends_on: [CMT-001, AUTH-008]
    evidence:
      - deployment: local
        tests: [CMT-007-B, CMT-007-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T09:21:52.377Z"

  - id: CMT-008
    kind: security
    behavior: Only the author can edit a thread or reply; the author, a human administrator, or a principal that can manage any artifact can delete one.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-008-B, description: "Edit and delete one's own thread and reply, then delete another member's comment as a human administrator."}
      failure: {id: CMT-008-F, description: "Another member's edit and delete are denied, and an administrator's edit of someone else's comment is denied while the administrator's delete succeeds and is recorded."}
    deployments: *all
    status: behavior_verified
    depends_on: [CMT-001, AUTH-008]
    evidence:
      - deployment: local
        tests: [CMT-008-B, CMT-008-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T09:21:52.377Z"

  - id: CMT-009
    kind: security
    behavior: Every comment operation is project-scoped, and a cross-project or cross-installation identifier fails as not found without revealing which identifier exists.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-009-B, description: "Run every comment operation inside its own project and observe results scoped to that project and installation."}
      failure: {id: CMT-009-F, description: "The same artifact, version, thread, and reply identifiers presented under a different project return not found."}
    deployments: *all
    status: behavior_verified
    depends_on: [CMT-001, AUTH-008, PRJ-002]
    evidence:
      - deployment: local
        tests: [CMT-009-B, CMT-009-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T09:21:52.377Z"

  - id: CMT-010
    kind: behavior
    behavior: Comment creates are idempotent by idempotency key, and a replay returns the original record marked as a replay.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-010-B, description: "Repeat a thread create and a reply create with the same idempotency key and receive the original record marked as replayed."}
      failure: {id: CMT-010-F, description: "The same idempotency key with a different body is rejected as a conflict and creates no duplicate record."}
    deployments: *all
    status: behavior_verified
    depends_on: [CMT-001, PUB-006]
    evidence:
      - deployment: local
        tests: [CMT-010-B, CMT-010-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T09:21:52.377Z"

  - id: CMT-011
    kind: behavior
    behavior: Every comment mutation appends an attributed action record naming the thread's artifact and version.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-011-B, description: "Perform every comment mutation through human and agent principals and inspect action records that name the responsible principal, artifact, and version."}
      failure: {id: CMT-011-F, description: "A comment mutation cannot commit without its action record in the same transaction."}
    deployments: *all
    status: behavior_verified
    depends_on: [CMT-001, AUD-001]
    evidence:
      - deployment: local
        tests: [CMT-011-B, CMT-011-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T09:21:52.377Z"

  - id: CMT-012
    kind: behavior
    behavior: The HTTP API, MCP tools, and web application expose the same comment operations with the same authorization, and change polling with a since time and a cursor returns every change at least once to a poller that resumes from the time its previous pass started.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-012-B, description: "Drive equivalent comment operations through HTTP and MCP and page through changes with a since time and a cursor; the web application exercises the same routes in the browser suite."}
      failure: {id: CMT-012-F, description: "MCP and HTTP cannot return different results for the same principal, and a poll resuming from the time its previous pass started cannot miss an update."}
    deployments: *all
    status: behavior_verified
    depends_on: [CMT-001, CMT-007, ARC-006]
    evidence:
      - deployment: local
        tests: [CMT-012-B, CMT-012-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T09:21:52.377Z"

  - id: CMT-013
    kind: security
    behavior: The version file route serves exact manifest-entry bytes to artifact-read principals with non-renderable headers on the application origin and never on the content domain.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-013-B, description: "Read the exact stored bytes of a manifest entry as an artifact-read principal on the application origin and observe headers that prevent the response from rendering as a document while allowing private immutable browser caching of the version-pinned bytes."}
      failure: {id: CMT-013-F, description: "Anonymous, public-link, and read-incapable-key requests are denied, the response cannot render as a document on the application origin, and an unknown path returns not found without revealing which paths exist."}
    deployments: *all
    status: behavior_verified
    depends_on: [CMT-002, MAN-001, AUTH-008]
    evidence:
      - deployment: local
        tests: [CMT-013-B, CMT-013-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T09:21:52.377Z"

  - id: CMT-014
    kind: security
    behavior: The review viewer executes artifact HTML only inside an opaque-origin sandboxed document that holds no credential, and comment writes happen only in the signed-in application document.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-014-B, description: "Review an artifact version in the viewer and observe artifact HTML running in an opaque-origin sandboxed document while every comment write is made by the signed-in application document."}
      failure: {id: CMT-014-F, description: "Hostile artifact JavaScript inside the viewer cannot reach the application origin, the comment API, cookies, or storage."}
    deployments: *all
    status: behavior_verified
    depends_on: [SEC-001, CMT-013]
    evidence:
      - deployment: local
        tests: [CMT-014-B, CMT-014-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-26T18:29:39.022Z"

  - id: CMT-015
    kind: behavior
    behavior: Review routes use a dedicated artifact-first viewport shell; comments and version navigation are closed by default, exact-version and linked-source context stay compact, on-demand surfaces overlay rather than crush the artifact on narrow screens, sharing stays version-specific, and focus mode always has a visible exit.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: CMT-015-B, description: "Open one review route and observe no management shell, the exact artifact and version in one compact bar, the artifact receiving the remaining viewport, comments and version navigation opening only when requested, a version-specific share action, and an explicit focus-mode exit."}
      failure: {id: CMT-015-F, description: "At a narrow viewport, opening comments or version navigation overlays the artifact instead of shrinking it, closing the surface restores the artifact, and focus mode never removes its visible exit control."}
    deployments: *all
    status: behavior_verified
    depends_on: [CMT-012, CMT-014]
    evidence:
      - deployment: local
        tests: [CMT-015-B, CMT-015-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-23T23:50:31.798Z"

  - id: CMT-016
    kind: behavior
    behavior: A Review URL resolves its named project, artifact, and version directly, independent of catalog pagination, and preserves that exact identity through loading, refresh, and browser history.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: review-route-resolution}
    acceptance:
      behavior: {id: CMT-016-B, description: "Open an exact Review URL for an artifact beyond the first catalog page and for one historical version, and observe the named artifact and version after initial load, refresh, and browser history navigation."}
      failure: {id: CMT-016-F, description: "An unknown, deleted, foreign-project, or mismatched artifact or version produces an explicit unavailable state and never selects the first loaded artifact, the current version, or another project as a fallback."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local browser evidence proves direct current and historical resolution, refresh and history preservation, and explicit failure without fallback. Equivalent evidence is not yet recorded for every team deployment.
    depends_on: [ART-002, VER-001, CMT-015]
    evidence:
      - deployment: local
        tests: [CMT-016-B, CMT-016-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-25T17:52:50.473Z"

  - id: CMT-017
    kind: behavior
    behavior: Review sharing leads with the exact selected full-screen Review URL, including the selected immutable version and valid selected file path, while the moving latest link and immutable raw link remain explicitly secondary.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: exact-version-sharing}
    acceptance:
      behavior: {id: CMT-017-B, description: "Share a current version, a historical version, and a selected nested file; the primary copied link and agent prompt preserve the exact version, focus view, and valid file path, while Latest and Raw are labeled secondary links."}
      failure: {id: CMT-017-F, description: "Sharing cannot silently substitute the current version, omit a selected valid path, label a moving link as exact, expose a bootstrap credential, or enable Share while the selected version is unresolved."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local browser evidence proves exact-version-first sharing for current, historical, and nested-file selections. Equivalent evidence is not yet recorded for every team deployment.
    depends_on: [CMT-016, PUB-013, VER-001]
    evidence:
      - deployment: local
        tests: [CMT-017-B, CMT-017-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-25T17:52:50.473Z"

  - id: CMT-018
    kind: security
    behavior: The sandboxed Review viewer loads relative and root-relative files for a private or historical multi-file version through a short-lived read-only preview lease bound to that exact version, without receiving an application credential or weakening raw-content sessions.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: private-multi-file-review}
    acceptance:
      behavior: {id: CMT-018-B, description: "Review private current and historical HTML whose nested entry loads relative CSS, JavaScript, images, fonts, module imports, and same-version fetches; every request stays on the leased exact-version content origin in supported browsers and local and team deployments."}
      failure: {id: CMT-018-F, description: "A missing, expired, forged, cross-version, cross-artifact, non-manifest, mutating, or application-origin lease request fails closed; artifact JavaScript receives no application cookie, API credential, reusable cross-version authority, or access to another version's bytes."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local browser and service evidence proves exact-version private historical rendering and lease rejection. The complete supported-browser and per-team-deployment matrix remains unrecorded.
    depends_on: [AUTH-015, CMT-014, CNT-005, SEC-001]
    evidence:
      - deployment: local
        tests: [CMT-018-B, CMT-018-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-25T17:51:55.551Z"
      - deployment: local
        tests: [CMT-018-B, CMT-018-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-25T17:52:50.473Z"

  - id: CMT-019
    kind: behavior
    behavior: Canonical Review displays each complete root-and-reply conversation and supports creating, editing, and deleting replies through the existing reply, authorship, resolution, and polling contracts.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: complete-review-conversations}
    acceptance:
      behavior: {id: CMT-019-B, description: "Open Review on a thread with an existing reply, see the reply without expansion, then create, edit, and delete a reply and observe the complete updated conversation."}
      failure: {id: CMT-019-F, description: "Resolved threads cannot offer reply creation, another author's reply cannot offer unauthorized editing, and reload or polling cannot show a reply count without the stored replies."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local browser evidence proves complete Review conversations and reply mutation behavior. Equivalent evidence for each team deployment remains unrecorded.
    depends_on: [CMT-004, CMT-005, CMT-008, CMT-012, CMT-016]
    evidence:
      - deployment: local
        tests: [CMT-019-B, CMT-019-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-25T19:16:53.330Z"

  - id: CMT-020
    kind: constraint
    behavior: A comment thread referenced by a queued, claimed, or delivered dispatch cannot be deleted singly or by bulk clear; addressed, failed, and canceled dispatches release their threads, and every backend decides dispatch membership and deletion atomically without rewriting the dispatch package.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: dispatch-bound-comment-deletion}
    acceptance:
      behavior: {id: CMT-020-B, description: "Single deletion returns DISPATCH_STATE_CONFLICT for queued, claimed, and delivered dispatches; bulk clear skips and counts those threads; addressed, failed, and canceled dispatches permit deletion without changing the dispatch record."}
      failure: {id: CMT-020-F, description: "A concurrent dispatch creation and comment deletion on SQLite or Postgres commits exactly one complete outcome: either the dispatch keeps an existing thread or deletion succeeds and dispatch creation is rejected."}
    deployments: *all
    status: behavior_verified
    proof_gap: SQLite conformance evidence plus Postgres integration and D1 runtime qualification prove the deletion guard and atomic race behavior. Equivalent recorded evidence for every deployed-team target remains unrecorded.
    depends_on: [CMT-008, CMT-011, DSP-003, DSP-007, PRS-005]
    evidence:
      - deployment: local
        tests: [CMT-020-B, CMT-020-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-27T00:19:45.636Z"

  - id: CMT-021
    kind: behavior
    behavior: Review downloads an artifact's selected immutable version in standard and full-screen modes; one-file versions return the original file, while multi-file versions return a streamed path-preserving ZIP without opening another Review panel.
    owner: artifact-comments
    source: {file: artifact-comments-spec.md, anchor: complete-version-downloads}
    acceptance:
      behavior: {id: CMT-021-B, description: "Download one-file and multi-file current and historical versions from standard and full-screen Review; verify original filenames, ZIP paths, exact bytes, stable archive metadata, and unchanged Review state."}
      failure: {id: CMT-021-F, description: "Anonymous, unauthorized, cross-project, cross-artifact, and mismatched-version requests return no bytes, and downloading cannot open comments, change the selected version, or leave full-screen mode."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local service and browser evidence proves exact one-file and multi-file downloads, immutable historical bytes, archive authorization, and unchanged Review state. Equivalent evidence for every team deployment remains unrecorded.
    depends_on: [CMT-013, CMT-015, VER-001]
    evidence:
      - deployment: local
        tests: [CMT-021-B, CMT-021-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-09-03T16:08:06.755Z"
      - deployment: local
        tests: [CMT-021-B, CMT-021-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-09-03T16:09:11.243Z"

  - id: ADM-001
    kind: behavior
    behavior: Artifact Server ships one canonical React application for Review and settings, plus the isolated Review frame; every former application route redirects to the equivalent canonical destination without serving or loading a legacy application bundle.
    owner: web-application
    source: {file: single-application-administration-spec.md, anchor: decision}
    acceptance:
      behavior: {id: ADM-001-B, description: "Build and open Review and every settings route from a clean installation, then follow each compatibility URL and observe the equivalent canonical destination with valid project, artifact, version, path, and focus context preserved."}
      failure: {id: ADM-001-F, description: "The production build and HTTP asset surface contain no legacy React entry or screen, and no compatibility URL serves the old application or loses its existing query context."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local package and browser evidence proves the single React application, isolated Review frame, canonical settings routes, and compatibility behavior. Equivalent deployed-team evidence remains unrecorded.
    depends_on: [AUTH-026, CMT-015, CMT-016]
    evidence:
      - deployment: local
        tests: [ADM-001-B, ADM-001-F]
        result: pass
        run: project/evidence/local-package.json
        recorded_at: "2026-08-26T18:33:14.862Z"

  - id: ADM-002
    kind: behavior
    behavior: Canonical settings list active and archived projects, create and open a project, and provide one project-local surface for rename, archive, unarchive, and capability-gated optional Git history with estimate confirmation before enablement.
    owner: web-application
    source: {file: single-application-administration-spec.md, anchor: project-settings}
    acceptance:
      behavior: {id: ADM-002-B, description: "Create and rename a project, archive and unarchive it, return to it in Review, and—when an optional Git provider is available—review an estimate before enabling and later disabling Git history while the displayed state follows the server result."}
      failure: {id: ADM-002-F, description: "A failed create or rename preserves the entered name, archive cannot erase reads or immutable history, unavailable Git cannot be enabled, enablement without estimate confirmation is refused, and the interface never invents project ACLs or exposes provider secrets and internals."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local browser evidence proves project lifecycle behavior and the absent-provider boundary. A configured provider's estimate and enable-disable browser flow, plus team deployments, remain unrecorded.
    depends_on: [PRJ-003, GIT-010, GIT-012]
    evidence:
      - deployment: local
        tests: [ADM-002-B, ADM-002-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-26T03:02:41.357Z"

  - id: ADM-003
    kind: security
    behavior: Canonical member settings let an installation administrator list, admit, and deactivate members through the closed admission model while preserving the existing self, last-administrator, local-owner, session, key, and attribution protections.
    owner: web-application
    source: {file: single-application-administration-spec.md, anchor: members}
    acceptance:
      behavior: {id: ADM-003-B, description: "As an administrator, list active and inactive members, admit a member and administrator by provider email, and deactivate an eligible member while durable attributed records remain."}
      failure: {id: ADM-003-F, description: "A non-administrator direct route or mutation is forbidden, the UI does not claim to send an invitation, and current-member, last-administrator, and local-owner administrator deactivation remain refused without changing membership."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local browser evidence proves member admission and deactivation in the canonical application. Equivalent browser evidence for a non-administrator and each team deployment remains unrecorded; service tests retain those authority boundaries.
    depends_on: [AUTH-001, AUTH-027, AUTH-028]
    evidence:
      - deployment: local
        tests: [ADM-003-B, ADM-003-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-26T03:02:41.357Z"

  - id: ADM-004
    kind: security
    behavior: Canonical API-key settings let an installation administrator list, issue, rotate, and revoke scoped expiring keys, and expose a newly issued or rotated secret exactly once before discarding it from frontend state.
    owner: web-application
    source: {file: single-application-administration-spec.md, anchor: api-keys}
    acceptance:
      behavior: {id: ADM-004-B, description: "Issue a minimally scoped expiring member or service key, copy its one-time secret, rotate it and copy the replacement, then revoke the active key and observe its status."}
      failure: {id: ADM-004-F, description: "A non-administrator, missing capability, missing future expiration, inactive owner, stale key, or repeated reveal attempt fails without exposing a full existing secret or leaving it recoverable from frontend state."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local browser evidence proves issue, one-time display, frontend secret disposal, rotation, and revocation. Equivalent browser evidence for every rejected owner or capability case and each team deployment remains unrecorded; service tests retain those authority boundaries.
    depends_on: [AUTH-009, AUTH-027]
    evidence:
      - deployment: local
        tests: [ADM-004-B, ADM-004-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-26T03:02:41.357Z"

  - id: ADM-005
    kind: security
    behavior: Canonical public-link settings let an installation administrator page across projects, inspect active public destinations, and make a bounded selection account-required with explicit partial-success retry and cache-recall copy; public-link creation remains on the artifact Share surface.
    owner: web-application
    source: {file: single-application-administration-spec.md, anchor: public-links}
    acceptance:
      behavior: {id: ADM-005-B, description: "Page through active public links from multiple projects, open their public and Review destinations, make one and a bounded selection private, and retry a stale failed item without rolling back successful items."}
      failure: {id: ADM-005-F, description: "A non-administrator, oversized or duplicate selection, stale version, or cross-installation item is refused per item; the interface does not create links here or promise recall of downloaded or externally cached copies."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local browser evidence proves cross-project inventory, one and bulk access reduction, partial success, and stale retry. Equivalent browser evidence for each authorization rejection and team deployment remains unrecorded; service tests retain those boundaries.
    depends_on: [AUTH-007, AUTH-018, CMT-017]
    evidence:
      - deployment: local
        tests: [ADM-005-B, ADM-005-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-26T03:02:41.357Z"

  - id: ADM-006
    kind: behavior
    behavior: Every canonical settings route is refresh- and history-safe, responsive, keyboard accessible, and explicit about loading, empty, success, pending, forbidden, conflict, partial-failure, and retry states without weakening server authorization or crowding the artifact-first Review layout.
    owner: web-application
    source: {file: single-application-administration-spec.md, anchor: shared-interaction-contract}
    acceptance:
      behavior: {id: ADM-006-B, description: "Navigate each settings route by pointer and keyboard at wide and narrow viewports, refresh and use browser history, complete its primary operation, return to the preserved Review context, and receive visible and announced progress and success states."}
      failure: {id: ADM-006-F, description: "Direct unauthorized routes show a forbidden state rather than empty data, failed mutations retain recoverable input and offer bounded retry, settings do not cause page-level horizontal overflow, and no permanent settings navigation consumes Review viewport space."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local browser evidence proves accessible canonical settings, stable direct routes, preserved Review return context, and bounded failure states. The complete narrow-screen and non-administrator matrix for every settings page and team deployment remains unrecorded.
    depends_on: [AUTH-008, AUTH-026, ADM-001]
    evidence:
      - deployment: local
        tests: [ADM-006-B, ADM-006-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-26T03:02:41.357Z"

  - id: ADM-007
    kind: behavior
    behavior: Before the legacy application is removed, canonical Review provides the existing browser operations for version comparison, action history, artifact tombstoning, linked-source freshness and capture, eligible live view, and comment dispatch with agent presence by reusing their established product contracts.
    owner: web-application
    source: {file: single-application-administration-spec.md, anchor: legacy-capability-parity}
    acceptance:
      behavior: {id: ADM-007-B, description: "In canonical Review, compare two versions, page action history, tombstone an artifact after confirmation, inspect and capture a drifted linked source, open its eligible live view, and send a comment to a connected agent while observing its stated presence."}
      failure: {id: ADM-007-F, description: "Unavailable capabilities remain absent, destructive confirmation cannot be bypassed, linked operations cannot appear outside the qualified local deployment, dispatch authority and presence follow existing contracts, and deleting the legacy bundle cannot remove a still-specified browser operation."}
    deployments: *all
    status: behavior_verified
    proof_gap: Local browser evidence proves canonical comparison, action history, tombstoning, linked capture, dispatch, and presence through their existing contracts. Eligible live-view and equivalent team-deployment evidence remain unrecorded.
    depends_on: [ART-006, AUD-001, DIF-001, LNK-003, LNK-004, LNK-007, DSP-010, PRS-004, PRS-006, ADM-001]
    evidence:
      - deployment: local
        tests: [ADM-007-B, ADM-007-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-26T03:02:41.357Z"

  - id: DSP-001
    kind: behavior
    behavior: An agent registers itself with one upsert on its connection key within its own principal, listing derives whether it is connected from its claim polling, and a stale agent row is removed without touching dispatch history.
    owner: agent-dispatch
    source: {file: agent-dispatch-spec.md, anchor: conformance-and-testing}
    acceptance:
      behavior: {id: DSP-001-B, description: "Register an agent, register again with the same connection key, and observe one row that keeps its identifier, refreshed name and session, and a connected state that follows claim polling, where one held poll with an empty mailbox stamps liveness exactly once when the request arrives."}
      failure: {id: DSP-001-F, description: "Removing a stale agent row leaves its dispatches intact and still attributed to the recorded name, an agent registered in another installation never appears in this installation's listing, and another principal presenting the same connection key registers a separate agent instead of taking over the first one and the dispatches queued for it."}
    deployments: *all
    status: behavior_verified
    depends_on: [AUTH-008, PRJ-002]
    evidence:
      - deployment: local
        tests: [DSP-001-B, DSP-001-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T20:30:21.763Z"

  - id: DSP-002
    kind: security
    behavior: Registering, claiming, and reporting on a dispatch require a service principal holding the agent-connect capability, and only the principal holding the claim may report on it.
    owner: agent-dispatch
    source: {file: agent-dispatch-spec.md, anchor: conformance-and-testing}
    acceptance:
      behavior: {id: DSP-002-B, description: "Register, claim, and report delivered and failed with a service key that holds the agent-connect capability and with the local all-capability token."}
      failure: {id: DSP-002-F, description: "A key that holds only artifact read authority cannot register or claim, and a report from a principal that does not hold the claim is refused as a state conflict."}
    deployments: *all
    status: behavior_verified
    depends_on: [DSP-001, AUTH-008]
    evidence:
      - deployment: local
        tests: [DSP-002-B, DSP-002-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T18:31:17.376Z"

  - id: DSP-003
    kind: behavior
    behavior: One send creates one dispatch that carries its threads in order, accepts one to one hundred threads from the same project, and replays by idempotency key.
    owner: agent-dispatch
    source: {file: agent-dispatch-spec.md, anchor: conformance-and-testing}
    acceptance:
      behavior: {id: DSP-003-B, description: "Send a bundle of open threads to a registered agent and observe one dispatch that keeps the requested order, and a repeat with the same idempotency key that returns the original marked as a replay."}
      failure: {id: DSP-003-F, description: "An empty, oversized, cross-project, resolved-thread, or already-dispatched bundle is rejected and marks no thread, so a rejected send leaves the project exactly as it was."}
    deployments: *all
    status: behavior_verified
    depends_on: [DSP-001, CMT-001, CMT-010]
    evidence:
      - deployment: local
        tests: [DSP-003-B, DSP-003-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T18:31:17.376Z"

  - id: DSP-004
    kind: behavior
    behavior: A dispatched thread leaves the default comment listings on every surface and is findable only through the dispatched filter, while reading that one thread directly still works.
    owner: agent-dispatch
    source: {file: agent-dispatch-spec.md, anchor: conformance-and-testing}
    acceptance:
      behavior: {id: DSP-004-B, description: "Send a bundle, then list comments through the HTTP API and through MCP with no filter, with the include value, and with the only value, and read one dispatched thread directly; the HTTP API and MCP answer the same for the same principal and the web application uses the same routes."}
      failure: {id: DSP-004-F, description: "A dispatched thread cannot appear in any default listing on any surface, and the filter cannot return a thread from another project or another installation."}
    deployments: *all
    status: behavior_verified
    depends_on: [DSP-003, CMT-012]
    evidence:
      - deployment: local
        tests: [DSP-004-B, DSP-004-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T18:31:17.376Z"

  - id: DSP-005
    kind: behavior
    behavior: An agent claims the oldest queued dispatch addressed to it, holds one claim at a time, and a waiting claim call returns a dispatch or an empty answer within the requested wait.
    owner: agent-dispatch
    source: {file: agent-dispatch-spec.md, anchor: conformance-and-testing}
    acceptance:
      behavior: {id: DSP-005-B, description: "Queue three bundles for one agent and observe them claimed oldest first, one at a time, each after the previous is reported, with the waiting call answering within its bound."}
      failure: {id: DSP-005-F, description: "A second claim while one is held returns an empty answer, and two agents claiming at the same moment never receive the same dispatch."}
    deployments: *all
    status: behavior_verified
    depends_on: [DSP-003, DSP-002]
    evidence:
      - deployment: local
        tests: [DSP-005-B, DSP-005-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T18:31:17.376Z"

  - id: DSP-006
    kind: behavior
    behavior: A claim carries a lease, and a lease that expires returns the dispatch to the queue so it is delivered again rather than lost.
    owner: agent-dispatch
    source: {file: agent-dispatch-spec.md, anchor: conformance-and-testing}
    acceptance:
      behavior: {id: DSP-006-B, description: "Claim a dispatch, let its lease expire without a report, and observe the dispatch queued again and claimable by the same agent after a restart."}
      failure: {id: DSP-006-F, description: "A claimer that returns after its lease expired cannot report on the dispatch it no longer holds, and no moment exists in which two claims of one dispatch are active."}
    deployments: *all
    status: behavior_verified
    depends_on: [DSP-005]
    evidence:
      - deployment: local
        tests: [DSP-006-B, DSP-006-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T18:31:17.376Z"

  - id: DSP-007
    kind: behavior
    behavior: A dispatch moves only through the recorded delivery states, and a terminal state never changes again.
    owner: agent-dispatch
    source: {file: agent-dispatch-spec.md, anchor: conformance-and-testing}
    acceptance:
      behavior: {id: DSP-007-B, description: "Walk one dispatch from queued through claimed, delivered, and addressed, and observe each transition stamped with its own time."}
      failure: {id: DSP-007-F, description: "Every transition the machine does not allow, including any report or cancel against a terminal state, is refused as a state conflict and no recorded time moves backwards."}
    deployments: *all
    status: behavior_verified
    depends_on: [DSP-005, DSP-006]
    evidence:
      - deployment: local
        tests: [DSP-007-B, DSP-007-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T18:31:17.376Z"

  - id: DSP-008
    kind: behavior
    behavior: A delivered dispatch becomes addressed when every thread in its bundle is resolved, and that is recorded once.
    owner: agent-dispatch
    source: {file: agent-dispatch-spec.md, anchor: conformance-and-testing}
    acceptance:
      behavior: {id: DSP-008-B, description: "Resolve every thread of a delivered bundle through the comment operations and read the dispatch as addressed with the time it was first observed."}
      failure: {id: DSP-008-F, description: "Resolving all but one thread leaves the dispatch delivered, and reopening a thread afterwards does not undo or restamp an addressed dispatch."}
    deployments: *all
    status: behavior_verified
    depends_on: [DSP-007, CMT-005]
    evidence:
      - deployment: local
        tests: [DSP-008-B, DSP-008-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T18:31:17.376Z"

  - id: DSP-009
    kind: behavior
    behavior: A dispatch that fails, is canceled, or names an agent that has been gone too long releases its threads, and the threads return to the default listings.
    owner: agent-dispatch
    source: {file: agent-dispatch-spec.md, anchor: conformance-and-testing}
    acceptance:
      behavior: {id: DSP-009-B, description: "Report a failure, cancel another dispatch, and leave a third queued for an agent that stops polling; each releases its threads and the threads appear again in the default listings with their replies intact."}
      failure: {id: DSP-009-F, description: "An addressed dispatch releases nothing while its threads stay resolved, reopening one of them returns that thread to the default listings and to the sendable set without altering the dispatch record, and a released thread cannot be released twice or attached to a second active dispatch while one is active."}
    deployments: *all
    status: behavior_verified
    depends_on: [DSP-004, DSP-007]
    evidence:
      - deployment: local
        tests: [DSP-009-B, DSP-009-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T20:30:21.763Z"

  - id: DSP-010
    kind: security
    behavior: Sending and canceling a dispatch require a direct human member or a principal that can manage any artifact, and every dispatch operation is project-scoped.
    owner: agent-dispatch
    source: {file: agent-dispatch-spec.md, anchor: conformance-and-testing}
    acceptance:
      behavior: {id: DSP-010-B, description: "Send and cancel as an admitted human member and as a service key that can manage any artifact, and list and read dispatches with artifact read authority."}
      failure: {id: DSP-010-F, description: "A key holding only the agent-connect capability can neither send nor cancel, and a dispatch, agent, or thread identifier presented under a different project returns not found without revealing which identifier exists."}
    deployments: *all
    status: behavior_verified
    depends_on: [DSP-003, AUTH-008, PRJ-002]
    evidence:
      - deployment: local
        tests: [DSP-010-B, DSP-010-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T18:31:17.376Z"

  - id: DSP-011
    kind: behavior
    behavior: The bridge renders one bundle as one message in the recorded shape and always hands it to the agent as follow-up work rather than interrupting it.
    owner: agent-dispatch
    source: {file: agent-dispatch-spec.md, anchor: conformance-and-testing}
    acceptance:
      behavior: {id: DSP-011-B, description: "Render a bundle through the bridge library and observe the sender line, optional note, numbered items with artifact, version, path, quoted selection, body, and thread identifier, and the closing reply-and-resolve instruction."}
      failure: {id: DSP-011-F, description: "A rendered message never begins with a slash, and no path through the bridge hands a message to the agent as an interruption or without naming follow-up delivery."}
    deployments: [local]
    status: behavior_verified
    depends_on: [DSP-005]
    evidence:
      - deployment: local
        tests: [DSP-011-B, DSP-011-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T19:41:01.313Z"

  - id: DSP-012
    kind: behavior
    behavior: The bridge never disturbs its host. Without configuration it stays dormant, network failure backs off within bounds, and a lost session ends the loop without raising an error into the host.
    owner: agent-dispatch
    source: {file: agent-dispatch-spec.md, anchor: conformance-and-testing}
    acceptance:
      behavior: {id: DSP-012-B, description: "Start the bridge with no origin or credential and observe one notice and no polling, then start it configured and observe registration, claiming, delivery reporting, and a clean shutdown."}
      failure: {id: DSP-012-F, description: "With the server unreachable and with an invalidated session handle, the loop backs off within its recorded bounds or ends, and no error reaches the host."}
    deployments: [local]
    status: behavior_verified
    depends_on: [DSP-011]
    evidence:
      - deployment: local
        tests: [DSP-012-B, DSP-012-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-18T20:30:21.763Z"

  - id: DSP-013
    kind: behavior
    behavior: The bridge reports delivered only after its host admits the message. An asynchronous refusal fails that dispatch and leaves the bridge available for later work, while a synchronous invalidated host handle still ends the loop.
    owner: agent-dispatch
    source: {file: agent-dispatch-spec.md, anchor: conformance-and-testing}
    acceptance:
      behavior: {id: DSP-013-B, description: "Hold a claimed dispatch while host admission is pending, resolve that handoff, and observe delivery; after a separate refused handoff, observe the same bridge deliver the next bundle."}
      failure: {id: DSP-013-F, description: "Delete an OpenCode target while its asynchronous handoff is pending and observe a failed dispatch with its comments returned to the open list, then select another session and deliver later work without restarting the bridge."}
    deployments: [local]
    status: behavior_verified
    proof_gap: The shared bridge and OpenCode adapter are exercised through injected host ports against a real local server; live OpenCode and Claude transport acceptance remain adapter qualification checks.
    depends_on: [DSP-009, DSP-012]
    evidence:
      - deployment: local
        tests: [DSP-013-B, DSP-013-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-27T01:14:27.292Z"

  - id: BRP-001
    kind: behavior
    behavior: The extracted bridge core is host-agnostic. It drives a fake host through register, claim, deliver, reply, and resolve against a real server, and its module graph reaches no Pi code.
    owner: agent-bridge
    source: {file: agent-presence-and-bridge-spec.md, anchor: the-reusable-bridge-protocol}
    acceptance:
      behavior: {id: BRP-001-B, description: "A fake host port drives the extracted core through registration with capabilities, a claim, a delivered report, and comment reply and resolve against a spawned server, and the dispatch reaches addressed."}
      failure: {id: BRP-001-F, description: "The bridge core module graph resolves to no Pi module and no host-specific dependency; only host-neutral imports appear."}
    deployments: [local]
    status: behavior_verified
    proof_gap: Verified with fake hosts against the local deployment; two adapters (Pi and OpenCode) now consume the package, but the OpenCode side is proven through a fake plugin context rather than a live opencode binary.
    depends_on: [DSP-011, DSP-012]
    evidence:
      - deployment: local
        tests: [BRP-001-B, BRP-001-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-25T21:29:14.000Z"

  - id: PRS-001
    kind: behavior
    behavior: Agent listings derive activity and the active dispatch from durable dispatch state without requiring an activity beacon.
    owner: agent-presence
    source: {file: agent-presence-and-bridge-spec.md, anchor: conformance-sketch-ids-reserved-all-specified}
    acceptance:
      behavior: {id: PRS-001-B, description: "A fresh connected agent reads idle, a claimed or delivered bundle reads working with its dispatch ID, and resolving the complete bundle returns the agent to idle."}
      failure: {id: PRS-001-F, description: "A stale heartbeat reads disconnected even while a claim exists, and repeated reads do not write or extend activity state."}
    deployments: [local]
    status: behavior_verified
    depends_on: [DSP-001, DSP-007]
    evidence:
      - deployment: local
        tests: [PRS-001-B, PRS-001-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-25T21:42:39.000Z"

  - id: PRS-002
    kind: behavior
    behavior: An optional activity beacon refines a connected agent's state, expires after 60 seconds, and never makes a stale agent appear connected.
    owner: agent-presence
    source: {file: agent-presence-and-bridge-spec.md, anchor: conformance-sketch-ids-reserved-all-specified}
    acceptance:
      behavior: {id: PRS-002-B, description: "Thinking and replying beacons surface as working, overwrite in place, decay after 60 seconds to derived activity, and an idle beacon clears the refinement immediately."}
      failure: {id: PRS-002-F, description: "A beacon for an agent with a stale heartbeat is accepted as best-effort input but never decorates that agent as connected or working."}
    deployments: [local]
    status: behavior_verified
    depends_on: [PRS-001]
    evidence:
      - deployment: local
        tests: [PRS-002-B, PRS-002-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-25T21:42:39.000Z"

  - id: PRS-003
    kind: security
    behavior: Only the principal that registered an agent can submit its activity beacon, and refused requests disclose no foreign agent identity.
    owner: agent-presence
    source: {file: agent-presence-and-bridge-spec.md, anchor: conformance-sketch-ids-reserved-all-specified}
    acceptance:
      behavior: {id: PRS-003-B, description: "An agent-connect principal beacons its own registered agent and the finer activity state appears in the authenticated agent listing."}
      failure: {id: PRS-003-F, description: "Another principal receives the same not-found result for a foreign and fabricated agent ID, a human principal is denied, and no refused beacon changes listing state."}
    deployments: [local]
    status: behavior_verified
    depends_on: [PRS-002, DSP-002]
    evidence:
      - deployment: local
        tests: [PRS-003-B, PRS-003-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-25T21:42:39.000Z"

  - id: PRS-005
    kind: behavior
    behavior: Bulk comment clearing stays scoped to one artifact, records deletions, skips actively dispatched work, and reports deleted and skipped counts.
    owner: agent-presence
    source: {file: agent-presence-and-bridge-spec.md, anchor: conformance-sketch-ids-reserved-all-specified}
    acceptance:
      behavior: {id: PRS-005-B, description: "Clearing resolved or all threads deletes exactly the eligible artifact threads, records one ledger action per deletion, and repeating the operation is safe."}
      failure: {id: PRS-005-F, description: "Actively dispatched threads are skipped and counted, insufficient authority deletes nothing, and MCP returns the same result shape as HTTP."}
    deployments: [local]
    status: behavior_verified
    depends_on: [CMT-005, CMT-011, DSP-003]
    evidence:
      - deployment: local
        tests: [PRS-005-B, PRS-005-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-25T21:42:39.000Z"

  - id: PRS-004
    kind: behavior
    behavior: With exactly one connected agent the send button dispatches immediately with no dialog and offers an undo that cancels from queued or claimed. An undo after a terminal state reports the conflict honestly.
    owner: agent-presence
    source: {file: agent-presence-and-bridge-spec.md, anchor: frictionless-send-no-confirmation-dialog}
    acceptance:
      behavior: {id: PRS-004-B, description: "One connected agent sends on a single click with no dialog, the undo toast cancels the queued dispatch server-side, the dialog still opens for a bundle note, and a caret menu handles a multi-agent choice."}
      failure: {id: PRS-004-F, description: "An undo against a dispatch that reached a terminal state surfaces the state conflict in the toast and does not silently re-cancel."}
    deployments: [local]
    status: behavior_verified
    proof_gap: Proven in the browser suite against the local deployment; the zero-agent state, note dialog, and multi-agent caret are exercised in the same spec rather than separate requirements.
    depends_on: [DSP-005, PRS-001]
    evidence:
      - deployment: local
        tests: [PRS-004-B, PRS-004-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-25T21:56:38.766Z"

  - id: PRS-006
    kind: behavior
    behavior: Presence renders as the agent's branded avatar whose ring carries the state, with a popover stating the state in words, motion only on live states, and a static fallback under reduced motion.
    owner: agent-presence
    source: {file: agent-presence-and-bridge-spec.md, anchor: presence-in-the-ui}
    acceptance:
      behavior: {id: PRS-006-B, description: "The avatar ring tracks idle, working, and replying from real server state and the popover appears on hover and focus with the state in words."}
      failure: {id: PRS-006-F, description: "Under reduced motion no animation runs and the states stay distinguishable, and a disconnected agent disables send with a reason."}
    deployments: [local]
    status: behavior_verified
    proof_gap: Ring states are asserted via data attributes and computed styles in the browser suite; visual appearance is reviewed by hand.
    depends_on: [PRS-001, PRS-002]
    evidence:
      - deployment: local
        tests: [PRS-006-B, PRS-006-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-25T21:56:38.766Z"

  - id: PRS-007
    kind: behavior
    behavior: Agent registration accepts any valid kind slug, normalizes declared capabilities to known keys, ignores unknown capability keys, and answers with protocol version 1.
    owner: agent-presence
    source: {file: agent-presence-and-bridge-spec.md, anchor: the-reusable-bridge-protocol}
    acceptance:
      behavior: {id: PRS-007-B, description: "Any valid kind slug registers, round-trips through the agent listing with its normalized capabilities, and the registration response carries protocol version 1."}
      failure: {id: PRS-007-F, description: "A kind that is not a valid slug is refused with a validation failure and registers nothing."}
    deployments: [local]
    status: behavior_verified
    proof_gap: Slug widening is exercised through HTTP against SQLite; the Postgres and D1 migrations that drop the kind CHECK constraint are covered by their runtime suites' registration paths but no dedicated widening test runs against external storage.
    depends_on: [DSP-001]
    evidence:
      - deployment: local
        tests: [PRS-007-B, PRS-007-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-25T21:29:14.000Z"

  - id: SND-001
    kind: behavior
    behavior: Review loads every comment page for the exact version, presents one exact open-undispatched count, and makes sending all open comments the primary human action while preserving sent-state inspection and recovery.
    owner: web-application
    source: {file: send-all-spec.md, anchor: conformance-ids-reserved-ledger-entries-land-with-the-build}
    acceptance:
      behavior: {id: SND-001-B, description: "Load more than one API page of comments, send every open undispatched thread in one human action, and observe the exact count, complete Sent filter, Addressed state after resolution, pin removal, and canceled sends returning their threads to the open list."}
      failure: {id: SND-001-F, description: "Pagination cannot lower the displayed count or omit a thread from send-all, and a sent thread cannot remain pinned or in the open list while a canceled thread cannot remain hidden."}
    deployments: [local]
    status: behavior_verified
    proof_gap: Local browser evidence uses one principal and exercises 101 comments as exactly two server-bounded dispatches; larger counts, more than two batches, and other deployments remain unrecorded.
    depends_on: [CMT-012, DSP-004, PRS-004]
    evidence:
      - deployment: local
        tests: [SND-001-B, SND-001-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-26T18:29:39.022Z"

  - id: SND-002
    kind: behavior
    behavior: Review derives the send-all destination and copy from connected agent presence, remembers the last destination per principal and project, and never silently substitutes another agent.
    owner: web-application
    source: {file: send-all-spec.md, anchor: conformance-ids-reserved-ledger-entries-land-with-the-build}
    acceptance:
      behavior: {id: SND-002-B, description: "Send to one connected agent, choose and remember a project default from the multi-agent caret menu, and send to a mailbox-tier agent while the control and toast state the true destination and queue behavior."}
      failure: {id: SND-002-F, description: "No connected agent, no open thread, and a present-but-disconnected remembered default disable the main action with their exact reasons; a missing remembered registration is forgotten, and a disconnected default never falls through to another connected agent."}
    deployments: [local]
    status: behavior_verified
    proof_gap: Local browser evidence uses one principal; it proves a disconnected default by aging a still-listed registration beyond the heartbeat window and separately proves that a deleted registration is forgotten. Other principals and deployments remain unrecorded.
    depends_on: [PRS-001, PRS-004, BRP-002, SND-001]
    evidence:
      - deployment: local
        tests: [SND-002-B, SND-002-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-26T18:29:39.022Z"

  - id: BRP-002
    kind: behavior
    behavior: Any MCP-capable agent joins the dispatch loop at the mailbox tier through one inbox tool with implicit registration, a rendered sanitized bundle that names its actual MCP comment tools on claim, honest delivery reports, and strict per-principal isolation.
    owner: agent-bridge
    source: {file: agent-presence-and-bridge-spec.md, anchor: prior-art-the-live-session-bridge-research}
    acceptance:
      behavior: {id: BRP-002-B, description: "An MCP principal lists its inbox with implicit mailbox registration, claims the oldest dispatch as a rendered sanitized mailbox-profile bundle byte-identical to the shared render contract and naming comment_reply plus comment_resolve, reports delivered, and the agent listing shows the mailbox tier; those MCP tools drive the dispatch to addressed."}
      failure: {id: BRP-002-F, description: "A second principal never sees the first principal's dispatches, a claim with an empty inbox answers cleanly, and a delivered report for a dispatch the caller does not hold is refused without state change."}
    deployments: [local]
    status: behavior_verified
    proof_gap: The render mirror in src/mcp is pinned byte-for-byte against the package render by the acceptance test rather than shared as one module; drift fails the test but the duplication itself is accepted and documented.
    depends_on: [BRP-001, DSP-004, CMT-012]
    evidence:
      - deployment: local
        tests: [BRP-002-B, BRP-002-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-27T01:30:08.040Z"

  - id: NDG-001
    kind: behavior
    behavior: A principal whose mailbox agent has queued dispatches sees exactly one derived, priority-ordered nudge appended to unrelated MCP tool results, naming the real count, stepping down to the unfinished-claim and settling states as work progresses, and disappearing once nothing is pending.
    owner: agent-bridge
    source: {file: tool-result-nudges-spec.md, anchor: design}
    acceptance:
      behavior: {id: NDG-001-B, description: "With queued mailbox dispatches, an unrelated tool result carries exactly one queued-work nudge naming the real count; claiming steps it down to the unfinished-claim nudge and resolving the bundle to the settling echo; an empty queue yields no nudge."}
      failure: {id: NDG-001-F, description: "With work queued, an error result and a dispatch_inbox result each carry no nudge."}
    deployments: [local]
    status: behavior_verified
    proof_gap: Queue scanning is capped at the first ten projects; a queue in an unscanned project is claimable but uncounted, and no test exercises a principal in more than ten projects.
    depends_on: [BRP-002]
    evidence:
      - deployment: local
        tests: [NDG-001-B, NDG-001-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-26T16:23:33.278Z"

  - id: NDG-002
    kind: behavior
    behavior: Nudges never alter the underlying tool result and never cross principals. Structured content and existing content items are byte-identical with and without a pending nudge, the nudge is one bounded sanitized trailing item, and a second principal sees none of the first principal's counts.
    owner: agent-bridge
    source: {file: tool-result-nudges-spec.md, anchor: rules}
    acceptance:
      behavior: {id: NDG-002-B, description: "structuredContent and the pre-existing content items are byte-identical with and without a pending nudge, and the nudge is one bounded trailing text item passed through the shared sanitization."}
      failure: {id: NDG-002-F, description: "A second principal calling the same tools sees none of the first principal's counts, with or without a mailbox agent of its own."}
    deployments: [local]
    status: behavior_verified
    proof_gap: Nudges quote only counts and server-minted ids in v1, so the sanitization path is proven by a focused unit test on the composer rather than by hostile text reaching a live nudge.
    depends_on: [NDG-001]
    evidence:
      - deployment: local
        tests: [NDG-002-B, NDG-002-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-26T16:23:33.278Z"

  - id: DRF-001
    kind: behavior
    behavior: Comment draft text survives in-app navigation and a page reload, restores into the same composer with a draft marker, and is gone after the comment posts and after explicit discard.
    owner: web-application
    source: {file: comment-drafts-spec.md, anchor: design-two-layers}
    acceptance:
      behavior: {id: DRF-001-B, description: "Draft text survives a version switch, artifact navigation, and a page reload, restoring into the same composer with the draft marker."}
      failure: {id: DRF-001-F, description: "After the comment posts, and after explicit discard, no draft remains in memory or in browser storage."}
    deployments: [local]
    status: behavior_verified
    proof_gap: Frontend-only by owner decision; drafts are proven in one browser profile against the local deployment and do not exist across devices.
    depends_on: [CMT-001]
    evidence:
      - deployment: local
        tests: [DRF-001-B, DRF-001-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-26T16:24:08.705Z"

  - id: DRF-002
    kind: behavior
    behavior: Drafts are principal-scoped and bounded. Another principal's draft never restores, logout clears only the departing principal's drafts, a reply draft never restores into the new-thread composer, and closing over a non-empty draft prompts.
    owner: web-application
    source: {file: comment-drafts-spec.md, anchor: design-two-layers}
    acceptance:
      behavior: {id: DRF-002-B, description: "A foreign principal's mirrored draft never restores and survives the signed-in principal's logout, and a reply draft never restores into the new-thread composer."}
      failure: {id: DRF-002-F, description: "Logout through the real session client clears the departing principal's drafts, and closing the tab over a non-empty draft triggers the leave prompt."}
    deployments: [local]
    status: behavior_verified
    proof_gap: Local mode has one browser principal, so the second principal is represented by a principal-keyed mirror entry rather than a second interactive sign-in.
    depends_on: [DRF-001]
    evidence:
      - deployment: local
        tests: [DRF-002-B, DRF-002-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-26T16:24:08.705Z"

  - id: WMC-001
    kind: behavior
    behavior: When a model context is present the review application registers seven provenance-prefixed WebMCP tools; one get_view orients, and mutations through the tools update the server and the UI with each result carrying the post-mutation thread and counts. Without a model context the application behaves identically and logs nothing.
    owner: web-application
    source: {file: webmcp-review-tools-spec.md, anchor: out-of-the-box-tool-set-v1-seven-tools}
    acceptance:
      behavior: {id: WMC-001-B, description: "The seven tools register with provenance names; get_view orients; reply then resolve through the tools update the server and the UI, each result carrying the updated thread and post-mutation counts with no read-back."}
      failure: {id: WMC-001-F, description: "Without a model context the application behaves identically and logs nothing, and the per-user toggle unregisters and re-registers the tools live."}
    deployments: [local]
    status: behavior_verified
    proof_gap: document.modelContext is faked in the browser suite to the adapter's reading of the WebMCP draft (commit bd99438, August 2026); fidelity to the real browser API is untested until a WebMCP-capable browser drives it.
    depends_on: [CMT-012]
    evidence:
      - deployment: local
        tests: [WMC-001-B, WMC-001-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-26T16:24:08.705Z"

  - id: WMC-002
    kind: behavior
    behavior: WebMCP tools never widen authority. Every call is refused or allowed exactly as the same session's UI operation, tools never register on content frames, and descriptions stay bounded and quote no untrusted text.
    owner: web-application
    source: {file: webmcp-review-tools-spec.md, anchor: stances}
    acceptance:
      behavior: {id: WMC-002-B, description: "A missing thread and an archived project refuse a tool call with the identical failure code the same session receives through the UI path."}
      failure: {id: WMC-002-F, description: "No non-main frame holds a registration, and every description is at or under 300 characters, carries provenance, and never contains seeded hostile text."}
    deployments: [local]
    status: behavior_verified
    proof_gap: Descriptions are static literals, so the no-untrusted-text assertion guards future changes rather than a live path; resolve and reopen read before writing, so an archived-project refusal is proven at the read.
    depends_on: [WMC-001]
    evidence:
      - deployment: local
        tests: [WMC-002-B, WMC-002-F]
        result: pass
        run: project/evidence/browser.json
        recorded_at: "2026-08-26T16:24:08.705Z"

  - id: PLN-001
    kind: behavior
    behavior: One Artifact Server installation connects to one Plannotator organization through browser approval in the first integration release.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-001-B, description: "An Artifact Server administrator opens Plannotator, signs in, selects one organization, approves, and sees a healthy connection in both products."}
      failure: {id: PLN-001-F, description: "A second organization, non-administrator, replayed callback, wrong server, and connection-claim race cannot create or take over the connection."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [AUTH-001]
    evidence: []

  - id: PLN-002
    kind: constraint
    behavior: Connecting does not copy user accounts or forward WorkOS tokens, browser cookies, MCP tokens, reusable user credentials, or Plannotator API keys.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-002-B, description: "Trace pairing and managed operations and observe only connection identity and short-lived signed requests at Artifact Server."}
      failure: {id: PLN-002-F, description: "Credential scanning finds no Plannotator or WorkOS user credential in Artifact Server records, logs, storage, content, or Git."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-001]
    evidence: []

  - id: PLN-003
    kind: behavior
    behavior: Plannotator owns sign-in, its organization, project and workspace records, workspace permissions, its own workspace comments, annotations, replies, notifications, and review state; Artifact Server owns paired project records, artifact IDs, versions, manifests, files, delivery, comparisons, artifact access settings, and comment threads on its own versions.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-003-B, description: "Complete a managed publish and review and confirm that each record, including each product's own comments, is stored only by its owning system with stable cross-references."}
      failure: {id: PLN-003-F, description: "Artifact Server does not create a second organization, workspace, workspace membership, workspace comment, notification, or review-state record."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-001, ART-001, VER-001]
    evidence: []

  - id: PLN-004
    kind: security
    behavior: One Plannotator organization maps to one Artifact Server installation and each Plannotator project maps to one Artifact Server project; connected projects use the normal Artifact Server project, artifact, version, storage, audit, and access model rather than a separate managed area.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-004-B, description: "Pair one organization and two projects, publish through Artifact Server and Plannotator, and observe one stable installation and project identity for each paired project."}
      failure: {id: PLN-004-F, description: "Another organization, installation, connection, project, guessed ID, stale binding, and conflicting existing-project binding cannot claim, cross, or duplicate the paired project."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PRJ-002, PLN-003]
    evidence: []

  - id: PLN-005
    kind: behavior
    behavior: Plannotator workspaces reference artifacts and exact versions from their paired project; a workspace ID identifies only the referring collaboration context.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-005-B, description: "Reference and review a project artifact from two workspaces and retain stable installation, project, artifact, exact version, workspace, and actor references."}
      failure: {id: PLN-005-F, description: "Moving, unfiling, deleting, or changing visibility of a workspace cannot move, delete, or retarget the project artifact or version."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-004]
    evidence: []

  - id: PLN-006
    kind: security
    behavior: Plannotator checks project or workspace permission and signs a short-lived request limited to one connection, installation, paired project, actor, operation, and named artifact or version; workspace ID is present only when it supplies the narrow reference context.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-006-B, description: "Authorize project publish, list, read, compare, visibility, and exact workspace-reference reads with minimum claims and five-minute-or-shorter expiry."}
      failure: {id: PLN-006-F, description: "Reject wrong signature, issuer, audience, connection, installation, project, workspace context, actor, operation, artifact, version, time, and replayed request ID."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-001, PLN-005]
    evidence: []

  - id: PLN-007
    kind: security
    behavior: Artifact Server verifies the Plannotator request through its normal authorization layer and records the external actor in its action log.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-007-B, description: "Execute each delegated mutation and observe the connection, project, optional referring workspace, external actor, artifact, version, operation, and outcome in audit evidence."}
      failure: {id: PLN-007-F, description: "A Plannotator-signed request cannot bypass installation or project policy, operation scope, or action logging."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-006, AUD-001, AUTH-008]
    evidence: []

  - id: PLN-008
    kind: security
    behavior: Opening a private managed version uses a short-lived single-use Artifact Server URL and first-party read-only content session rather than a Plannotator cookie.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-008-B, description: "Authorize in Plannotator, consume the one-use URL as a top-level page, remove it from the clean URL, and load all exact-version assets."}
      failure: {id: PLN-008-F, description: "Replay, expiration, another user, project, workspace context, artifact, version, host, or iframe-only cookie path cannot gain access."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-006, AUTH-014, AUTH-015]
    evidence: []

  - id: PLN-009
    kind: behavior
    behavior: Review mode uses a separate isolated review address and may add a small bridge to HTML responses for that session only; normal responses and stored versions remain unchanged.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-009-B, description: "Compare stored bytes, normal responses, downloads, manifests, Git, and explicit review responses and observe the bridge only in review HTML."}
      failure: {id: PLN-009-F, description: "Review mode cannot alter stored bytes, fingerprints, exact-version identity, normal caching, non-HTML files, or later normal requests."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-008, ART-004]
    evidence: []

  - id: PLN-010
    kind: security
    behavior: The review bridge receives no reusable credential and exchanges only bounded origin-checked, session-checked review messages with Plannotator.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-010-B, description: "Identify route, selected text, and selected element and exchange the allowed message schema within one review session."}
      failure: {id: PLN-010-F, description: "Hostile artifact JavaScript, wrong origin, wrong session, malformed message, replay, service worker, CSP, and expired session cannot impersonate the bridge or obtain authority."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-009, SEC-001]
    evidence: []

  - id: PLN-011
    kind: behavior
    behavior: Plannotator comments record installation, artifact, exact version, route, and anchor so a comment continues to open the reviewed version after later publishes.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-011-B, description: "Comment on version 12, publish version 13, and reopen the comment against unchanged version 12 with its route and anchor."}
      failure: {id: PLN-011-F, description: "Current-version movement, restore, rename, disconnect, or later publication cannot silently retarget the comment to different bytes."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-010, VER-001]
    evidence: []

  - id: PLN-012
    kind: security
    behavior: Pairing records support health, disconnect, verification-key rotation, bounded overlap, revocation, and an audit trail in both products.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-012-B, description: "Rotate keys without interrupting valid in-flight work, disconnect, and observe new operations and renewals stop with complete audit records."}
      failure: {id: PLN-012-F, description: "Old keys after overlap, revoked connection, wrong organization or project, stale connection state, and replayed approval cannot authorize work."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-001, PLN-006, AUD-001]
    evidence: []

  - id: PLN-013
    kind: behavior
    behavior: Connecting does not silently move existing artifacts; pairing an existing Artifact Server project with a Plannotator project is an explicit administrator action with defined conflict, unlink, archive, rollback, and reconnect behavior.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-013-B, description: "Connect a server with existing projects and artifacts, confirm no changes, then explicitly pair one existing project while preserving every ID and link."}
      failure: {id: PLN-013-F, description: "Connection, reconnect, disconnect, workspace changes, name conflicts, and failed pairing cannot silently expose, duplicate, move, retarget, archive, or lose a project artifact."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-004, PLN-005]
    evidence: []

  - id: PLN-017
    kind: security
    behavior: A workspace permission may open one referenced project artifact or exact version through a short-lived read-only session, but it never grants project-library listing or artifact mutation.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-017-B, description: "Open one referenced artifact version from private, organization-gated, link-view, and link-edit workspaces through the approved narrow session without exposing the project list."}
      failure: {id: PLN-017-F, description: "Workspace access, including public and link-edit access, cannot list the project library or publish, restore, change visibility, delete, or open an unreferenced artifact or version."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-005, PLN-006, PLN-008]
    evidence: []

  - id: PLN-014
    kind: deployment
    behavior: A reachable server connects directly; a private server requires a customer-provided route or outbound-only connector limited to the paired Artifact Server service.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-014-B, description: "Connect through direct reachability and the selected private route while exposing only the paired Artifact Server service."}
      failure: {id: PLN-014-F, description: "Pairing never changes firewall rules, creates a general network proxy, exposes another service, or makes an account-required artifact public."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-001, SEC-002]
    evidence: []

  - id: PLN-015
    kind: behavior
    behavior: Plannotator and Artifact Server fail closed and preserve references when either product or the private connector is unavailable.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: plannotator}
    acceptance:
      behavior: {id: PLN-015-B, description: "Interrupt each component, observe explicit connection state, retain artifact references, and recover without re-pairing when allowed."}
      failure: {id: PLN-015-F, description: "Outage, reconnect, duplicate delivery, and stale health cannot create unauthorized operations, silent secondary copies, or lost IDs."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-012, PLN-014]
    evidence: []

  - id: PLN-016
    kind: release_gate
    behavior: If the injected review bridge cannot pass browser, CSP, hostile-script, service-worker, anchor, and credential-isolation tests, the supported fallback is a browser extension.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: PLN-016-B, description: "Record the bridge decision with conformance evidence or pass the same review suite through the browser-extension fallback."}
      failure: {id: PLN-016-F, description: "The product never falls back to placing a reusable Plannotator or Artifact Server credential in artifact JavaScript."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-010]
    evidence: []

  - id: ARC-001
    kind: constraint
    behavior: The product core is one modular application and does not import a specific database, blob store, login provider, background-job system, Git provider, or deployment framework.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: ARC-001-B, description: "Run core service tests with in-memory or fake ports and replace each provider through its documented adapter."}
      failure: {id: ARC-001-F, description: "A dependency-boundary test fails when core product code imports a concrete infrastructure provider or deployment framework."}
    deployments: *all
    status: specified
    depends_on: []
    evidence: []

  - id: ARC-002
    kind: constraint
    behavior: Infrastructure adapters expose product operations such as committing a version or issuing a private-content session instead of leaking raw SQL, bucket, cookie, or provider APIs into callers.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: ARC-002-B, description: "Exercise each port through provider-neutral product inputs and outputs across at least two adapter implementations."}
      failure: {id: ARC-002-F, description: "Contract checks reject an adapter or caller that requires provider-specific types, credentials, or query syntax outside the adapter."}
    deployments: *all
    status: specified
    depends_on: [ARC-001]
    evidence: []

  - id: ARC-003
    kind: constraint
    behavior: SQLite, D1, and Postgres share product behavior but keep separate migrations, indexes, and provider-appropriate optimized queries.
    owner: database-adapters
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: ARC-003-B, description: "Run the same repository conformance suite against every supported database while applying only that database's migrations and queries."}
      failure: {id: ARC-003-F, description: "Provider-specific SQL or an unsupported migration cannot be routed through another database adapter or silently skipped."}
    deployments: *all
    status: specified
    depends_on: [ARC-002]
    evidence: []

  - id: ARC-004
    kind: security
    behavior: Database and blob operations use the documented stage, verify, immutable-blob, transactional-record order because those systems do not share a transaction.
    owner: publishing
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: ARC-004-B, description: "Inject a failure after every publish step and recover to either no committed version or one complete immutable version."}
      failure: {id: ARC-004-F, description: "No failure point may expose a committed version with a missing or mutable referenced blob."}
    deployments: *all
    status: specified
    depends_on: [PUB-001, PUB-005]
    evidence: []

  - id: ARC-005
    kind: security
    behavior: Every login, OAuth token, API key, local token, MCP request, and Plannotator request is converted once into the same provider-neutral internal principal and policy checks.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: ARC-005-B, description: "Authorize equivalent principals from each supported authentication method and observe the same object and capability decisions."}
      failure: {id: ARC-005-F, description: "Provider claims, tokens, cookies, or keys cannot bypass tenant, membership, capability, or object authorization by reaching a handler directly."}
    deployments: *all
    status: specified
    depends_on: [AUTH-008, MCP-009, PLN-007]
    evidence: []

  - id: ARC-006
    kind: constraint
    behavior: HTTP, MCP, and CLI adapters call the same application services for overlapping artifact operations; adapter choice depends on caller and file locality and never creates a second product or authorization implementation.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: ARC-006-B, description: "Execute equivalent list, open, publish, compare, restore, tag, share, and delete operations through every applicable adapter and observe equivalent identities, authorization, idempotency, audit, and result semantics."}
      failure: {id: ARC-006-F, description: "Dependency checks and hostile adapter tests fail when an MCP tool or CLI command duplicates product policy, bypasses application authorization, or claims access to a remote client path."}
    deployments: *all
    status: specified
    depends_on: [ARC-001, ARC-002, ARC-005, MCP-009]
    evidence: []

  - id: DEP-001
    kind: deployment
    behavior: The same artifact, version, access, HTTP, and MCP contracts run on a laptop, one server, Kubernetes, Cloudflare, AWS, and GCP; Azure teams use the Kubernetes contract on AKS.
    owner: deployment
    source: {file: artifact-server-product-spec.html, anchor: deployment}
    acceptance:
      behavior: {id: DEP-001-B, description: "Run the external-storage conformance suite without product-contract changes on every advertised deployment."}
      failure: {id: DEP-001-F, description: "A target cannot be marked supported when it changes an ID, manifest, visibility, authorization, HTTP, or MCP behavior."}
    deployments: *all
    status: specified
    depends_on: [REL-006]
    evidence: []

  - id: DEP-002
    kind: deployment
    behavior: Official installation surfaces are Artifact Server local commands, Docker Compose, Helm for any supported Kubernetes cluster including AKS, a direct Alchemy Cloudflare project, and direct Pulumi projects for AWS and GCP.
    owner: deployment
    source: {file: artifact-server-product-spec.html, anchor: deployment}
    acceptance:
      behavior: {id: DEP-002-B, description: "Create each target with its documented native command and obtain the required URLs, resource identifiers, healthy server, and support manifest."}
      failure: {id: DEP-002-F, description: "An official path cannot require a customer to write infrastructure-framework code or manually invent required resources."}
    deployments: *all
    status: specified
    depends_on: [DEP-003]
    evidence: []

  - id: DEP-003
    kind: deployment
    behavior: Artifact Server does not wrap infrastructure lifecycle tools; operators use Compose, Helm, Alchemy, or Pulumi directly while every package implements one shared input, output, secret, evidence, and product-probe contract.
    owner: deployment
    source: {file: artifact-server-product-spec.html, anchor: deployment}
    acceptance:
      behavior: {id: DEP-003-B, description: "Preview, apply, inspect, and customize each complete native project while preserving the shared deployment outputs and product behavior."}
      failure: {id: DEP-003-F, description: "The Artifact Server CLI cannot proxy an infrastructure plan, hold infrastructure state, reinterpret provider errors, or require a hidden generated project."}
    deployments: *all
    status: specified
    depends_on: [ARC-001]
    evidence: []

  - id: DEP-004
    kind: deployment
    behavior: The default local target runs directly on the host without Docker, using SQLite, local blob storage, a local token, isolated localhost content origins, and Git handoff disabled by default. A local container is optional, and Cloudflare Artifacts may be configured separately through REST.
    owner: deployment
    source: {file: artifact-server-product-spec.html, anchor: deployment}
    acceptance:
      behavior: {id: DEP-004-B, description: "Install and complete the local publish, open, version, compare, visibility, MCP, restart, and optional-Git workflows without an external service."}
      failure: {id: DEP-004-F, description: "Local operation does not require Docker, another container runtime, browser OAuth, a cloud account, a hosted database, or internet access."}
    deployments: [local]
    status: specified
    depends_on: [MCP-013, CNT-004]
    evidence: []

  - id: DEP-005
    kind: deployment
    behavior: The one-server Compact Compose target runs exactly one container with SQLite and one persistent data directory, and it preserves complete installation state through restart, replacement, backup, and restore.
    owner: deployment
    source: {file: phase-6-packaging.md, anchor: compact-compose}
    acceptance:
      behavior: {id: DEP-005-B, description: "Deploy Compact Compose, publish a file and complete site, restart and replace the container, back up the stopped volume, restore into a clean volume, and preserve all IDs, records, pointers, manifests, action attribution, access settings, and bytes."}
      failure: {id: DEP-005-F, description: "Compact Compose rejects scaling, an ephemeral or uninitialized data path, bad permissions, missing generated secrets, invalid domain isolation, and incomplete identity-provider configuration without reporting ready."}
    deployments: [single_server]
    status: behavior_verified
    depends_on: [OPS-003]
    evidence:
      - deployment: single_server
        tests: [DEP-005-B, DEP-005-F]
        result: pass
        run: project/evidence/compact-compose.json
        recorded_at: "2026-08-17T03:10:29.404Z"

  - id: DEP-020
    kind: deployment
    behavior: External-storage Compose connects the production image to existing Postgres and object storage through a supported adapter, can run more than one application process, and stores no durable state on the application container filesystem.
    owner: deployment
    source: {file: phase-6-packaging.md, anchor: external-storage-compose}
    acceptance:
      behavior: {id: DEP-020-B, description: "Deploy External-storage Compose against real Postgres and object storage, replace every application container, and preserve IDs, records, pointers, manifests, action attribution, access settings, and bytes."}
      failure: {id: DEP-020-F, description: "External-storage Compose rejects incomplete provider configuration, unavailable or incompatible providers, and schema mismatch without reporting ready; the released service contains no application-data mount or container-local fallback."}
    deployments: [single_server]
    status: behavior_verified
    depends_on: [OPS-003, ARC-003]
    evidence:
      - deployment: single_server
        tests: [DEP-020-B, DEP-020-F]
        result: pass
        run: project/evidence/external-storage-compose.json
        recorded_at: "2026-08-17T03:12:03.334Z"

  - id: DEP-006
    kind: deployment
    behavior: The Kubernetes target uses stateless application replicas, Postgres, durable native or S3-compatible blob storage, and no artifact data on pod-local filesystems.
    owner: deployment
    source: {file: artifact-server-product-spec.html, anchor: deployment}
    acceptance:
      behavior: {id: DEP-006-B, description: "Publish while replicas roll, replace every pod, and confirm IDs, bytes, current pointers, and private delivery remain correct."}
      failure: {id: DEP-006-F, description: "Pod loss, rescheduling, or concurrent replicas cannot lose committed data, split the current pointer, or rely on a pod-local repository."}
    deployments: [kubernetes]
    status: behavior_verified
    depends_on: [ARC-003, OPS-001]
    evidence:
      - deployment: kubernetes
        tests: [DEP-006-B, DEP-006-F]
        result: pass
        run: project/evidence/helm-kubernetes.json
        recorded_at: "2026-08-17T03:12:42.551Z"

  - id: DEP-007
    kind: deployment
    behavior: The Cloudflare target uses Workers, D1 for metadata, R2 for file bytes, Alchemy for provisioning, WorkOS for hosted MCP authorization, and an off-by-default Cloudflare Artifacts binding for Git handoff.
    owner: deployment
    source: {file: artifact-server-product-spec.html, anchor: deployment}
    acceptance:
      behavior: {id: DEP-007-B, description: "Provision a clean Cloudflare deployment and pass publish, delivery, private access, MCP OAuth, backup, failure, and optional-history tests."}
      failure: {id: DEP-007-F, description: "D1 never stores artifact file bytes, optional history failure never blocks primary storage, and a missing optional provider leaves core behavior intact."}
    deployments: [cloudflare]
    status: implementing
    proof_gap: Selected live D1, R2, WorkOS, routing, cleanup, and recovery probes exist, but no DEP-007 run covers the complete clean provision, publish, delivery, private access, OAuth, backup, failure, optional-history, and optional-provider failure matrix.
    depends_on: [DEP-021, MCP-010, GIT-007, GATE-003]
    evidence: []

  - id: DEP-008
    kind: deployment
    behavior: The default AWS target is a direct Pulumi project that creates ECS Fargate, RDS PostgreSQL, S3, workload identity, secrets, networking, DNS, TLS, telemetry, and required support outputs.
    owner: deployment
    source: {file: artifact-server-product-spec.html, anchor: deployment}
    acceptance:
      behavior: {id: DEP-008-B, description: "Create, upgrade, roll back, recover state, back up, restore, and delete the AWS target with native S3 and private-network options."}
      failure: {id: DEP-008-F, description: "A failed update cannot orphan durable data, expose private content, or require Pulumi Cloud."}
    deployments: [aws]
    status: implementing
    proof_gap: Mocked Pulumi tests prove configuration and the resource graph, and live reports cover selected public-stack lifecycle probes; the complete native-S3, private-network, failed-update, state, backup/restore, and no-Pulumi-Cloud acceptance run is absent.
    depends_on: [DEP-003, DEP-021, OPS-003]
    evidence: []

  - id: DEP-009
    kind: deployment
    behavior: The default GCP target is a direct Pulumi project that creates Cloud Run, Cloud SQL PostgreSQL, native Google Cloud Storage, workload identity, secrets, networking, DNS, TLS, telemetry, and required support outputs.
    owner: deployment
    source: {file: artifact-server-product-spec.html, anchor: deployment}
    acceptance:
      behavior: {id: DEP-009-B, description: "Create, upgrade, roll back, recover state, back up, restore, and delete the GCP target with native GCS and private-network options."}
      failure: {id: DEP-009-F, description: "The supported path cannot depend on an S3 compatibility shim, lose durable state during replacement, or require Pulumi Cloud."}
    deployments: [gcp]
    status: implementing
    proof_gap: Mocked Pulumi tests prove configuration and the resource graph, and live reports cover selected public-stack lifecycle probes; the acceptance still names a private-network option that is not advertised, and complete native-GCS, replacement, state, backup/restore, and no-Pulumi-Cloud proof is absent.
    depends_on: [DEP-003, DEP-021, OPS-003]
    evidence: []

  - id: DEP-011
    kind: constraint
    behavior: The external runtime consumes one provider-neutral factory with immutable blob, staging, readiness, and shutdown capabilities; supported factories cover S3-compatible storage, native Google Cloud Storage, and Worker R2 without cloud SDK types entering product or protocol code. A native Azure Blob factory is available as preview and does not imply a supported Azure deployment.
    owner: blob-storage
    source: {file: artifact-server-product-spec.html, anchor: deployment}
    acceptance:
      behavior: {id: DEP-011-B, description: "Run the immutable-blob, staging, readiness, shutdown, and streaming contract suite against every first-party driver and its real managed provider before calling that driver supported."}
      failure: {id: DEP-011-F, description: "A driver cannot mutate an existing fingerprint, return bytes for another installation, claim success before durable availability, or leave an interrupted multipart upload."}
    deployments: *all
    status: behavior_verified
    depends_on: [ARC-002]
    evidence:
      - deployment: single_server
        tests: [DEP-011-B, DEP-011-F]
        result: pass
        run: project/evidence/s3-minio.json
        recorded_at: "2026-08-17T03:07:23.036Z"

  - id: DEP-012
    kind: deployment
    behavior: Installer versions are pinned, vendor-hosted infrastructure state is optional, customer-owned state uses an existing encrypted and versioned backend, and every installation emits a support manifest naming product, schema, adapter, and installer versions.
    owner: deployment
    source: {file: artifact-server-product-spec.html, anchor: deployment}
    acceptance:
      behavior: {id: DEP-012-B, description: "Recreate an installation from pinned inputs and inspect a complete, secret-free support manifest."}
      failure: {id: DEP-012-F, description: "An install cannot silently float infrastructure versions, require vendor-hosted state, let the main stack create the store that contains its own state, or place credentials in the support manifest."}
    deployments: *all
    status: specified
    depends_on: [DEP-002]
    evidence: []

  - id: DEP-021
    kind: deployment
    behavior: Every cloud package accepts the shared installation, domain, ingress, capacity, database, backup, deletion, identity, telemetry, state, and secret-reference inputs and returns the shared URL, digest, provider-resource, identity, network, log, state, and support-manifest outputs without returning a secret.
    owner: deployment
    source: {file: cloud-deployment-contract.md, anchor: shared-operator-inputs}
    acceptance:
      behavior: {id: DEP-021-B, description: "Validate one minimal and one fully configured stack for each cloud, apply it, and verify every required runtime value and machine-readable output against the shared contract."}
      failure: {id: DEP-021-F, description: "Reject unpinned images, equal application and content domains, invalid capacity, missing production deletion protection, missing public DNS, unknown inputs, secret outputs, and a main stack that creates its own state backend."}
    deployments: [cloudflare, aws, gcp]
    status: implementing
    proof_gap: Shared contract parsing and mocked package graphs cover many inputs and outputs, but no minimal and fully configured live apply for all three clouds verifies every required runtime value, output, and hostile input under DEP-021.
    depends_on: [DEP-002, DEP-003, DEP-012, DEP-014, DEP-016]
    evidence: []

  - id: DEP-022
    kind: constraint
    behavior: The external runtime, lifecycle inspection, and integrity scanner depend only on the object-storage provider factory; AWS, Google, and Cloudflare SDK imports stay inside their provider adapters and deployment packages, while the preview Azure SDK stays inside its storage adapter.
    owner: blob-storage
    source: {file: decisions/0017-native-cloud-projects-and-storage-provider-boundary.md, anchor: decision}
    acceptance:
      behavior: {id: DEP-022-B, description: "Build the server with only provider-neutral storage types crossing the runtime boundary and exercise the configured factory against real object storage."}
      failure: {id: DEP-022-F, description: "Dependency checks reject a cloud storage SDK import from application, core, HTTP, MCP, external-runtime, lifecycle, or repository code."}
    deployments: *external_storage
    status: behavior_verified
    depends_on: [ARC-002, DEP-011]
    evidence:
      - deployment: single_server
        tests: [DEP-022-B, DEP-022-F]
        result: pass
        run: project/evidence/s3-minio.json
        recorded_at: "2026-08-17T03:07:23.036Z"

  - id: DEP-013
    kind: security
    behavior: A trusted installation directory derives installation identity and storage assignment; a request cannot select an unverified installation ID, database, bucket, or prefix.
    owner: hosted-policy
    source: {file: artifact-server-product-spec.html, anchor: deployment}
    acceptance:
      behavior: {id: DEP-013-B, description: "Resolve requests through trusted host and identity data and prove correct database, bucket, key, and prefix selection."}
      failure: {id: DEP-013-F, description: "Host headers, paths, query parameters, tokens from another installation, and guessed IDs cannot redirect a request into another storage assignment."}
    deployments: *external_storage
    status: specified
    depends_on: [AUTH-014]
    evidence: []

  - id: DEP-014
    kind: deployment
    behavior: External-storage and hosted deployments provide a separate registrable content domain, wildcard DNS, and wildcard certificates; local deployment provides isolated wildcard localhost hosts.
    owner: deployment
    source: {file: artifact-server-product-spec.html, anchor: deployment}
    acceptance:
      behavior: {id: DEP-014-B, description: "Resolve and validate application and unique version hosts through supported DNS, TLS, proxy, and localhost configurations."}
      failure: {id: DEP-014-F, description: "A same-site application subdomain, invalid certificate, untrusted forwarded host, or path-only alias cannot be advertised as the supported isolation boundary."}
    deployments: *all
    status: behavior_verified
    depends_on: [CNT-003, CNT-004]
    evidence:
      - deployment: cloudflare
        tests: [DEP-014-B]
        result: pass
        run: project/evidence/cloudflare-phase11-content.json
        recorded_at: "2026-08-16T17:44:26.049Z"

  - id: DEP-015
    kind: deployment
    behavior: Artifact Server publishes one digest-pinned Linux OCI image for amd64 and arm64; the image contains the compiled CLI and production dependencies, runs as non-root with a read-only root filesystem, and stores durable data only through the selected profile's declared storage.
    owner: deployment
    source: {file: phase-6-packaging.md, anchor: image-contract}
    acceptance:
      behavior: {id: DEP-015-B, description: "Build and run both architectures, execute compact and external-storage workflows from the released image, replace the container, and verify the image digest and secret-free support manifest."}
      failure: {id: DEP-015-F, description: "The image cannot require root, a writable root filesystem, source files, development packages, floating tags, or undeclared container-local durable state."}
    deployments: [single_server, kubernetes, aws, gcp]
    status: specified
    depends_on: [DEP-005, DEP-006, DEP-012]
    evidence: []

  - id: DEP-016
    kind: security
    behavior: Deployed configuration supports mounted secret files, validates the application and wildcard content origins before serving, and trusts forwarded host and protocol values only from configured proxies.
    owner: deployment
    source: {file: phase-6-packaging.md, anchor: configuration-and-secrets}
    acceptance:
      behavior: {id: DEP-016-B, description: "Start Compose and Kubernetes packages with mounted secret files behind a configured TLS proxy and resolve both the application and unique content hosts."}
      failure: {id: DEP-016-F, description: "Conflicting direct and file credentials, unreadable secret files, untrusted forwarded hosts, invalid wildcard DNS or certificates, and incomplete provider configuration fail before the process reports ready."}
    deployments: [single_server, kubernetes, aws, gcp]
    status: specified
    depends_on: [DEP-014, SEC-004]
    evidence: []

  - id: DEP-017
    kind: deployment
    behavior: The Kubernetes chart deploys stateless Artifact Server replicas and references existing Postgres, object storage, secrets, DNS, TLS, and ingress infrastructure; it does not bundle durable providers or store artifact state on pod-local filesystems.
    owner: deployment
    source: {file: phase-6-packaging.md, anchor: kubernetes-contract}
    acceptance:
      behavior: {id: DEP-017-B, description: "Install the chart with two replicas, publish and read during a rolling update, replace every original pod, and pass the chart test against real Postgres and S3-compatible storage."}
      failure: {id: DEP-017-F, description: "Pod loss, node drain, unavailable providers, invalid secret references, or a failed migration cannot lose committed state, bypass readiness, or silently fall back to pod-local storage."}
    deployments: [kubernetes]
    status: behavior_verified
    depends_on: [DEP-006, DEP-015, DEP-016, OPS-001, OPS-002]
    evidence:
      - deployment: kubernetes
        tests: [DEP-017-B, DEP-017-F]
        result: pass
        run: project/evidence/helm-kubernetes.json
        recorded_at: "2026-08-17T03:12:42.551Z"

  - id: DEP-018
    kind: deployment
    behavior: Every released image and Helm chart has an immutable digest, SBOM, source-linked build provenance, signature, and declared compatibility matrix; generated deployment files never use latest tags.
    owner: deployment
    source: {file: phase-6-packaging.md, anchor: supply-chain-contract}
    acceptance:
      behavior: {id: DEP-018-B, description: "Verify image and chart signatures, provenance, SBOM contents, pinned dependencies, source revision, and compatibility metadata from a clean release download."}
      failure: {id: DEP-018-F, description: "A release with a floating image, unverifiable origin, missing dependency inventory, embedded test credential, or undocumented compatibility range cannot be published."}
    deployments: [single_server, kubernetes, aws, gcp]
    status: specified
    depends_on: [DEP-012, DEP-015]
    evidence: []

  - id: DEP-019
    kind: deployment
    behavior: The direct local release is one offline-extractable Node archive containing the compiled CLI, POSIX and Windows launchers, and production dependencies, with its replaceable program directory separate from the persistent data directory.
    owner: deployment
    source: {file: phase-6-packaging.md, anchor: direct-local-package-contract}
    acceptance:
      behavior: {id: DEP-019-B, description: "Extract the archive into a clean directory, run its real launcher, publish and open a file, replace the program directory, restart against the same data, restore a stopped backup into an empty directory, and preserve artifact ID, version ID, pointer, and bytes."}
      failure: {id: DEP-019-F, description: "Building and running the extracted package cannot require Docker, pnpm, TypeScript, a source checkout, package-registry access, an external service, a development dependency, or a platform-specific native Node extension."}
    deployments: [local]
    status: behavior_verified
    depends_on: [DEP-004]
    evidence:
      - deployment: local
        tests: [DEP-019-B, DEP-019-F]
        result: pass
        run: project/evidence/local-package.json
        recorded_at: "2026-08-17T03:08:46.924Z"

  - id: OPS-001
    kind: behavior
    behavior: Every non-local deployment exposes health and readiness checks that distinguish process health from database, blob, migration, and configuration readiness.
    owner: operations
    source: {file: artifact-server-product-spec.html, anchor: implementation}
    acceptance:
      behavior: {id: OPS-001-B, description: "Probe a healthy instance and each declared dependency and receive stable machine-readable readiness reasons."}
      failure: {id: OPS-001-F, description: "A process with a missing migration, unavailable database, inaccessible blob store, or invalid content-domain configuration cannot report ready."}
    deployments: *external_storage
    status: behavior_verified
    depends_on: [ARC-002]
    evidence:
      - deployment: single_server
        tests: [OPS-001-B, OPS-001-F]
        result: pass
        run: project/evidence/external-storage-runtime.json
        recorded_at: "2026-08-17T03:08:19.183Z"

  - id: OPS-002
    kind: deployment
    behavior: Supported upgrades run explicit migrations, preserve backward-compatible recovery information, and provide a tested rollback or roll-forward procedure for each deployment.
    owner: operations
    source: {file: artifact-server-product-spec.html, anchor: implementation}
    acceptance:
      behavior: {id: OPS-002-B, description: "Upgrade from every supported prior version with live artifacts, verify all contracts, and complete the documented recovery path."}
      failure: {id: OPS-002-F, description: "Interrupted migration, old replica, incompatible schema, and failed infrastructure update cannot silently corrupt data or report success."}
    deployments: *external_storage
    status: specified
    depends_on: [ARC-003, OPS-003]
    evidence: []

  - id: OPS-003
    kind: deployment
    behavior: Backup and restore preserve installation IDs, artifact IDs, version IDs, action IDs, manifests, referenced bytes, current pointers, access settings, and audit attribution.
    owner: operations
    source: {file: artifact-server-product-spec.html, anchor: implementation}
    acceptance:
      behavior: {id: OPS-003-B, description: "Back up a populated deployment, restore it into a clean supported environment, and compare every required identity, pointer, record, and byte."}
      failure: {id: OPS-003-F, description: "Missing, mismatched, cross-installation, partially restored, or mutable data makes restore fail closed and prevents the target from reporting ready."}
    deployments: *all
    status: behavior_verified
    depends_on: [ART-001, ART-004, AUD-001]
    evidence:
      - deployment: single_server
        tests: [OPS-003-B, OPS-003-F]
        result: pass
        run: project/evidence/compact-compose.json
        recorded_at: "2026-08-17T03:10:29.404Z"
      - deployment: cloudflare
        tests: [OPS-003-B]
        result: pass
        run: project/evidence/cloudflare-phase11-qualification.json
        recorded_at: "2026-08-16T17:44:26Z"
      - deployment: aws
        tests: [OPS-003-B]
        result: pass
        run: project/evidence/aws-phase11-qualification.json
        recorded_at: "2026-08-16T03:24:47Z"
      - deployment: gcp
        tests: [OPS-003-B]
        result: pass
        run: project/evidence/gcp-phase11-qualification.json
        recorded_at: "2026-08-16T14:36:48Z"

  - id: OPS-004
    kind: behavior
    behavior: An integrity check verifies every committed manifest and referenced blob without changing stored records or bytes.
    owner: operations
    source: {file: artifact-server-product-spec.html, anchor: implementation}
    acceptance:
      behavior: {id: OPS-004-B, description: "Scan a valid installation and report all manifests, fingerprints, sizes, paths, and blobs consistent."}
      failure: {id: OPS-004-F, description: "Detect missing blobs, digest mismatches, invalid paths, orphaned current pointers, and cross-installation references without repairing them silently."}
    deployments: *all
    status: behavior_verified
    depends_on: [MAN-001, MAN-006]
    evidence:
      - deployment: aws
        tests: [OPS-004-B]
        result: pass
        run: project/evidence/aws-phase11-qualification.json
        recorded_at: "2026-08-16T03:24:47Z"
      - deployment: gcp
        tests: [OPS-004-B]
        result: pass
        run: project/evidence/gcp-phase11-qualification.json
        recorded_at: "2026-08-16T14:36:48Z"

  - id: OPS-005
    kind: release_gate
    behavior: A deployment is not supported for teams until its database-and-blob backup and restore procedure is documented and passes conformance tests.
    owner: operations
    source: {file: artifact-server-product-spec.html, anchor: implementation}
    acceptance:
      behavior: {id: OPS-005-B, description: "Follow only the published operator procedure on a populated deployment and obtain a verified clean restore."}
      failure: {id: OPS-005-F, description: "A target lacking repeatable backup, restore, integrity, and recovery evidence cannot be marked team-ready or supported."}
    deployments: *external_storage
    status: behavior_verified
    depends_on: [OPS-003, OPS-004]
    evidence:
      - deployment: aws
        tests: [OPS-005-B]
        result: pass
        run: project/evidence/aws-phase11-qualification.json
        recorded_at: "2026-08-16T03:24:47Z"
      - deployment: gcp
        tests: [OPS-005-B]
        result: pass
        run: project/evidence/gcp-phase11-qualification.json
        recorded_at: "2026-08-16T14:36:48Z"

  - id: OPS-006
    kind: constraint
    behavior: The initial release has no automatic expiry of committed versions and no automatic reclamation of committed or race-left blobs.
    owner: operations
    source: {file: artifact-server-product-spec.html, anchor: architecture}
    acceptance:
      behavior: {id: OPS-006-B, description: "Publish, race, restore, restart, and wait beyond staging expiry and confirm every committed version and referenced byte remains."}
      failure: {id: OPS-006-F, description: "Cleanup may delete only expired uncommitted staging records and cannot select a committed or possibly referenced blob."}
    deployments: *all
    status: implementing
    proof_gap: Cleanup-selection failure evidence exists, but no one OPS-006-B acceptance run combines publication, a concurrent publish race, restore, process restart, and retention beyond staging expiry.
    depends_on: [PUB-009, ART-007]
    evidence:
      - deployment: local
        tests: [OPS-006-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"
      - deployment: cloudflare
        tests: [OPS-006-F]
        result: pass
        run: project/evidence/cloudflare-phase11-qualification.json
        recorded_at: "2026-08-16T17:44:26Z"
      - deployment: aws
        tests: [OPS-006-F]
        result: pass
        run: project/evidence/aws-phase11-qualification.json
        recorded_at: "2026-08-16T03:24:47Z"
      - deployment: gcp
        tests: [OPS-006-F]
        result: pass
        run: project/evidence/gcp-phase11-qualification.json
        recorded_at: "2026-08-16T14:36:48Z"

  - id: OPS-007
    kind: release_gate
    behavior: Committed-blob garbage collection remains disabled until a backup-aware durable lease or mark-and-sweep design passes concurrency, crash, restore, and replica tests.
    owner: operations
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: OPS-007-B, description: "Before enablement, prove the collector preserves live, newly committed, concurrently restored, backed-up, and in-flight blobs across crashes."}
      failure: {id: OPS-007-F, description: "Any uncertain reference, lease, backup, transaction, or replica state retains the blob and records why it was not reclaimed."}
    deployments: *all
    status: specified
    depends_on: [OPS-003, OPS-006]
    evidence: []

  - id: OPS-008
    kind: behavior
    behavior: Operators can inspect versions, adapters, configuration health, storage assignments, migrations, queues, and recent failures without exposing secrets.
    owner: operations
    source: {file: artifact-server-product-spec.html, anchor: implementation}
    acceptance:
      behavior: {id: OPS-008-B, description: "Produce a diagnostic bundle sufficient to identify the active product and provider state while preserving artifact and installation boundaries."}
      failure: {id: OPS-008-F, description: "Diagnostics never include bearer tokens, API keys, cookies, authorization codes, refresh tokens, private signing keys, or credential-bearing URLs."}
    deployments: *all
    status: specified
    depends_on: [DEP-012]
    evidence: []

  - id: OPS-009
    kind: behavior
    behavior: Deployed processes emit sampled structured request logs, complete request metrics, and traces with server-generated request IDs, bounded route names, and no credentials or raw request URLs; server failures and requests taking at least one second are never omitted from logs.
    owner: operations
    source: {file: artifact-server-product-spec.html, anchor: implementation}
    acceptance:
      behavior: {id: OPS-009-B, description: "Send HTTP and MCP requests through a deployed process and receive correlated structured logs, request metrics, spans, and response request IDs through a standard OTLP collector."}
      failure: {id: OPS-009-F, description: "Telemetry excludes authorization values, cookies, query strings, caller-controlled request IDs, raw artifact identifiers, and unbounded request paths."}
    deployments: *all
    status: behavior_verified
    depends_on: [ARC-002]
    evidence:
      - deployment: local
        tests: [OPS-009-B, OPS-009-F]
        result: pass
        run: project/evidence/observability.json
        recorded_at: "2026-08-17T03:08:16.359Z"

  - id: OPS-010
    kind: behavior
    behavior: A deployed process receiving SIGTERM stops reporting ready, allows routing withdrawal to propagate, drains accepted requests to a deadline, closes providers, flushes telemetry, and exits without claiming an uncommitted publish succeeded.
    owner: operations
    source: {file: phase-6-packaging.md, anchor: shutdown-and-readiness}
    acceptance:
      behavior: {id: OPS-010-B, description: "Terminate idle, reading, uploading, and committing containers during Compose and Kubernetes replacement and observe the documented durable result for every request."}
      failure: {id: OPS-010-F, description: "A draining process cannot remain ready, accept unbounded new work, exceed the termination deadline, leak providers, or return a successful publish that disappears after exit."}
    deployments: [single_server, kubernetes, aws, gcp]
    status: specified
    depends_on: [OPS-001, PUB-003, PUB-004]
    evidence: []

  - id: OPS-011
    kind: deployment
    behavior: Compact installations move to external-storage Postgres and object storage through a verified export and import that preserves installation, artifact, version, action, manifest, access, audit, pointer, and byte identity.
    owner: operations
    source: {file: phase-6-packaging.md, anchor: compact-to-external-storage-transfer}
    acceptance:
      behavior: {id: OPS-011-B, description: "Freeze a populated compact installation, export it, import it into empty external providers, pass integrity checks, and continue publishing with every prior ID, link contract, and byte preserved."}
      failure: {id: OPS-011-F, description: "A partial, mismatched, concurrently changing, cross-installation, or already-populated import target fails closed and cannot report ready."}
    deployments: [single_server, kubernetes]
    status: specified
    depends_on: [OPS-003, OPS-004, DEP-005, DEP-006]
    evidence: []

  - id: REL-001
    kind: release_gate
    behavior: The local-owner first-release mode includes automatic credential-free browser access, one-process offline operation, single-file and complete-site publishing, immutable versions, comparisons, restore, two read settings, HTTP, MCP, the artifact route of the Artifact Server skill, and browser isolation. Optional Git history is deferred and is not a first-release gate.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: implementation}
    acceptance:
      behavior: {id: REL-001-B, description: "Run the entire local requirement set from a clean install through restart and recovery and record passing evidence in this ledger."}
      failure: {id: REL-001-F, description: "The local release cannot be declared complete when any applicable behavior or hostile test lacks passing local evidence."}
    deployments: [local]
    status: specified
    depends_on: [AUTH-023, AUTH-024, AUTH-026, DEP-004, DEP-019, MCP-016, MCP-018, MCP-019, REL-006]
    evidence: []

  - id: REL-002
    kind: release_gate
    behavior: The private-team first-release mode includes Compose, individual browser login, explicit member admission, scoped keys, Postgres and blob drivers, Kubernetes Helm, private multi-file delivery, backup, restore, upgrade, health, and the explicit server-operation route of the Artifact Server skill.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: implementation}
    acceptance:
      behavior: {id: REL-002-B, description: "Pass every external-storage requirement on one server and every replicated requirement with multi-replica Kubernetes and record deployment evidence."}
      failure: {id: REL-002-F, description: "A private-team target cannot be called supported when private delivery, backup, restore, upgrade, health, authorization, or its advertised availability evidence is missing; compact single-server mode explicitly makes no failover claim."}
    deployments: [single_server, kubernetes]
    status: specified
    depends_on: [AUTH-025, AUTH-026, AUTH-027, AUTH-028, DEP-005, DEP-006, GATE-002, MCP-018, MCP-019, OPS-005, REL-006]
    evidence: []

  - id: REL-003
    kind: release_gate
    behavior: The optional Cloudflare deployment includes Workers, D1, R2, browser login, WorkOS MCP authorization, public CDN delivery, trusted installation routing, tenant isolation, audit, and recovery; artifactserver.com service-operator policy is not a core OSS release gate.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: implementation}
    acceptance:
      behavior: {id: REL-003-B, description: "Pass the complete Cloudflare technical requirement set under provider failure, OAuth, restore, and cross-installation tests."}
      failure: {id: REL-003-F, description: "The Cloudflare package cannot be called supported until its tenant-isolation, recovery, authorization, and deployment gates have passing evidence; optional service policy cannot block the core OSS release."}
    deployments: [cloudflare]
    status: specified
    depends_on: [DEP-007, MCP-017, MCP-019, REL-006]
    evidence: []

  - id: REL-004
    kind: release_gate
    behavior: Each direct-cloud release includes its official installer, native object storage, private-network option, upgrades, rollback, state recovery, backup, restore, deletion, and the external-storage Helm alternative.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: implementation}
    acceptance:
      behavior: {id: REL-004-B, description: "Independently pass create-to-delete and full product conformance on AWS and GCP and publish per-target evidence."}
      failure: {id: REL-004-F, description: "Success on one cloud cannot stand in for evidence on another, and a target with incomplete lifecycle or native-storage tests remains unsupported."}
    deployments: *direct_clouds
    status: specified
    depends_on: [DEP-008, DEP-009, MCP-018, MCP-019, REL-006]
    evidence: []

  - id: REL-005
    kind: release_gate
    behavior: The Plannotator integration is released only after pairing, managed-storage isolation, signed operations, exact-version opening, disconnect, recovery, and the selected review surface pass their full suites.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: implementation}
    acceptance:
      behavior: {id: REL-005-B, description: "Run the integration acceptance and hostile matrices on every advertised connected deployment and record both products' evidence."}
      failure: {id: REL-005-F, description: "A partial pairing, unavailable private route, failed review surface, or missing cross-product audit evidence cannot be advertised as one-click supported integration."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-015, PLN-016, REL-006]
    evidence: []

  - id: REL-006
    kind: release_gate
    behavior: A requirement is complete only when its behavior test and hostile or failure test pass on every applicable advertised deployment and the evidence is recorded in this ledger.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: implementation}
    acceptance:
      behavior: {id: REL-006-B, description: "Validate the ledger and compute complete evidence coverage for every requirement in a release and deployment."}
      failure: {id: REL-006-F, description: "The validator rejects missing tests, missing deployments, malformed evidence, unresolved dependencies, and a verified status without complete passing evidence."}
    deployments: *all
    status: specified
    depends_on: []
    evidence: []

  - id: REL-007
    kind: release_gate
    behavior: The first Artifact Server release includes both the local-owner and private-team access modes and cannot be declared complete when either mode lacks its full behavior, hostile, packaging, or recovery evidence.
    owner: product-core
    source: {file: local-owner-and-private-team-access-spec.md, anchor: conformance-requirements}
    acceptance:
      behavior: {id: REL-007-B, description: "From clean installations, pass the complete local-owner workflow and the complete private-team workflow on compact single-server, external-storage single-server, and two-replica Kubernetes targets, with all applicable ledger evidence attached."}
      failure: {id: REL-007-F, description: "Refuse the first-release declaration when local access still needs a browser token or sign-in step, or when any team identity, admission, scoped-client, private-content, ingress, restart, backup, restore, upgrade, mobile-browser, or hostile-boundary proof is missing."}
    deployments: [local, single_server, kubernetes]
    status: specified
    depends_on: [REL-001, REL-002, REL-006]
    evidence: []

  - id: SCP-001
    kind: exclusion
    behavior: Artifact Server does not build source code, install packages, host databases or server functions for artifacts, or run artifact-specific backend processes.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: scope}
    acceptance:
      behavior: {id: SCP-001-B, description: "Publish and serve only finished browser files while the server process list and network activity show no artifact-specific runtime."}
      failure: {id: SCP-001-F, description: "Build manifests, package files, server entry points, and backend dependencies cannot cause package installation, compilation, process execution, or database provisioning."}
    deployments: *all
    status: specified
    depends_on: [PRD-002]
    evidence: []

  - id: SCP-002
    kind: exclusion
    behavior: The first release has no custom PDF or office viewer, media conversion, adaptive streaming, thumbnailing, transcription, ZIP browsing, Markdown renderer, syntax-highlighting interface, or binary-media comparison engine.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: scope}
    acceptance:
      behavior: {id: SCP-002-B, description: "Open browser-supported media directly and download unsupported files using only generic content delivery."}
      failure: {id: SCP-002-F, description: "Uploading a document, archive, image, audio, or video file cannot enqueue conversion, extraction, analysis, rendering, or preview work."}
    deployments: *all
    status: specified
    depends_on: [PRD-002, CNT-001]
    evidence: []

  - id: SCP-003
    kind: exclusion
    behavior: Artifact Server does not store notifications, workspace collaboration, or workspace membership.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: scope}
    acceptance:
      behavior: {id: SCP-003-B, description: "Inspect product records and APIs and observe artifact metadata, versions, storage, access, audit, comment threads on its own versions, and pairing references only."}
      failure: {id: SCP-003-F, description: "No Artifact Server endpoint or database table can create or become the authority for notification, workspace collaboration, or workspace membership records."}
    deployments: *all
    status: specified
    depends_on: [PLN-003]
    evidence: []

  - id: SCP-004
    kind: exclusion
    behavior: Optional Git handoff is only a private derivative of Artifact Server versions and is not general-purpose source-code hosting.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: scope}
    acceptance:
      behavior: {id: SCP-004-B, description: "Create only Artifact Server-controlled version commits through the history adapter."}
      failure: {id: SCP-004-F, description: "Users cannot push arbitrary branches, host unrelated repositories, make Git the render source, or bypass artifact authorization through Git."}
    deployments: *all
    status: specified
    depends_on: [GIT-001, GIT-002]
    evidence: []

  - id: SCP-005
    kind: exclusion
    behavior: Artifact Server does not run arbitrary add-ons or third-party programs inside the server.
    owner: product-core
    source: {file: artifact-server-product-spec.html, anchor: scope}
    acceptance:
      behavior: {id: SCP-005-B, description: "Extend only through documented deployment, storage, auth, Git, MCP, and integration contracts."}
      failure: {id: SCP-005-F, description: "Configuration or uploaded content cannot load arbitrary server plugins, native modules, hooks, or executable extensions."}
    deployments: *all
    status: specified
    depends_on: [ARC-001]
    evidence: []

  - id: SCP-006
    kind: exclusion
    behavior: Artifact Server does not automatically change firewalls or create a general-purpose tunnel into a customer's network.
    owner: deployment
    source: {file: artifact-server-product-spec.html, anchor: scope}
    acceptance:
      behavior: {id: SCP-006-B, description: "Keep network reachability as explicit customer deployment configuration and limit any optional connector to the paired Artifact Server service."}
      failure: {id: SCP-006-F, description: "Install, public-link, MCP, and Plannotator flows cannot silently open ingress, modify a firewall, proxy arbitrary hosts, or expose another service."}
    deployments: *external_storage
    status: specified
    depends_on: [AUTH-004, PLN-014]
    evidence: []

  - id: SCP-007
    kind: exclusion
    behavior: The server does not fetch arbitrary URLs supplied by a client as a publishing mechanism.
    owner: publishing
    source: {file: artifact-server-product-spec.html, anchor: scope}
    acceptance:
      behavior: {id: SCP-007-B, description: "Accept publication bytes through file-upload while reserving local path reads for the separately verified local-import helper."}
      failure: {id: SCP-007-F, description: "A URL, redirect chain, internal address, file URL, or cloud metadata address cannot cause server-side retrieval."}
    deployments: *all
    status: behavior_verified
    depends_on: [PUB-011]
    evidence:
      - deployment: local
        tests: [SCP-007-B, SCP-007-F]
        result: pass
        run: project/evidence/local-foundation.json
        recorded_at: "2026-08-17T03:17:21.421Z"

  - id: SCP-008
    kind: constraint
    behavior: Standalone access uses one installation membership group and does not add a separate member list or ACL for each project or artifact.
    owner: authorization
    source: {file: artifact-server-product-spec.html, anchor: scope}
    acceptance:
      behavior: {id: SCP-008-B, description: "Confirm that admitted human members can read and manage artifacts in every project while service mutations require explicit capabilities."}
      failure: {id: SCP-008-F, description: "A project or artifact cannot create an undocumented reader ACL or inherit Plannotator workspace membership."}
    deployments: *all
    status: specified
    depends_on: [PRJ-003, AUTH-001, AUTH-006, PLN-004]
    evidence: []

  - id: HOST-001
    kind: security
    behavior: Public hosting enforces measured per-installation and per-principal quotas, rate limits, upload limits, version limits, and egress controls before artifactserver.com public links launch.
    owner: hosted-policy
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: HOST-001-B, description: "Exercise documented default and maximum limits under normal and burst load and observe clear retry and quota responses without cross-installation impact."}
      failure: {id: HOST-001-F, description: "Oversized, excessive, parallel, distributed, and retry-amplified workloads cannot bypass limits, exhaust another installation's allowance, or create unbounded spend."}
    deployments: *hosted
    status: not_applicable
    rationale: Hosted quotas and spend controls are optional artifactserver.com operating policy, not a core OSS first-release requirement; retain this candidate only for traceability until a hosted service has an owner and launch plan.
    depends_on: [PUB-008, GATE-009]
    evidence: []

  - id: HOST-002
    kind: security
    behavior: Public hosting has an executable-file policy and documented malware, phishing, copyright, report, suspension, deletion, appeal, and domain-reputation procedures.
    owner: hosted-policy
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: HOST-002-B, description: "Run a tabletop and staging exercise from report intake through containment, audit, communication, deletion or restoration, and domain-reputation monitoring."}
      failure: {id: HOST-002-F, description: "A malicious or disputed artifact cannot remain publicly reachable because the system lacks project and actor lookup, suspension, evidence preservation, or deletion controls."}
    deployments: *hosted
    status: not_applicable
    rationale: Malware, copyright, appeal, and reputation operations belong to an optional artifactserver.com service policy, not the core OSS implementation; retain this candidate only for traceability.
    depends_on: [AUTH-012, AUD-001]
    evidence: []

  - id: HOST-003
    kind: security
    behavior: Hosted customer controls explicitly define encryption, regional placement, audit export, legal hold, permanent deletion, backup frequency, restore target, acceptable data-loss window, availability, and support tier before regulated-team sales.
    owner: hosted-policy
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: HOST-003-B, description: "Map every published promise to configuration, enforcement, monitoring, backup, restore, deletion, audit, and support evidence."}
      failure: {id: HOST-003-F, description: "Marketing, contract, or user-interface claims cannot exceed measured and tested technical behavior for the selected region and tier."}
    deployments: *hosted
    status: not_applicable
    rationale: Regulated-enterprise promises and sales controls are outside the simple OSS first release and must not drive speculative product features; retain this candidate only for traceability.
    depends_on: [OPS-003, OPS-008, GATE-010, GATE-011]
    evidence: []

  - id: GATE-001
    kind: release_gate
    behavior: Private multi-file delivery must prove both top-level raw-content sessions and exact-version embedded Review leases in supported browsers before the private-team release.
    owner: content-delivery
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-001-B, description: "Complete the private current and historical HTML, asset, navigation, expiry, logout, exact-version isolation, local and team deployment, and supported-browser matrix with recorded results."}
      failure: {id: GATE-001-F, description: "Third-party cookie assumptions, application credentials in artifact frames, reusable cross-version authority, asset authorization gaps, or cross-version lease or cookie reach block the team release."}
    deployments: *external_storage
    status: implementing
    proof_gap: Top-level raw-content sessions have focused HTTP evidence. Exact-version Review leases pass local browser qualification in Chromium, Firefox, and WebKit and pass a Postgres/S3 restart probe, but the complete navigation, expiry, logout, and browser matrix has not been recorded on every team deployment.
    depends_on: [AUTH-015, AUTH-016, AUTH-017, CMT-018]
    evidence: []

  - id: GATE-002
    kind: release_gate
    behavior: Wildcard DNS, certificates, localhost hosts, proxies, forwarded-host validation, and private-network requirements must be documented and tested before each external-storage deployment is supported.
    owner: deployment
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-002-B, description: "Install through every supported network and proxy pattern and verify unique version hosts, TLS, redirects, cookies, links, and hostile host handling."}
      failure: {id: GATE-002-F, description: "A deployment with unresolved DNS, certificate, proxy, hostname, cookie, or browser compatibility cannot be declared supported."}
    deployments: *all
    status: specified
    depends_on: [DEP-014]
    evidence: []

  - id: GATE-003
    kind: release_gate
    behavior: The hosted service begins with one D1 database only after load and failure tests, and chooses a tested installation-directory rollout or external Postgres control plane before a second database is required.
    owner: database-adapters
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-003-B, description: "Measure D1 latency, contention, growth, backup, restore, and failure limits and record the threshold and tested second-database design."}
      failure: {id: GATE-003-F, description: "Adding bindings, accepting a request-supplied installation ID, or manually moving data cannot be presented as automatic sharding or a supported control plane."}
    deployments: *hosted
    status: specified
    depends_on: [DEP-013]
    evidence: []

  - id: GATE-004
    kind: release_gate
    behavior: The off-by-default Cloudflare Artifacts adapter is advertised only after current access, pricing, repository and rate limits, token behavior, Git compatibility, project selection, estimate and budget behavior, namespace isolation, bounded live-test cleanup, failure containment, deletion, jurisdiction, cost, and recovery are verified.
    owner: git-history
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-004-B, description: "Complete the bounded live Cloudflare Artifacts binding, REST, smart-HTTP, token, per-project switch, estimate, budget, namespace, run-manifest cleanup, backfill, disable, deletion, recovery, limit, and cost probes and document the supported envelope."}
      failure: {id: GATE-004-F, description: "Absent beta access, invalid configuration, stale pricing, a provider or test bound, missing Git behavior, cleanup failure, or provider outage cannot touch another namespace or block startup, readiness, saved versions, delivery, or core comparison."}
    deployments: *all
    status: specified
    depends_on: [GIT-007, GIT-012, GIT-013, GIT-014]
    evidence: []

  - id: GATE-005
    kind: release_gate
    behavior: Hosted WorkOS MCP authorization ships only after live consent, token lifetime, refresh rotation, revocation, claims, audience, CIMD, DCR, callback, and stale-client probes pass.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-005-B, description: "Run fresh and stale-state browser authorization, refresh, revoke, disconnect, and reconnect tests in Codex, Claude Code, claude.ai where reachable, and compatibility clients."}
      failure: {id: GATE-005-F, description: "Wrong issuer, audience, callback, PKCE, registration, revoked grant, stale token, or cross-tenant object access cannot authorize an MCP tool."}
    deployments: *hosted
    status: implementing
    proof_gap: Codex and Claude Code staging flows cover selected consent, refresh, revoke, CIMD, and DCR behavior, but the fresh/stale named-client matrix and every callback, PKCE, registration, revoked, stale, and cross-tenant denial are incomplete.
    depends_on: [MCP-010, MCP-011, MCP-012]
    evidence: []

  - id: GATE-006
    kind: release_gate
    behavior: Embedded Better Auth MCP OAuth is not supported until its beta path passes interoperability, security, migration, durable-state, refresh, revoke, recovery, CIMD, and DCR tests.
    owner: mcp
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-006-B, description: "Run the complete hosted OAuth matrix against the embedded provider and document operational responsibility and upgrade behavior."}
      failure: {id: GATE-006-F, description: "Beta incompatibility, lost client or consent state, weak audience binding, refresh replay, failed migration, or missing revocation keeps the option disabled."}
    deployments: *external_storage
    status: specified
    depends_on: [MCP-014]
    evidence: []

  - id: GATE-007
    kind: release_gate
    behavior: AWS and GCP remain unsupported until their default managed-container projects independently pass create, upgrade, rollback, state recovery, backup, restore, workload-identity, delete, and every advertised ingress-mode test; the direct GCP target advertises public ingress only, while private GCP teams use the qualified Helm path on GKE; Azure is not a direct target and uses the qualified Helm path on AKS.
    owner: deployment
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-007-B, description: "Publish a complete signed evidence run for the full lifecycle on each cloud and each advertised runtime variant."}
      failure: {id: GATE-007-F, description: "Documentation, code generation, success on another cloud, or a create-only smoke test cannot qualify a deployment as supported."}
    deployments: *direct_clouds
    status: specified
    depends_on: [DEP-008, DEP-009]
    evidence: []

  - id: GATE-008
    kind: release_gate
    behavior: Public artifactserver.com links do not launch until abuse, executable-file, malware, phishing, copyright, reputation, suspension, and deletion policy is both decided and exercised.
    owner: hosted-policy
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-008-B, description: "Complete policy approval and operational exercises for every public-hosting abuse path with responsible teams and response evidence."}
      failure: {id: GATE-008-F, description: "A public-link launch is blocked when any report, containment, deletion, appeal, or domain-reputation path has no responsible team or working control."}
    deployments: *hosted
    status: not_applicable
    rationale: This is an optional artifactserver.com launch-policy gate, not an OSS release gate; core content isolation and authorization safety remain covered by the technical requirements.
    depends_on: [HOST-002]
    evidence: []

  - id: GATE-009
    kind: release_gate
    behavior: Default and maximum file count, file size, artifact size, version count, text-diff size, rate, retention, and egress limits come from measured tests and published cost envelopes.
    owner: hosted-policy
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-009-B, description: "Benchmark representative and hostile workloads on every target, choose limits, and record their cost, latency, memory, storage, and retry effects."}
      failure: {id: GATE-009-F, description: "An unmeasured or unenforced limit cannot be presented as a supported capacity or used to predict hosting cost."}
    deployments: *all
    status: not_applicable
    rationale: The OSS release makes no universal capacity or hosting-cost promise. Enforced input bounds remain core safety requirements, while target capacity claims require their own measured evidence when a maintainer chooses to advertise them.
    depends_on: [PUB-008, DIF-003]
    evidence: []

  - id: GATE-010
    kind: release_gate
    behavior: Availability, backup frequency, restore-time target, acceptable data-loss window, and support tiers must be explicit and proven before team and hosted reliability promises are published.
    owner: operations
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-010-B, description: "Exercise dependency failure, backup, point-in-time recovery, region or node loss, and operator response against each proposed reliability target."}
      failure: {id: GATE-010-F, description: "A recovery or availability promise cannot exceed measured end-to-end evidence or omit database, blob, DNS, identity, and integration dependencies."}
    deployments: *external_storage
    status: specified
    depends_on: [OPS-003, OPS-005]
    evidence: []

  - id: GATE-011
    kind: release_gate
    behavior: Encryption-key control, regional placement, audit export, legal hold, and permanent deletion are decided and verified before selling the corresponding regulated-team claim.
    owner: hosted-policy
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-011-B, description: "Trace each enterprise control through configuration, enforcement, storage, backup, export, deletion, monitoring, and customer-visible evidence."}
      failure: {id: GATE-011-F, description: "Backups, replicas, CDN copies, Git history, logs, or integration references cannot be omitted from a claimed regional, hold, encryption, export, or deletion boundary."}
    deployments: *external_storage
    status: specified
    depends_on: [OPS-003, GIT-001, AUD-001]
    evidence: []

  - id: GATE-012
    kind: release_gate
    behavior: Customer-owned content domains remain unsupported until certificate issuance, cookie scope, unique-version origins, abuse response, CDN behavior, revocation, and domain removal are designed and tested.
    owner: content-delivery
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-012-B, description: "Prove the complete domain lifecycle and browser security model without weakening application and version origin isolation."}
      failure: {id: GATE-012-F, description: "Domain takeover, stale certificate, unsafe cookie scope, shared version origin, broken purge, or unresolved abuse responsibility keeps custom domains disabled."}
    deployments: *external_storage
    status: specified
    depends_on: [CNT-003, DEP-014]
    evidence: []

  - id: GATE-013
    kind: release_gate
    behavior: The Plannotator review bridge must pass hostile-artifact, strict policy, multi-page, single-page, service-worker, anchor, expiry, and browser compatibility tests or be replaced by the browser-extension fallback.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-013-B, description: "Run the review security and compatibility matrix and record the supported bridge or extension decision."}
      failure: {id: GATE-013-F, description: "Any reusable credential exposure, stored-byte mutation, origin confusion, service-worker control, anchor corruption, or unsupported-browser silent failure blocks that review surface."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-009, PLN-010, PLN-016]
    evidence: []

  - id: GATE-014
    kind: release_gate
    behavior: Existing standalone artifact attachment to Plannotator remains unavailable until move-or-copy semantics, permissions, IDs, links, rollback, retry, and disconnect behavior are decided and tested.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-014-B, description: "Record the chosen semantics and pass authorization, identity, failure, recovery, and disconnect tests for an explicit attachment."}
      failure: {id: GATE-014-F, description: "Pairing alone, a failed action, retry, or disconnect cannot silently move, copy, expose, duplicate, or orphan existing artifacts."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-013]
    evidence: []

  - id: GATE-015
    kind: release_gate
    behavior: One-click private Plannotator connection is advertised only after one route is selected and its health, upgrade, replica, egress, reachability, scope, and failure behavior pass tests.
    owner: plannotator-integration
    source: {file: artifact-server-product-spec.html, anchor: decisions}
    acceptance:
      behavior: {id: GATE-015-B, description: "Qualify customer networking, Cloudflare Tunnel, or the product connector with a published install-to-recovery test matrix."}
      failure: {id: GATE-015-F, description: "A route that exposes another service, grants inbound general network access, hides failure, loses pairing state, or lacks a responsible support team cannot be called one-click."}
    deployments: *plannotator_capable
    status: specified
    depends_on: [PLN-014, PLN-015]
    evidence: []

  - id: LNK-001
    kind: constraint
    behavior: Linked artifacts are off by default, exist only on the local deployment behind capability discovery, reference the file in place, and are created only by an explicit protocol call naming the path.
    owner: local-workspace
    source: {file: local-workspace-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: LNK-001-B, description: "Enable linked artifacts on a local deployment, observe the advertised capability, link a file through the MCP tool and the HTTP endpoint, and verify the file stays at its original path and is never copied, moved, watched, or scanned into an artifact without that explicit call."}
      failure: {id: LNK-001-F, description: "With the feature off or on any non-local deployment, the capability is absent, every linked-artifact route answers the stable capability-unavailable shape, and enabling the flag outside the local runtime fails startup; no file on disk becomes an artifact without an explicit link call."}
    deployments: *all
    status: implementing
    proof_gap: The acceptance-ID tests prove the off-by-default 501 shape, capability discovery, reference-in-place linking over MCP and HTTP, and the absence of scanning on the local deployment, and a worker runtime test proves the Cloudflare absence; the single-server, kubernetes, aws, and gcp deployment suites do not yet assert the absence shape, and no recorded run is attached to these IDs yet.
    depends_on: [ART-001, VER-001]
    evidence: []

  - id: LNK-007
    kind: security
    behavior: The live view streams the source's current disk bytes with no-store caching only to admitted members authenticated on the local deployment over the artifact's live origin; every other reader receives only captured immutable versions.
    owner: local-workspace
    source: {file: local-workspace-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: LNK-007-B, description: "As an admitted local member, read a linked artifact's live view, edit the file on disk, re-read, and observe the current bytes with no-store caching while captured-version routes keep immutable caching."}
      failure: {id: LNK-007-F, description: "Public-link possession, anonymous requests, non-member sessions, content-origin version routes, and every non-local deployment never receive a live disk byte, and a missing or unreadable source degrades the live view to the last captured version without an error."}
    deployments: *all
    status: implementing
    proof_gap: The acceptance-ID tests prove no-store live delivery to an admitted local member, the 401 for anonymous and version-cookie callers, the captured-only public path under drift, and the degrade-to-captured behavior, and a worker runtime test proves the Cloudflare absence; the single-server, kubernetes, aws, and gcp deployment suites do not yet assert the absence, and no recorded run is attached to these IDs yet.
    depends_on: [LNK-001, AUTH-008]
    evidence: []

  - id: LNK-008
    kind: behavior
    behavior: A comment thread on a linked artifact anchors to a captured version, and creating one on a drifted binding implicitly captures first, attributed to the commenting principal, in the same request.
    owner: local-workspace
    source: {file: local-workspace-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: LNK-008-B, description: "Comment on an in-sync linked artifact and observe the thread on the current version with no new version; drift the file, comment again, and observe one implicit capture attributed to the commenter with the thread anchored to the new version."}
      failure: {id: LNK-008-F, description: "An implicit capture aborted by a drift race fails the whole comment request with the retryable drift error and creates no thread, and no thread ever anchors to live bytes or to a version that was not durably captured."}
    deployments: [local]
    status: implementing
    proof_gap: The acceptance-ID tests prove the in-sync anchor, the implicit capture attributed to the commenting principal, and that an aborted implicit capture creates no thread and no version; the abort is forced through the action ledger rather than a genuine mid-read drift race, so the retryable drift error on that race is unproved, and no recorded run is attached to these IDs yet.
    depends_on: [LNK-004, CMT-001]
    evidence: []

  - id: LNK-002
    kind: behavior
    behavior: Linking a file creates an ordinary artifact with an initial captured version through the normal publish pipeline, so a linked artifact is never versionless.
    owner: local-workspace
    source: {file: local-workspace-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: LNK-002-B, description: "Link one regular file and receive an artifact whose first version carries the file's verified bytes, canonical manifest, action record, and idempotency result."}
      failure: {id: LNK-002-F, description: "Linking a directory, symlink, special file, missing path, or unreadable file creates no artifact and no version; replaying the same link idempotency key returns the original artifact."}
    deployments: [local]
    status: implementing
    proof_gap: The acceptance-ID tests drive the HTTP link route and prove the first captured version, its canonical manifest, the link action record, the refusals for a directory, symlink, socket, missing, and unreadable path, and idempotent replay; the MCP and CLI link surfaces are not exercised by these IDs, and no recorded run is attached to them yet.
    depends_on: [LNK-001, PUB-001]
    evidence: []

  - id: LNK-003
    kind: behavior
    behavior: External modification, removal, and unreadability of a linked source surface as binding freshness on metadata reads without creating, changing, or deleting any version.
    owner: local-workspace
    source: {file: local-workspace-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: LNK-003-B, description: "Modify, remove, and restore the source file and observe the binding freshness move through modified, missing, and back while the version list and delivered bytes stay identical."}
      failure: {id: LNK-003-F, description: "A freshness refresh cannot write a version, an action record, or any artifact mutation, and a failed stat degrades only the freshness field, never the read."}
    deployments: [local]
    status: implementing
    proof_gap: The acceptance-ID tests observe freshness through the authenticated artifact read while the database refuses every version and action write, and they cover modification, replacement, removal, restoration, and a failed stat; freshness reported through the MCP read surface is not exercised by these IDs, and no recorded run is attached to them yet.
    depends_on: [LNK-001]
    evidence: []

  - id: LNK-004
    kind: behavior
    behavior: Capture publishes the source's current bytes as a new immutable version using descriptor-verified fingerprint checks, an idempotency key, and the publish current-version conflict behavior.
    owner: local-workspace
    source: {file: local-workspace-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: LNK-004-B, description: "Modify the source, capture, and receive a new version whose bytes hash-match the file read from one verified descriptor; capturing an in-sync binding replays the current version without a new one."}
      failure: {id: LNK-004-F, description: "A file that changes between fingerprint checks aborts the capture with a retryable drift error and no version, and a stale expected current version returns the publish conflict shape with the actual current version."}
    deployments: [local]
    status: implementing
    proof_gap: The acceptance-ID tests prove that captured bytes hash-match the file on disk, that an in-sync capture replays the current version under a fresh key, and that a stale expected current version returns the publish conflict naming the actual current version with no version written; a file that changes between the two fingerprint checks cannot be forced deterministically through the HTTP boundary, so the retryable drift abort is unproved, and no recorded run is attached to these IDs yet.
    depends_on: [LNK-002, PUB-006]
    evidence: []

  - id: LNK-005
    kind: behavior
    behavior: Relink re-points a binding at a moved file under an expected content hash while preserving the artifact identity, versions, comments, and attachments.
    owner: local-workspace
    source: {file: local-workspace-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: LNK-005-B, description: "Move the source file, relink with the expected hash, and observe the same artifact ID, version list, and comment threads with a healthy binding at the new path."}
      failure: {id: LNK-005-F, description: "A relink whose target bytes do not match the expected hash is rejected and changes nothing, and a relink to a path outside the link roots or inside the data directory is refused."}
    deployments: [local]
    status: implementing
    proof_gap: The acceptance-ID tests prove a moved file relinks under its expected hash with the same artifact ID, version list, and comment threads, and that a mismatched hash, a path outside every root, and a path inside the data directory each change nothing; artifact attachments are not exercised by these IDs, and no recorded run is attached to them yet.
    depends_on: [LNK-002]
    evidence: []

  - id: LNK-006
    kind: security
    behavior: Link paths are canonicalized, restricted to configured link roots, denied for the server's own data and database files, accepted only from authorized principals over the loopback application origin, and never select storage or appear in public or content-origin responses.
    owner: local-workspace
    source: {file: local-workspace-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: LNK-006-B, description: "Link inside a configured root as an admitted member over loopback and read the binding path back only through authenticated application-origin metadata."}
      failure: {id: LNK-006-F, description: "Paths outside every root, the data directory, database files, symlink escapes, anonymous or public-link callers, and non-loopback origins are all refused; no public, content-origin, or log surface reveals a source path, and no request path ever resolves against the linked filesystem."}
    deployments: [local]
    status: implementing
    proof_gap: The acceptance-ID tests prove root containment, dot-dot and symlink escape refusals, data-directory and database self-protection, anonymous and non-loopback refusals, path non-disclosure on every refusal body, and manifest-only delivery; no recorded run is attached to these IDs yet.
    depends_on: [LNK-001, AUTH-008]
    evidence: []

  - id: KAN-001
    kind: behavior
    behavior: Each project has exactly one Kanban board with the four fixed columns, created on first use.
    owner: kanban
    source: {file: local-workspace-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: KAN-001-B, description: "Read a fresh project's board and receive the four fixed columns empty; the same board answers every subsequent read."}
      failure: {id: KAN-001-F, description: "A card naming an unknown column is rejected, and no operation can create a second board or a new column."}
    deployments: *all
    status: specified
    depends_on: [PRJ-002]
    evidence: []

  - id: KAN-002
    kind: behavior
    behavior: Cards enforce the documented bounds on title, description, labels, assignee, paused placement, and attachments.
    owner: kanban
    source: {file: local-workspace-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: KAN-002-B, description: "Create and edit cards at every documented bound and read each stored field back unchanged."}
      failure: {id: KAN-002-F, description: "An oversize title or description, a ninth label, a duplicate case-folded label, paused outside in-progress, and a fifty-first attachment are each rejected without a partial write."}
    deployments: *all
    status: specified
    depends_on: [KAN-001]
    evidence: []

  - id: KAN-003
    kind: behavior
    behavior: Card mutations use per-card revisions so edits to different cards merge while same-card edits conflict and return the current card.
    owner: kanban
    source: {file: local-workspace-spec.md, anchor: conformance-requirements-to-add}
    acceptance:
      behavior: {id: KAN-003-B, description: "