# Contributing to ACOP

ACOP is a specification, not a library. That changes what a good
contribution looks like: the deliverable is precise normative text, not
working code. This document describes how changes are proposed, what the
review bar is, and which changes require a version bump.

## Before you open a pull request

Run the validator:

```bash
npm ci && npm test
```

It checks that every JSON file parses, every schema compiles under Ajv
(2020-12), every conformance fixture matches the fixture envelope, every
schema `$id` matches its published path, and every relative Markdown link
resolves. CI runs the same command, so a failure here is a failure there.

## Proposing a change

Open an issue before writing text for anything that changes normative
behavior. Describe the coordination problem first and the proposed
mechanism second — ACOP exists to solve concrete multi-agent contention
problems, and a proposal that cannot name the failure it prevents is
unlikely to be accepted.

Editorial fixes (typos, broken links, clearer prose that does not change
meaning) can go straight to a pull request.

## Normative language

Normative clauses use RFC 2119 / RFC 8174 keywords in all capitals: MUST,
MUST NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, OPTIONAL. Lowercase uses
of those words are ordinary English and carry no requirement.

Two rules follow from that:

- Do not use a keyword in all capitals unless you intend a testable
  requirement. "The server SHOULD be fast" is not testable; delete it or
  make it measurable.
- Every MUST that an implementation can violate should be reachable by a
  conformance fixture. If you add one and cannot write the fixture, say so
  in the pull request and explain why.

## What requires a version bump

See [acop.md § Versioning policy](./acop.md#versioning-policy) for the
normative rules. In short:

| Change                                                     | Effect          |
| ---------------------------------------------------------- | --------------- |
| New optional field, new enum member in an open vocabulary, new RECOMMENDED behavior | Minor bump |
| New required field, removed field, narrowed type, changed status code, transition moved from optional to forbidden | Major bump |
| Typo, clarified prose with unchanged meaning, new example, new non-normative note | No bump |

If you are unsure whether a change is additive, assume it is breaking and
argue the other way in review.

### Published schemas are frozen

Files published under `schemas/v1.0/` are immutable once released. A
schema fix — even a bug fix — ships as a new version directory. Editing a
released schema in place silently changes the meaning of an already-stable
`$id`, which breaks every consumer that cached it. The only edits
permitted to a released schema are ones that cannot affect validation
outcomes, such as a `description` correction.

## Conformance fixtures

New normative behavior needs a fixture in [fixtures/](./fixtures/). Pick the
kind that matches what you are asserting — `http` for a request/response,
`document` for whether a document is accepted, `transition` for whether a
state change is permitted. All three are documented in
[fixtures/README.md](./fixtures/README.md).

General:

- One scenario per file, named `<subject>.<scenario>.json`, with `name`
  matching the filename.
- State a `reason` on every negative expectation. Without one, a reviewer
  cannot tell an intentional rejection from a malformed fixture.
- Cite the clause in `spec_ref` so a reviewer can confirm the fixture tests
  a real requirement rather than an invented one.
- Add the fixture to the inventory table in
  [fixtures/README.md](./fixtures/README.md); the validator does not
  enforce that, but review will.

For `http` fixtures:

- Use `depends_on` to declare ordering rather than assuming the runner
  executes files alphabetically.
- Use `captures` to export values that later fixtures reference as
  `${variable_name}`, rather than hardcoding an identifier a real
  implementation would have generated. Anything the runner must supply
  belongs in [fixtures/runner-inputs.json](./fixtures/runner-inputs.json).
- Prefer `body_match.kind: "subset"`. Implementations MAY return
  additional fields, so `"exact"` should be reserved for cases where extra
  fields would themselves be a conformance violation.

For `document` fixtures, set `enforced_by` honestly. `schema` means JSON
Schema catches it; `spec` means it does not. The validator runs every
document fixture against its schema and rejects both mislabellings, so
guessing here fails the build rather than sliding through.

## Extensions

The orchestration and compliance extensions are stable at v1.0 and are
subject to the same additive-versus-breaking rules as core. Each is
versioned independently: an additive change to compliance does not bump
orchestration or core.

New extensions should live in their own `acop-<name>.md` and
`acop-<name>.schema.json` pair, start at v0.1, and be labeled experimental
in both the document header and the README table. Do not add extension
concepts to core.

Promoting an extension from experimental to stable requires all of:

- an RFC 2119 pass, with a Conventions section and every normative clause
  in all capitals
- a state machine for every status field the extension introduces, with
  required, optional, and forbidden transitions enumerated
- a Conformance section listing what an implementation MUST do
- conformance fixtures covering the schema-enforceable rules *and* the
  rules JSON Schema cannot express
- every open design question resolved in the document — a stable spec does
  not ship with an "Open questions" section describing its own semantics

## Vendor-specific fields

ACOP reserves the `x.<vendor>.` prefix for extension blocker codes; see
[acop.md § Blocker code namespaces](./acop.md#blocker-code-namespaces).
Use it rather than proposing a core code for something only one
implementation needs. A vendor prefix that sees adoption across several
implementations is a good argument for promoting it into core later.

## Reference implementation

The reference implementation lives in
[BogDB](https://github.com/BeyondOrdinary/BogDB) and is **not normative**. Where it
disagrees with this specification, the specification wins and the
implementation has a bug. A pull request that changes the spec to match
implementation behavior needs to justify the behavior on its own merits.

## Licensing

Contributions are accepted under the [Apache License 2.0](./LICENSE), the
license covering this repository. By opening a pull request you confirm
you have the right to contribute the text under those terms.
