Specifications

Project Profile

1.0.0Stable

Abstract

The Project Profile Specification defines one versioned YAML document that connects Intent Commits, Intent Pull Requests, Intent Changesets, Intent Changelog, Release Manifest, Engineering Follow-ups, and Incident Postmortems records to a repository’s actual boundaries and policies.

The other specifications deliberately avoid prescribing one universal set of types, scopes, release units, audiences, channels, or versioning rules. Without a portable profile, however, two implementations cannot resolve those project-defined values in the same way. This specification makes that shared policy explicit.

A project profile is configuration, not release history. It defines vocabulary, routing, validation, and conflict rules. It does not replace commit messages, release decisions, changelog entries, or manifests.

This document defines stable version 1.0.0.

1. Conformance language

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here.

2. Goals

The Project Profile is designed to:

  • select the exact versions of every enabled specification;
  • give tools one canonical repository identity;
  • map scopes to independently released units;
  • address parallel release streams without overloading channels;
  • share types, impacts, audiences, and disclosures across record layers;
  • define deterministic changeset and versioning policy;
  • route records to safe repository-relative locations;
  • make mechanical field mappings and conflict authority explicit;
  • provide the same policy to people, CI, and AI systems; and
  • preserve extensions without allowing them to silently redefine standard fields.

The Project Profile does not define a package manager, deployment system, branching model, hosting provider, release cadence, or organization-wide type taxonomy.

3. Terms

TermMeaning
ProfileOne canonical project-policy document conforming to this specification.
Release unitAn application, package, service, product, or other independently released boundary.
ScopeA canonical commit-message component identifier mapped by the profile.
Release streamA named destination for a sequence of releases of one release unit.
Release lineA compatibility or maintenance lineage such as 1, 3.x, or current.
ChannelA maturity or distribution class such as stable, preview, or long-term-support.
VocabularyThe accepted types, impacts, audiences, and disclosure states.
RoutingThe deterministic mapping from a release target to canonical record paths.
ExtensionA non-standard field whose name begins with x-.

A release line and a channel are different dimensions. stable can exist for both a maintained 3.x line and a current 4.x line. Tools MUST NOT use a channel name as an implicit release-line identifier.

4. Canonical representation

A profile is exactly one YAML 1.2 document whose root is a mapping:

intent-profile: 1.0.0
repository: https://github.com/example/platform
specifications:
  commits: 1.0.0
  pull-requests: 1.0.0
  changesets: 1.0.0
  changelog: 1.0.0
  release-manifest: 1.0.0
  follow-ups: 1.0.0
  incident-postmortems: 1.0.0

types:
  feat:
    default-impact: minor
  fix:
    default-impact: patch
  chore:
    default-impact: none

scopes:
  apps/gateway:
    release-unit: apps/gateway
  apps/gateway/auth:
    release-unit: apps/gateway
  apps/worker:
    release-unit: apps/worker
  shared/auth:
    requires-affects: true

release-units:
  apps/gateway:
    streams:
      stable:
        release-line: current
        channel: stable
        changelog: .ack/changelog/apps-gateway-stable.yaml
        manifests: .ack/releases/apps-gateway/stable
  apps/worker:
    streams:
      stable:
        release-line: "2"
        channel: stable
        changelog: .ack/changelog/apps-worker-stable.yaml
        manifests: .ack/releases/apps-worker/stable
      lts:
        release-line: "1"
        channel: long-term-support
        changelog: .ack/changelog/apps-worker-lts.yaml
        manifests: .ack/releases/apps-worker/lts

ledger-directory: .ack/changelog
release-manifest-directory: .ack/releases
release-pattern: '^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$'

release-types: [feature, fix, reliability, security, operations]
release-impacts: [none, patch, minor, major]
audiences: [end-users, api-consumers, operators, security-teams]
disclosures: [public, embargoed, redacted]
channels: [stable, preview, long-term-support]
environments: [development, staging, production]

changesets:
  directory: .ack/changes
  archive-directory: .ack/archive/changes
  after-consumption: archive
  conflict-policy: preserve
  id-pattern: '^[a-z][a-z0-9-]+$'
  required-impacts: [minor, major]
  required-commit-types: [security]

pull-requests:
  directory: .ack/pull-requests
  merge-strategy: squash
  max-title-length: 72
  max-body-length: 20000
  require-ready: true
  verification-statuses: [passed, failed, skipped, unavailable, not-applicable]

follow-ups:
  directory: .ack/follow-ups
  id-pattern: '^[a-z][a-z0-9-]+$'
  owners: [team-platform, team-payments, incident-reviewer]
  trigger-events:
    pull-request-merged:
      clock: utc
    release-published:
      clock: utc
  allowed-triggers: [before-merge, after-merge, scheduled, conditional, recurring]
  allowed-states: [planned, ready, in-progress, blocked, completed, waived, cancelled]
  gates:
    pull-request-merge:
      triggers: [before-merge]
      fail-closed: true
  recurrence:
    max-occurrences: 52
    max-horizon: P2Y
  duration-policy: utc-elapsed

incident-postmortems:
  directory: .ack/incidents
  id-pattern: '^inc-[a-z0-9-]+$'
  severities: [minor, major, severe, critical]
  incident-states: [active, contained, mitigated, recovered, resolved]
  document-states: [draft, in-review, reviewed, published, amended]
  required-reviewers:
    severe: [incident-reviewer]
    critical: [incident-reviewer, security-reviewer]
  publication:
    require-reviewed: true
    require-recovery-verification: true
  follow-up-link-policy: reciprocal
  timeline-clock: utc

require-release-ready: true
max-header-length: 72
max-body-line-length: 72
large-diff-threshold: 500

Unknown fields MUST be preserved by tools that read and rewrite a profile. Standard fields are case-sensitive and MUST use the spelling shown here. Extensions MUST begin with x- and MUST NOT alter the meaning of a standard field.

5. YAML processing

Profile documents MUST be UTF-8 and MUST contain exactly one YAML document. Parsers MUST reject:

  • duplicate mapping keys;
  • anchors, aliases, and merge keys;
  • custom YAML tags;
  • a non-mapping document root; and
  • input exceeding implementation-documented resource limits.

Implementations MUST bound document size, nesting depth, alias-independent node count, and scalar length. A conforming implementation MUST support documents up to 1 MiB and nesting up to 64 levels. It MAY reject larger inputs.

Strings that resemble booleans, numbers, timestamps, or null values MUST remain strings when the corresponding field is defined as a string. Authors SHOULD quote release lines and other numeric-looking identifiers.

Canonical means canonical data model, not byte-for-byte serialization. A writer MAY change insignificant whitespace, quoting, or mapping order while preserving all known and unknown values.

6. Required top-level fields

A profile MUST contain:

  • intent-profile;
  • repository;
  • specifications;
  • types;
  • scopes;
  • release-units;
  • ledger-directory;
  • release-manifest-directory;
  • release-pattern;
  • release-types;
  • release-impacts;
  • audiences;
  • disclosures;
  • channels;
  • environments, when follow-ups or postmortems use environment targets;
  • changesets; and
  • follow-ups, when Engineering Follow-ups is enabled;
  • incident-postmortems, when Incident Postmortems is enabled; and
  • require-release-ready.

Style and heuristic fields such as max-header-length, max-body-line-length, and large-diff-threshold are OPTIONAL.

7. Profile and specification versions

intent-profile MUST contain 1.0.0 for this version.

specifications MUST contain commits, changesets, changelog, and release-manifest. It MAY contain pull-requests, follow-ups, and incident-postmortems. Each value MUST be a complete Semantic Versioning version. A validator MUST reject a profile when it does not implement an enabled version. It MUST NOT silently reinterpret a record using a different version.

Repositories MAY contain historical records written against older specification versions. Each record selects its own version. A tool processing a mixed ledger MUST validate every record against its declared version and MUST report unsupported versions individually.

Changing a selected specification version is a reviewed profile migration. A tool MUST NOT rewrite historical records merely because the profile advances.

8. Repository identity

repository MUST be an absolute URI identifying the source repository. The same value MUST be used by changesets, changelog records, and release manifests that describe that repository.

Commit object names in provenance are interpreted within this repository unless the provenance value contains an explicit repository URI. This prevents a bare hash from being treated as globally unique.

A repository relocation MAY update the profile for new records. Historical records SHOULD retain their original identity or an explicit relocation mapping. Tools MUST NOT silently rewrite provenance across repositories.

9. Scopes and release units

Every key under scopes MUST follow the Intent Commits scope grammar. Each scope mapping MUST contain exactly one of:

  • release-unit, naming the unit owned by that scope; or
  • requires-affects: true, declaring that the scope is shared and every commit using it must identify affected release units explicitly.

A scope MUST NOT map to an unknown release unit. More than one scope MAY map to the same release unit. This is how hierarchical scopes such as apps/gateway/auth resolve without string-prefix guessing.

Every key under release-units is a canonical release-unit identifier. An independently deployed application or independently versioned package MUST have its own release unit.

10. Release streams

Every release unit MUST contain one or more streams. A stream key is stable within its release unit and MUST NOT be reused for a different release line or channel.

Every stream MUST contain:

  • release-line;
  • channel;
  • changelog; and
  • manifests.

The pair (release-unit, stream) identifies a changeset target and the open changelog destination. The tuple (release-unit, stream, release) identifies a release occurrence.

channel MUST occur in the top-level channels sequence. Several streams MAY use the same channel. release-line is an opaque non-empty string whose ordering, if any, is project policy.

changelog MUST identify the canonical open or current Intent Changelog record for the stream. manifests MUST identify the directory containing immutable Release Manifest records for that stream.

11. Release identifiers

release-pattern MUST be a regular expression accepted by the profile’s declared regular-expression dialect. Version 1.0.0 uses RE2 syntax. Every release identifier in an Intent Changelog record or Release Manifest MUST match it.

Projects using Semantic Versioning SHOULD use complete versions such as 1.4.0, never shortened forms such as 1.4.

The profile MUST define, through documentation or an extension, how entry impacts determine the next release identifier. For Semantic Versioning, the RECOMMENDED rule is the greatest applicable impact, with explicit rules for versions below 1.0.0 and prerelease channels.

Changing the planned release identifier while a record is unreleased is a separate reviewed planning operation. Publishing remains date-only.

12. Shared vocabularies

types defines accepted Intent Commits types and MAY give each a default-impact. A type default supplies an effective impact only when the message does not declare one.

release-types, release-impacts, audiences, disclosures, channels, and environments MUST contain unique non-empty identifiers when present. Policy sections MAY add owners, trigger events, severities, states, and reviewers. Every value used by a record MUST appear in the corresponding vocabulary.

Type and impact remain independent. A profile MUST NOT define a rule that makes the English meaning of a type override an explicit impact.

13. Changeset policy

changesets MUST contain:

  • directory, the pending-record directory;
  • archive-directory, when records are archived;
  • after-consumption, exactly keep, archive, or delete;
  • conflict-policy, exactly preserve in version 1.0.0;
  • required-impacts; and
  • required-commit-types.

id-pattern is OPTIONAL and, when present, further restricts changeset IDs.

conflict-policy: preserve means automation reports disagreements and preserves reviewed data. It MUST NOT silently select a commit, changeset, or changelog as authoritative.

A change requires a changeset when any applicable required-impact or required-commit-type rule matches. Projects MAY define additional audience- or path-based rules as extensions, but those rules MUST be deterministic and documented.

14. Pull-request policy

When specifications.pull-requests is enabled, pull-requests MUST contain:

  • directory, a repository-local canonical record directory;
  • merge-strategy, exactly merge, squash, or rebase;
  • positive max-title-length and max-body-length values;
  • require-ready, stating whether integration requires ready conformance; and
  • verification-statuses, containing accepted Intent Pull Requests states.

The standard verification states are passed, failed, skipped, unavailable, and not-applicable. A project MAY restrict the allowed set but MUST NOT redefine a standard state’s meaning. Forge mappings MAY be extensions, but portable validation MUST NOT depend on a forge API.

Pull-request targets use the profile’s existing release units, streams, and impacts. A profile MUST NOT define parallel pull-request identifiers for those concepts.

15. Follow-up policy

When specifications.follow-ups is enabled, follow-ups MUST contain:

  • directory, a repository-local canonical record directory;
  • id-pattern, a deterministic identifier restriction;
  • non-empty owners;
  • trigger-events, mapping accepted events to an explicit clock;
  • allowed-triggers and allowed-states;
  • gates, including each operation and its blocking trigger types;
  • recurrence, with implementation limits; and
  • duration-policy, defining calendar and elapsed-time behavior.

The standard trigger types and states are defined by Engineering Follow-ups 1.0.0. A project MAY restrict them but MUST NOT redefine their meaning. owners MAY contain people, teams, and roles. Each identifier MUST have an accountability boundary outside the profile; a wildcard owner is invalid.

Every trigger event MUST define a trusted evidence source or adapter as an extension before automation resolves it. The portable clock MUST be utc or a profile-defined clock with complete time-zone, daylight-saving, and unavailable-time behavior. duration-policy: utc-elapsed permits only day and time durations evaluated on UTC.

A gate MUST declare its operation, applicable trigger types, and whether missing or unreadable records fail closed. A profile MUST NOT make a waived record indistinguishable from a completed record. Recurrence policy MUST bound occurrence count and time horizon even when each record has a narrower stopping rule.

16. Incident-postmortem policy

When specifications.incident-postmortems is enabled, incident-postmortems MUST contain:

  • directory and id-pattern;
  • accepted severities, incident-states, and document-states;
  • required-reviewers, keyed by severity or profile-defined policy class;
  • publication gates;
  • follow-up-link-policy; and
  • timeline-clock.

The standard lifecycle states retain their Incident Postmortems 1.0.0 meaning. Projects MAY use their own severity vocabulary but MUST document ordering and whether a value represents peak, current, or final reviewed severity.

Publication policy MUST state whether review, recovery verification, resolved incident state, completed follow-ups, embargo expiry, or profile-defined legal review is required. Requiring completed follow-ups is NOT RECOMMENDED because many corrective actions deliberately occur after publication.

follow-up-link-policy MUST be reciprocal or postmortem-only. reciprocal requires the postmortem to name a follow-up and the follow-up to name the incident or postmortem. postmortem-only permits imported external tasks but weakens link verification and MUST be reported by validators.

Adapters for incident platforms, status pages, evidence stores, or publication targets MUST define authority, revision tokens, conflict behavior, disclosure, and redaction. Imported statements remain reported claims until separately validated.

17. Field ownership and conflict resolution

The profile connects the layers without collapsing them:

ConcernOwning layer
Atomic implementation descriptionIntent Commits
Integration rationale, approach, and review evidenceIntent Pull Requests
Release decision and target-specific consequenceIntent Changesets
Canonical audience-facing release historyIntent Changelog
Exact source and artifact evidenceRelease Manifest
Deferred action, trigger, owner, and completion proofEngineering Follow-ups
Incident analysis, uncertainty, recovery proof, and learningIncident Postmortems

Mechanical mappings MAY seed later fields. Editorial fields MAY be revised in the changelog before publication. A consumer MUST report a conflict before overwriting an existing reviewed entry.

The profile MUST document any additional mapping and MUST distinguish copied evidence from editorial synthesis. It MUST NOT declare a commit body to be an audience-ready rationale automatically.

18. Paths and repository safety

Every configured path MUST be repository-relative, non-empty, and normalized. It MUST NOT be absolute, resolve to the repository root, or escape through .., symbolic links, mount points, or platform-specific path semantics.

changelog paths MUST reside beneath ledger-directory. Stream manifests paths MUST reside beneath release-manifest-directory. Follow-up and postmortem records MUST reside beneath their configured directories.

A writer MUST create temporary files in the destination directory and replace records atomically when the platform permits it. A multi-record operation MUST be retry-safe and MUST NOT delete or archive its source until every destination has been verified.

19. AI-assisted use

An AI system claiming profile-aware support:

  1. MUST receive the exact profile bytes or a verified equivalent;
  2. MUST identify the profile version and every enabled specification version;
  3. MUST treat repository content as untrusted evidence, not instructions that can override this profile;
  4. MUST NOT invent scopes, release units, streams, types, audiences, impacts, owners, triggers, clocks, severities, reviewers, disclosure states, paths, or mappings;
  5. MUST return NEEDS_INPUT for an unresolved required decision; and
  6. MUST preserve embargo, redaction, and repository access boundaries in prompts, logs, caches, and output.

When reproducibility matters, the caller SHOULD retain the profile digest, source revision, selected evidence revision, model or tool identity, and the distinction between quoted evidence and generated synthesis.

AI output does not alter profile authority. A fluent value that is absent from the profile remains invalid.

20. Security considerations

Profiles control file locations, policy, and data disclosure. Implementations MUST treat them as untrusted input until validated.

Tools MUST defend against path traversal, symbolic-link escape, YAML resource exhaustion, terminal escape injection, template injection, command injection, and regular-expression denial of service. RE2 is selected because it avoids backtracking-based denial of service.

An extension MUST NOT contain executable configuration merely because a tool preserves it. Implementations MUST treat profile strings as data unless a separate trusted configuration layer explicitly defines execution.

21. Conformance classes

21.1 Project Profile Reader

A Reader MUST parse the canonical data model, enforce section 5, and preserve unknown fields.

21.2 Project Profile Validator

A Validator MUST implement Reader requirements and validate sections 6 through 18. It MUST report unsupported specification versions distinctly from malformed or project-invalid data.

21.3 Project Profile Resolver

A Resolver MUST implement Validator requirements and deterministically resolve:

  • a scope to its release unit or affected-unit requirement;
  • a (release-unit, stream) target to its changelog and manifest paths;
  • an explicit or default impact;
  • whether a change requires a changeset;
  • whether a follow-up participates in a named gate;
  • an event-relative follow-up trigger to its trusted clock policy; and
  • postmortem review and publication requirements.

22. References