Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ repository still gets a decision, never by following the link; no release carrie
- :memo: docs(changelog): regenerate CHANGELOG.md for the EX-S05 lane
- :memo: docs(openspec): correct test attribution in the REQ-EX-S05-05 amendment
- :memo: docs(changelog): regenerate CHANGELOG.md after rebase onto origin/main
- :memo: docs(planning): mark REF-EX C1-C8 landed; archetype-goldens manifest v2
- :memo: docs(changelog): regenerate CHANGELOG.md for the EX-S07 lane
- :memo: docs(examples): state C5's measured zero incremental --coverage credit
- :memo: docs(examples): note infra-vars has no fileEvents rule at all (C8)
- :memo: docs(openspec): amend REQ-EX-S07-03/04 to match the measured implementation
- :memo: docs(changelog): regenerate CHANGELOG.md for the EX-S07 lane follow-ups
- :memo: docs(changelog): regenerate CHANGELOG.md for the EX-S07 lane

### Features
- :sparkles: feat(docs): gate example pack and format claims against dogfood
Expand All @@ -125,6 +132,8 @@ repository still gets a decision, never by following the link; no release carrie
- :sparkles: feat(examples): thicken infra-vars nested tfvars maps (EX-S04)
- :sparkles: feat(examples): close REF-EX C1-C4 in topic-registry/service-catalog
- :sparkles: feat(examples): EX-S05 HCL honesty — govern .tf, pin the measured opaque decision
- :sparkles: feat(examples): close REF-EX C6 placement allow-list (infra-vars)
- :sparkles: feat(examples): close REF-EX C7 referenced-resource-ownership (gap demo)

### Fixes
- :bug: fix(ci): pin ci-audit-test in the AUD-S18 check-stage list
Expand All @@ -140,6 +149,8 @@ repository still gets a decision, never by following the link; no release carrie
- :white_check_mark: test(release): key the merge-skip proof on commit shape, not subject prefix
- :white_check_mark: test(examples): close REQ-EX-S05-05 non-vacuity gap for infra-vars .tf governance
- :white_check_mark: test(examples): close REQ-EX-S05-05's other disjunct (fixture deletion)
- :white_check_mark: test(examples): close REF-EX C5 quota-ceiling-from-fact explicitly
- :white_check_mark: test(examples): pin REF-EX C8 companion-file delete as REVIEW (known limitation)
## [0.2.0] - 2026-08-09

### Chores
Expand Down
8 changes: 7 additions & 1 deletion docs/planning/archetype-goldens.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Archetype golden corpus — `assent test` seed manifest

**Manifest version:** `1`
**Manifest version:** `2`
**Owned by:** P3-E3-S04
**Corpus root:** [`examples/archetypes/`](https://github.com/PlatformRelay/assent/tree/main/examples/archetypes)
**Inventory:** [`archetypes.md`](archetypes.md)
Expand Down Expand Up @@ -32,6 +32,12 @@ quadruple (or a `negative/` / case-subdir variant of that shape). `decision` is
| `examples/archetypes/no-destruction/delete/` | `BLOCK` | File delete; never author-thread authorization. |
| `examples/archetypes/no-destruction/rename/` | `REVIEW` | Rename ≥ delete strictness; `require-review`. |
| `examples/archetypes/no-destruction/near-similarity/` | `BLOCK` | Near-similarity must not downgrade below delete. |
| `examples/archetypes/quota-ceiling/` | `APPROVE` | REF-EX C5 — in-band partition bump against a stubbed quota fact; empty findings. |
| `examples/archetypes/quota-ceiling/negative/` | `REVIEW` | Over-quota → `challenge` / `bounded-change.out-of-band` (same mechanism as `bounded-change/negative`, named for C5 discoverability). |
| `examples/archetypes/placement-allow-list/` | `APPROVE` | REF-EX C6 — `instance_set` change onto an allow-listed value (stubbed `facts.placement.allowed.value`); empty findings. |
| `examples/archetypes/placement-allow-list/negative/` | `REVIEW` | `instance_set` off the allow-list → `require-review` / `placement.disallowed-instance-set`. |
| `examples/archetypes/referenced-resource-ownership/` | `APPROVE` | REF-EX C7 (gap demo, judgment call (b)) — `acl.resource` names a resource the stubbed `facts.resource_owner.owner.value` confirms the author's group owns; empty findings. |
| `examples/archetypes/referenced-resource-ownership/negative/` | `REVIEW` | Resolved owner does not match the author's groups → `require-review` / `acl.resource-ownership-mismatch`. |

**Index (not a golden quadruple):** `examples/archetypes/no-destruction/expected.yaml`
lists the three case directories above and reaffirms `onFailure.effect: require-review`
Expand Down
9 changes: 9 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ to the HCL parser, so a `.tf` file's content, blocks or bare literals alike, is
opaque and falls back to REVIEW, never a partial parse (ADR-0003) — see the
`infra-vars` pack's `tf-opaque` case. Only `.tfvars` gets structured diffing today.

**Known limitation (REF-EX C8, REF-GAP-3):** deleting a file the pack's class does not
match (e.g. a companion `envs/prod/NOTES.md` alongside `infra-vars`' `*.tfvars`) is caught
only by the class-agnostic unmatched-whole-file-DELETE fail-safe (D-063/D-064,
`internal/core/aggregate/coverage.go`), which raises the decision to REVIEW with no
obligation attached — see the `infra-vars` pack's `vars/companion-delete` case (a
**measured**, not wished, decision). This is not cross-file correlation: v1 does not know
"delete A and append B" are related, and would REVIEW an unrelated companion delete the
same way. Out of v1 engine scope.

The authored surfaces here are the **frozen** `assent.dev/v1alpha1` schemas under
`schemas/`, not drafts; the compatibility promises attached to them are in
[`API_STABILITY.md`](../API_STABILITY.md).
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# REF-EX C6 (placement allow-list) — a value change is bounded by an allow-list
# FACT the diff itself cannot see (an in-repo placement/capacity registry,
# stubbed here; see builtin/repo-file, REF-GAP-2). Governed entry: one workload
# per file.
name: orders-api
owner: orders-team
instance_set: standard-4
min_replicas: 3
max_replicas: 12
4 changes: 4 additions & 0 deletions examples/archetypes/placement-allow-list/expected.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# instance_set standard-4 -> standard-8, both on the stubbed allow-list.
# Satisfied prove -> no finding.
decision: APPROVE
findings: []
5 changes: 5 additions & 0 deletions examples/archetypes/placement-allow-list/facts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
author:
login: alice
groups: [orders-team]
placement:
allowed: [standard-2, standard-4, standard-8]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: orders-api
owner: orders-team
instance_set: standard-8
min_replicas: 3
max_replicas: 12
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: orders-api
owner: orders-team
instance_set: standard-4
min_replicas: 3
max_replicas: 12
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# instance_set standard-4 -> gpu-16, not on the stubbed allow-list.
decision: REVIEW
findings:
- rule: instance-set-allow-list
obligation: placement
effect: require-review
subject: infra-vars:orders-api
points: 0
code: placement.disallowed-instance-set
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
author:
login: alice
groups: [orders-team]
placement:
allowed: [standard-2, standard-4, standard-8]
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name: orders-api
owner: orders-team
instance_set: gpu-16
min_replicas: 3
max_replicas: 12
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# REF-EX C5 (quota-ceiling-from-fact) — a value change is bounded by a FACT the
# diff itself cannot see (an in-repo quota registry, stubbed here; see
# builtin/repo-file, REF-GAP-2). Governed entry: one topic per file.
name: analytics.clicks.v1
owner: analytics-team
partitions: 10
replication_factor: 3
retention_hours: 72
cleanup_policy: delete
schema:
format: avro
subject: analytics.clicks.v1-value
description: >
Clickstream events for the analytics domain.
3 changes: 3 additions & 0 deletions examples/archetypes/quota-ceiling/expected.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# partitions 10 -> 18 (<= stubbed quota 20). Satisfied prove -> no finding.
decision: APPROVE
findings: []
5 changes: 5 additions & 0 deletions examples/archetypes/quota-ceiling/facts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
author:
login: alice
groups: [analytics-team]
quota:
max_partitions: 20
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: analytics.clicks.v1
owner: analytics-team
partitions: 18
replication_factor: 3
retention_hours: 72
cleanup_policy: delete
schema:
format: avro
subject: analytics.clicks.v1-value
description: >
Clickstream events for the analytics domain.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: analytics.clicks.v1
owner: analytics-team
partitions: 10
replication_factor: 3
retention_hours: 72
cleanup_policy: delete
schema:
format: avro
subject: analytics.clicks.v1-value
description: >
Clickstream events for the analytics domain.
9 changes: 9 additions & 0 deletions examples/archetypes/quota-ceiling/negative/expected.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# partitions 10 -> 34 exceeds the stubbed quota ceiling (20).
decision: REVIEW
findings:
- rule: partition-change-bounds
obligation: bounded-change
effect: challenge
subject: topic-registry:analytics.clicks.v1
points: 1
code: bounded-change.out-of-band
5 changes: 5 additions & 0 deletions examples/archetypes/quota-ceiling/negative/facts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
author:
login: alice
groups: [analytics-team]
quota:
max_partitions: 20
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: analytics.clicks.v1
owner: analytics-team
partitions: 34
replication_factor: 3
retention_hours: 72
cleanup_policy: delete
schema:
format: avro
subject: analytics.clicks.v1-value
description: >
Clickstream events for the analytics domain.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# REF-EX C7 (referenced-resource-ownership, judgment call (b)) — a GAP demo, not
# a new builtin: an ACL entry naming another team's resource cannot be
# authorized from the diff alone. facts.resource_owner.owner stubs the shipped
# builtin/resource-owner shape (REF-GAP-1) as the ground truth. Vacuous when the
# entry carries no acl.resource (this base has acl.grants but no acl.resource
# yet; head adds resource/owner as LEAF keys under the same existing acl
# mapping — adding acl as a whole new subtree would go opaque, E1-S05).
name: connectors.status.v1
owner: connectors-team
partitions: 6
replication_factor: 3
retention_hours: 168
cleanup_policy: delete
schema:
format: avro
subject: connectors.status.v1-value
description: >
Connector health/status events.
acl:
grants:
connectors-team: read
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# acl.resource ADD names platform.connector-pool; the resolved fact
# (platform-team) IS in facts.author.groups.value. Satisfied prove -> no finding.
decision: APPROVE
findings: []
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
author:
login: alice
groups: [connectors-team, platform-team]
resource_owner:
owner: platform-team
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: connectors.status.v1
owner: connectors-team
partitions: 6
replication_factor: 3
retention_hours: 168
cleanup_policy: delete
schema:
format: avro
subject: connectors.status.v1-value
description: >
Connector health/status events.
acl:
grants:
connectors-team: read
resource: platform.connector-pool
owner: platform-team
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: connectors.status.v1
owner: connectors-team
partitions: 6
replication_factor: 3
retention_hours: 168
cleanup_policy: delete
schema:
format: avro
subject: connectors.status.v1-value
description: >
Connector health/status events.
acl:
grants:
connectors-team: read
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# acl.resource ADD names billing.ledger-pool; the resolved fact (finance-team)
# is NOT in facts.author.groups.value -> require-review.
decision: REVIEW
findings:
- rule: referenced-resource-ownership
obligation: resource-ownership
effect: require-review
subject: topic-registry:connectors.status.v1
points: 0
code: acl.resource-ownership-mismatch
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
author:
login: alice
groups: [connectors-team, platform-team]
# The resolved fact (finance-team) does NOT match the head's self-declared
# acl.owner (billing-team) either — the predicate never reads entry.acl.owner,
# only the resolved fact, precisely because a self-declared claim cannot be
# trusted (that is the gap C7 demonstrates).
resource_owner:
owner: finance-team
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: connectors.status.v1
owner: connectors-team
partitions: 6
replication_factor: 3
retention_hours: 168
cleanup_policy: delete
schema:
format: avro
subject: connectors.status.v1-value
description: >
Connector health/status events.
acl:
grants:
connectors-team: read
resource: billing.ledger-pool
owner: billing-team
4 changes: 2 additions & 2 deletions examples/packs/infra-vars/.assent/bindings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ bindings:
environment: dev
packs: [vars]
risk: { threshold: 10 }
require: [ownership, bounded-change]
require: [ownership, bounded-change, placement]
- class: infra-vars
environment: prod
packs: [vars]
risk: { threshold: 4 }
require: [ownership, bounded-change]
require: [ownership, bounded-change, placement]
21 changes: 21 additions & 0 deletions examples/packs/infra-vars/.assent/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,27 @@ classes:
# the HCL producer (so a literal-only Terraform config file could structurally
# diff, matching tfvars) is future engine work, not yet built.
match: { paths: ["envs/**/*.tfvars", "envs/**/*.tf"] }
# KNOWN LIMITATION (REF-EX C8, REF-GAP-3, out of v1 engine scope): this class
# matches only *.tfvars and *.tf. A COMPANION file outside that match — e.g.
# envs/prod/NOTES.md — is unclassified (ADR-0008 §1), and its deletion is
# caught only by the class-agnostic D-063/D-064 unmatched-whole-file-DELETE
# fail-safe (internal/core/aggregate/coverage.go), which raises the decision
# to REVIEW with no obligation/rule attached (see vars/companion-delete in
# .assent/tests/vars/cases.yaml — a MEASURED, not wished, REVIEW). This is
# NOT cross-file correlation: the engine has no notion that NOTES.md is
# "related" to compute.tfvars, and would REVIEW an unrelated companion
# delete identically. v1 does not correlate "delete A and append B" across
# files — that remains REF-GAP-3, likely out of v1 scope.
#
# A GOVERNED *.tfvars delete is REVIEW too, by the SAME class-agnostic
# escalation, not a distinct file-lifecycle rule: this pack (unlike
# topic-registry/service-catalog) declares no fileEvents rule at all
# (`.assent/packs/vars/rules/*.yaml` has none), so `fileDeleteGoverned`
# (internal/core/aggregate/coverage.go) finds nothing governing ANY delete,
# governed path or not — read directly from that function rather than run,
# since `assent test` cannot express a whole-file delete of a `.tfvars`
# fixture either way (inline cases.yaml refuses non-lossless `.tfvars`
# marshal; the directory form requires the file present on both sides).
providers:
author:
type: builtin/gitlab-groups
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Placement allow-list (REF-EX C6) — instance_set (a keyed workload scalar, EX-S04)
# must stay on a fact-sourced allow-list. facts.placement.allowed.value is a stub
# for a real placement/capacity registry (REF-GAP-2 shape, builtin/repo-file):
# an in-repo-state fact no live provider is called for under `assent test`
# (ADR-0014). Pointer-scoped to /workloads/*/instance_set so this rule is vacuous
# (no match at all) on every existing S01/S04 case, none of which touch
# instance_set — the shipped goldens stay green untouched.
apiVersion: assent.dev/v1alpha1
kind: MergePolicy
metadata:
name: vars-placement-allow-list
spec:
entries:
infra-vars:
mode: map
root: /workloads
rules:
- name: instance-set-allow-list
phase: enforce
match:
valueChanges:
pointers: ["/workloads/*/instance_set"]
kinds: [modify]
prove:
obligation: placement
when: 'new in facts.placement.allowed.value'
onFailure:
effect: require-review
code: placement.disallowed-instance-set
Loading