Releases: MosslandOpenDevs/agentic-assurance-profile
Release list
v0.4.0
A usability-focused minor: makes adoption harder to get wrong at the
entry point, turns the invariant register into a core obligation, and
hardens the archived profile (exclusivity + a required non-empty mapped
system artifact + an untouched-template guard; semantic §6.6 content
enforcement remains tracked in #40).
- Profile classification is now an explicit first step of adoption.
docs/ADOPTION.md§4.0 ("Classify the profile first") makes profile
selection an evidence-based finding — a cheap §5 trigger scan with
file:lineevidence, a bias toward escalation, an adversarial
self-check of the cited evidence, and the classified set declared in
adoption.yaml's enforcedprofiles:field rather than only in the
handoff prose. The prior "start atcore/ lite is the default /
selectcoreonly at first" framing is flipped throughout (§0, §3.0,
§3.2, §4.0, §5);README.mdandREADME.ko.mdroute a bare "apply
this profile" prompt into classify-first; andPROFILE.md§5
clarifies that the smallest applicable set covers the system's actual
nature. Documentation only — no schema or validator change. - Existing tool output has a stated position in the core model.
docs/MAPPINGS.md§5 (new, non-normative) shows how to reference what a
repository's tools already produce — specification workflows, tests,
scanners and code-review tools, agent change records, build attestations —
from the registers instead of restating their results by hand. Each tool
class is placed against what it does not establish, because an assurance
argument fails when a strong answer to one question is filed as the answer
to another: a review tool reporting no findings is coverage, not proof, and
an agent change record is evidence of the action, not of correctness. §5.2
binds an evidence reference to a revision, release, artifact, or deployment
(PROFILE.md§11) and covers the restricted case; §5.5 states what no tool
supplies — intent, claim wording, defeater disposition, residual acceptance
— and that an agent-drafted record carries human authority only when the
owner's own approval act anchors it (PROFILE.md§7).README.mdand
README.ko.mdroute to it from the "complements your existing toolchain"
claim, which previously had nothing behind it. Documentation only — no
schema or validator change. - Profile composition is now explicit and aligned with validation.
Every non-archivedspecialized profile implicitly inherits §6.1
coreobligations. For an active adopter, the canonical smallest
declaration is[core]when no specialized trigger fires; otherwise it
lists every fired specialized profile and omitscore(an explicit
coreremains allowed and changes no obligation).archivedis
normatively exclusive, replaces §6.1–§6.5 active obligations while
retaining the pin and root agent instructions, and records its four §6.6
facts in the system artifact resolved frompaths.system(default
assurance/SYSTEM.md). This closes the gap where the validator enforced
exclusivity and artifact placement more strongly than the authoritative
profile text. The validator rejects an empty archived system artifact at
every stage and, atHUMAN_REVIEWEDorCONFORMANT, any of the four exact
shipped archived placeholders. It still does not determine whether replacement prose states
all four facts or is truthful; that structured semantic enforcement remains
#40, with the owner review guide as the explicit content backstop. - At least one invariant is now required at
core(previously an
obligation only fromservice).PROFILE.md§6.1, the lite envelope
schema (invariantsnow required), and the split-layout file-presence
and non-emptiness checks all enforce it — a repository with nothing
that must stay true has not found its invariants yet. - A minimal lite template (
templates/assurance.minimal.yaml) ships
the required-minimumcoreadoption — purpose, non-goals, system, one
invariant, one residual — with only the fields an adopter must fill, so
the fulltemplates/assurance.yamlis now the expanded alternative rather
than the default minimal starting point. The self-check validates both
templates, so neither can drift. - The adoption template no longer defaults to
core.
templates/adoption.yaml(and the copy example in
AGENTIC_ASSURANCE.md) ship aREPLACE_WITH_CLASSIFIED_PROFILE
sentinel inprofiles:— the central self-check substitutes it to a
valid enum, but an adopter who copies the template must replace it with
the classified set or validation fails on the unfilled placeholder, so
no adoption silently inherits acoredefault. (This is a completion
guard; detecting a wrong profile against the actual code remains the
under-classification backstop, tracked in #41.) - The normative stage and entry-artifact contracts are now explicit.
PROFILE.md§17 defines the cumulativeDRAFT,HUMAN_REVIEWED, and
CONFORMANTladder rather than leaving its substance only in the adoption
guide and schema descriptions. DRAFT includes applicable semantic checks;
HUMAN_REVIEWED requires a recorded classification (UNKNOWN allowed) for
every active critical invariant. Independently of review stage, every active
VERIFIEDcritical invariant needs at least one enforcement and one
verification reference; underservice, every critical invariant needs
both references regardless of conclusion status. A conformance claim requires an explicit
adoption_stage: CONFORMANT, where no critical residual remainsOPEN, no
claim or critical invariant isCONTRADICTED, everyVERIFIEDcritical
invariant has evidence, every critical invariant has an intent other than
UNKNOWNorACCIDENTAL, and public repositories carry noRESTRICTEDor
EMBARGOEDregister entry. At every stage, placeholder substitution remains
schema-only: it cannot fabricate an invariant mechanism or authority, a
residual acceptance/resolution record, or a closed-defeater resolution.
Closed defeater meanings and their mandatory non-blank disposition grounds
are now normative in §12. §17 also distinguishes the adopter's
human-approved full normative claim from the validator's structural and
mechanically decidable subset. §6.1 now expressly
requires rootAGENTIC_ASSURANCE.mdand rootAGENTS.mdreading-order
artifacts, and defines one system-description content minimum regardless of
lite, split, or mapped layout. The fuller §7 reconstruction remains the
normalSHOULD, not a mapping-only hard requirement. - Input and path handling now fail closed and remain resource-bounded.
Duplicate mapping keys in YAML or JSON are rejected instead of silently
using the last value. YAML merge keys are rejected before PyYAML can expand
a merge-alias DAG; ordinary anchors and aliases remain supported under the
logical-node bound, including for pre-v0.4 last-key-wins base comparison.
Policy YAML is normalized to the JSON-compatible data
model used by the schemas: binary, set/ordered-map, cyclic, and non-finite
values are rejected, while YAML dates are normalized to ISO strings.
Non-finite JSON constants and non-UTF-8 policy inputs are rejected; every
policy YAML input is limited to 5,242,880 bytes and
100,000 logical nodes after alias expansion, preventing compact alias-DAG
denial of service. Policy JSON is limited to 10,485,760 bytes, 256 nesting
levels, and 500,000 nodes; YAML and JSON numeric source tokens are limited to
4,096 characters on every supported Python version. Invalid implicit YAML
dates and other scalar-constructor failures now produce controlled diagnostics
rather than tracebacks. Adopter-owned prose and review files read directly by
the validator are each limited to 5,242,880 bytes: the two root assurance
guides, mapped system artifact, required service threat model, and declared
human-review record. The self-check matrix now includes Python 3.14 while
retaining 3.10 as the compatibility floor. Self-check meta-validates every JSON Schema and scans
tracked filenames losslessly even when a filename contains a newline;
schema references use an explicit offline registry, so an unresolved or
remote$reffails with a controlled diagnostic without network access;
malformed approval timestamps and HTTP(S) approval URLs are checked
explicitly at every stage rather than depending on optional JSON Schema
format packages. They produce ordinary diagnostics rather than a parser
traceback; approval URLs must name a host, contain no user information, use
a numeric in-range port when one is present, use a DNS/IPv4-style or
bracketed hexadecimal IPv6 host, and contain only valid percent escapes and
RFC 3986 path/query/fragment characters under the profile's deliberately
narrow ASCII HTTP(S) URL grammar (percent-encoded path/query/fragment data
must decode as UTF-8; internationalized hosts use an ASCII IDNA A-label
spelling; the complete RFC 3986 host surface is not claimed).
Public metadata pointerssecurity.restricted_recordand residual
private_detail_locationnow share a bounded non-actionable ASCII label
grammar (letters, digits, dot, underscore, and hyphen; at most 128
characters), so syntactically actionable URLs, slash paths, and@account
identifiers cannot pass merely because they are nonblank. The validator
cannot determine whether an otherwise valid opaque label is itself a secret;
never place a secret there. Replace an actionable locator with a public label
such asexternal_private_systemand keep the locator only in the restricted
system.
Non-empty policy strings made only of separators
or invisible format characters are rejected with their JSON path instead of
satisfying a required semantic value. Release identifiers use canonical
ASCII SemVer numbers (no leading zero; r...
v0.3.2 — change-control every recorded human decision
Extends the register policy diff from "reviewed items cannot silently disappear" (v0.3.1) to change control over every recorded human decision: acceptance, terminal dispositions, accountability, re-review commitments, both residual assessment axes, and the assurance-graph edges. From a fifth external review of v0.3.1. No schema changes; existing adopters see stricter drift findings only on pull requests that change a reviewed decision. See CHANGELOG.md.
Canonical pin for adopters: v0.3.2 @ aac49ef7f0d8a8e8762113df8b7bf1784eaa2e54 (this tag's commit).
Review class: SOLE_OWNER_ATTESTED + AUTOMATION_VERIFIED. The external technical review is cited, not counted as an approving review (GOVERNANCE.md §2).
Fixed — register policy diff: human decisions are change-controlled
- Residual acceptance is gated. Any status transition into
ACCEPTEDis now a finding. Accepting a risk is a human decision (PROFILE.md §3, §12) and the acceptance fields are self-declared strings, so an agent could previously fabricateaccepted_by/accepted_at/acceptance_rationale, flip a critical residualOPEN → ACCEPTED, and turn a failingCONFORMANTstate green with no finding. Rewriting or removing an existing acceptance record is likewise a finding. - A recorded judgement value cannot be silently unset. Every weakening check is pair-keyed, so unsetting a value was a free first hop — drop it in one pull request (nothing to compare, silent), record the weaker value in the next (no baseline, silent), while the one-step edit was an error the whole time. Removing, emptying, or de-stringing
status(all registers),severity,proof_tier,impact,uncertainty, or anINTENDEDintent.classificationis now a finding. The residual/defeater disposition gates additionally fire on the head arriving at a gated status whatever the base recorded. - Defeater terminal dispositions are gated.
MITIGATED → RESOLVEDandMITIGATED → WITHDRAWNwere invisible inside a single "closed" class, though the schema definesMITIGATEDas risk reduced, not eliminated. - Assurance-graph edges are protected. Removing items from claims'
defeaters/residuals, invariants'assumptions/limitations/defeaters/residuals(at every severity — edges are graph structure, not evidence volume), defeaters'affected_claims/affected_invariants/evidence, and residuals'affected_claims/affected_invariants/mitigation. review_afteris a kept commitment. Removal, replacement with an unparsable value, and pushing out a date that has already passed are findings. Rescheduling a future date is deliberately not one.- Also: residual
uncertaintydowngrades (impact's previously unprotected twin axis), entryownerchanges, andhuman_review.reviewer/human_review.recordchanges in the adoption declaration.
Security
- Symlinked base registers no longer fail open. The drift job materializes the base side as a detached
git worktreeinstead of per-filegit showwrites.git showrenders a symlink blob as its target-path string, so a symlinked register materialized as a regular file holding a path string, loaded as unusable, and dropped out of the policy diff silently — one innocuous pull request converting a register to a symlink disabled its protection for every later one. - A register that parses but is not a mapping with its list, a lite assurance file that is not a mapping or whose section is not a list, and a path that exists but is not a readable regular file (directory, broken symlink) are now reported instead of silently skipped.
- Duplicate head IDs fail closed. The diff compares by stable ID (last-one-wins), so a shadow entry under a duplicated ID was invisible to it. This no longer depends on the structure job being configured as a required check.
Deliberately not added
Recorded so the reasoning survives: disclosure reclassification (not a strength axis; the risky direction on a public repository is already a CONFORMANT error; retriage is routine), rescheduling a review_after date that has not yet passed (a red check on the act the schedule exists to produce would teach adopters to ignore the check), strengthening promotions, and unrecognized-string overwrites (pair-keyed the same way, but flagging them would also flag an adopter repairing a value that predates the stricter schema — that remains the schema enum check's job).
Upgrade actions when re-pinning
None required. Update upstream.version, upstream.commit, and the reusable workflow's @ reference to this tag's commit in the same change. Pull requests that change a reviewed decision now need the same stage-proportional Assurance policy change: acknowledgment as deletions and closures. Adopters whose registers are in-tree symlinks: the base side of the policy diff previously dropped such registers silently; they are now compared like regular files.
v0.3.1 — complete the register policy diff
Completes the register policy diff so a base-branch, human-reviewed assurance item cannot silently disappear regardless of the form the change takes — deletion, whole-register removal, or a status that closes it out. From a fourth external review of v0.3.0. No schema changes; existing adopters see only stricter drift-job findings, and only on pull requests that actually remove reviewed assurance. See CHANGELOG.md.
Canonical pin for adopters: v0.3.1 @ 48c5b53214c3710f0f22492302044a7ece96fcdc (this tag's commit).
Fixed — register policy diff completeness
- Whole-register removal is now caught (was fail-open). The diff skipped a register entirely when the head branch lacked it, so deleting an optional register file (e.g.
INVARIANTS.yamlunder thecoreprofile, where it is not required) erased every reviewed entry with no finding. A base register absent on the head is now a "register removed" finding listing the former IDs; an unreadable head register fails closed. - Closing dispositions are now caught. A residual moved to
RESOLVED, a defeater moved toMITIGATED/RESOLVED/WITHDRAWN, and a recordedCONTRADICTEDstatus cleared (moving away fromCONTRADICTED) each retire a tracked concern without deleting its ID; now findings, under the same stage-proportional acknowledgment. Re-opening and recording a new contradiction remain non-findings. - Claim basis removal is now caught. Removing a claim's
evidence, supportinginvariants, orlimitationsitems is flagged — stripping a claim's basis is a mechanism change, not a wording change.
Security
- The drift job's assurance-diff step runs
gitwith--literal-pathspecs, screens pull-request-controlledpaths:values through an in-tree containment check (matching the validator's accept-set) before using them as pathspecs or write targets, and fails closed ifgit differrors instead of proceeding with an empty diff.
Upgrade actions when re-pinning
Update upstream.version, upstream.commit, and the caller's @ reference to the SHA above in the same change; the pull-request description needs an Assurance policy change: <why> line. The caller must pin the workflow by full SHA (unchanged from v0.3.0).
v0.3.0 — workflow trust anchor, register-level policy diff
Trust-boundary honesty and register-level policy protection, from a third external review of v0.2.1. No adoption-schema shape changes to the adoption file itself; the register schemas now reject empty/whitespace-only semantic strings and profile-mandated registers must be non-empty (minor release — theoretically breaking for adopters relying on vacuous passes; none known). See CHANGELOG.md.
Canonical pin for adopters: v0.3.0 @ 13f4f2d57d780a35cf0b890cdc5da190eae4c325 (this tag's commit).
Security / trust boundary
- Trusted-checkout-first. Every job verifies the workflow's own identity (
job.workflow_repository== canonical, and the caller pins it by full 40-char SHA — tag/branch callers are rejected) and checks out that exact source as the pinned profile.upstream.commitmust equal the workflow's own SHA; the v0.2.1 version-pinned pyyaml bootstrap is gone (no install precedes the trusted checkout). GitHub.com only. - The caller-workflow boundary is documented honestly: a pull request runs its own version of the caller, so it can swap the
@reference — no reusable-workflow content can defend that. Controls: CODEOWNERS on.github/workflows/(in the adopter bundle), organization Actions allow-lists, and organization rulesets with required workflows (GitHub Team/Enterprise). A green check is an input to human review, not a tamper-proof verdict.
Upgrade actions when re-pinning
- Update
upstream.version,upstream.commit, and the caller's@reference to the SHA above in the same change. The pull-request description needs anAssurance policy change: <why>line (the policy regression check flags every pin move). - The caller must pin the workflow by full SHA (a tag/branch
@reference is now rejected).
Also in this release
- Register-level policy regression (stable-ID base/head diff): deleted entries; invariant severity/status/intent weakenings and evidence removal; claim status/proof-tier downgrades; residual impact downgrades.
CONTRADICTEDis treated as an honesty upgrade, never flagged. Adoption-level findings gainhuman_owner,paths.*, andpublic_assurance_root. - Stage-proportional acknowledgment:
Assurance policy change:downgrades findings to warnings only while the base declaration isDRAFT; fromHUMAN_REVIEWEDon, findings stay errors even when acknowledged. - Visibility-aware disclosure: at
CONFORMANT,RESTRICTED/EMBARGOEDentries are errors only in public repositories (CI passes the repository's actual visibility;--repo-visibilityfor standalone runs). - Profile-mandated registers must be non-empty; register schemas reject empty/whitespace-only semantic strings.
actionlint(digest-pinned) added to CI; GOVERNANCE.md defines honest review classes.- 70-case validator regression suite.
v0.2.1 — adopter-CI trust boundary fix
Security hardening of the reusable adopter CI plus honest-signal fixes, from two external reviews of v0.2.0. No adoption-schema changes; existing registers validate identically. See CHANGELOG.md for the full list.
Canonical pin for adopters: v0.2.1 @ 6de26c28573bd1d145dad75529debb8a89d0d5d2 (this tag's commit).
Security
- The reusable workflow no longer checks out the validator from a repository named in the pull-request-mutable adoption file: the validator always comes from the canonical upstream, the declared repository is validated as data, and the caller's
@reference must equalupstream.commit(now enforced). This closes a code-execution vector where a pull request could point CI at attacker-controlled validator code. permissions: contents: read,persist-credentials: false, full-SHA action pins, and a universal hash-pinned dependency lock in both workflows.- All pre-v0.2.1 releases carry the CI issue — re-pin before running the reusable workflow on a repository that accepts external pull requests (see SECURITY.md).
Upgrade actions when re-pinning
- Update
upstream.version,upstream.commit, and the caller workflow's@reference to the SHA above in the same change; the PR description needs anAssurance policy change: <why>line (the new policy regression check flags every pin move). - Required-check rename:
assurance / conformance→assurance / declared-stage. - Recommended caller
on:update:pull_requesttypes[opened, synchronize, reopened, edited, ready_for_review](docs/ADOPTION.md §3.4).
Also in this release
CONFORMANTenforces the mechanically checkable subset of PROFILE §17 (criticalOPENresiduals,CONTRADICTEDentries, evidence-freeVERIFIEDcriticals,RESTRICTED/EMBARGOEDmaterial).- Pull-request policy regression gate: stage downgrades, component removal/narrowing, and pin moves require explicit acknowledgment.
- Impact routing precision: rename-safe change detection; a component is satisfied only when the added lines of the assurance diff reference its invariant IDs (token-boundary matched); findings surface as annotations and a job-summary table.
- Lite envelope schema rejects unknown top-level keys and empty prose fields (
extensionsnamespace for local keys). - 42-case validator regression suite, run on a Python 3.10/3.12/3.13 matrix.
v0.2.0
The register becomes a regression gate, the safest usage becomes the easiest
usage, and a green check can no longer be misread. All three features trace to
the two pilot adoptions and two external reviews of the v0.1 line.
Highlights
- Impact routing — an optional
components:map (path globs → invariant
IDs) plus a pull-request drift gate: touched components must be answered by
an assurance update, the affected invariant IDs in the PR body, or an
explicitAssurance impact: none+Reason:statement. Warn-first;
strict-driftescalates. - core-lite — a four-file adoption for
corerepositories (AGENTS.md
section,AGENTIC_ASSURANCE.md,adoption.yamlwithlayout: lite, and a
singleassurance.yaml), down from the second pilot's 25-file first
adoption. Register item shapes stay defined solely by the register schemas. - Adoption stages + attributable approval — self-declared, self-binding
adoption_stage: DRAFT | HUMAN_REVIEWED | CONFORMANT; CI checks split into
structureandconformance(skipped while DRAFT);human_review.approvals
records who approved, where, and when. data-curationpromoted from provisional (every §6.4 obligation exercised
by the second pilot);agent-runtimeremains provisional.
Adopter impact / upgrade actions
- Re-pin optional; v0.1.x pins remain valid. Upgrading adopters update
upstream.version→v0.2.0,upstream.commit→ the commit this tag
points to, and the workflow@reference in one reviewed change. - Required-check rename:
assurance / validate→assurance / structure
(plus newassurance / conformance). Update branch-protection settings when
re-pinning. - Adoptions without the new optional fields behave byte-identically.
Full changelog: CHANGELOG.md
v0.1.2
Semantic validation: an evidence-free VERIFIED no longer passes.
Adopter impact / upgrade actions
- Optional upgrade; existing pins remain valid. Re-pinning adopters get
seven new semantic checks — six ERROR-level (duplicate IDs; dangling
cross-references;VERIFIEDcritical invariants without enforcement and
verification;INTENDEDwithoutintent.authority; high-impact
ACCEPTEDresiduals withoutacceptance_rationale;RESOLVEDentries
without recorded grounds) and one WARN-level (passedreview_after
dates;--strict-review-datesescalates). Both current pilot registers
pass all seven unchanged. - Conclusion status and intent classification remain independent axes: a
VERIFIEDinvariant with intentUNKNOWNis legitimate. - Informative minimum layouts aligned with normative
PROFILE.md§6.1:
assurance/INVARIANTS.yamlis recommended atcore, required from
service.
Full changelog: CHANGELOG.md
v0.1.1
Post-release hardening from external review: close the gap between creating
assurance documents and binding them.
Adopter impact / upgrade actions
- Optional upgrade — no obligations changed and no re-pin is required.
Adopters who want the new CODEOWNERS binding copy
templates/github/CODEOWNERSand follow adoption guide §3.5; existing
v0.1.0pins remain valid.
Added
- Adopter
CODEOWNERStemplate covering the assurance layer (AGENTS.md,
AGENTIC_ASSURANCE.md,.agentic-assurance/,assurance/, the CI caller
workflow), with the honest single-maintainer caveat; adoption guide §3.5
documents the binding steps and names the documents-without-binding
failure mode.
Changed
- Adoption guide §4.1 and the review guide now recommend keeping the
invariant register at roughly 5–15 entries per repository.
Full changelog: CHANGELOG.md
v0.1.0
First stable release of the v0.1 line. Two completed pilot adoptions validated
the full cycle end to end: a private brownfield service (archaeology → human
intent review → recorded outcomes → scoped remediations → pin upgrade) and a
public repository adopted from a bare kick-off prompt, whose review surfaced
the tag-pin and prose-provenance rules included here.
Adopter impact / upgrade actions
- Upgrade from a
v0.1.0-rc.1orunreleasedpin in one reviewed change
(ADOPTION.md §2.1):upstream.version→v0.1.0,
upstream.commit→3ba48728f1d72a94655a6c74aa5b122cc55e0f64
(the commit this tag points to), and the CI caller workflow@reference
→ the same SHA. - From this release the
adopter-validateworkflow rejects a release pin
whose commit is not the tag commit. - The prose-provenance rule (PROFILE.md §7) is a SHOULD-level normative
addition to archaeology practice; existing artifacts need no changes. - Schemas are unchanged since
v0.1.0-rc.1.
Full changelog: CHANGELOG.md
v0.1.0-rc.1
First tagged release candidate of the v0.1 line, after one complete brownfield
pilot adoption (archaeology → §4.3 human review → recorded outcomes → scoped
remediations).
Adopter impact / upgrade actions
- Adopters pinned to
unreleasedcommits upgrade in one reviewed change
(ADOPTION.md §2.1):upstream.version→v0.1.0-rc.1,
upstream.commit→b18eeef92538a1fe7ad8e7ec883a84aa0a4742db, and the CI
caller workflow@reference → the same SHA. - All schema changes are backward-compatible additions.
- Pinning
version: unreleasedremains valid only for commits whoseVERSION
file readsunreleased(PROFILE.md §16).
Full changelog: CHANGELOG.md