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
4 changes: 2 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ No functional implementation is authorized in Phase 0.

## Phase 1A: contract decision

- [ ] Decide compatibility of `subactor/twin` `Observation` and `EvidenceRef`
- [x] Decide compatibility of `subactor/twin` `Observation` and `EvidenceRef`
for `data2dsl` in [`ticket-002`](project/ticket-002/README.md).
- [ ] Publish the pinned evidence and consequences as a decision document.
- [x] Publish the pinned evidence and consequences as a decision document.

No implementation or changes to external repositories are authorized by this
ticket.
Expand Down
195 changes: 195 additions & 0 deletions docs/decisions/ADR-001-twin-observation-evidence-compatibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# ADR-001: Twin `Observation` and `EvidenceRef` compatibility

- **Status:** Accepted for planning
- **Date:** 2026-08-17
- **Decision owner:** `data2dsl` ticket-002
- **Inspected repository:** `subactor/twin`
- **Pinned revision:** `a3a8b759dc87bc4398f86bf8df25a16f1309314e`

## Decision question

Can `data2dsl` reuse the current `subactor/twin` `Observation` and
`EvidenceRef` contracts as its neutral input and evidence boundary without
copying them, depending on the Twin runtime, or inventing incompatible
semantics?

## Verdict

EXTEND

The existing messages are the preferred lineage and a strong foundation, but
they are not sufficient as-is for deterministic, language-neutral data
comparison. `data2dsl` must not fork or silently reinterpret them. A later,
separately authorized contract ticket must define an additive, versioned and
effect-free extension or profile before comparator implementation begins.

This decision does not authorize a change to `subactor/twin`, a dependency on
its runtime, a final DSL, an adapter, or product implementation.

## Evidence baseline

All evidence below was inspected from one clean checkout at the pinned
revision. Git blob identifiers make each artifact independently verifiable.

| Evidence class | Artifact | Git blob |
| --- | --- | --- |
| Protobuf contract | `proto/twin/v1/twin.proto` | `03cd991fd42c9e57bc587dcac403b466b60e5e6e` |
| Normative standard | `spec/TWIN_STANDARD.md` | `78e87890c6b4937840930aa059b079402095b192` |
| Reference profile | `profiles/generic-twin.json` | `167e6560660d53a56aa47ecb9ef1014941c97ffe` |
| Validator/generator | `src/twin_standard.py` | `dbc3919bbe47be0fe4b4dae2ac67898b8571e97e` |
| Tests | `tests/test_twin_standard.py` | `a6cbec3febc8ee3c1938764b0a958ce3ad5ad877` |
| Package metadata | `pyproject.toml` | `1df981ce8f924da1cdca17a3201cf2125c255211` |
| Maturity statement | `README.md` | `f759b2af7eb34c9f25163e9e4bd5577d41b028bb` |
| Version marker | `VERSION` | `0d4d1249434dba8d7fcb8949a2e361f70308cc48` |

The package is currently `0.1.0.dev0` / `0.1.0-dev`, and its README says the
initial contract is under review. This is evidence of contract maturity, not a
reason to discard the lineage.

## Implemented contract

### Protobuf

`EvidenceRef` contains `evidence_id`, `aggregate_id`, `target_uri`,
`media_type`, and `digest_sha256` as bytes.

`Observation` contains `observation_id`, `aggregate_id`, `target_uri`,
`metric`, `ObservationStatus status`, `google.protobuf.Any value`,
`observed_at` and `expires_at` timestamps, and repeated `EvidenceRef evidence`.

`ObservationStatus` distinguishes `OBSERVED`, `UNEVALUABLE` and `EXPIRED`.
Publishing is exposed as `PublishObservationCommand` and an RPC that emits
`ObservationPublished`; that command path is part of the state-changing Twin
model, not a neutral library boundary for `data2dsl`.

### Standard and profile

Section 2.3 of the standard requires observations to join to an aggregate and
target URI, carry observed time and expiry, and carry evidence with the same
join keys. Missing or unavailable measurements are `UNEVALUABLE` and must not
be treated as healthy. Reporting evidence is explicitly separate from an
enforcing decision.

The reference profile reinforces this with `evidenceRequired: true`, join
keys `aggregate_id` and `target_uri`, `unevaluableState: UNEVALUABLE`, and
`UNEVALUABLE` excluded from healthy states. Those invariants align with
reuse-first provenance and with the required separation between source
observation state and comparison result.

### Validator and tests

The validator checks that protobuf messages and enum members exist, but its
required field sets are intentionally structural:

- `EvidenceRef`: `evidence_id`, `aggregate_id`, `target_uri`;
- `Observation`: `observation_id`, `aggregate_id`, `target_uri`, `status`,
`evidence`.

It does not structurally require `metric`, `value`, time fields, `media_type`
or `digest_sha256`, and it does not validate message instances. Tests cover
profile invariants, the required protobuf surface, `UNEVALUABLE`, generation
and transport declarations. They do not define cross-language `Any`
canonicalization or scalar/set equality for a data comparator.

At the pinned revision, this command was run on Windows:

```text
PYTHONPATH=src python -m pytest -q -p no:cacheprovider
```

Result: `73 passed, 7 subtests passed, 1 failed`. The only failure is
`test_generation_emits_only_declared_contract_files`: expected POSIX
`proto/twin/v1/twin.proto` but discovered the Windows representation
`proto\\twin\\v1\\twin.proto`. It is unrelated to the semantics under this
decision, but prevents claiming a completely green external checkout.

## Field-level fit

### `Observation`

| Field | Fit for `data2dsl` | Consequence |
| --- | --- | --- |
| `observation_id` | Reusable identity slot; uniqueness/canonical form is unspecified here. | Preserve it; an extension must state identity rules if used for reproducibility. |
| `aggregate_id` | Useful join key but coupled to a Twin aggregate. | Accept when supplied; do not require a live Twin aggregate or runtime. |
| `target_uri` | Strong subject join key under the profile. | Reuse it, while defining URI canonicalization and the supported subject vocabulary. |
| `metric` | Useful label, but no versioned vocabulary, unit or dimensions. | Extend with metric identity, unit and dimensions. |
| `status` | Correctly models source availability. | Preserve it; never overload it with comparison outcomes such as equal/different. |
| `value` | `Any` is extensible but underspecified for neutral comparison. | Define an allowlisted typed scalar/set model, type URLs and canonical equality. |
| `observed_at` | Useful provenance time. | Preserve it as source observation time. |
| `expires_at` | Useful freshness boundary. | Preserve it, but add an explicit query/window model where needed. |
| `evidence` | Correct provenance attachment point. | Reuse the relationship and strengthen evidence reproducibility below. |

### `EvidenceRef`

| Field | Fit for `data2dsl` | Consequence |
| --- | --- | --- |
| `evidence_id` | Useful stable reference, but resolution semantics are absent. | Preserve it and define how an authorized consumer resolves it. |
| `aggregate_id` | Supports the normative join, but inherits Twin coupling. | Keep as a join key without requiring runtime access. |
| `target_uri` | Strong subject join key, not an evidence locator. | Preserve it; do not pretend it locates the source bytes. |
| `media_type` | Correct content descriptor, weakly enforced by the validator. | Require and validate it in the extension/profile. |
| `digest_sha256` | Correct immutable content check, but length/presence are weakly enforced. | Require a 32-byte digest and verify it before evidence is accepted. |

For reproducible data acquisition, the current message lacks a normative
source locator/revision, normalized query parameters, extractor identity and
version, and optional record/span/pagination coordinates. Those additions
must not expose secrets; credentials remain outside the serialized contract.

## Required extension boundary

A future contract proposal must provide all of the following before the
`data2dsl` comparator can depend on it:

1. An effect-free observation/evidence profile or additive messages usable
without Twin commands, events, authority checks or storage.
2. Deterministic typed values for the initial scalar and set cases, including
allowed `Any` type URLs, ProtoJSON form, nullability, numeric precision,
ordering and equality rules.
3. Versioned subject and metric identities, units, dimensions and an explicit
observation/query window where a single timestamp is insufficient.
4. A resolvable evidence descriptor with immutable source revision, normalized
query/extraction metadata, content type and verified digest.
5. Instance validation and cross-language fixtures proving that equivalent
values serialize and compare identically.
6. A stable released contract revision before it becomes a required external
dependency.

Comparison outcomes must remain separate from `ObservationStatus`. For
example, `MATCH`, `MISMATCH` or comparison `UNEVALUABLE` belong to a result
contract whose inputs point back to the source observations and evidence.

## Why not `REUSE AS-IS`

The schema proves structural presence, not the value semantics required by a
deterministic comparator. Reusing it without an extension would force
`data2dsl` to invent private meanings for `Any`, metrics, units, sets and
evidence resolution. That would violate the reuse-first rule while appearing
to comply with it.

## Why not `REJECT`

The identity, target, time, availability and evidence concepts already match
the intended architecture. The standard also makes the critical distinction
between unavailable data, health and enforcement. Rejection would duplicate
good contract lineage and create unnecessary translation work.

## Consequences for `data2dsl`

- Treat the capability-map candidate as `EXTEND`, not as implemented or
reusable as-is. Updating that map requires its own authorized ticket.
- Do not add a runtime dependency on `subactor/twin` and do not copy or fork
these protobuf messages.
- Block comparator implementation on deterministic typed-value and
subject/metric/window semantics.
- Preserve `aggregate_id` and `target_uri` joins when present, without
assuming that a Twin service is running.
- Preserve content digests and the separation between source status,
comparison outcome and enforcing action.
- Any proposal to change `subactor/twin`, `wellmanifest/dsl` or another
repository requires a separate ticket and explicit authority.

## Revisit triggers

Re-evaluate this decision when `subactor/twin` publishes a stable revision
that adds the required neutral value/evidence semantics, or when a different
existing Wellmanifest contract demonstrably supplies them without creating a
second competing model.
22 changes: 15 additions & 7 deletions project/ticket-002/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
- **ID**: ticket-002
- **Owner**: unresolved:human
- **Status**: IN_PROGRESS
- **Workflow state**: EDIT
- **Workflow state**: VALIDATION
- **Created**: 2026-08-13

## Goal and scope
Expand All @@ -20,15 +20,23 @@ changes, and external coordination.

## Acceptance criteria

- [ ] AC-01: The decision pins the inspected `subactor/twin` revision.
- [ ] AC-02: Evidence covers protobuf, normative contract, validator code,
- [x] AC-01: The decision pins the inspected `subactor/twin` revision.
- [x] AC-02: Evidence covers protobuf, normative contract, validator code,
reference profile and relevant tests.
- [ ] AC-03: Field-level fit and gaps for both `Observation` and `EvidenceRef`
- [x] AC-03: Field-level fit and gaps for both `Observation` and `EvidenceRef`
are explicit.
- [ ] AC-04: Exactly one verdict among `REUSE AS-IS`, `EXTEND`, and `REJECT` is
- [x] AC-04: Exactly one verdict among `REUSE AS-IS`, `EXTEND`, and `REJECT` is
selected with rationale.
- [ ] AC-05: Consequences and prohibited assumptions for `data2dsl` are stated.
- [ ] AC-06: No other repository is modified and the governance gate passes.
- [x] AC-05: Consequences and prohibited assumptions for `data2dsl` are stated.
- [x] AC-06: No other repository is modified and the governance gate passes.

## Result

The accepted decision is
[`ADR-001`](../../docs/decisions/ADR-001-twin-observation-evidence-compatibility.md):
**EXTEND**. The Twin messages remain the preferred lineage, but deterministic
typed values and reproducible evidence resolution require a separately
authorized, additive contract extension before implementation.

## Participants

Expand Down
34 changes: 34 additions & 0 deletions project/ticket-002/ai-codex-logs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
2026-08-17 compatibility decision evidence log

Pinned source:
- repository: subactor/twin
- revision: a3a8b759dc87bc4398f86bf8df25a16f1309314e
- worktree: clean before and after inspection

Evidence blobs:
- proto/twin/v1/twin.proto: 03cd991fd42c9e57bc587dcac403b466b60e5e6e
- spec/TWIN_STANDARD.md: 78e87890c6b4937840930aa059b079402095b192
- profiles/generic-twin.json: 167e6560660d53a56aa47ecb9ef1014941c97ffe
- src/twin_standard.py: dbc3919bbe47be0fe4b4dae2ac67898b8571e97e
- tests/test_twin_standard.py: a6cbec3febc8ee3c1938764b0a958ce3ad5ad877
- pyproject.toml: 1df981ce8f924da1cdca17a3201cf2125c255211
- README.md: f759b2af7eb34c9f25163e9e4bd5577d41b028bb
- VERSION: 0d4d1249434dba8d7fcb8949a2e361f70308cc48

External validation:
- command: PYTHONPATH=src python -m pytest -q -p no:cacheprovider
- result: 73 passed, 7 subtests passed, 1 failed
- failure: Windows path separator mismatch in
test_generation_emits_only_declared_contract_files
- relevance: unrelated to Observation/EvidenceRef semantics; recorded in ADR

Decision:
- verdict: EXTEND
- no external repository was modified
- no runtime dependency or product implementation was added

Local validation:
- ADR evidence-class search: passed
- exact verdict search: passed (`## Verdict` followed by `EXTEND`)
- git diff --check: passed
- project/governance-check.bat --actor agent: GOV-PASS, 0 errors, 0 warnings
9 changes: 8 additions & 1 deletion project/ticket-002/ai-codex.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,14 @@ from the stronger semantics actually enforced by the validator and tests.

- Initialized the bounded ticket and recorded SESSION_EXECUTION_AUTHORIZATION
from the request to execute this work.
- No product or external-repository changes are authorized.
- Pinned the clean `subactor/twin` checkout at
`a3a8b759dc87bc4398f86bf8df25a16f1309314e`.
- Inspected and recorded immutable evidence for the protobuf contract,
normative standard, generic profile, validator, tests and maturity markers.
- Published `ADR-001` with the single verdict `EXTEND`, field-by-field gaps,
the required additive boundary and explicit prohibitions for `data2dsl`.
- Ran the external Twin test suite and the local governance gate. No product
code, dependency or external repository was modified.

## Blockers

Expand Down
7 changes: 7 additions & 0 deletions project/ticket-002/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,10 @@
- Initial governance scaffold created.
- No human participant identity or content was generated.
- Recorded the bounded compatibility-decision scope and explicit non-goals.

## [0.2.0] - 2026-08-17

- Pinned current `subactor/twin` evidence at `a3a8b759`.
- Accepted ADR-001 with the unambiguous compatibility verdict `EXTEND`.
- Documented field-level fit, required additions, test evidence and prohibited
assumptions without changing another repository or implementing behavior.
2 changes: 1 addition & 1 deletion project/ticket-002/intent.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"origin": "health"
},
"delivery": {
"acceptedBaseSha": "201708c82da161bf1f514da015ec95b2964b8347",
"acceptedBaseSha": "ef910bcddd3ef491ac631bda7453d4ae7cf65309",
"targetBranch": "main",
"outcome": "Publish one pinned, evidence-backed compatibility decision for subactor/twin Observation and EvidenceRef.",
"nonGoals": [
Expand Down
7 changes: 5 additions & 2 deletions project/ticket-003/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

- **ID**: ticket-003
- **Owner**: unresolved:human
- **Status**: IN_PROGRESS
- **Workflow state**: EDIT
- **Status**: DONE
- **Workflow state**: DONE
- **Created**: 2026-08-13

## Goal and scope
Expand Down Expand Up @@ -33,6 +33,9 @@ The root README is now the canonical onboarding description of the planned
product. It distinguishes intended behavior from unimplemented contracts and
links detailed capability evidence rather than duplicating it.

The result is integrated on the default branch at
`ef910bcddd3ef491ac631bda7453d4ae7cf65309`.

## Participants

- Human participant: unresolved; no user-* file was created by this script.
Expand Down
5 changes: 5 additions & 0 deletions project/ticket-003/ai-codex-logs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ Final validation:
- git diff --check passed;
- GOV-PASS: 0 errors, 0 warnings;
- subactor/twin, wellmanifest/dsl and semcod/todo2code clean.

Closure evidence:
- integrated default branch head: ef910bcddd3ef491ac631bda7453d4ae7cf65309
- GitHub PR 1 state: MERGED
- closure changes are governance-only
2 changes: 2 additions & 0 deletions project/ticket-003/ai-codex.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ behavior without presenting unimplemented contracts as available features.
roadmap, current state and governance.
- Marked conceptual examples and the composition graph as non-final so the
README does not overstate implementation maturity.
- Verified the result is integrated on the default branch and closed the
completed ticket through a governance-only update.

## Blockers

Expand Down
1 change: 1 addition & 0 deletions project/ticket-003/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
- Recorded the bounded README and contributor-onboarding scope.
- Expanded the root README into the canonical product overview without adding
implementation or changing existing technical evidence.
- Closed the completed ticket from the integrated default branch.