Skip to content

✨ feat(examples): EX-S07 REF-EX C5-C8 facts stubs - #64

Merged
konih merged 11 commits into
mainfrom
lane/ex-s07
Aug 16, 2026
Merged

✨ feat(examples): EX-S07 REF-EX C5-C8 facts stubs#64
konih merged 11 commits into
mainfrom
lane/ex-s07

Conversation

@konih

@konih konih commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes REF-EX C5–C8 with stubbed facts, no live provider calls (openspec/specs/p5-ex-complex-examples/spec.md EX-S07).

  • C5 (quota-ceiling, topic-registry): the existing bounded-change rule already covered facts.quota.max_partitions; adds a discoverable named case plus a facts-omitted edge case pinning the E2 fail-safe (unresolved fact → REVIEW, never APPROVE). The named case earns zero incremental --coverage credit (verified empirically) but the fail-safe pin is genuinely load-bearing.
  • C6 (placement allow-list, infra-vars): new instance-set-allow-list rule, pointer-scoped to /workloads/*/instance_set, both polarities genuinely covered.
  • C7 (referenced-resource-ownership, topic-registry): new rule extending the EXISTING acl shape from EX-S06's wildcard-grant (additive acl.resource/acl.owner leaf keys, not a new acl object — avoids opaque-diff and avoids flipping S06's goldens). Pointer-scoped vacuity guard, not the spec's literal !has(entry.acl), because S06's fixtures already populate entry.acl without acl.resource.
  • C8 (companion-file delete, infra-vars): inline cases.yaml case (directory form can't express deletes — verified against the harness source), measured (not assumed) REVIEW via the class-agnostic D-063/D-064 unmatched-file-delete escalation; corrects the spec's own Edge clause since infra-vars declares no fileEvents rule.

Every load-bearing claim across all four patterns was independently reproduced by the reviewer against the real engine, not just read from the implementer's report.

Also amends REQ-EX-S07-03/04 in the spec to match the measured implementation.

Test plan

  • task check — fully green, including changelog-verify
  • task coverage — 91.1% (required 91%)
  • ./bin/assent test --coverage examples/packs/topic-registry — 9/9 rules, both polarities covered
  • ./bin/assent test --coverage examples/packs/infra-vars — 6/6 rules, both polarities covered
  • go test ./cmd/assent/ -run TestAssentTestNeverCallsProviderHost — passes
  • Independent review: APPROVE on first round (two non-blocking P3 notes, logged as follow-ups)

konih added 11 commits August 16, 2026 12:55
The pack already wires facts.quota.max_partitions into bounded-change.yaml's
partition-change-bounds rule (D-071 deferral note). This gives the
quota-ceiling-from-fact pattern its own discoverable, both-polarity test
directory plus a facts-omitted edge case (an unresolved quota fact must fail
safe to REVIEW, never APPROVE — mirrors internal/adoptertest's own hermetic
unresolved-fact testdata) and an examples/archetypes/quota-ceiling/ seed.
New instance-set-allow-list rule (obligation `placement`) checks the S04
`instance_set` workload field against a stubbed facts.placement.allowed.value
list. Pointer-scoped to /workloads/*/instance_set so every existing S01/S04
goldens stay vacuous (untouched). Added to bindings.yaml require: (vacuously
satisfied on all pre-existing cases). Both polarities pass and earn genuine
--coverage credit; examples/archetypes/placement-allow-list/ seeds the pattern.
…demo)

New referenced-resource-ownership rule (obligation `resource-ownership`) checks
a stubbed facts.resource_owner.owner.value (builtin/resource-owner shape,
REF-GAP-1) against facts.author.groups.value whenever a topic's acl.resource
names another team's resource. Pointer-scoped to /*/acl/resource so the rule
is vacuous on every topic that never declares it — including S06's
wildcard-grant goldens, which already populate acl.grants without
acl.resource; a bare `!has(entry.acl)` guard (the spec's own shorthand) would
NOT have been vacuous there, so pointer-scoping is used instead (documented in
the rule file). Not a new builtin: facts.resource_owner.owner.value is a
fixture literal, never resolved from the referenced resource's own file.
acl.owner is carried alongside acl.resource as the entry's self-declared,
untrusted claim — the predicate reads only the resolved fact. Both polarities
pass and earn genuine --coverage credit; examples/archetypes/
referenced-resource-ownership/ seeds the pattern.
…n limitation)

envs/prod/NOTES.md is outside infra-vars' class match (*.tfvars/*.tf); its
deletion in head is caught only by the class-agnostic D-063/D-064 unmatched
whole-file-DELETE fail-safe escalation, never a class-specific rule. Ran
against the real engine before pinning: decision is a MEASURED REVIEW with the
synthetic aggregate.unmatchedDelete finding, no obligation attached. Documented
as a known limitation (not a feature) in the pack's config.yaml and
examples/README.md — v1 does not correlate "delete A and append B" across
files (REF-GAP-3, out of v1 engine scope). No second class added.
…t v2

backlog.md's REF-EX row and REF-GAP-1..3 rows now point at the landed EX-S07
fixtures instead of the future-tense "not started". archetype-goldens.md
bumps to manifest version 2 with the three new C5-C7 archetype rows
(quota-ceiling, placement-allow-list, referenced-resource-ownership).
Verified by temporarily moving quota-ceiling/ out of the tree and re-running
--coverage: deleting it does not redden the gate, because bounded-change/ and
bounded-change/negative/ already supply partition-change-bounds' both-polarity
credit. Documented so a reader does not assume the directory is load-bearing
for --coverage; facts-omitted/ remains load-bearing for the engine's fail-safe
behaviour (dogfood-examples would catch a regression there).
A governed *.tfvars delete hits the SAME class-agnostic D-063/D-064
unmatched-whole-file-DELETE escalation as the ungoverned companion, not a
distinct file-lifecycle rule — this pack (unlike topic-registry/
service-catalog) declares no fileEvents rule in any of its rule files. Stated
as a direct reading of fileDeleteGoverned rather than a measured case: assent
test cannot express a whole-file delete of a .tfvars fixture either way
(inline cases.yaml refuses a non-lossless .tfvars marshal; the directory form
requires the file on both sides).
…entation

REQ-EX-S07-03's Test: path said referenced-ownership/; the directory is
resource-ownership/ because assent lint's tests-per-rule hard error requires
the case name to be one of {rule.Name, obligation}. REQ-EX-S07-04's Test: path
implied a directory-form companion-delete/ case; it is an inline cases.yaml
case because the directory form cannot express a whole-file delete
(readSingleFilePair errors when head/<file> is absent). Also corrects the
REQ-EX-S07-04 Edge clause: infra-vars has no fileEvents rule at all, so a
governed *.tfvars delete hits the same class-agnostic escalation as the
ungoverned companion, not a distinct rule. Mirrors the REQ-EX-S05-05
amendment precedent (b08be34) — spec-first still means the spec must track
what was actually measured, not what was assumed before implementation.
@konih
konih merged commit b40f74a into main Aug 16, 2026
8 checks passed
@konih
konih deleted the lane/ex-s07 branch August 16, 2026 11:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant