iterate-kernel 0.1.0-draft.1 → 0.1.2
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/README.md +62 -0
- package/fixtures/decision-log-chain.ok-01.json +13 -0
- package/fixtures/decision-log-entry.ok-01.json +9 -0
- package/fixtures/dimension-context.ok-01.json +50 -0
- package/fixtures/evidence-pack.ok-01.json +69 -0
- package/fixtures/evidence-pack.ok-02.json +34 -0
- package/fixtures/evidence-pack.ok-03.json +69 -0
- package/fixtures/evidence-pack.ok-04-legacy-draft.json +59 -0
- package/fixtures/evidence-pack.ok-05-pixelbounds-null.json +53 -0
- package/fixtures/recipe-config.ok-01.json +37 -0
- package/fixtures/report.ok-01.html +33 -0
- package/fixtures/report.ok-01.md +30 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -35,14 +35,76 @@ APIs it actually uses.
|
|
|
35
35
|
| `evidence-pack` / `parse` | the evidence pack shape, and parsing/validating one |
|
|
36
36
|
| `evidence-decision` | the **transcription**: evidence (attribution level, circuit-breaker level, pass/fail/inconclusive) → a decision outcome and a human summary. It reads fields the engine already decided; it never infers. |
|
|
37
37
|
| `decision-log-entry` / `decision-log` | the append-only decision-log entry and the `opID ↔ entry` hash chain that makes it auditable |
|
|
38
|
+
| `dimension-context` / `parse` | the dimension-coverage transcription: a plan plus what the engine actually recorded → verified / unverified / unplanned, and one line to put in a summary. It validates id *shape*, never which ids exist — that list belongs to whoever configured the run. |
|
|
38
39
|
| `errors` / `schemas` / `canonical-json` / `recipe-config` | `KernelSchemaError`, the JSON Schemas, canonical serialisation, recipe validation |
|
|
39
40
|
|
|
41
|
+
## A runnable example
|
|
42
|
+
|
|
43
|
+
This is the whole surface in one file, and it is the shape the API actually wants. Two details
|
|
44
|
+
cost real time to discover, so they are written out here rather than left to the error messages:
|
|
45
|
+
|
|
46
|
+
- **the ledger path is a first argument, not a field.** There is no default location, on purpose:
|
|
47
|
+
a durable audit chain should not be created wherever a process happened to start.
|
|
48
|
+
- **`entryId` and `createdAt` are yours to supply** (`sequence` and `prevEntryHash` are derived
|
|
49
|
+
from the ledger and must *not* be sent). `newDecisionEntryId()` mints one in the required
|
|
50
|
+
`dl_<26 Crockford>` form.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { decisionOutcomeFromEvidence, decisionSummaryFromEvidence } from "iterate-kernel/evidence-decision"
|
|
54
|
+
import { appendDecisionLogEntry, newDecisionEntryId } from "iterate-kernel/decision-log"
|
|
55
|
+
import { parseEvidencePack, parseDimensionContextInput } from "iterate-kernel/parse"
|
|
56
|
+
import { dimensionContext, formatDimensionContext } from "iterate-kernel/dimension-context"
|
|
57
|
+
import { resolve } from "node:path"
|
|
58
|
+
|
|
59
|
+
const pack = parseEvidencePack(await readFile("evidence.json", "utf8").then(JSON.parse))
|
|
60
|
+
const outcome = decisionOutcomeFromEvidence(pack)
|
|
61
|
+
|
|
62
|
+
// the transcription — never an inference; it reads what the engine already decided
|
|
63
|
+
console.log(outcome, decisionSummaryFromEvidence(pack))
|
|
64
|
+
|
|
65
|
+
// the audit chain — refuses to append onto a tail it cannot re-hash
|
|
66
|
+
appendDecisionLogEntry(resolve("ledger.jsonl"), {
|
|
67
|
+
entryId: newDecisionEntryId(),
|
|
68
|
+
createdAt: new Date().toISOString(),
|
|
69
|
+
operationId: pack.operationId,
|
|
70
|
+
outcome,
|
|
71
|
+
summary: decisionSummaryFromEvidence(pack),
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// dimension coverage — `recorded` is what the engine logged, not what you hoped it would
|
|
75
|
+
const input = parseDimensionContextInput({
|
|
76
|
+
planned: [{ id: "correctness" }, { id: "security" }, { id: "ui-ux" }],
|
|
77
|
+
recorded: { security: { decisions: 3, operationIds: [pack.operationId] } },
|
|
78
|
+
})
|
|
79
|
+
// -> "1/3 dimensions verified, 2 unverified (correctness, ui-ux), 3 decisions"
|
|
80
|
+
console.log(formatDimensionContext(dimensionContext(input)))
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`parseDimensionContextInput` returns the *validated input*; `dimensionContext` computes the
|
|
84
|
+
context; `formatDimensionContext` renders the line. Anything recorded but never planned shows up
|
|
85
|
+
as `unplanned` — a reporter that quietly dropped it would be the failure this exists to prevent.
|
|
86
|
+
|
|
40
87
|
## Versioning
|
|
41
88
|
|
|
42
89
|
`0.1.x` is pre-stable. The schemas and the transcription rules are the contract every
|
|
43
90
|
consumer depends on, so a change to either is a minor-version change at minimum, and the
|
|
44
91
|
fixtures in `fixtures/` are the executable statement of what the contract means.
|
|
45
92
|
|
|
93
|
+
## The fixtures are the portable half of the contract
|
|
94
|
+
|
|
95
|
+
`schemas/` and `fixtures/` ship in the tarball — `test/packaging.test.mjs` packs locally and
|
|
96
|
+
refuses a corpus that did not make it into the artifact. Each fixture states its own rules in
|
|
97
|
+
its `comment`, written so a second implementation can be coded from the file without reading the
|
|
98
|
+
TypeScript. That is the only way this contract reaches the consumers that cannot import it:
|
|
99
|
+
`iterate-harness` is Python and `glasspaned` is Swift.
|
|
100
|
+
|
|
101
|
+
Those consumers do not read this package at runtime. They vendor a copy of the corpus pinned by
|
|
102
|
+
sha256 — `iterate-harness/tests/kernel_fixtures/`, checked by its `scripts/check_kernel_fixtures.py`
|
|
103
|
+
(`--source kernel/fixtures` inside the monorepo, registry mode in the split repo). Moving a fixture
|
|
104
|
+
therefore means re-recording that pin in the same change, and the check fails in whichever
|
|
105
|
+
direction the bytes disagree. A cross-implementation comparison that can be skipped silently is
|
|
106
|
+
not a contract; it is a note nobody reads.
|
|
107
|
+
|
|
46
108
|
## Consumers
|
|
47
109
|
|
|
48
110
|
Vendored or installed, a consumer's kernel is one of two things, and the difference is a
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"comment": "Cross-implementation anchor for the decision log chain (kernel/src/decision-log.ts). A line's bytes ARE canonicalJson(entry) — keys sorted by UTF-16 code unit, no insignificant whitespace — so prevEntryHash of line i+1 equals sha256_hex of line i, and genesis carries an empty prevEntryHash. Any language that can sort keys and sha256 can verify this file; the kernel test recomputes the hashes with an external tool (shasum/openssl), so a TypeScript-only chain cannot pass silently.",
|
|
3
|
+
"lines": [
|
|
4
|
+
"{\"createdAt\":\"2026-09-25T04:00:00.000Z\",\"entryId\":\"dl_01K2ABCDEFGHJKMNPQRSTVWXZ0\",\"outcome\":\"pass\",\"prevEntryHash\":\"\",\"sequence\":0,\"summary\":\"attach Finder; window matched the attached pid\"}",
|
|
5
|
+
"{\"createdAt\":\"2026-09-25T04:00:01.000Z\",\"entryId\":\"dl_01K2ABCDEFGHJKMNPQRSTVWXZ1\",\"operationId\":\"op_01K2ABCDEFGHJKMNPQRSTVWXZ9\",\"outcome\":\"fail\",\"prevEntryHash\":\"f7c3b4198c27ad0e5947efd2d50dedced3e02f0171411fbf6c67f07e22d13d4d\",\"sequence\":1,\"summary\":\"act set-value refused: element not focusable\"}",
|
|
6
|
+
"{\"createdAt\":\"2026-09-25T04:00:02.000Z\",\"entryId\":\"dl_01K2ABCDEFGHJKMNPQRSTVWXZ2\",\"outcome\":\"inconclusive\",\"prevEntryHash\":\"db250a8182952a7ceb4240bcfcc48f639d452514e6ee9e8401111a57127f69c3\",\"sequence\":2,\"summary\":\"observe timed out while the app was modal\"}"
|
|
7
|
+
],
|
|
8
|
+
"hashes": [
|
|
9
|
+
"f7c3b4198c27ad0e5947efd2d50dedced3e02f0171411fbf6c67f07e22d13d4d",
|
|
10
|
+
"db250a8182952a7ceb4240bcfcc48f639d452514e6ee9e8401111a57127f69c3",
|
|
11
|
+
"7b89c488c39f680343eec27cee805092140a43ef50e15f25a81133c1f154076b"
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"entryId": "dl_0123456789ABCDEFGHJKMNPQRS",
|
|
3
|
+
"sequence": 0,
|
|
4
|
+
"prevEntryHash": "",
|
|
5
|
+
"operationId": "op_0123456789ABCDEFGHJKMNPQRS",
|
|
6
|
+
"summary": "act press on button 'Submit' (op_0123456789ABCDEFGHJKMNPQRS): actConfirmed=true, axChanged=true, assertion enabled=true passed",
|
|
7
|
+
"outcome": "pass",
|
|
8
|
+
"createdAt": "2026-09-14T12:34:56.789Z"
|
|
9
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"comment": "Cross-implementation anchor for dimensionContext (kernel/src/dimension-context.ts). The rules a second implementation must reproduce, written so it can be coded from this file without reading the TypeScript: (1) planned entries keep the caller's order; status is `verified` iff recorded[id].decisions >= 1, else `unverified`, and an absent id is the same as a recorded zero — `{decisions: 0}`. (2) A recorded id absent from the plan becomes one `unplanned` entry, sorted by id ascending in UTF-16 code unit order. (3) totals.decisions sums planned and unplanned alike, each decision counted once; verified + unverified === planned always. (4) A duplicate planned id throws KERNEL_E_DIMENSION_DUPLICATE rather than collapsing. The ids here are the nine the iterate config owns (config/config.schema.json $defs.dimension.enum); the kernel validates their *shape* and never enumerates them, which is why this fixture may name them without the kernel knowing they exist.",
|
|
3
|
+
"input": {
|
|
4
|
+
"planned": [
|
|
5
|
+
{ "id": "correctness", "label": "正确性", "focus": "Crash risks, logic errors, concurrency." },
|
|
6
|
+
{ "id": "security" },
|
|
7
|
+
{ "id": "performance" },
|
|
8
|
+
{ "id": "architecture" },
|
|
9
|
+
{ "id": "style-tests" },
|
|
10
|
+
{ "id": "tech-debt" },
|
|
11
|
+
{ "id": "spec-compliance" },
|
|
12
|
+
{ "id": "frontend-backend" },
|
|
13
|
+
{ "id": "ui-ux", "label": "UI/UX" }
|
|
14
|
+
],
|
|
15
|
+
"recorded": {
|
|
16
|
+
"correctness": { "decisions": 6, "operationIds": ["op_01K2ABCDEFGHJKMNPQRSTVWXZ9"] },
|
|
17
|
+
"security": { "decisions": 3 },
|
|
18
|
+
"performance": { "decisions": 0 },
|
|
19
|
+
"architecture": { "decisions": 2 },
|
|
20
|
+
"style-tests": { "decisions": 1 },
|
|
21
|
+
"tech-debt": { "decisions": 1 },
|
|
22
|
+
"spec-compliance": { "decisions": 0 },
|
|
23
|
+
"frontend-backend": { "decisions": 4 },
|
|
24
|
+
"ui-ux": { "decisions": 1 },
|
|
25
|
+
"concurrency": { "decisions": 2 }
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"expected": {
|
|
29
|
+
"planned": [
|
|
30
|
+
{
|
|
31
|
+
"id": "correctness",
|
|
32
|
+
"status": "verified",
|
|
33
|
+
"label": "正确性",
|
|
34
|
+
"focus": "Crash risks, logic errors, concurrency.",
|
|
35
|
+
"evidence": { "decisions": 6, "operationIds": ["op_01K2ABCDEFGHJKMNPQRSTVWXZ9"] }
|
|
36
|
+
},
|
|
37
|
+
{ "id": "security", "status": "verified", "evidence": { "decisions": 3 } },
|
|
38
|
+
{ "id": "performance", "status": "unverified", "evidence": { "decisions": 0 } },
|
|
39
|
+
{ "id": "architecture", "status": "verified", "evidence": { "decisions": 2 } },
|
|
40
|
+
{ "id": "style-tests", "status": "verified", "evidence": { "decisions": 1 } },
|
|
41
|
+
{ "id": "tech-debt", "status": "verified", "evidence": { "decisions": 1 } },
|
|
42
|
+
{ "id": "spec-compliance", "status": "unverified", "evidence": { "decisions": 0 } },
|
|
43
|
+
{ "id": "frontend-backend", "status": "verified", "evidence": { "decisions": 4 } },
|
|
44
|
+
{ "id": "ui-ux", "status": "verified", "label": "UI/UX", "evidence": { "decisions": 1 } }
|
|
45
|
+
],
|
|
46
|
+
"unplanned": [{ "id": "concurrency", "status": "unplanned", "evidence": { "decisions": 2 } }],
|
|
47
|
+
"totals": { "planned": 9, "verified": 7, "unverified": 2, "unplanned": 1, "decisions": 20 }
|
|
48
|
+
},
|
|
49
|
+
"expectedLine": "7/9 dimensions verified, 2 unverified (performance, spec-compliance), 1 unplanned (concurrency), 20 decisions"
|
|
50
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "glasspane.evidence/0.1",
|
|
3
|
+
"operationId": "op_0123456789ABCDEFGHJKMNPQRS",
|
|
4
|
+
"createdAt": "2026-09-14T12:34:56.789Z",
|
|
5
|
+
"attribution": {
|
|
6
|
+
"level": "soft",
|
|
7
|
+
"contaminated": false
|
|
8
|
+
},
|
|
9
|
+
"circuitBreaker": {
|
|
10
|
+
"level": 0
|
|
11
|
+
},
|
|
12
|
+
"signals": {
|
|
13
|
+
"act": {
|
|
14
|
+
"selector": {
|
|
15
|
+
"role": "button",
|
|
16
|
+
"title": "Submit"
|
|
17
|
+
},
|
|
18
|
+
"action": "press",
|
|
19
|
+
"actConfirmed": true
|
|
20
|
+
},
|
|
21
|
+
"axEvent": {
|
|
22
|
+
"treeDigestBefore": "00112233445566778899aabbccddeeff",
|
|
23
|
+
"treeDigestAfter": "ffeeddccbbaa99887766554433221100",
|
|
24
|
+
"nodeCount": 128,
|
|
25
|
+
"axChanged": true,
|
|
26
|
+
"latencyMs": 42
|
|
27
|
+
},
|
|
28
|
+
"handlerProbe": null,
|
|
29
|
+
"stateDiff": null,
|
|
30
|
+
"pixelDiff": {
|
|
31
|
+
"changedPixelRatio": 0.023,
|
|
32
|
+
"bounds": {
|
|
33
|
+
"x": 100,
|
|
34
|
+
"y": 200,
|
|
35
|
+
"width": 80,
|
|
36
|
+
"height": 28
|
|
37
|
+
},
|
|
38
|
+
"windowId": 12
|
|
39
|
+
},
|
|
40
|
+
"responsiveness": {
|
|
41
|
+
"responsive": true,
|
|
42
|
+
"pingMs": 3
|
|
43
|
+
},
|
|
44
|
+
"crash": {
|
|
45
|
+
"processAliveBefore": true,
|
|
46
|
+
"processAliveAfter": true
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"assertion": {
|
|
50
|
+
"kind": "element_property",
|
|
51
|
+
"selector": {
|
|
52
|
+
"role": "button",
|
|
53
|
+
"title": "Submit"
|
|
54
|
+
},
|
|
55
|
+
"property": "enabled",
|
|
56
|
+
"expected": true,
|
|
57
|
+
"actual": true,
|
|
58
|
+
"passed": true
|
|
59
|
+
},
|
|
60
|
+
"diagnosis": {
|
|
61
|
+
"class": "NO_ANOMALY",
|
|
62
|
+
"report": {
|
|
63
|
+
"path": "act.press -> ax-confirm -> tree-digest -> pixel-diff",
|
|
64
|
+
"anomaly": "none: operation confirmed, AX tree changed, pixels changed",
|
|
65
|
+
"evidence": "op_0123456789ABCDEFGHJKMNPQRS soft attribution; axChanged=true (digest 00112233445566778899aabbccddeeff -> ffeeddccbbaa99887766554433221100); changedPixelRatio=0.023; pingMs=3",
|
|
66
|
+
"next": "no action required; assertion passed"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "glasspane.evidence/0.1",
|
|
3
|
+
"operationId": "op_112233445566778899AABBCCDD",
|
|
4
|
+
"createdAt": "2026-09-14T12:35:00.001Z",
|
|
5
|
+
"attribution": {
|
|
6
|
+
"level": "soft",
|
|
7
|
+
"contaminated": false
|
|
8
|
+
},
|
|
9
|
+
"circuitBreaker": {
|
|
10
|
+
"level": 1,
|
|
11
|
+
"reason": "screen-recording-denied"
|
|
12
|
+
},
|
|
13
|
+
"signals": {
|
|
14
|
+
"act": {
|
|
15
|
+
"selector": {
|
|
16
|
+
"role": "checkBox",
|
|
17
|
+
"identifier": "agree-checkbox"
|
|
18
|
+
},
|
|
19
|
+
"action": "confirm",
|
|
20
|
+
"actConfirmed": true
|
|
21
|
+
},
|
|
22
|
+
"axEvent": {
|
|
23
|
+
"treeDigestBefore": "00000000000000000000000000000001",
|
|
24
|
+
"treeDigestAfter": "00000000000000000000000000000002",
|
|
25
|
+
"nodeCount": 57,
|
|
26
|
+
"axChanged": true,
|
|
27
|
+
"latencyMs": 12.5
|
|
28
|
+
},
|
|
29
|
+
"handlerProbe": null,
|
|
30
|
+
"stateDiff": null
|
|
31
|
+
},
|
|
32
|
+
"assertion": null,
|
|
33
|
+
"diagnosis": null
|
|
34
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "glasspane.evidence/0.1",
|
|
3
|
+
"operationId": "op_0PAAAABBBBCCCCDDDDEEEEFFFF",
|
|
4
|
+
"createdAt": "2026-09-19T09:41:02.500Z",
|
|
5
|
+
"attribution": {
|
|
6
|
+
"level": "strong",
|
|
7
|
+
"contaminated": false
|
|
8
|
+
},
|
|
9
|
+
"circuitBreaker": {
|
|
10
|
+
"level": 0
|
|
11
|
+
},
|
|
12
|
+
"signals": {
|
|
13
|
+
"act": {
|
|
14
|
+
"selector": {
|
|
15
|
+
"role": "AXButton",
|
|
16
|
+
"title": "OK Press",
|
|
17
|
+
"identifier": "ok-press"
|
|
18
|
+
},
|
|
19
|
+
"action": "press",
|
|
20
|
+
"actConfirmed": true
|
|
21
|
+
},
|
|
22
|
+
"axEvent": {
|
|
23
|
+
"treeDigestBefore": "0f1e2d3c4b5a69788796a5b4c3d2e1f0",
|
|
24
|
+
"treeDigestAfter": "00112233445566778899aabbccddeeff",
|
|
25
|
+
"nodeCount": 24,
|
|
26
|
+
"axChanged": true,
|
|
27
|
+
"latencyMs": 21.4
|
|
28
|
+
},
|
|
29
|
+
"handlerProbe": {
|
|
30
|
+
"probeVersion": "gp-probe/0.1.0",
|
|
31
|
+
"hitCount": 3,
|
|
32
|
+
"handlers": [
|
|
33
|
+
{ "file": "probe-demo/ProbeDemoApp.swift", "line": 64 },
|
|
34
|
+
{ "file": "probe-demo/ProbeDemoApp.swift", "line": 65 }
|
|
35
|
+
],
|
|
36
|
+
"lateCount": 0
|
|
37
|
+
},
|
|
38
|
+
"stateDiff": {
|
|
39
|
+
"source": "z3-kvc",
|
|
40
|
+
"changed": true,
|
|
41
|
+
"entries": [
|
|
42
|
+
{ "key": "demo.count", "before": "0", "after": "1" }
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"pixelDiff": {
|
|
46
|
+
"changedPixelRatio": 0.014,
|
|
47
|
+
"bounds": { "x": 12, "y": 34, "width": 96, "height": 28 },
|
|
48
|
+
"windowId": 4210
|
|
49
|
+
},
|
|
50
|
+
"responsiveness": {
|
|
51
|
+
"responsive": true,
|
|
52
|
+
"pingMs": 2.1
|
|
53
|
+
},
|
|
54
|
+
"crash": {
|
|
55
|
+
"processAliveBefore": true,
|
|
56
|
+
"processAliveAfter": true
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"assertion": null,
|
|
60
|
+
"diagnosis": {
|
|
61
|
+
"class": "NO_ANOMALY",
|
|
62
|
+
"report": {
|
|
63
|
+
"path": "act.press -> probe-window -> handler/state -> ax-digest -> pixel-diff",
|
|
64
|
+
"anomaly": "none: operation confirmed, AX tree changed and pixels changed",
|
|
65
|
+
"evidence": "op_0PAAAABBBBCCCCDDDDEEEEFFFF strong attribution; actConfirmed=true",
|
|
66
|
+
"next": "no action required; continue the recipe"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "glasspane.evidence/0.1-draft",
|
|
3
|
+
"operationId": "op_04DRAFTPACK000000000000000",
|
|
4
|
+
"createdAt": "2026-09-17T13:33:39.275Z",
|
|
5
|
+
"attribution": {
|
|
6
|
+
"level": "soft",
|
|
7
|
+
"contaminated": false
|
|
8
|
+
},
|
|
9
|
+
"circuitBreaker": {
|
|
10
|
+
"level": 0
|
|
11
|
+
},
|
|
12
|
+
"signals": {
|
|
13
|
+
"act": {
|
|
14
|
+
"selector": {
|
|
15
|
+
"role": "AXButton",
|
|
16
|
+
"title": "Submit"
|
|
17
|
+
},
|
|
18
|
+
"action": "press",
|
|
19
|
+
"actConfirmed": true
|
|
20
|
+
},
|
|
21
|
+
"axEvent": {
|
|
22
|
+
"treeDigestBefore": "f84988c2d9a2edf3972aa9a247279fce",
|
|
23
|
+
"treeDigestAfter": "0b7d3f1a5c8e2946d1a70c5e8b342f61",
|
|
24
|
+
"nodeCount": 4,
|
|
25
|
+
"axChanged": true,
|
|
26
|
+
"latencyMs": 18.7
|
|
27
|
+
},
|
|
28
|
+
"handlerProbe": null,
|
|
29
|
+
"stateDiff": null,
|
|
30
|
+
"pixelDiff": {
|
|
31
|
+
"changedPixelRatio": 0.018,
|
|
32
|
+
"bounds": {
|
|
33
|
+
"x": 512,
|
|
34
|
+
"y": 344,
|
|
35
|
+
"width": 168,
|
|
36
|
+
"height": 32
|
|
37
|
+
},
|
|
38
|
+
"windowId": 12
|
|
39
|
+
},
|
|
40
|
+
"responsiveness": {
|
|
41
|
+
"responsive": true,
|
|
42
|
+
"pingMs": 3
|
|
43
|
+
},
|
|
44
|
+
"crash": {
|
|
45
|
+
"processAliveBefore": true,
|
|
46
|
+
"processAliveAfter": true
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"assertion": null,
|
|
50
|
+
"diagnosis": {
|
|
51
|
+
"class": "NO_ANOMALY",
|
|
52
|
+
"report": {
|
|
53
|
+
"path": "act.press -> ax-digest -> pixel-diff",
|
|
54
|
+
"anomaly": "none: operation confirmed, AX tree changed, pixels changed",
|
|
55
|
+
"evidence": "op_04DRAFTPACK000000000000000 soft attribution; axChanged=true; changedPixelRatio=0.018; pingMs=3",
|
|
56
|
+
"next": "no action required; continue the recipe"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "glasspane.evidence/0.1",
|
|
3
|
+
"operationId": "op_05AXTREEMAP000000000000000",
|
|
4
|
+
"createdAt": "2026-09-21T07:12:44.500Z",
|
|
5
|
+
"attribution": {
|
|
6
|
+
"level": "strong",
|
|
7
|
+
"contaminated": false
|
|
8
|
+
},
|
|
9
|
+
"circuitBreaker": {
|
|
10
|
+
"level": 0
|
|
11
|
+
},
|
|
12
|
+
"signals": {
|
|
13
|
+
"act": {
|
|
14
|
+
"selector": {
|
|
15
|
+
"role": "AXButton",
|
|
16
|
+
"title": "Toggle"
|
|
17
|
+
},
|
|
18
|
+
"action": "press",
|
|
19
|
+
"actConfirmed": true
|
|
20
|
+
},
|
|
21
|
+
"axEvent": {
|
|
22
|
+
"treeDigestBefore": "9f2c6a04d81b3e57c206af9d4b7e1358",
|
|
23
|
+
"treeDigestAfter": "9f2c6a04d81b3e57c206af9d4b7e1358",
|
|
24
|
+
"nodeCount": 6,
|
|
25
|
+
"axChanged": false,
|
|
26
|
+
"latencyMs": 2.4
|
|
27
|
+
},
|
|
28
|
+
"handlerProbe": null,
|
|
29
|
+
"stateDiff": null,
|
|
30
|
+
"pixelDiff": {
|
|
31
|
+
"changedPixelRatio": 0,
|
|
32
|
+
"windowId": 12
|
|
33
|
+
},
|
|
34
|
+
"responsiveness": {
|
|
35
|
+
"responsive": true,
|
|
36
|
+
"pingMs": 4
|
|
37
|
+
},
|
|
38
|
+
"crash": {
|
|
39
|
+
"processAliveBefore": true,
|
|
40
|
+
"processAliveAfter": true
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"assertion": null,
|
|
44
|
+
"diagnosis": {
|
|
45
|
+
"class": "T2",
|
|
46
|
+
"report": {
|
|
47
|
+
"path": "act.press -> ax-digest -> pixel-diff",
|
|
48
|
+
"anomaly": "act confirmed but neither the AX tree nor the pixels changed",
|
|
49
|
+
"evidence": "op_05AXTREEMAP000000000000000 strong attribution; axChanged=false; changedPixelRatio=0",
|
|
50
|
+
"next": "verify the selector targets a live element; run observe before retrying"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "glasspane.recipe/0.1-draft",
|
|
3
|
+
"name": "smoke-check-submit",
|
|
4
|
+
"steps": [
|
|
5
|
+
{
|
|
6
|
+
"kind": "act",
|
|
7
|
+
"params": {
|
|
8
|
+
"selector": {
|
|
9
|
+
"role": "button",
|
|
10
|
+
"title": "Submit"
|
|
11
|
+
},
|
|
12
|
+
"action": "press"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"kind": "observe",
|
|
17
|
+
"params": {
|
|
18
|
+
"maxDepth": 4
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"kind": "assert",
|
|
23
|
+
"params": {
|
|
24
|
+
"selector": {
|
|
25
|
+
"role": "button",
|
|
26
|
+
"title": "Submit"
|
|
27
|
+
},
|
|
28
|
+
"property": "enabled",
|
|
29
|
+
"expected": true
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"kind": "diagnose",
|
|
34
|
+
"params": {}
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<div class="gp-evidence" id="op_0PAAAABBBBCCCCDDDDEEEEFFFF">
|
|
2
|
+
<h1>op_0PAAAABBBBCCCCDDDDEEEEFFFF · NO_ANOMALY · normal</h1>
|
|
3
|
+
<dl class="gp-summary">
|
|
4
|
+
<dt>operationId</dt><dd>op_0PAAAABBBBCCCCDDDDEEEEFFFF</dd>
|
|
5
|
+
<dt>createdAt</dt><dd>2026-09-19T09:41:02.500Z</dd>
|
|
6
|
+
<dt>schemaVersion</dt><dd>glasspane.evidence/0.1</dd>
|
|
7
|
+
<dt class="gp-line">·</dt><dd>attribution: strong | contaminated=false</dd>
|
|
8
|
+
<dt class="gp-line">·</dt><dd>circuitBreaker: level 0 (normal)</dd>
|
|
9
|
+
<dt class="gp-line">·</dt><dd>act press AXButton "OK Press" #ok-press: confirmed</dd>
|
|
10
|
+
<dt class="gp-line">·</dt><dd>axEvent: changed=true nodes=24 latencyMs=1234.57</dd>
|
|
11
|
+
<dt class="gp-line">·</dt><dd>handlerProbe: probeVersion=gp-probe/0.1.0 hitCount=3 late=1 handlers=[probe-demo/ProbeDemoApp.swift:64, probe-demo/ProbeDemoApp.swift:65]</dd>
|
|
12
|
+
<dt class="gp-line">·</dt><dd>stateDiff: source=z3-kvc changed=true entries=[demo.count "0" -> "1", demo.label "idle" -> "pressed"]</dd>
|
|
13
|
+
<dt class="gp-line">·</dt><dd>pixelDiff: changedRatio=0.123457 windowId=4210 bounds=12,34,96,28</dd>
|
|
14
|
+
<dt class="gp-line">·</dt><dd>responsiveness: responsive=true pingMs=2.1</dd>
|
|
15
|
+
<dt class="gp-line">·</dt><dd>crash: aliveBefore=true aliveAfter=true</dd>
|
|
16
|
+
</dl>
|
|
17
|
+
<section class="gp-section">
|
|
18
|
+
<h2>PATH</h2>
|
|
19
|
+
<p>act.press -> probe-window -> handler/state -> ax-digest -> pixel-diff</p>
|
|
20
|
+
</section>
|
|
21
|
+
<section class="gp-section">
|
|
22
|
+
<h2>ANOMALY</h2>
|
|
23
|
+
<p>none: operation confirmed, AX tree changed and pixels changed</p>
|
|
24
|
+
</section>
|
|
25
|
+
<section class="gp-section">
|
|
26
|
+
<h2>EVIDENCE</h2>
|
|
27
|
+
<p>op_0PAAAABBBBCCCCDDDDEEEEFFFF strong attribution; actConfirmed=true</p>
|
|
28
|
+
</section>
|
|
29
|
+
<section class="gp-section">
|
|
30
|
+
<h2>NEXT</h2>
|
|
31
|
+
<p>no action required; continue the recipe</p>
|
|
32
|
+
</section>
|
|
33
|
+
</div>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# op_0PAAAABBBBCCCCDDDDEEEEFFFF · NO_ANOMALY · normal
|
|
2
|
+
|
|
3
|
+
**operationId**: op_0PAAAABBBBCCCCDDDDEEEEFFFF
|
|
4
|
+
**createdAt**: 2026-09-19T09:41:02.500Z
|
|
5
|
+
**schemaVersion**: glasspane.evidence/0.1
|
|
6
|
+
* attribution: strong | contaminated=false
|
|
7
|
+
* circuitBreaker: level 0 (normal)
|
|
8
|
+
* act press AXButton "OK Press" #ok-press: confirmed
|
|
9
|
+
* axEvent: changed=true nodes=24 latencyMs=1234.57
|
|
10
|
+
* handlerProbe: probeVersion=gp-probe/0.1.0 hitCount=3 late=1 handlers=[probe-demo/ProbeDemoApp.swift:64, probe-demo/ProbeDemoApp.swift:65]
|
|
11
|
+
* stateDiff: source=z3-kvc changed=true entries=[demo.count "0" -> "1", demo.label "idle" -> "pressed"]
|
|
12
|
+
* pixelDiff: changedRatio=0.123457 windowId=4210 bounds=12,34,96,28
|
|
13
|
+
* responsiveness: responsive=true pingMs=2.1
|
|
14
|
+
* crash: aliveBefore=true aliveAfter=true
|
|
15
|
+
|
|
16
|
+
## PATH
|
|
17
|
+
|
|
18
|
+
act.press -> probe-window -> handler/state -> ax-digest -> pixel-diff
|
|
19
|
+
|
|
20
|
+
## ANOMALY
|
|
21
|
+
|
|
22
|
+
none: operation confirmed, AX tree changed and pixels changed
|
|
23
|
+
|
|
24
|
+
## EVIDENCE
|
|
25
|
+
|
|
26
|
+
op_0PAAAABBBBCCCCDDDDEEEEFFFF strong attribution; actConfirmed=true
|
|
27
|
+
|
|
28
|
+
## NEXT
|
|
29
|
+
|
|
30
|
+
no action required; continue the recipe
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iterate-kernel",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "iterate ecosystem shared kernel: schemas, the evidence->decision transcription, the decision-log audit chain and public validators. Verification reasoning stays in the engine; this layer transcribes.",
|
|
6
6
|
"type": "module",
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
"files": [
|
|
63
63
|
"dist",
|
|
64
64
|
"schemas",
|
|
65
|
+
"fixtures",
|
|
65
66
|
"README.md"
|
|
66
67
|
],
|
|
67
68
|
"scripts": {
|