yarramate 1.14.0 → 1.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/ARCHITECTURE-STATES.md +149 -0
- package/docs/EVIDENCE.md +429 -0
- package/docs/INTERROGATION.md +533 -0
- package/docs/NATIVE-DOCUMENT.md +582 -0
- package/docs/SEMANTIC-GRAPH.md +177 -0
- package/package.json +7 -2
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Architecture states
|
|
2
|
+
|
|
3
|
+
Architecture states are optional planning contexts for comparing a baseline,
|
|
4
|
+
one or more transitions, and a target without copying the native model or
|
|
5
|
+
overloading operational lifecycle.
|
|
6
|
+
|
|
7
|
+
## Authoring
|
|
8
|
+
|
|
9
|
+
A native document may declare states:
|
|
10
|
+
|
|
11
|
+
```yaml
|
|
12
|
+
states:
|
|
13
|
+
- id: baseline
|
|
14
|
+
kind: baseline
|
|
15
|
+
name: Current architecture
|
|
16
|
+
|
|
17
|
+
- id: migration
|
|
18
|
+
kind: transition
|
|
19
|
+
name: Migration plateau
|
|
20
|
+
after: baseline
|
|
21
|
+
|
|
22
|
+
- id: target
|
|
23
|
+
kind: target
|
|
24
|
+
name: Target architecture
|
|
25
|
+
after: migration
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`kind` is one of `baseline`, `transition`, or `target`. `after` is an optional
|
|
29
|
+
local or globally qualified architecture-state reference. Ordering must be
|
|
30
|
+
acyclic. Core does not require one state of each kind, require a linear plan,
|
|
31
|
+
or interpret ordering as approval or execution progress.
|
|
32
|
+
|
|
33
|
+
Concepts and relationships may declare where they are present:
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
concepts:
|
|
37
|
+
- id: shared-service
|
|
38
|
+
kind: applicationComponent
|
|
39
|
+
name: Shared service
|
|
40
|
+
|
|
41
|
+
- id: legacy-service
|
|
42
|
+
kind: applicationComponent
|
|
43
|
+
name: Legacy service
|
|
44
|
+
presentIn: [baseline, migration]
|
|
45
|
+
|
|
46
|
+
- id: modern-service
|
|
47
|
+
kind: applicationComponent
|
|
48
|
+
name: Modern service
|
|
49
|
+
presentIn: [migration, target]
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
An unscoped concept is present in every declared architecture state. An
|
|
53
|
+
unscoped relationship is present wherever both endpoint concepts are present.
|
|
54
|
+
An explicit relationship scope may narrow that inferred presence, but cannot
|
|
55
|
+
place the relationship in a state where either endpoint is absent. Authors
|
|
56
|
+
therefore annotate only subjects that vary.
|
|
57
|
+
|
|
58
|
+
Architecture states and lifecycle status are orthogonal. `planned`, `current`,
|
|
59
|
+
and `retired` remain operational lifecycle claims; baseline, transition, and
|
|
60
|
+
target are planning contexts.
|
|
61
|
+
|
|
62
|
+
## Graph v2 claims
|
|
63
|
+
|
|
64
|
+
Each state compiles as a globally qualified concept with Core `plateau` kind,
|
|
65
|
+
its authored name, `yarramate/state/type`, and optional
|
|
66
|
+
`yarramate/state/after` claim. `presentIn` entries compile to
|
|
67
|
+
`yarramate/state/present-in` reference claims.
|
|
68
|
+
|
|
69
|
+
Presence claim IDs encode the globally qualified state identity rather than a
|
|
70
|
+
file path or list position, so reordering authoring does not change identity.
|
|
71
|
+
The feature uses the existing graph-v2 subject and claim shape; it does not
|
|
72
|
+
introduce graph v3.
|
|
73
|
+
|
|
74
|
+
## Projection
|
|
75
|
+
|
|
76
|
+
The `states` projection selector accepts globally qualified state identities:
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
query:
|
|
80
|
+
states:
|
|
81
|
+
- roadmap#target
|
|
82
|
+
relationships: between
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
State selectors combine with other projection filters using logical AND.
|
|
86
|
+
Several state values combine with logical OR. State concepts themselves are
|
|
87
|
+
not included in a state-filtered result. Like other projection selectors, an
|
|
88
|
+
unavailable state is portable and produces no matches.
|
|
89
|
+
|
|
90
|
+
## Comparison
|
|
91
|
+
|
|
92
|
+
The typed `compareArchitectureStates(graph, from, to)` API and CLI classify
|
|
93
|
+
subjects as added, removed, or retained:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
yarramate ask .yarramate/workspace.yaml \
|
|
97
|
+
--compare roadmap#baseline roadmap#target
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Optional LikeC4 views
|
|
101
|
+
|
|
102
|
+
A normal state projection can be exported without any new native syntax:
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
yarramate-likec4 export-project \
|
|
106
|
+
.yarramate/projections/state-engine-target.yaml \
|
|
107
|
+
.yarramate/integrations/likec4/subject-mapping.yaml \
|
|
108
|
+
.yarramate-out/state-target \
|
|
109
|
+
--kinds .yarramate/integrations/likec4/kind-mapping.yaml \
|
|
110
|
+
.yarramate/workspace.yaml
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
For a comparison view, the projection selects the union of both states and the
|
|
114
|
+
adapter receives their ordered comparison:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
yarramate-likec4 export-project \
|
|
118
|
+
.yarramate/projections/state-engine-change.yaml \
|
|
119
|
+
.yarramate/integrations/likec4/subject-mapping.yaml \
|
|
120
|
+
.yarramate-out/state-change \
|
|
121
|
+
--compare yarramate-evolution#adapter-foundation \
|
|
122
|
+
yarramate-evolution#state-foundation \
|
|
123
|
+
--kinds .yarramate/integrations/likec4/kind-mapping.yaml \
|
|
124
|
+
.yarramate/workspace.yaml
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The adapter derives `yarramateChange` metadata and local concept styles from
|
|
128
|
+
Core's comparison result. Both states must appear in `query.states`; otherwise
|
|
129
|
+
the adapter reports `YMLC106`. An unknown compared state reports `YMLC105` at
|
|
130
|
+
its portable state selector. These are adapter correctness checks, not
|
|
131
|
+
architecture completeness or approval rules.
|
|
132
|
+
|
|
133
|
+
Colors and borders remain disposable LikeC4 presentation. Native documents,
|
|
134
|
+
graph v2, and the state-comparison result contain no renderer styling.
|
|
135
|
+
|
|
136
|
+
The comparison result conforms to
|
|
137
|
+
`schema/yarramate-state-comparison.schema.json` and uses format
|
|
138
|
+
`yarramate/state-comparison/v1`; `yarramate ask --compare --json` nests it
|
|
139
|
+
under a `comparison` key inside the `yarramate/ask-result/v1` envelope.
|
|
140
|
+
The result is a deterministic structural comparison, not an assessment,
|
|
141
|
+
migration plan, approval, or completeness claim.
|
|
142
|
+
|
|
143
|
+
## Deliberate boundary
|
|
144
|
+
|
|
145
|
+
This foundation does not allow names, kinds, owners, lifecycle values, or
|
|
146
|
+
other claim values to vary by state. Supporting state-scoped claims would
|
|
147
|
+
change claim interpretation and requires a separate graph-version decision.
|
|
148
|
+
It also does not implement a planning workflow, dates, work packages,
|
|
149
|
+
automatic transition derivation, or an external framework metamodel.
|
package/docs/EVIDENCE.md
ADDED
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
# Evidence overlays
|
|
2
|
+
|
|
3
|
+
Evidence overlays evaluate existing native architecture subjects and claims
|
|
4
|
+
without changing canonical documents or graph v2. Their normative structure is
|
|
5
|
+
`schema/yarramate-evidence.schema.json`.
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
format: yarramate/evidence/v1
|
|
9
|
+
id: repository-observation
|
|
10
|
+
version: "1.0"
|
|
11
|
+
provider: repository-audit
|
|
12
|
+
observations:
|
|
13
|
+
- subject: yarramate-engine#compiler
|
|
14
|
+
result: confirmed
|
|
15
|
+
evidence:
|
|
16
|
+
uri: repo:src/compiler.ts
|
|
17
|
+
- claim: yarramate-repository#compiler-source-realizes-compiler
|
|
18
|
+
result: contradicted
|
|
19
|
+
evidence:
|
|
20
|
+
uri: repo:src/compiler.ts
|
|
21
|
+
message: Expected implementation marker was not found
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Each observation targets exactly one globally qualified graph subject or
|
|
25
|
+
stable claim ID. It has one controlled result:
|
|
26
|
+
|
|
27
|
+
- `confirmed` — the provider observed evidence supporting the target;
|
|
28
|
+
- `contradicted` — the provider observed evidence conflicting with the target;
|
|
29
|
+
- `unknown` — the provider cannot determine a result;
|
|
30
|
+
- `not-observed` — the provider looked but found no relevant observation.
|
|
31
|
+
|
|
32
|
+
These results are facts reported by the named provider. A contradiction does
|
|
33
|
+
not by itself fail Core validation, and confirmation is not approval.
|
|
34
|
+
|
|
35
|
+
The `evidence.uri` value is opaque to YarraMate Core. Its provider owns URI
|
|
36
|
+
resolution and external validity. An optional non-empty message may explain
|
|
37
|
+
the observation; arbitrary provider metadata is not accepted. One syntactic
|
|
38
|
+
reading is the exception (ADR 0130): artifact coverage, below, compares
|
|
39
|
+
`repo:<path>` locators against a declared scope as strings — still without
|
|
40
|
+
resolving, opening, or validating anything a locator points at.
|
|
41
|
+
|
|
42
|
+
## Value observations
|
|
43
|
+
|
|
44
|
+
An observation may additionally report the value it read, by carrying an
|
|
45
|
+
observed `key` and `value` together (ADR 0075):
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
observations:
|
|
49
|
+
- subject: shop#customer-data
|
|
50
|
+
result: confirmed
|
|
51
|
+
key: region
|
|
52
|
+
value: us-east-1
|
|
53
|
+
evidence:
|
|
54
|
+
uri: repo:infra/main.tf#L12
|
|
55
|
+
message: aws_s3_bucket.customer_data region
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The two fields are required together: a key without a value, or a value
|
|
59
|
+
without a key, is rejected. The key is provider-owned naming with no
|
|
60
|
+
whitespace; the value is any non-empty string, compared verbatim.
|
|
61
|
+
|
|
62
|
+
`key` and `value` do not replace or reinterpret `result`. The result still
|
|
63
|
+
answers whether the target holds up at all, which is a presence or absence
|
|
64
|
+
judgment; the keyed value reports a fact that a declared expectation can be
|
|
65
|
+
compared against. A provider that reads several facts in one place may report
|
|
66
|
+
several keys at one target, and each key at a target at most once. Its
|
|
67
|
+
presence result is still stated once per target.
|
|
68
|
+
|
|
69
|
+
Providers own their key vocabulary. Core neither defines key names nor
|
|
70
|
+
resolves them: it only compares the reported value with the value a
|
|
71
|
+
constraint declared it expects.
|
|
72
|
+
|
|
73
|
+
## Evaluation
|
|
74
|
+
|
|
75
|
+
Generic evaluation checks:
|
|
76
|
+
|
|
77
|
+
- every subject target exists in graph v2;
|
|
78
|
+
- every claim target exists in graph v2;
|
|
79
|
+
- one evidence document evaluates a target at most once;
|
|
80
|
+
- versioned evidence document identities are unique in one workspace.
|
|
81
|
+
|
|
82
|
+
Successful evaluation produces deterministic
|
|
83
|
+
`yarramate/evidence-report/v1` JSON with counts and sorted observations. Its
|
|
84
|
+
normative structure is `schema/yarramate-evidence-report.schema.json`. The
|
|
85
|
+
input semantic graph is not modified.
|
|
86
|
+
|
|
87
|
+
No command emits the per-document report directly: it is a library-level
|
|
88
|
+
format. Workspace evidence declared in the manifest is evaluated by
|
|
89
|
+
`yarramate reconcile` — the aggregated reconciliation report below — and
|
|
90
|
+
gated by `yarramate check --strict`. Structural or reference correctness
|
|
91
|
+
failures emit `yarramate/diagnostic-result/v1` with exit status `1`; status
|
|
92
|
+
`2` means invocation or file access failed.
|
|
93
|
+
|
|
94
|
+
The typed API exposes `loadEvidence`, `evaluateEvidence`, and
|
|
95
|
+
`evaluateEvidenceWorkspace`. Evidence documents may be declared in the
|
|
96
|
+
optional `evidence` category of a workspace manifest, in which case
|
|
97
|
+
`yarramate check` validates them against the compiled graph.
|
|
98
|
+
|
|
99
|
+
`yarramate check --strict` additionally fails the check (exit `1`) when any
|
|
100
|
+
evidence observation is `contradicted`, rendering each contradiction as a
|
|
101
|
+
source-located `YM901` diagnostic anchored at the declared claim. A
|
|
102
|
+
contradicted expectation surfaces the same way, anchored at the authored
|
|
103
|
+
expected value, with no gate semantics of its own. `unknown`
|
|
104
|
+
and `not-observed` results stay advisory. A strict pass reports how many
|
|
105
|
+
observations it evaluated, so a gate over zero evidence is visible rather
|
|
106
|
+
than silently vacuous (ADR 0047).
|
|
107
|
+
|
|
108
|
+
## Reconciliation
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
yarramate reconcile .yarramate/workspace.yaml
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
This command evaluates every evidence overlay declared by the manifest and
|
|
115
|
+
emits deterministic `yarramate/reconciliation-report/v1` JSON. Its normative
|
|
116
|
+
schema is `schema/yarramate-reconciliation-report.schema.json`.
|
|
117
|
+
|
|
118
|
+
The summary counts all observations. The `findings` array contains only
|
|
119
|
+
`contradicted`, `unknown`, and `not-observed` results, ordered by target and
|
|
120
|
+
provider, plus the `stale-attestation` and `unconfirmed-attestation`
|
|
121
|
+
findings described below. Confirmed observations remain summarized rather
|
|
122
|
+
than repeated so a reviewer or agent can focus on unresolved evidence.
|
|
123
|
+
|
|
124
|
+
When a finding targets the primary claim of a declared relationship, it also
|
|
125
|
+
carries an optional `asserted` object with the declared `from`, `to`, and
|
|
126
|
+
`kind` (and `name` when present), so the disagreement between the model and
|
|
127
|
+
the evidence is visible in the finding itself:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"target": { "type": "claim", "id": "payments#payment-api-writes-ledger" },
|
|
132
|
+
"asserted": {
|
|
133
|
+
"from": "payments#payment-api",
|
|
134
|
+
"to": "payments#ledger",
|
|
135
|
+
"kind": "yarramate/core@0.1#access",
|
|
136
|
+
"name": "Records payments"
|
|
137
|
+
},
|
|
138
|
+
"result": "contradicted",
|
|
139
|
+
"provider": "repository-inspection",
|
|
140
|
+
"evidenceDocument": "payments-repository@1.0",
|
|
141
|
+
"evidence": {
|
|
142
|
+
"uri": "repo:src/payments.ts",
|
|
143
|
+
"message": "Payment API writes to the billing store, not the ledger"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Subject-targeted findings and findings on relationship sub-claims (such as
|
|
149
|
+
`…~name`) do not carry `asserted`.
|
|
150
|
+
|
|
151
|
+
### Declared expectations
|
|
152
|
+
|
|
153
|
+
When a constraint declares an expected observation
|
|
154
|
+
(`expects` in `docs/NATIVE-DOCUMENT.md`), reconciliation compares the declared
|
|
155
|
+
value with what the named provider observed. A declared expectation is matched
|
|
156
|
+
to observations by provider and key. The observation's own target anchors its
|
|
157
|
+
provenance but does not narrow the match, because a keyed value is a fact
|
|
158
|
+
about the project rather than about one subject, and several constraints may
|
|
159
|
+
legitimately expect the same fact.
|
|
160
|
+
|
|
161
|
+
A disagreement is an ordinary `contradicted` finding, rendered with both
|
|
162
|
+
sides: the declared expectation with the source location where it was
|
|
163
|
+
authored, and the observed value with its provider, evidence document, and
|
|
164
|
+
locator.
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"target": {
|
|
169
|
+
"type": "claim",
|
|
170
|
+
"id": "shop#customer-data~expects-residency"
|
|
171
|
+
},
|
|
172
|
+
"expectation": {
|
|
173
|
+
"provider": "terraform-scan",
|
|
174
|
+
"key": "region",
|
|
175
|
+
"expected": "ap-southeast-2",
|
|
176
|
+
"observed": "us-east-1",
|
|
177
|
+
"declared": {
|
|
178
|
+
"document": "shop",
|
|
179
|
+
"path": "architecture/shop.yaml",
|
|
180
|
+
"pointer": "/concepts/1/constraints/0/expects/value",
|
|
181
|
+
"line": 18,
|
|
182
|
+
"column": 18
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
"result": "contradicted",
|
|
186
|
+
"provider": "terraform-scan",
|
|
187
|
+
"evidenceDocument": "shop-terraform@1.0",
|
|
188
|
+
"evidence": {
|
|
189
|
+
"uri": "repo:infra/main.tf#L12",
|
|
190
|
+
"message": "aws_s3_bucket.customer_data region"
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
The summary counts `expectationsCompared`, the declared expectations a
|
|
196
|
+
matching observation reached, and `expectationsWithoutObservation`, those no
|
|
197
|
+
provider reported on. An expectation nobody observed is listed in a top-level
|
|
198
|
+
`unobservedExpectations` array, sorted by claim then key, and never converted
|
|
199
|
+
into a finding: no provider disagreed, so there is nothing to accuse, and the
|
|
200
|
+
same discipline applies as for unobserved subjects (ADR 0049). An unobserved
|
|
201
|
+
expectation is therefore reported honestly rather than passing as satisfied,
|
|
202
|
+
and it does not fail `check --strict`.
|
|
203
|
+
|
|
204
|
+
The summary also counts `current` concepts that appear in no observation at
|
|
205
|
+
all — neither targeted directly, nor through a claim they own, nor as an
|
|
206
|
+
endpoint of an observed relationship claim — as `subjectsWithoutEvidence`.
|
|
207
|
+
When the count is positive the report lists them in a top-level
|
|
208
|
+
`unobservedSubjects` array, sorted lexicographically. This is not a finding:
|
|
209
|
+
no provider looked and disagreed; reconciliation simply has no opinion, and
|
|
210
|
+
the report says so instead of letting the gap pass as verified.
|
|
211
|
+
|
|
212
|
+
A finding is advisory evidence, not a proposed replacement claim, validation
|
|
213
|
+
error, CI verdict, or authorization to modify the native model.
|
|
214
|
+
|
|
215
|
+
## Artifact coverage
|
|
216
|
+
|
|
217
|
+
Unobserved subjects answer only half of the coverage question: they report
|
|
218
|
+
declared intent no observation supports, and nothing reported code the model
|
|
219
|
+
never mentions at all (#175, ADR 0130). A workspace manifest may therefore
|
|
220
|
+
declare a `coverage` list of glob patterns naming the artifacts the model
|
|
221
|
+
intends to cover:
|
|
222
|
+
|
|
223
|
+
```yaml
|
|
224
|
+
coverage:
|
|
225
|
+
- src/**/*.ts
|
|
226
|
+
- schema/*.json
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
`reconcile` — only `reconcile` — resolves the patterns against the root of
|
|
230
|
+
the git repository the manifest lives in. An artifact is any selected file
|
|
231
|
+
git can see there: tracked, or untracked and not ignored. An observation
|
|
232
|
+
claims an artifact when its locator is `repo:<path>`, with any `#fragment`
|
|
233
|
+
stripped; a locator naming a directory claims everything beneath it; a
|
|
234
|
+
locator in any other scheme claims nothing. The summary counts
|
|
235
|
+
`artifactsInScope` and `unclaimedArtifacts` exactly when coverage was
|
|
236
|
+
assessed, and a positive count lists the paths in a top-level
|
|
237
|
+
`unclaimedArtifacts` array, sorted, beside a `coverageScope` echo of the
|
|
238
|
+
declared patterns.
|
|
239
|
+
|
|
240
|
+
When coverage was not assessed — no scope declared, or no git repository —
|
|
241
|
+
the report says why in `notes` rather than staying silent, and a declared
|
|
242
|
+
pattern that selects no artifact gets a note naming it: a dead glob is
|
|
243
|
+
indistinguishable from a typo. An unclaimed artifact is absence, never
|
|
244
|
+
accusation: no finding is fabricated, and `check --strict` does not read
|
|
245
|
+
the list — the same line unobserved subjects and unobserved expectations
|
|
246
|
+
hold.
|
|
247
|
+
|
|
248
|
+
## Stale attestations
|
|
249
|
+
|
|
250
|
+
An attestation records that an accountable human accepted a subject *as
|
|
251
|
+
stated on a date*. `reconcile` reports when that sign-off no longer covers
|
|
252
|
+
the current wording (ADR 0074). Using git, it compares the attestation's
|
|
253
|
+
`on` date against the commits that touched the attested subject's `name`
|
|
254
|
+
and `description` spans; if the wording changed later, it emits a
|
|
255
|
+
`stale-attestation` finding:
|
|
256
|
+
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"target": { "type": "subject", "id": "policy#refund-rule" },
|
|
260
|
+
"result": "stale-attestation",
|
|
261
|
+
"attestation": {
|
|
262
|
+
"topic": "signed-off",
|
|
263
|
+
"by": "policy#compliance-lead",
|
|
264
|
+
"on": "2026-01-15"
|
|
265
|
+
},
|
|
266
|
+
"provider": "git",
|
|
267
|
+
"changedAt": "2026-06-01T12:00:00+00:00",
|
|
268
|
+
"evidence": {
|
|
269
|
+
"uri": "git:9f2c1ab…",
|
|
270
|
+
"message": "Attestation \"signed-off\" by policy#compliance-lead on 2026-01-15 predates the current wording of policy#refund-rule: the description changed in commit 9f2c1ab on 2026-06-01T12:00:00+00:00."
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
This finding kind has no `evidenceDocument`: no provider authored it, so
|
|
276
|
+
its provider is `git`. When the change is only in the working tree the
|
|
277
|
+
locator is `git:worktree` and `changedAt` is absent.
|
|
278
|
+
|
|
279
|
+
The comparison rule is exact. A sign-off dated `on` covers every commit up
|
|
280
|
+
to and including the end of that calendar day in UTC; a change counts as
|
|
281
|
+
later only when its committer timestamp is at or past midnight UTC of the
|
|
282
|
+
following day. Only the `name` and `description` spans are compared in v1,
|
|
283
|
+
so marking a subject `current` or adding a reference does not reopen a
|
|
284
|
+
sign-off.
|
|
285
|
+
|
|
286
|
+
When git cannot answer honestly the report says so instead of guessing.
|
|
287
|
+
Outside a git repository, on a shallow clone, against an untracked
|
|
288
|
+
document, or when the sign-off predates the file's earliest commit, no
|
|
289
|
+
staleness finding is emitted and a note is added to a top-level `notes`
|
|
290
|
+
array:
|
|
291
|
+
|
|
292
|
+
```json
|
|
293
|
+
"notes": [
|
|
294
|
+
"Attestation staleness was not assessed: the workspace is not inside a git repository."
|
|
295
|
+
]
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
The `summary.staleAttestations` counter is present exactly when staleness
|
|
299
|
+
was assessed, so a report that never looked is distinguishable from one
|
|
300
|
+
that looked and found nothing. `check --strict` is unaffected: staleness
|
|
301
|
+
is a freshness signal about a human process, not a contradiction between
|
|
302
|
+
the model and observed reality, so it reports rather than gates.
|
|
303
|
+
|
|
304
|
+
## Unconfirmed attestations
|
|
305
|
+
|
|
306
|
+
`by` names the authority a judgment belongs to, resolved against the
|
|
307
|
+
model as a subject reference; `recordedBy` names whoever actually
|
|
308
|
+
wrote the record, when that is not the authority's own hand (ADR
|
|
309
|
+
0082). `reconcile` reports when the two disagree — a recorder is
|
|
310
|
+
present and names someone other than the authority itself — as an
|
|
311
|
+
`unconfirmed-attestation` finding:
|
|
312
|
+
|
|
313
|
+
```json
|
|
314
|
+
{
|
|
315
|
+
"target": { "type": "subject", "id": "policy#refund-rule" },
|
|
316
|
+
"result": "unconfirmed-attestation",
|
|
317
|
+
"attestation": {
|
|
318
|
+
"topic": "signed-off",
|
|
319
|
+
"by": "policy#compliance-lead",
|
|
320
|
+
"recordedBy": "yarramate-apply-agent",
|
|
321
|
+
"on": "2026-01-15"
|
|
322
|
+
},
|
|
323
|
+
"provider": "model",
|
|
324
|
+
"declared": {
|
|
325
|
+
"document": "policy",
|
|
326
|
+
"path": "architecture/policy.yaml",
|
|
327
|
+
"pointer": "/concepts/1/attestations/0/topic",
|
|
328
|
+
"line": 24,
|
|
329
|
+
"column": 16
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
This finding kind has no `evidenceDocument` and involves no git
|
|
335
|
+
lookup: its provider is `model`, because the disagreement is legible
|
|
336
|
+
from the attestation claim alone. `declared` locates the authored
|
|
337
|
+
attestation entry — the same source location the claim carries, its
|
|
338
|
+
`topic` line — rather than an external observation. A recorder that names
|
|
339
|
+
the authority itself — by its qualified id or its document-local
|
|
340
|
+
form — is a self-recorded sign-off and produces no finding.
|
|
341
|
+
|
|
342
|
+
The `summary.unconfirmedAttestations` counter is present whenever a
|
|
343
|
+
graph was compiled, so a report that found nothing unconfirmed is
|
|
344
|
+
distinguishable from one that never had a graph to check against.
|
|
345
|
+
`check --strict` is unaffected: an unconfirmed recorder is a fact
|
|
346
|
+
about who wrote a record, not a contradiction between the model and
|
|
347
|
+
observed reality, so it reports rather than gates.
|
|
348
|
+
|
|
349
|
+
## Writing overlays
|
|
350
|
+
|
|
351
|
+
An overlay is a workspace document, so `yarramate apply` writes it the way
|
|
352
|
+
it writes a model document: `add-observation`, `update-observation`, and
|
|
353
|
+
`delete-observation` address an evidence document declared by the manifest's
|
|
354
|
+
`evidence` list (ADR 0089). Before this the only way to record what a
|
|
355
|
+
provider read was to open the file, which is exactly the hand-editing the
|
|
356
|
+
apply loop exists to prevent — a reviewer who adds a concept through the
|
|
357
|
+
visual canvas or a batch has no path to the evidence for it.
|
|
358
|
+
|
|
359
|
+
```yaml
|
|
360
|
+
format: yarramate/operations/v1
|
|
361
|
+
operations:
|
|
362
|
+
- op: add-observation
|
|
363
|
+
document: .yarramate/evidence/repository.yaml
|
|
364
|
+
observation:
|
|
365
|
+
subject: yarramate-engine#compiler
|
|
366
|
+
result: confirmed
|
|
367
|
+
evidence:
|
|
368
|
+
uri: repo:src/compiler.ts
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
An observation is addressed by the pair (target, key) rather than by an
|
|
372
|
+
`id`, because an overlay entry has none: `reconcile` already treats that
|
|
373
|
+
pair as unique per document (ADR 0075, `YM803`). The target is the
|
|
374
|
+
observation's `subject` or `claim`; a keyless observation is the presence
|
|
375
|
+
claim for its target, so an absent `key` is itself an address rather than a
|
|
376
|
+
wildcard. `update-observation` names the entry the same way and changes
|
|
377
|
+
whatever else it carries — `result`, `value`, `evidence.uri`,
|
|
378
|
+
`evidence.message` — scalars replacing in place. Retraction is explicit and
|
|
379
|
+
narrow: `remove: [message]` is the only retraction an observation admits,
|
|
380
|
+
because `message` is the only optional field it holds, and setting and
|
|
381
|
+
removing it in one operation is rejected rather than ordered.
|
|
382
|
+
`delete-observation` removes the whole entry.
|
|
383
|
+
|
|
384
|
+
The gate is the one every batch passes. The candidate workspace compiles,
|
|
385
|
+
then every touched overlay is loaded and evaluated against the compiled
|
|
386
|
+
graph, before a single byte is written: an observation whose subject the
|
|
387
|
+
graph does not carry rejects the batch with `YM801` and leaves every source
|
|
388
|
+
unchanged. `yarramate/apply-result/v1` counts the work as
|
|
389
|
+
`addedObservations`, `updatedObservations`, and `deletedObservations`
|
|
390
|
+
alongside the concept and relationship counts.
|
|
391
|
+
|
|
392
|
+
## Boundary
|
|
393
|
+
|
|
394
|
+
Evidence overlays do not:
|
|
395
|
+
|
|
396
|
+
- introduce independent observed claims;
|
|
397
|
+
- mutate graph v2 or native documents;
|
|
398
|
+
- define completeness or CI failure policy;
|
|
399
|
+
- grant approval or governance status;
|
|
400
|
+
- require Graphify or another provider;
|
|
401
|
+
- interpret provider-specific URIs.
|
|
402
|
+
|
|
403
|
+
A later opt-in policy layer may decide how a report affects CI. Independent
|
|
404
|
+
observed claims would require a separate semantic contract rather than an
|
|
405
|
+
unstructured extension of this format.
|
|
406
|
+
|
|
407
|
+
Constraint satisfaction uses this same boundary. A provider may target a
|
|
408
|
+
stable claim such as
|
|
409
|
+
`yarramate-engine#compiler~constraint-tool-neutral`; its result is a
|
|
410
|
+
constraint assessment, not Core conformance. Core does not execute policy
|
|
411
|
+
rules, interpret missing observations, manage exceptions, or convert a result
|
|
412
|
+
into CI failure.
|
|
413
|
+
|
|
414
|
+
A declared expectation does not change that boundary. Comparing two strings is
|
|
415
|
+
not a rule engine: Core still holds no policy language, no waivers, no
|
|
416
|
+
exceptions, and no opinion about which value is correct. It reports that the
|
|
417
|
+
model and a provider disagree, and leaves the judgment to a reviewer.
|
|
418
|
+
|
|
419
|
+
Diagnostics use `YM801` for an unknown subject, `YM802` for an unknown claim,
|
|
420
|
+
`YM803` for a duplicate target, and `YM804` for a duplicate evidence document.
|
|
421
|
+
The schemas are exported as `yarramate/schema/evidence` and
|
|
422
|
+
`yarramate/schema/evidence-report`. The reconciliation schema is exported as
|
|
423
|
+
`yarramate/schema/reconciliation-report`.
|
|
424
|
+
|
|
425
|
+
Evidence locators also answer the inverse question. `ask --where`
|
|
426
|
+
(ADR 0068) reads the same observations as verified code locations for
|
|
427
|
+
matched subjects — so every observation authored for reconciliation
|
|
428
|
+
doubles as a pointer, and every subject a `--where` answer lists as
|
|
429
|
+
unobserved is a nudge toward the missing observation.
|