@penpair/web 0.3.7 → 0.4.0
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/adapters.md +1 -1
- package/docs/approvals.md +33 -2
- package/docs/artifacts.md +23 -3
- package/docs/coverage.md +20 -4
- package/docs/design-releases.md +162 -0
- package/docs/guide.md +20 -3
- package/docs/handoff.md +1 -1
- package/docs/integration-maps.md +171 -0
- package/docs/journey-maps.md +139 -0
- package/examples/design-release-maps/README.md +72 -0
- package/examples/design-release-maps/integration.json +181 -0
- package/examples/design-release-maps/journey.json +187 -0
- package/examples/design-release-maps/sample-source.md +8 -0
- package/package.json +2 -2
package/docs/adapters.md
CHANGED
|
@@ -27,7 +27,7 @@ Use it when your application uses Marwes UI. Follow the [adapter overview](marwe
|
|
|
27
27
|
5. Run a project provider to open that state, read it back, capture the browser and compare the image.
|
|
28
28
|
6. Review the screenshots and differences; record human approval separately.
|
|
29
29
|
|
|
30
|
-
The adapter checks that the returned evidence identifies the requested case and expected state, references the correct unchanged baseline, and has matching
|
|
30
|
+
The adapter checks that the returned evidence identifies the requested case and expected state, references the correct unchanged baseline, and has matching image dimensions/scale (PNG or static lossless WebP) and font evidence. A complete result within the configured difference threshold is technical evidence, not visual approval or an accessibility assessment.
|
|
31
31
|
|
|
32
32
|
The provider is project code with an `async runCase(test)` export. It supplies actual route/theme/state/fixture setup, browser readback, screenshot capture and image comparison through the project's pinned tools. It can integrate the project's existing Reflection/browser checker. The adapter itself does not install a browser or execute a particular Reflection engine automatically.
|
|
33
33
|
|
package/docs/approvals.md
CHANGED
|
@@ -8,7 +8,7 @@ penpair approve --page Dashboard --frame FRAME_ID --write \
|
|
|
8
8
|
# Include --case CONFIGURED_BASELINE_ID for a rich theme/state/fixture case.
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Preview captures stable evidence and records nothing. Recording captures again and appends a schema-1 owner-words record to `design/approvals.json`, with file/page/frame IDs, revision, scale, actual theme/render context, optional declared case,
|
|
11
|
+
Preview captures stable evidence and records nothing. Recording captures again and appends a schema-1 owner-words record to `design/approvals.json`, with file/page/frame IDs, revision, scale, actual theme/render context, optional declared case, encoded-image SHA-256, date, identity, exact note and record hash. The immutable image lives under `design/approvals/SHA256.webp` or the preserved PNG form `design/approvals/SHA256.png`. A local exclusive append lock prevents lost records; a stale lock requires inspection. The file is atomically replaced after image bytes exist. Prior records are retained.
|
|
12
12
|
|
|
13
13
|
The command records supplied words; it cannot authenticate a person or establish consent. An agent needs the owner's actual approval for the exact reviewed artifact and must never invent words or run this as a routine automatic success step. No approvals were recorded by this implementation task. Content hashes detect changes, not identity. An empty note/identity, unstable capture, mismatched case, altered approved bytes or credential redaction refuses publication.
|
|
14
14
|
|
|
@@ -16,4 +16,35 @@ The command records supplied words; it cannot authenticate a person or establish
|
|
|
16
16
|
|
|
17
17
|
An exceptional `--apply --update --force-reason 'EXPLICIT_REASON'` may save a reference without a matching owner record. Its provenance says `forced-reference`; the reason persists. Rich case coverage and the implementation-case adapter refuse to count that waiver as owner-approved evidence. A waived reference is useful for an experiment, but cannot silently satisfy the design acceptance gate. Empty reasons and reasons without apply/update refuse.
|
|
18
18
|
|
|
19
|
-
The latest revision is a conservative invalidation boundary: an unrelated design edit may require fresh approval even if pixels stay equal.
|
|
19
|
+
The latest revision is a conservative invalidation boundary: an unrelated design edit may require fresh approval even if pixels stay equal. An image alone does not approve structure, behavior or accessibility. Approval records remain local/project artifacts until reviewed; no publish, client configuration or consumer-repository edit occurs automatically.
|
|
20
|
+
|
|
21
|
+
## Image format and migration
|
|
22
|
+
|
|
23
|
+
New image approvals default to static lossless WebP. `approve --format png` or
|
|
24
|
+
`approve --format webp` selects an exact encoding. For `approve --case CASE_ID`
|
|
25
|
+
without explicit `--format`, the baseline resolver preserves an existing
|
|
26
|
+
reference's actual format; otherwise it uses `baselines.format`, then WebP.
|
|
27
|
+
An approval without `--case` uses explicit `--format` or WebP. Review the actual
|
|
28
|
+
encoded candidate before supplying owner words; equal decoded pixels do not make
|
|
29
|
+
PNG and WebP byte approvals interchangeable.
|
|
30
|
+
|
|
31
|
+
Changing `baselines.format` or supplying `baselines --format webp` alone does not
|
|
32
|
+
convert an existing PNG reference. Preview migration explicitly:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
penpair baselines --format webp --migrate-format
|
|
36
|
+
penpair approve --page Dashboard --frame FRAME_ID --case CASE_ID --format webp
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
After inspecting the new-format artifact and obtaining the owner's actual words,
|
|
40
|
+
record it using the same approval command with `--write --by OWNER --note
|
|
41
|
+
EXACT_OWNER_WORDS`. Then apply the migration:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
penpair baselines --format webp --migrate-format --apply --update
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The CLI requires `--format` with `--migrate-format`; applying requires `--update`.
|
|
48
|
+
Normal exact-image/case approval rules still apply. Prior PNG approval records
|
|
49
|
+
and generations stay intact; migration publishes a new immutable generation.
|
|
50
|
+
Public `export` and `shots` output remain PNG and are independent of this choice.
|
package/docs/artifacts.md
CHANGED
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
# Capture and approval provenance
|
|
2
2
|
|
|
3
|
-
Baseline manifests use schema 2. `capturedRevision` identifies the coherent capture run, while each frame has separate `captured` and `approved` records. Those records identify the file, page and frame by immutable ID, revision,
|
|
3
|
+
Baseline manifests use schema 2. `capturedRevision` identifies the coherent capture run, while each frame has separate `captured` and `approved` records. Those records identify the file, page and frame by immutable ID, revision, encoded-image hash, scale, active theme names, capture time, penpair version, reported Penpot API version and browser user agent when available. A missing environment value is recorded as unknown; the record does not establish that fonts loaded correctly or identify every rendering dependency.
|
|
4
4
|
|
|
5
|
-
An unchanged reference retains its original approval record. A changed image recaptured without `--update` retains its approved bytes, path, revision and hash, while `captured` describes the new candidate. Legacy images without trustworthy provenance are marked `legacy`; a current revision is never invented for them. Changing a baseline still requires the owner's `--apply --update`.
|
|
5
|
+
An unchanged reference retains its original approval record. A changed image recaptured without `--update` retains its approved bytes, path, revision and hash, while `captured` describes the new candidate. Legacy images without trustworthy provenance are marked `legacy`; a current revision is never invented for them. Changing a baseline still requires the owner's `--apply --update`. Exact owner words are retained separately in [approval records](approvals.md); manifest provenance alone cannot manufacture consent.
|
|
6
6
|
|
|
7
7
|
All configured frames must be present and stable. File/page/revision evidence is checked inside exports and across consecutive exports; the complete frame listing is checked again after capture. Intervening changes, failures or cancellation do not publish a new complete manifest. There is no partial-publication mode.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Baseline captures live in immutable `captures/<capture-id>/<baseline-id>.webp` or `.png` generations. New references default to static lossless WebP; existing PNG references keep PNG during ordinary captures and updates. Historical `<baseline-id>.png` files are not renamed or converted implicitly. Read approved image paths from manifest frame `file` fields. Generated Reflection cases already use those paths. `penpair-baselines.json` is the authoritative commit point and is published last with a same-directory atomic rename. Its `casesFile` points to the exact immutable case file for that generation. The root `reflection-cases.json` remains a convenience for existing config imports; when reading it together with a manifest, require matching `captureId`, or follow `casesFile` from the manifest. Independent root files cannot be replaced as one filesystem transaction.
|
|
10
10
|
|
|
11
11
|
A process interrupted during output may leave an unreferenced capture generation. Previous manifest references remain usable; inspect before cleaning generations. Staging directories are removed on handled errors. This is filesystem publication safety, not a power-loss-proof multi-file transaction or a remote backup.
|
|
12
12
|
|
|
13
13
|
Standalone PNG export and full-file archive candidates also stage complete bytes before publication. Archives use exclusive creation and never replace an existing file. PNG exports atomically replace the requested output only after a stable result. The export report includes target provenance. Archive restore verification remains a separate scratch import/readback task.
|
|
14
|
+
|
|
15
|
+
## Baseline encoding and explicit migration
|
|
16
|
+
|
|
17
|
+
Always follow the manifest's exact `file` path and encoded-byte hash; do not
|
|
18
|
+
construct a `.png` or `.webp` path from the baseline ID. PNG and WebP with identical
|
|
19
|
+
pixels have different approval identities. An existing reference keeps its
|
|
20
|
+
actual encoding even when `baselines.format` or `--format` selects another
|
|
21
|
+
format. New references choose explicit `--format`, then config, then WebP.
|
|
22
|
+
|
|
23
|
+
An explicit `--format webp --migrate-format` previews migration. Publishing it
|
|
24
|
+
also requires `--apply --update` and the normal matching exact new-format approval
|
|
25
|
+
(or explicit waiver rules). Earlier immutable generations and owner records
|
|
26
|
+
remain unchanged. See [approval migration](approvals.md#image-format-and-migration).
|
|
27
|
+
|
|
28
|
+
WebP conversion is lossless and independently verifies decoded RGBA bytes,
|
|
29
|
+
dimensions and ICC preservation. Animation, unsupported bit depth, excessive
|
|
30
|
+
size or pixel/metadata mismatch refuses conversion and preserves the previous
|
|
31
|
+
manifest. Public PNG exports, shot generations and pinned release-source PNG
|
|
32
|
+
renders retain their existing format; baseline defaults do not redefine those
|
|
33
|
+
artifacts.
|
package/docs/coverage.md
CHANGED
|
@@ -20,9 +20,9 @@ A baseline frame may declare an explicit viewport, theme label, UI state, fixtur
|
|
|
20
20
|
|
|
21
21
|
`theme`, `state` and `fixture` are declared design intent. A label alone does not prove actual theme activation, application state or data loading. Optional `activeThemeIds` asserts the complete exact active native theme-ID set at capture; omit it for a manually styled frame and retain that uncertainty. Baseline capture remains read-only toward the Penpot document: it never switches themes. Use the separate [mode trial](mode-verification.md) for temporary theme switching.
|
|
22
22
|
|
|
23
|
-
Frame geometry must match the declared CSS viewport within less than 0.01 CSS px per axis, allowing floating-point noise from Penpot transforms and auto sizing. Baseline capture, case approval and offline coverage use the same tolerance.
|
|
23
|
+
Frame geometry must match the declared CSS viewport within less than 0.01 CSS px per axis, allowing floating-point noise from Penpot transforms and auto sizing. Baseline capture, case approval and offline coverage use the same tolerance. Encoded image dimensions (PNG or static lossless WebP) must still exactly equal the declared viewport multiplied by the observed export scale and rounded to whole pixels; the geometry tolerance never applies to image dimensions. A failed viewport/theme assertion marks `case-mismatch`, exits incomplete and preserves the previous generation. New provenance retains raw, unrounded design dimensions, active native theme IDs where available, API/tool version, renderer description and capture time. Font names are declarations; loaded font versions remain unobserved.
|
|
24
24
|
|
|
25
|
-
Case metadata is part of approval identity. Changing a fixture/state/theme/viewport declaration requires `--apply --update` even if the
|
|
25
|
+
Case metadata is part of approval identity. Changing a fixture/state/theme/viewport declaration requires `--apply --update` even if the image bytes happen to match. Moving a matching image to a different file/page/frame identity also requires review. Recapture preserves the original approval until that explicit update. Metadata is pinned before asynchronous capture.
|
|
26
26
|
|
|
27
27
|
## Required matrix
|
|
28
28
|
|
|
@@ -30,7 +30,7 @@ Add `baselines.coverage.required` as an explicit list of route/viewport/theme/st
|
|
|
30
30
|
|
|
31
31
|
See [an example matrix](../examples/coverage-matrix.json) spanning desktop/mobile, light/dark and an empty state. Only request combinations the product intends to support; no matrix is inferred from frame sizes or names.
|
|
32
32
|
|
|
33
|
-
`penpair baselines coverage --json` runs offline. It loads the version-2 manifest, checks the configured file pin, validates project-bound artifact paths, independently hashes approved PNG bytes and reports:
|
|
33
|
+
`penpair baselines coverage --json` runs offline. It loads the version-2 manifest, checks the configured file pin, validates project-bound artifact paths, independently hashes approved PNG or static lossless WebP bytes and reports:
|
|
34
34
|
|
|
35
35
|
- `missing-case`: no configured frame for the required tuple.
|
|
36
36
|
- `missing-capture`: a frame is configured but has no approved capture.
|
|
@@ -41,7 +41,7 @@ See [an example matrix](../examples/coverage-matrix.json) spanning desktop/mobil
|
|
|
41
41
|
|
|
42
42
|
`designCasesComplete` means all requested design slots have matching approved intent. `browserVerification: not-run` and `accessibility: not-assessed` remain separate, even when every design slot is complete. Unknown font loading, absent activation assertions and missing renderer metadata are listed. The offline report exits 3 for gaps; it never connects to Penpot or loads project extensions.
|
|
43
43
|
|
|
44
|
-
Ordinary `baselines` can publish a coherent capture of its configured frames while the broader required matrix still has gaps; that command returns incomplete when configured requirements remain uncovered. The manifest distinguishes capture completeness from matrix coverage. An incomplete capture itself still publishes nothing. Manifest reads are bounded to 16 MiB and each approved
|
|
44
|
+
Ordinary `baselines` can publish a coherent capture of its configured frames while the broader required matrix still has gaps; that command returns incomplete when configured requirements remain uncovered. The manifest distinguishes capture completeness from matrix coverage. An incomplete capture itself still publishes nothing. Manifest reads are bounded to 16 MiB and each approved image check to 64 MiB; exceeding those bounds cannot produce covered evidence.
|
|
45
45
|
|
|
46
46
|
## Browser integration
|
|
47
47
|
|
|
@@ -62,3 +62,19 @@ Baseline entries require `frame` or `frameId`, or both. `frameId` is a unique bo
|
|
|
62
62
|
When both are supplied, a different current board name reports `renamed` and the entry is never captured under its stale name. Review the rename and update the expected name before retrying. ID-only entries follow the ID and report its current name. Page searches stop with an explicit error if the 10,000-shape budget truncates the listing.
|
|
63
63
|
|
|
64
64
|
`approve --case CASE_ID --page PAGE --frame ID` compares `--frame` directly with a configured `frameId`; name-only cases retain the unique-name check. Nested frames use the same exact frame-ID capture identity for approval matching. The baseline manifest continues to record `frameId`; Reflection case format is unchanged.
|
|
65
|
+
|
|
66
|
+
## Image encoding
|
|
67
|
+
|
|
68
|
+
New baseline references default to static lossless WebP. Existing PNG references
|
|
69
|
+
and approvals retain their exact original bytes, paths and hashes during normal
|
|
70
|
+
capture/update. Neither `baselines.format` nor `--format` alone migrates an
|
|
71
|
+
existing reference. Use explicit `--format webp --migrate-format` for a preview;
|
|
72
|
+
application also requires `--apply --update` and matching exact new-format image
|
|
73
|
+
approval. A PNG approval does not cover equivalent WebP pixels. See
|
|
74
|
+
[approval and migration](approvals.md#image-format-and-migration).
|
|
75
|
+
|
|
76
|
+
WebP conversion preserves exact dimensions, decoded RGBA pixels including RGB
|
|
77
|
+
under transparency, and the source ICC profile. Unsupported animated/16-bit
|
|
78
|
+
input or failed conversion verification leaves the prior generation intact.
|
|
79
|
+
The conversion budget is 64 megapixels; geometry tolerance never relaxes image
|
|
80
|
+
pixel-size or pixel-identity checks.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Design releases
|
|
2
|
+
|
|
3
|
+
A design release freezes a reviewed design handoff for an explicit product SemVer,
|
|
4
|
+
independent of the Penpair package version. It joins
|
|
5
|
+
[journey maps](journey-maps.md), [integration maps](integration-maps.md), exact
|
|
6
|
+
design cases and immutable evidence so a later implementation agent can identify
|
|
7
|
+
what was reviewed. This is a design release, separate from publishing Penpair's
|
|
8
|
+
npm packages or accepting a frontend implementation.
|
|
9
|
+
|
|
10
|
+
## Local commands
|
|
11
|
+
|
|
12
|
+
Create the plan from actual source inspection, using your own product SemVer.
|
|
13
|
+
These paths illustrate project-owned inputs. A release accepts at most 100
|
|
14
|
+
selected source screens. Use the local project command, such as
|
|
15
|
+
`pnpm exec penpair`, when installed as a dependency.
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
# Save a planned release, then inspect the remote assembly preview.
|
|
19
|
+
penpair design-release plan --from design/releases/1.0.0/plan.json \
|
|
20
|
+
--out design/releases/1.0.0/release.json
|
|
21
|
+
penpair design-release assemble --from design/releases/1.0.0/release.json
|
|
22
|
+
|
|
23
|
+
# After reviewing the preview and authorizing the assembly write:
|
|
24
|
+
penpair design-release assemble --from design/releases/1.0.0/release.json --apply
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Next, perform the guided native copy and record actual source/target identities
|
|
28
|
+
in `receipts.json`. Verification reads the live frames and saves evidence;
|
|
29
|
+
finalization below is a preview and records no owner approval.
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
penpair design-release verify --from design/releases/1.0.0/release.json \
|
|
33
|
+
--receipts design/releases/1.0.0/receipts.json
|
|
34
|
+
penpair design-release finalize --from design/releases/1.0.0/release.json
|
|
35
|
+
penpair design-release check --from design/releases/1.0.0/release.json --live
|
|
36
|
+
penpair design-release context --from design/releases/1.0.0/release.json --draft
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Only apply finalization after the owner supplies actual words for the exact
|
|
40
|
+
verified candidate, as described below. After finalization, omit `--draft` to
|
|
41
|
+
request approved context. Missing required proof keeps verification/finalization
|
|
42
|
+
incomplete; these commands do not bypass the native support limits.
|
|
43
|
+
|
|
44
|
+
## Prepare and assemble
|
|
45
|
+
|
|
46
|
+
Use the `design-release` command family to plan, assemble, verify, finalize,
|
|
47
|
+
check and produce context. Use the installed command's help for current argument
|
|
48
|
+
names. Planning exposes required inputs and unresolved work. Assembly records
|
|
49
|
+
identities and hashes; it does not invent source observations or owner approval.
|
|
50
|
+
Each selected source needs its complete `inspection` reference (project-relative
|
|
51
|
+
`path` and exact `sha256`). Pin a stable source PNG through its `render` reference
|
|
52
|
+
before verification; a draft without this reference cannot pass fidelity. A
|
|
53
|
+
source using tokens also needs a complete pinned token-inspection `dependencies`
|
|
54
|
+
reference. Required dependency changes invalidate the pinned source evidence.
|
|
55
|
+
|
|
56
|
+
Include the parent and every linked detail-map contract in the release's
|
|
57
|
+
`contracts` list, each with its independent exact review. A reviewed parent link
|
|
58
|
+
is not approval of the child graph. See [linked detail maps](integration-maps.md#linked-detail-maps).
|
|
59
|
+
|
|
60
|
+
Keep the release page in the same pinned Penpot file, named `release/<version>`.
|
|
61
|
+
Assembly creates the owned overview/map sections and reports `awaiting-copy`.
|
|
62
|
+
Copy source design frames natively using a reviewed, guided copy/paste operation
|
|
63
|
+
by a person or an authorized AI using existing browser tools. Assembly does not
|
|
64
|
+
perform an unsupported cross-page clone.
|
|
65
|
+
Preserve visual fidelity, native components, token bindings, text and layout;
|
|
66
|
+
do not recreate frames from screenshots or normalize their dimensions. A source
|
|
67
|
+
using auto height must retain it. Floating-point geometry noise is not a reason
|
|
68
|
+
to change source sizing.
|
|
69
|
+
|
|
70
|
+
The live sequence is read-only inspection, pinned snapshot, one idempotent write,
|
|
71
|
+
independent readback and stable exports that are looked at. Snippets stay under
|
|
72
|
+
90 KB. If a write response is uncertain, inspect what exists before retrying.
|
|
73
|
+
Keep unmanaged content intact; a page name alone cannot authorize replacement.
|
|
74
|
+
Do not copy via a lossy or structurally incomplete fallback when native fidelity
|
|
75
|
+
cannot be established: report the missing proof.
|
|
76
|
+
|
|
77
|
+
## Supported native verification limits
|
|
78
|
+
|
|
79
|
+
Native verification is deliberately narrower than native copy/paste. Selecting a
|
|
80
|
+
screen for this workflow does not establish that its content can be verified.
|
|
81
|
+
The current verifier blocks these cases:
|
|
82
|
+
|
|
83
|
+
- **All component instances, copies, main instances and component roots.** The
|
|
84
|
+
inspection cannot establish complete override state. Retaining links during a
|
|
85
|
+
copy is required, but it does not prove override fidelity.
|
|
86
|
+
- **Groups without an explicit `maskedGroup` observation.** An absent mask flag
|
|
87
|
+
is unknown, not proof that the group is unmasked.
|
|
88
|
+
- **Unknown text range/style observations**, including unobserved mixed-range
|
|
89
|
+
state, and any other unknown or missing required inspection field.
|
|
90
|
+
- **Paths/vector shapes whose actual path content was not observed.** A path
|
|
91
|
+
type or matching raster export cannot establish the native path data.
|
|
92
|
+
- Unsupported shape content, incomplete hierarchy, unobservable interactions or
|
|
93
|
+
missing pinned source render/dependency evidence.
|
|
94
|
+
|
|
95
|
+
A selected screen containing one of these cases remains blocked with a reason;
|
|
96
|
+
it cannot be finalized by waiving the finding or accepting equal pixels. Retain
|
|
97
|
+
its native structure and source evidence, then obtain the missing observation or
|
|
98
|
+
extend and validate inspection support before retrying. Do not detach components,
|
|
99
|
+
flatten groups, remove styles or substitute raster images to bypass the gate.
|
|
100
|
+
Simple screens whose required fields are fully observed can be assessed, but
|
|
101
|
+
that is not a claim of complete support for every native Penpot feature.
|
|
102
|
+
|
|
103
|
+
## Verify the package
|
|
104
|
+
|
|
105
|
+
Supply a project-owned receipt list with explicit `sourceId` and
|
|
106
|
+
`targetFrameId` values to `verify --receipts FILE`. Check release frame identities
|
|
107
|
+
against the selected sources and retain immutable inspection/export evidence
|
|
108
|
+
with exact paths and hashes. Compare source and release frames independently,
|
|
109
|
+
including component/token identity and sizing
|
|
110
|
+
behavior, and inspect stable exports. A current rendering cannot rewrite the
|
|
111
|
+
bytes of an already recorded artifact. Native release objects remain mutable,
|
|
112
|
+
including changes inherited through shared components and tokens. A later change
|
|
113
|
+
is drift and needs a new reviewed generation, not a silent refresh of finalized
|
|
114
|
+
evidence.
|
|
115
|
+
|
|
116
|
+
New baseline evidence uses lossless WebP. Existing PNG baselines and image
|
|
117
|
+
approvals remain valid in their original format. Conversion must be a deliberate
|
|
118
|
+
migration with new evidence and review; never change approved bytes in place.
|
|
119
|
+
Penpot can supply PNG during export, so conversion must retain exact dimensions
|
|
120
|
+
and pixels. Quality 100 alone does not establish lossless encoding.
|
|
121
|
+
|
|
122
|
+
The release needs matching exact-artifact review records and no unresolved
|
|
123
|
+
blocking findings. Preserve the distinction between:
|
|
124
|
+
|
|
125
|
+
- Map review: the owner's supplied words bind an exact contract hash.
|
|
126
|
+
- Design image approval: the existing exact case/image approval protocol.
|
|
127
|
+
- Technical verification: independently observed structure and image evidence.
|
|
128
|
+
- Implementation acceptance: actual application behavior, browser evidence and
|
|
129
|
+
owner review, assessed separately after implementation.
|
|
130
|
+
|
|
131
|
+
## Finalize and continue
|
|
132
|
+
|
|
133
|
+
The release record progresses from `planned` through `awaiting-copy` and
|
|
134
|
+
`verified` to `final`. Finalization records the reviewed release identity and
|
|
135
|
+
immutable evidence. It must not promote missing evidence, waivers or inferred owner approval into a
|
|
136
|
+
successful design gate. Finalized means the design package is ready to guide
|
|
137
|
+
implementation; it does not mean the application has been built or checked.
|
|
138
|
+
|
|
139
|
+
Finalization previews by default. Only use `finalize --apply --by OWNER --note
|
|
140
|
+
EXACT_WORDS` after the owner has supplied those words for the exact candidate.
|
|
141
|
+
Keep journal/run identity when reconciling interrupted remote work.
|
|
142
|
+
|
|
143
|
+
Run checks again before using the package later. Missing or modified artifacts,
|
|
144
|
+
changed map/source hashes and changed release evidence must remain visible as
|
|
145
|
+
drift or incomplete evidence. A saved-source check does not contact Penpot;
|
|
146
|
+
live freshness requires an explicit fresh observation. Context must identify
|
|
147
|
+
its verification scope and any truncation. Release context includes actual frozen
|
|
148
|
+
`mapContexts`, exact release-page `mapTargets`, independently pending implementation
|
|
149
|
+
status and next actions. Linked detail navigation targets the release's own child
|
|
150
|
+
boards; each child contract retains its separate review requirement.
|
|
151
|
+
Its `proposedBaselines` is a configuration fragment with the release page, WebP
|
|
152
|
+
format, baseline root and explicit target `frameId` entries. Review and merge it
|
|
153
|
+
into the existing `baselines` block; context does not rewrite project config or
|
|
154
|
+
approve the new target image identities.
|
|
155
|
+
|
|
156
|
+
Use `penpair-handoff` with the approved integration context, then `penpair-verify`
|
|
157
|
+
for the actual frontend. Keep those later implementation results separately;
|
|
158
|
+
never rewrite the finalized design to match an implementation failure.
|
|
159
|
+
|
|
160
|
+
The [reset-password example](../examples/design-release-maps/README.md) is an
|
|
161
|
+
unapproved fixture showing decisions and gaps. It is not a finalized release or
|
|
162
|
+
proof of a live Penpot copy.
|
package/docs/guide.md
CHANGED
|
@@ -10,6 +10,7 @@ consumer evidence.
|
|
|
10
10
|
| Path | Documents |
|
|
11
11
|
| --- | --- |
|
|
12
12
|
| First run / shared file | [Choose an installation route](installation.md), [manual installation](getting-started.md), [team](team.md), [validation](validation.md) |
|
|
13
|
+
| Intent / release | [Journey maps](journey-maps.md), [integration maps](integration-maps.md), [design releases](design-releases.md) |
|
|
13
14
|
| Build / handoff | [Cookbook](cookbook.md), [workflow](design-workflow.md), [kit](build-kit.md), [file scripts](run-file.md), [handoff](handoff.md) |
|
|
14
15
|
| Evidence | [Inspection](inspection.md), [advisory audits](audits.md), [snapshots](snapshots.md), [approvals](approvals.md), [coverage](coverage.md), [artifacts](artifacts.md) |
|
|
15
16
|
| Integration | [Companion adapters](adapters.md), [MCP](mcp.md), [formats](formats.md), [extension trust](extensions-trust.md), [credentials](credentials.md), [token adapter](marwes.md) |
|
|
@@ -95,6 +96,7 @@ For registered writes, supply an explicit `verify({ inspect, apply, readback })`
|
|
|
95
96
|
"baselines": {
|
|
96
97
|
"page": "Candidate",
|
|
97
98
|
"root": "tests/baselines",
|
|
99
|
+
"format": "webp",
|
|
98
100
|
"threshold": 0.05,
|
|
99
101
|
"frames": [
|
|
100
102
|
{ "frame": "F / candidates", "id": "candidates-desktop", "route": "candidates" },
|
|
@@ -107,8 +109,23 @@ For registered writes, supply an explicit `verify({ inspect, apply, readback })`
|
|
|
107
109
|
- Each entry requires `frame` or `frameId` (or both). `frameId` is a board UUID, unique across entries, resolved anywhere on the configured page. Frames inside boards, such as release frames inside section boards, need `frameId`. Name-only entries still match top-level frames only.
|
|
108
110
|
- With both fields, `frame` is an expected name: a changed name reports `renamed` and captures nothing for that entry. Review and update the expected name before retrying. ID-only entries use the board's current name in reports. A truncated page search (10,000 shapes) stops the capture instead of using a partial listing.
|
|
109
111
|
- For example: `{ "frameId": "10216397-acdf-805e-8008-d69b71f841d4", "frame": "Login / Empty", "id": "login-empty", "route": "login" }`.
|
|
110
|
-
- `id` names the image (`<id>.png`) and the check. `route` is the route in your app this frame is the design of; a frame without a route is exported but gets no check.
|
|
111
|
-
- Without `--apply` the command only looks and reports each frame as `new`, `same`, `changed`, `unstable` (the export never settled) or `missing`/`renamed`. `--apply` writes new images, `penpair-baselines.json` (file, revision, sizes, hashes) and `reflection-cases.json`. A `changed` image is replaced only with `--apply --update
|
|
112
|
+
- `id` names the image (`<id>.webp` for a new default reference; existing PNG references retain `.png`) and the check. `route` is the route in your app this frame is the design of; a frame without a route is exported but gets no check.
|
|
113
|
+
- Without `--apply` the command only looks and reports each frame as `new`, `same`, `changed`, `unstable` (the export never settled) or `missing`/`renamed`. `--apply` writes new images, `penpair-baselines.json` (file, revision, sizes, hashes) and `reflection-cases.json`. A `changed` image is replaced only with `--apply --update` and matching exact-artifact owner approval (or an explicitly recorded waiver); see [approval records](approvals.md). The exit code is 2 when a design differs from its image, 3 when a frame is missing, renamed or unstable.
|
|
114
|
+
|
|
115
|
+
New references default to static lossless WebP. `baselines.format` accepts
|
|
116
|
+
`"webp"` or `"png"`; a command's `--format` overrides that choice for new
|
|
117
|
+
references. Existing approved images keep their original encoding during ordinary
|
|
118
|
+
captures and updates, even when config or `--format` selects another format.
|
|
119
|
+
Approved byte hashes are never silently converted.
|
|
120
|
+
|
|
121
|
+
To preview an explicit migration, run `penpair baselines --format webp
|
|
122
|
+
--migrate-format`. After reviewing and recording matching new-format approval,
|
|
123
|
+
apply it with `penpair baselines --format webp --migrate-format --apply --update`.
|
|
124
|
+
`--migrate-format` requires explicit `--format`, and applying it requires
|
|
125
|
+
`--update`. Use `approve --format webp` (plus the intended `--case`, when present)
|
|
126
|
+
to review/record the same encoding; PNG approval cannot approve WebP bytes.
|
|
127
|
+
See [approval and migration details](approvals.md#image-format-and-migration).
|
|
128
|
+
Public `export` and `shots` remain PNG.
|
|
112
129
|
|
|
113
130
|
The generated `reflection-cases.json` holds, per route, the viewports (the image's exact size) and the `visualSmoke` cases (review-only, `strict: false`). A Reflection config uses it like this; only the route's own expectations are written by hand:
|
|
114
131
|
|
|
@@ -169,6 +186,6 @@ Use `inspect <shape-id> --page <name> --all` for bounded structured evidence wit
|
|
|
169
186
|
|
|
170
187
|
## State, theme and responsive coverage
|
|
171
188
|
|
|
172
|
-
Add explicit `frames[].case` metadata and a required matrix under `baselines.coverage`. Case geometry allows less than 0.01 CSS px of Penpot floating-point noise per axis;
|
|
189
|
+
Add explicit `frames[].case` metadata and a required matrix under `baselines.coverage`. Case geometry allows less than 0.01 CSS px of Penpot floating-point noise per axis; encoded image dimensions (PNG or lossless WebP) remain exact at the capture scale, and raw geometry stays in provenance. `baselines coverage --json` validates approved images offline and exposes missing/unsupported slots. Rich cases remain pending browser setup mappings; see [coverage semantics and approval](coverage.md).
|
|
173
190
|
|
|
174
191
|
For project-specific agent tools, use the [explicit-root stdio server and client examples](mcp.md). It exposes typed guarded services and defaults to omitting design-write tools.
|
package/docs/handoff.md
CHANGED
|
@@ -29,6 +29,6 @@ An optional schema-1 component map names exact source identities:
|
|
|
29
29
|
|
|
30
30
|
Names and equal pixels do not establish a mapping. There are no guessed library IDs in shipped maps: the adapter's native component catalogue awaits C1 proof. Static scalar props are owner-declared hints; text props resolve only explicit descendants of that instance. Missing text IDs stay unknown. No inferred click handlers, state transitions, keyboard behavior, accessibility roles, focus order or responsive layout claims are emitted. The current recorded state does not describe every breakpoint or theme.
|
|
31
31
|
|
|
32
|
-
`spec check` regenerates from the supplied structured capture and map, detecting manual edits, source/revision changes and mapping changes (exit 2). It does not contact Penpot or establish current live freshness.
|
|
32
|
+
`spec check` regenerates from the supplied structured capture and map, detecting manual edits, source/revision changes and mapping changes (exit 2). It does not contact Penpot or establish current live freshness. An image export manifest alone cannot prove structural/text freshness; use a new structured inspection rather than treating an unchanged image as proof. Live human handoff/adoption acceptance remains pending under I12; native mapping generation remains gated under C1. JSON output uses the shared command envelope.
|
|
33
33
|
|
|
34
34
|
Owner review can be retained as an [exact-artifact approval record](approvals.md). Changed baseline references require matching supplied owner words or an explicitly labeled waiver; a comparison metric does not supply approval.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Integration maps
|
|
2
|
+
|
|
3
|
+
An integration map links a reviewed user journey to the screens, routes,
|
|
4
|
+
components, state, data and verification work needed to implement it. It gives
|
|
5
|
+
agents a shared project record of what the solution must present and what the
|
|
6
|
+
current implementation actually presents.
|
|
7
|
+
|
|
8
|
+
Start with the [journey map](journey-maps.md) and complete [design evidence](handoff.md).
|
|
9
|
+
Inspect existing code before proposing new modules. Reuse project architecture;
|
|
10
|
+
a visual frame does not justify inventing a backend or component framework.
|
|
11
|
+
|
|
12
|
+
## Local commands
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
penpair integration-map check --from design/integrations/reset-password/map.json
|
|
16
|
+
penpair integration-map render --from design/integrations/reset-password/map.json --out design/integrations/reset-password/rendered
|
|
17
|
+
penpair integration-map context --from design/integrations/reset-password/map.json --out design/integrations/reset-password/context.json
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Use the local project command when installed as a dependency. Add `--live` to a
|
|
21
|
+
check only when an explicit fresh Penpot observation is needed; ordinary saved
|
|
22
|
+
input validation does not establish current live freshness.
|
|
23
|
+
|
|
24
|
+
## Record the gaps before building
|
|
25
|
+
|
|
26
|
+
Use stable requirements and connect each to relevant design cases, proposed or
|
|
27
|
+
existing code responsibilities, data contracts and verification evidence. Mark
|
|
28
|
+
claims `observed`, `proposed`, `owner-decision` or `unknown`. Distinguish visible
|
|
29
|
+
screen state from inferred behavior, and application intent from observed code.
|
|
30
|
+
Keep unresolved component identity, API behavior and accessibility semantics
|
|
31
|
+
explicit.
|
|
32
|
+
|
|
33
|
+
| Requirement | Design observation | Implementation observation | Finding and next action |
|
|
34
|
+
| --- | --- | --- | --- |
|
|
35
|
+
| `reset-error-retry` | Illustrative design has a retryable error with the address retained | Hypothetical implementation clears the address after a failed request | Blocking: the person must retype their address. Preserve the value and verify the failed-request/retry path; this example is not observed project evidence. |
|
|
36
|
+
|
|
37
|
+
Compare both directions: intended requirements without implementation, and
|
|
38
|
+
implemented behavior without an agreed rationale. Link concrete source/evidence
|
|
39
|
+
rather than reporting that a diagram or passing build proves completeness.
|
|
40
|
+
|
|
41
|
+
## Contract, drawings and edits
|
|
42
|
+
|
|
43
|
+
A schema-1 `integration-map` contract uses the same sources, nodes, edges,
|
|
44
|
+
requirements and findings as a journey contract. Its `journey` reference binds the
|
|
45
|
+
project-relative path and exact SHA-256 of its journey map. Component mapping
|
|
46
|
+
still requires exact source identities as described in [handoff](handoff.md);
|
|
47
|
+
familiar labels are insufficient.
|
|
48
|
+
|
|
49
|
+
The `integration-map` command family checks a contract, renders derived diagrams,
|
|
50
|
+
publishes managed native objects, imports native edits as a reviewable proposal,
|
|
51
|
+
accepts a proposal, records supplied owner review and emits bounded context.
|
|
52
|
+
Read installed help for exact arguments. Do not equate `accept` of an edit
|
|
53
|
+
proposal with owner `approve`, image approval or implementation acceptance.
|
|
54
|
+
|
|
55
|
+
Canonical JSON is authoritative. Mermaid, drawing plans and native Penpot boards
|
|
56
|
+
are derived views tied to its hash. A managed Penpot edit must become a proposal
|
|
57
|
+
against that hash; inspect the changes before accepting them. Unmanaged shapes
|
|
58
|
+
and ambiguous identities are not automatic contract edits. Publishing and
|
|
59
|
+
updating native drawings follow the full Penpot write protocol.
|
|
60
|
+
|
|
61
|
+
Semantic native import writes both the canonical proposal and a bound adjacent
|
|
62
|
+
`<proposal>.native.json` observation. Preserve both. Native acceptance rechecks
|
|
63
|
+
the live observation read-only before changing the canonical contract and saved
|
|
64
|
+
baseline; afterward republish explicitly to update native contract metadata.
|
|
65
|
+
A purely local semantic proposal without native observation can be accepted
|
|
66
|
+
offline. If canonical acceptance succeeded but saving the projection failed,
|
|
67
|
+
reconcile with the same proposal rather than blindly publishing again.
|
|
68
|
+
|
|
69
|
+
Geometry-only edits use a separate `map-presentation-proposal`. Acceptance checks
|
|
70
|
+
the exact canonical hash, saved baseline and current observed projection, captures
|
|
71
|
+
fresh stable evidence and adopts presentation without changing canonical bytes.
|
|
72
|
+
Renew native visual review: old review does not automatically cover new render
|
|
73
|
+
evidence. Future publication preserves accepted node positions and sizes.
|
|
74
|
+
Unsupported style/ownership changes and unmanaged objects remain conflicts.
|
|
75
|
+
|
|
76
|
+
Use clear typography, short labels and a neutral diagram theme. The diagram's
|
|
77
|
+
font defaults to Inter; an explicit presentation override belongs to the map.
|
|
78
|
+
Diagram presentation must not modify the application's tokens or theme.
|
|
79
|
+
|
|
80
|
+
## Readable titles and descriptions
|
|
81
|
+
|
|
82
|
+
Existing contracts remain supported. Optional map `summary` and `description`
|
|
83
|
+
add a short introduction and detailed context. A node's existing `label` remains
|
|
84
|
+
its title; optional `summary`, `description` and `icon` supply a one-line purpose,
|
|
85
|
+
longer explanation and semantic icon. Keep labels specific and concise instead
|
|
86
|
+
of repeating “proposed” or “unknown”; the origin badge supplies that distinction.
|
|
87
|
+
Descriptions still need to explain which evidence supports a claim and which
|
|
88
|
+
questions remain unresolved.
|
|
89
|
+
|
|
90
|
+
Native cards use compact titles, summaries, icons and connector ports. Full
|
|
91
|
+
original text and long descriptions remain in managed notes below the flow and
|
|
92
|
+
in generated Markdown/context; they must not disappear when card text is shortened.
|
|
93
|
+
Descriptions and icons belong to canonical intent: edits need proposal review and
|
|
94
|
+
renewed approval. Use one fixed icon key: `screen`, `action`, `decision`, `data`,
|
|
95
|
+
`service`, `code`, `check` or `link`. Icons use native vector paths, with no external
|
|
96
|
+
image URLs or asset downloads.
|
|
97
|
+
|
|
98
|
+
## Linked detail maps
|
|
99
|
+
|
|
100
|
+
Decompose oversized maps explicitly; Penpair does not automatically partition a
|
|
101
|
+
contract. Give each detail map its own canonical contract, native publication
|
|
102
|
+
and owner review. In the parent, a `kind: "detail-link"` node references exactly
|
|
103
|
+
one `sourceId`: that source must have `kind: "contract"`, a project-relative
|
|
104
|
+
`path`, the raw file-byte `sha256`, and exact `fileId`, `pageId` and `frameId` of
|
|
105
|
+
the published detail board in the same pinned file. This source byte hash is
|
|
106
|
+
distinct from the canonical hash used by a journey reference.
|
|
107
|
+
|
|
108
|
+
The linked child must have the same map kind as the parent. The link covers at
|
|
109
|
+
least one parent requirement through `requirementIds`, and the child retains
|
|
110
|
+
all those requirement IDs. Generated Markdown links to the contract; the native
|
|
111
|
+
card uses a `NavigateTo` interaction to its declared board. Missing/stale source
|
|
112
|
+
bytes or incompatible child requirements prevent readiness.
|
|
113
|
+
|
|
114
|
+
Parent context identifies the child handoff and its independent review rather
|
|
115
|
+
than inlining the child graph. Later agents must read that child contract too.
|
|
116
|
+
Include every parent and linked detail contract in the design release with its
|
|
117
|
+
own exact review. Publishing or approving the parent does not publish or approve
|
|
118
|
+
its detail maps.
|
|
119
|
+
|
|
120
|
+
## Implementation context
|
|
121
|
+
|
|
122
|
+
A context result should identify the exact map and journey, review/freshness,
|
|
123
|
+
open findings, requirements and linked source evidence. Bounded or truncated
|
|
124
|
+
context must say so; missing evidence remains pending. Freshness against supplied
|
|
125
|
+
saved files does not assert live Penpot freshness or functional correctness.
|
|
126
|
+
|
|
127
|
+
Later agents should:
|
|
128
|
+
|
|
129
|
+
1. Read the current map context and linked sources before implementing.
|
|
130
|
+
2. Surface stale inputs and blocking findings before relying on approval.
|
|
131
|
+
3. Implement within the reviewed scope; propose changes to intent separately.
|
|
132
|
+
4. Attach actual route/state, browser and behavior evidence to the project record.
|
|
133
|
+
5. Reconcile findings and seek implementation acceptance independently.
|
|
134
|
+
|
|
135
|
+
Use [Reflection Check](adapters.md#check-the-frontend-against-the-design) for actual
|
|
136
|
+
browser comparisons. It supplies visual evidence; behavior and accessibility
|
|
137
|
+
need their own checks. A low pixel difference does not approve architecture or
|
|
138
|
+
prove a working recovery flow.
|
|
139
|
+
|
|
140
|
+
## Design readiness and implementation readiness
|
|
141
|
+
|
|
142
|
+
A [design release](design-releases.md) can finalize a reviewed, internally
|
|
143
|
+
consistent design package while implementation is still `not-assessed`. That
|
|
144
|
+
separation is intentional: agents need stable approved design context before
|
|
145
|
+
they build. Never mark implementation accepted because a map was approved.
|
|
146
|
+
|
|
147
|
+
See the [worked reset-password example](../examples/design-release-maps/README.md)
|
|
148
|
+
for a proposed journey and integration map with visible unknowns.
|
|
149
|
+
|
|
150
|
+
Every local requirement must appear in a node or edge's `requirementIds`, and an
|
|
151
|
+
integration map retains all requirement IDs from its linked journey. Omitted
|
|
152
|
+
coverage prevents readiness and design finalization; drafts can still be checked
|
|
153
|
+
and rendered. Drawing plans explicitly become incomplete above a 16,384 px axis
|
|
154
|
+
or 64 KiB serialized plan budget. Split the map instead of publishing clipped
|
|
155
|
+
content.
|
|
156
|
+
|
|
157
|
+
## Publication recovery
|
|
158
|
+
|
|
159
|
+
After an uncertain write, inspect the actual target and retained run first. Resume
|
|
160
|
+
the original journal explicitly, keeping the original contract, sources and
|
|
161
|
+
target flags (including whether `--board-id` was omitted):
|
|
162
|
+
|
|
163
|
+
```sh
|
|
164
|
+
penpair integration-map publish --from design/integrations/reset-password/map.json \
|
|
165
|
+
--page-id PAGE_ID --apply --resume RUN_ID
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Use the original `--board-id` and `--projection` options if they were supplied.
|
|
169
|
+
Resume independently reconciles readback and exports; it does not blindly repeat
|
|
170
|
+
the write. Changed input or code signatures must refuse reuse. Inspect again and
|
|
171
|
+
start a new explicitly authorized run when needed; do not bypass those guards.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Journey maps
|
|
2
|
+
|
|
3
|
+
A journey map records what a person is trying to accomplish, which states they
|
|
4
|
+
encounter, and the decisions still needed before implementation. It is a
|
|
5
|
+
project-owned contract that later agents can read without recovering earlier
|
|
6
|
+
chats. Use an [integration map](integration-maps.md) to connect the journey to
|
|
7
|
+
application structure, and a [design release](design-releases.md) to freeze a
|
|
8
|
+
reviewed design handoff.
|
|
9
|
+
|
|
10
|
+
## Local commands
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
penpair journey-map check --from design/journeys/reset-password/map.json
|
|
14
|
+
penpair journey-map render --from design/journeys/reset-password/map.json --out design/journeys/reset-password/rendered
|
|
15
|
+
penpair journey-map context --from design/journeys/reset-password/map.json --out design/journeys/reset-password/context.json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Use your project's local command, such as `pnpm exec penpair`, when installed as
|
|
19
|
+
an application dependency. Rendering with `--out` writes local derived artifacts;
|
|
20
|
+
it does not publish into Penpot. Context is intended for reviewed inputs; drafts
|
|
21
|
+
must be explicit and cannot imply readiness.
|
|
22
|
+
|
|
23
|
+
## Start from observed intent
|
|
24
|
+
|
|
25
|
+
Inspect the actual frames and existing application before drafting. Record the
|
|
26
|
+
user goal, entry points, successful outcome, alternate paths and recovery. Use
|
|
27
|
+
stable requirement and node IDs so a finding can refer to the same requirement
|
|
28
|
+
through review and implementation. A frame establishes visible design facts;
|
|
29
|
+
it does not establish what a button does, how an API behaves or how keyboard
|
|
30
|
+
focus moves.
|
|
31
|
+
|
|
32
|
+
Every node, edge and requirement declares its origin:
|
|
33
|
+
|
|
34
|
+
| Origin | Meaning |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| `observed` | Directly supported by the referenced design, code or evidence |
|
|
37
|
+
| `proposed` | An AI or designer recommendation awaiting a decision |
|
|
38
|
+
| `owner-decision` | A decision actually supplied by the owner |
|
|
39
|
+
| `unknown` | Missing information; retain it as a question |
|
|
40
|
+
|
|
41
|
+
An origin is provenance, not approval. In particular, an `owner-decision` label
|
|
42
|
+
cannot replace a review record binding the owner's actual words to the exact
|
|
43
|
+
contract hash. Do not turn guesses into observations or invent approval notes.
|
|
44
|
+
|
|
45
|
+
## Keep the flow readable
|
|
46
|
+
|
|
47
|
+
Use short, specific node titles (`label`), optional one-line `summary` and longer
|
|
48
|
+
`description` text for evidence, decisions and unknowns. The map itself also
|
|
49
|
+
accepts optional `summary` and `description`. Origin badges distinguish observed
|
|
50
|
+
facts from proposals without repeating that status in every title. Optional
|
|
51
|
+
semantic `icon` values use fixed native vectors. Full notes remain available
|
|
52
|
+
below the flow and in Markdown/context; legacy contracts need no new fields.
|
|
53
|
+
See [titles and descriptions](integration-maps.md#readable-titles-and-descriptions).
|
|
54
|
+
These optional fields are part of reviewed canonical intent, so changing them
|
|
55
|
+
needs renewed approval.
|
|
56
|
+
|
|
57
|
+
## Contract and review
|
|
58
|
+
|
|
59
|
+
The schema-1 JSON contract contains `kind: "journey-map"`, `id`, `title`, `goal`,
|
|
60
|
+
`sources`, `nodes`, `edges`, `requirements` and `findings`. Sources retain their
|
|
61
|
+
SHA-256 and available path/file/page/frame/revision identity. Nodes and edges
|
|
62
|
+
carry readable labels and stable IDs; requirement links connect them to the
|
|
63
|
+
intended outcomes. Open blocking findings keep readiness pending. Resolving a
|
|
64
|
+
finding requires an explicit resolution, rather than deleting its history.
|
|
65
|
+
|
|
66
|
+
The `journey-map` command family supports checking, rendering, publishing,
|
|
67
|
+
importing managed edits as proposals, accepting proposals, recording supplied
|
|
68
|
+
approval, and producing bounded context. Consult the installed command's help
|
|
69
|
+
for arguments. Checking and rendering locally do not approve or publish a map.
|
|
70
|
+
Native publication is a Penpot write and needs the normal inspection, pinned
|
|
71
|
+
snapshot, one idempotent write, independent readback and inspected stable export.
|
|
72
|
+
Check the exported typeface against the canvas: a font available to the editor
|
|
73
|
+
can still be unavailable to its exporter. Correct font metadata and identical
|
|
74
|
+
consecutive exports do not prove font fidelity. Visible font substitution needs
|
|
75
|
+
correction before visual approval.
|
|
76
|
+
|
|
77
|
+
The contract is authoritative; Mermaid and native Penpot objects are derived
|
|
78
|
+
views. Managed native edits become a proposal against the exact prior contract
|
|
79
|
+
hash. Review the diff and accept it explicitly before regenerating dependent
|
|
80
|
+
views. A changed label or connector must not silently rewrite accepted intent.
|
|
81
|
+
An old proposal cannot overwrite a newer contract.
|
|
82
|
+
|
|
83
|
+
Owner review is a separate `artifact-review` record containing the artifact
|
|
84
|
+
identity, exact hash, supplied words, identity, date and record hash. Review is
|
|
85
|
+
not authenticated identity. Changed contracts or source hashes need fresh review;
|
|
86
|
+
matching saved inputs do not prove the live file is unchanged.
|
|
87
|
+
|
|
88
|
+
## Review gates
|
|
89
|
+
|
|
90
|
+
1. **Intent ready:** the goal, success/recovery paths, evidence and unknowns are
|
|
91
|
+
explicit. Blocking questions are answered or remain visibly blocking.
|
|
92
|
+
2. **Contract reviewed:** the owner reviewed the exact map and supporting
|
|
93
|
+
decisions. Technical checks and a neat diagram do not supply acceptance.
|
|
94
|
+
3. **Handoff ready:** the integration map references this exact journey hash,
|
|
95
|
+
required design cases exist, and outstanding implementation work is explicit.
|
|
96
|
+
|
|
97
|
+
## Reset-password example
|
|
98
|
+
|
|
99
|
+
The [worked example](../examples/design-release-maps/README.md) describes an
|
|
100
|
+
illustrative reset flow. An observed confirmation frame is distinct from a
|
|
101
|
+
proposed submission transition and an unknown expiry policy. The example is
|
|
102
|
+
unapproved and contains no fabricated inspection or owner evidence.
|
|
103
|
+
|
|
104
|
+
Keep loading, empty, error and success states proportionate to the feature.
|
|
105
|
+
Capture keyboard entry, focus movement, error announcements and responsive
|
|
106
|
+
behavior as explicit requirements or unknowns. The map does not establish that
|
|
107
|
+
any of these behaviors has been implemented or tested.
|
|
108
|
+
|
|
109
|
+
Contracts are bounded to 16 MiB, 1,000 nodes and 2,000 edges. Context has a
|
|
110
|
+
128 KiB limit and reports omissions explicitly. Source paths remain inside the
|
|
111
|
+
project. Labels and descriptions are escaped literal data in generated views.
|
|
112
|
+
|
|
113
|
+
Every local requirement must be connected through node/edge `requirementIds`.
|
|
114
|
+
A readable graph with unmapped requirements remains incomplete for readiness.
|
|
115
|
+
Drawing plans also refuse complete native publication above a 16,384 px axis or
|
|
116
|
+
64 KiB serialized plan size; split large maps into reviewable parts. Semantic
|
|
117
|
+
native imports retain a bound adjacent `.native.json` observation and require
|
|
118
|
+
fresh live readback during acceptance. Pure geometry changes instead produce a
|
|
119
|
+
presentation proposal, preserve canonical intent and require fresh visual review.
|
|
120
|
+
|
|
121
|
+
For explicit decomposition, use [linked detail maps](integration-maps.md#linked-detail-maps).
|
|
122
|
+
Journey details remain journey contracts, with independent publication and review;
|
|
123
|
+
parent approval does not cover a child map automatically.
|
|
124
|
+
|
|
125
|
+
## Publication recovery
|
|
126
|
+
|
|
127
|
+
After an uncertain write, inspect the actual target and retained run first. Resume
|
|
128
|
+
the original journal explicitly, keeping the original contract, sources and
|
|
129
|
+
target flags (including whether `--board-id` was omitted):
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
penpair journey-map publish --from design/journeys/reset-password/map.json \
|
|
133
|
+
--page-id PAGE_ID --apply --resume RUN_ID
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Use the original `--board-id` and `--projection` options if they were supplied.
|
|
137
|
+
Resume independently reconciles readback and exports; it does not blindly repeat
|
|
138
|
+
the write. Changed input or code signatures must refuse reuse. Inspect again and
|
|
139
|
+
start a new explicitly authorized run when needed; do not bypass those guards.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Reviewed-map workflow example
|
|
2
|
+
|
|
3
|
+
These contracts describe a **synthetic, unapproved** reset-password feature.
|
|
4
|
+
They are valid draft inputs, not a real Penpot inspection, code audit, owner
|
|
5
|
+
review or finalized design release. `sample-source.md` is their only observed
|
|
6
|
+
source. Proposed application architecture and unknown policy stay labeled.
|
|
7
|
+
|
|
8
|
+
From the repository root:
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
pnpm build
|
|
12
|
+
node packages/web/dist/cli.js journey-map render --from examples/design-release-maps/journey.json
|
|
13
|
+
node packages/web/dist/cli.js integration-map render --from examples/design-release-maps/integration.json
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Use the installed CLI entrypoint when working from a packaged installation.
|
|
17
|
+
Rendering is offline and establishes neither owner approval nor live fidelity.
|
|
18
|
+
Checks/context should retain the open blockers and missing reviews; this fixture
|
|
19
|
+
is intentionally not ready for implementation or release finalization.
|
|
20
|
+
|
|
21
|
+
## Read the map
|
|
22
|
+
|
|
23
|
+
```mermaid
|
|
24
|
+
flowchart LR
|
|
25
|
+
Entry["Enter email"]
|
|
26
|
+
Confirm["Check your email"]
|
|
27
|
+
Error["Retry request"]
|
|
28
|
+
Entry -->|"Success"| Confirm
|
|
29
|
+
Entry -->|"Failure"| Error
|
|
30
|
+
Error -->|"Retry"| Entry
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Each JSON node uses a concise `label` as its title, a one-line `summary`, a
|
|
34
|
+
longer `description` for evidence and decisions, and a fixed semantic `icon`.
|
|
35
|
+
Native cards show the compact title/summary with origin badges; detailed notes
|
|
36
|
+
retain the full explanation below the flow. The short labels above do not
|
|
37
|
+
change provenance: entry/confirmation are observations of the synthetic text,
|
|
38
|
+
while success, failure and retry behavior remain proposals. Policy and actual
|
|
39
|
+
code/browser evidence remain unknown.
|
|
40
|
+
|
|
41
|
+
This short illustration explains the intended flow; the JSON contract remains
|
|
42
|
+
authoritative. Generate full Mermaid/native drawing plans from it rather than
|
|
43
|
+
editing this illustration as if it updated the contract. A native drawing is
|
|
44
|
+
editable, but managed semantic changes must be imported as proposals, reviewed,
|
|
45
|
+
accepted against their base hash and approved again.
|
|
46
|
+
|
|
47
|
+
| Requirement | Intended result | Hypothetical mismatch | Next action |
|
|
48
|
+
| --- | --- | --- | --- |
|
|
49
|
+
| `reset-error-retry` | Keep the address after a failed request and allow retry | An implementation clears it and makes the person retype it | Confirm the proposed behavior, then test a real failed request and retry. This row is not observed project evidence. |
|
|
50
|
+
|
|
51
|
+
## Three review gates
|
|
52
|
+
|
|
53
|
+
1. **Intent ready:** inspect real source frames; decide request, disclosure,
|
|
54
|
+
expiry, recovery, loading and focus behavior. Do not convert unknown policy
|
|
55
|
+
into an inferred security rule.
|
|
56
|
+
2. **Design package reviewed:** replace synthetic sources with actual inspection
|
|
57
|
+
paths/hashes, review the exact journey/integration maps, assemble target
|
|
58
|
+
native frames in `release/<product-version>`, verify fidelity, then obtain
|
|
59
|
+
the actual owner words for the exact release candidate. Source image
|
|
60
|
+
approval does not approve new target frame identities.
|
|
61
|
+
3. **Implementation accepted:** implement against that stable context, observe
|
|
62
|
+
actual route/state/fixture behavior, compare browser images, test recovery
|
|
63
|
+
and accessibility, and review the results. Finalized design alone cannot
|
|
64
|
+
satisfy this gate.
|
|
65
|
+
|
|
66
|
+
No release plan with invented file IDs, frame IDs, transfer receipts or owner
|
|
67
|
+
words is included. Create a plan only after inspecting the actual pinned file
|
|
68
|
+
and selecting sources. The [release guide](../../docs/design-releases.md)
|
|
69
|
+
describes the native copy, immutable evidence and later drift checks.
|
|
70
|
+
|
|
71
|
+
New baselines default to static lossless WebP. Preserve existing approved PNG
|
|
72
|
+
bytes; format migration is explicit and requires normal exact-byte review.
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"kind": "integration-map",
|
|
4
|
+
"id": "reset-password-integration",
|
|
5
|
+
"title": "Reset implementation",
|
|
6
|
+
"goal": "Connect the proposed reset flow to implementation responsibilities without inventing existing code.",
|
|
7
|
+
"sources": [
|
|
8
|
+
{
|
|
9
|
+
"id": "sample-brief",
|
|
10
|
+
"kind": "other",
|
|
11
|
+
"path": "examples/design-release-maps/sample-source.md",
|
|
12
|
+
"sha256": "ab97f0a30f066e9a9f2689d1624608ea91287751cbc6a613542c0e97de187a96"
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"journey": {
|
|
16
|
+
"path": "examples/design-release-maps/journey.json",
|
|
17
|
+
"sha256": "956fbe3e9d4eb3519d714912ec89bfaedd2a8c2b8882d06dc5ee9c4c279439a9"
|
|
18
|
+
},
|
|
19
|
+
"nodes": [
|
|
20
|
+
{
|
|
21
|
+
"id": "reset-route",
|
|
22
|
+
"label": "Reset route",
|
|
23
|
+
"kind": "route",
|
|
24
|
+
"origin": "proposed",
|
|
25
|
+
"requirementIds": [
|
|
26
|
+
"reset-entry"
|
|
27
|
+
],
|
|
28
|
+
"summary": "Open /reset-password to begin the flow.",
|
|
29
|
+
"description": "Proposed route responsibility: enter the reset flow using the existing application router. The route and surrounding navigation have not been inspected. Reuse the actual project structure rather than treating this illustrative path as an approved architecture decision.",
|
|
30
|
+
"icon": "code"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "reset-form",
|
|
34
|
+
"label": "Reset form",
|
|
35
|
+
"kind": "component",
|
|
36
|
+
"origin": "proposed",
|
|
37
|
+
"requirementIds": [
|
|
38
|
+
"reset-entry",
|
|
39
|
+
"reset-error-retry"
|
|
40
|
+
],
|
|
41
|
+
"summary": "Collect an address and retain it on retry.",
|
|
42
|
+
"description": "Proposed form responsibility: collect the address, follow agreed validation and preserve input during recoverable failure. Inspect existing components before choosing an implementation. Form semantics and behavior need explicit review and real browser evidence.",
|
|
43
|
+
"icon": "screen"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "reset-mutation",
|
|
47
|
+
"label": "Reset service",
|
|
48
|
+
"kind": "data",
|
|
49
|
+
"origin": "unknown",
|
|
50
|
+
"requirementIds": [
|
|
51
|
+
"reset-request",
|
|
52
|
+
"reset-expiry"
|
|
53
|
+
],
|
|
54
|
+
"summary": "Agree the request and response contract.",
|
|
55
|
+
"description": "The endpoint, request payload, validation, response policy and expiry behavior are unknown. Obtain the actual project API and product decisions before implementation. This node does not claim that a service exists or prescribe a new backend.",
|
|
56
|
+
"icon": "service"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"id": "reset-feedback",
|
|
60
|
+
"label": "Request feedback",
|
|
61
|
+
"kind": "state",
|
|
62
|
+
"origin": "proposed",
|
|
63
|
+
"requirementIds": [
|
|
64
|
+
"reset-error-retry",
|
|
65
|
+
"reset-confirmation",
|
|
66
|
+
"reset-focus"
|
|
67
|
+
],
|
|
68
|
+
"summary": "Show confirmation or a recoverable error.",
|
|
69
|
+
"description": "Proposed feedback responsibility: present the agreed confirmation state after an accepted request and useful recovery after failure. Define focus and announcements with the actual application. The synthetic source does not establish these transitions or their accessibility.",
|
|
70
|
+
"icon": "decision"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"id": "browser-case",
|
|
74
|
+
"label": "Verify recovery",
|
|
75
|
+
"kind": "verification",
|
|
76
|
+
"origin": "unknown",
|
|
77
|
+
"requirementIds": [
|
|
78
|
+
"reset-error-retry",
|
|
79
|
+
"reset-confirmation",
|
|
80
|
+
"reset-focus",
|
|
81
|
+
"reset-expiry"
|
|
82
|
+
],
|
|
83
|
+
"summary": "Check retry, focus, and announcements.",
|
|
84
|
+
"description": "Verification is pending. Map approved design cases to actual route/state/fixture setup, then observe failed submission, retained input, retry and confirmation in the real browser. Assess keyboard and screen-reader behavior separately from visual comparison. No provider or result is supplied here.",
|
|
85
|
+
"icon": "check"
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"edges": [
|
|
89
|
+
{
|
|
90
|
+
"id": "route-form",
|
|
91
|
+
"from": "reset-route",
|
|
92
|
+
"to": "reset-form",
|
|
93
|
+
"label": "Compose",
|
|
94
|
+
"origin": "proposed",
|
|
95
|
+
"requirementIds": [
|
|
96
|
+
"reset-entry"
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"id": "form-request",
|
|
101
|
+
"from": "reset-form",
|
|
102
|
+
"to": "reset-mutation",
|
|
103
|
+
"label": "Submit",
|
|
104
|
+
"origin": "unknown",
|
|
105
|
+
"requirementIds": [
|
|
106
|
+
"reset-request"
|
|
107
|
+
]
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"id": "request-feedback",
|
|
111
|
+
"from": "reset-mutation",
|
|
112
|
+
"to": "reset-feedback",
|
|
113
|
+
"label": "Handle result",
|
|
114
|
+
"origin": "proposed",
|
|
115
|
+
"requirementIds": [
|
|
116
|
+
"reset-error-retry"
|
|
117
|
+
]
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"id": "feedback-evidence",
|
|
121
|
+
"from": "reset-feedback",
|
|
122
|
+
"to": "browser-case",
|
|
123
|
+
"label": "Verify behavior",
|
|
124
|
+
"origin": "proposed",
|
|
125
|
+
"requirementIds": [
|
|
126
|
+
"reset-error-retry"
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
"requirements": [
|
|
131
|
+
{
|
|
132
|
+
"id": "reset-entry",
|
|
133
|
+
"text": "Proposed: map the entry screen to the project route and existing form conventions after inspecting code.",
|
|
134
|
+
"origin": "proposed"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"id": "reset-request",
|
|
138
|
+
"text": "Unknown: endpoint, validation and response policy require the actual project contract.",
|
|
139
|
+
"origin": "unknown"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"id": "reset-error-retry",
|
|
143
|
+
"text": "Proposed: retain the entered address on failure; verify retry and accessible feedback in the real browser.",
|
|
144
|
+
"origin": "proposed"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"id": "reset-confirmation",
|
|
148
|
+
"text": "Proposed: render confirmation only after the agreed response; final request policy remains unknown.",
|
|
149
|
+
"origin": "proposed"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"id": "reset-expiry",
|
|
153
|
+
"text": "Unknown: expiry/repeated request behavior must follow the agreed product/security contract.",
|
|
154
|
+
"origin": "unknown"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"id": "reset-focus",
|
|
158
|
+
"text": "Proposed: implement and verify keyboard focus and announced error recovery.",
|
|
159
|
+
"origin": "proposed"
|
|
160
|
+
}
|
|
161
|
+
],
|
|
162
|
+
"findings": [
|
|
163
|
+
{
|
|
164
|
+
"id": "code-not-inspected",
|
|
165
|
+
"message": "No application code, route or component identity has been inspected for this synthetic example.",
|
|
166
|
+
"severity": "blocking",
|
|
167
|
+
"status": "open"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"id": "provider-pending",
|
|
171
|
+
"message": "No approved design cases, actual provider or browser evidence are supplied.",
|
|
172
|
+
"severity": "blocking",
|
|
173
|
+
"status": "open"
|
|
174
|
+
}
|
|
175
|
+
],
|
|
176
|
+
"presentation": {
|
|
177
|
+
"fontFamily": "Inter"
|
|
178
|
+
},
|
|
179
|
+
"summary": "Connect the reset flow to application responsibilities.",
|
|
180
|
+
"description": "This unapproved integration proposal links the synthetic journey to a route, form, service contract, feedback states and verification work. No application code, API or browser behavior has been inspected. Every proposed responsibility needs project evidence and review before implementation."
|
|
181
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"kind": "journey-map",
|
|
4
|
+
"id": "reset-password-journey",
|
|
5
|
+
"title": "Reset password",
|
|
6
|
+
"goal": "Request password-reset instructions and understand the next step.",
|
|
7
|
+
"sources": [
|
|
8
|
+
{
|
|
9
|
+
"id": "sample-brief",
|
|
10
|
+
"kind": "other",
|
|
11
|
+
"path": "examples/design-release-maps/sample-source.md",
|
|
12
|
+
"sha256": "ab97f0a30f066e9a9f2689d1624608ea91287751cbc6a613542c0e97de187a96"
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"nodes": [
|
|
16
|
+
{
|
|
17
|
+
"id": "address-entry",
|
|
18
|
+
"label": "Enter email",
|
|
19
|
+
"kind": "screen",
|
|
20
|
+
"origin": "observed",
|
|
21
|
+
"sourceIds": [
|
|
22
|
+
"sample-brief"
|
|
23
|
+
],
|
|
24
|
+
"requirementIds": [
|
|
25
|
+
"reset-entry"
|
|
26
|
+
],
|
|
27
|
+
"summary": "Provide an address for reset instructions.",
|
|
28
|
+
"description": "The synthetic brief includes an address-entry screen. No Penpot frame or application has been inspected. Field validation, submission behavior and the final wording still require project evidence or review.",
|
|
29
|
+
"icon": "screen"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "confirmation",
|
|
33
|
+
"label": "Check your email",
|
|
34
|
+
"kind": "screen",
|
|
35
|
+
"origin": "observed",
|
|
36
|
+
"sourceIds": [
|
|
37
|
+
"sample-brief"
|
|
38
|
+
],
|
|
39
|
+
"requirementIds": [
|
|
40
|
+
"reset-confirmation"
|
|
41
|
+
],
|
|
42
|
+
"summary": "Explain the next step after the request.",
|
|
43
|
+
"description": "The synthetic brief includes a confirmation screen. Its success transition and response messaging are proposed, not observed. Confirm the actual request and account-disclosure policy before implementing this state.",
|
|
44
|
+
"icon": "screen"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "recoverable-error",
|
|
48
|
+
"label": "Retry request",
|
|
49
|
+
"kind": "state",
|
|
50
|
+
"origin": "proposed",
|
|
51
|
+
"requirementIds": [
|
|
52
|
+
"reset-error-retry"
|
|
53
|
+
],
|
|
54
|
+
"summary": "Keep the address and offer a retry.",
|
|
55
|
+
"description": "Proposed recovery preserves the entered address after a failed request, explains the failure and allows another attempt. No inspected design or implementation establishes this behavior yet. Review it, then verify a real failure and retry.",
|
|
56
|
+
"icon": "action"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"id": "expiry-policy",
|
|
60
|
+
"label": "Request policy",
|
|
61
|
+
"kind": "decision",
|
|
62
|
+
"origin": "unknown",
|
|
63
|
+
"requirementIds": [
|
|
64
|
+
"reset-expiry"
|
|
65
|
+
],
|
|
66
|
+
"summary": "Decide expiry and repeat-request behavior.",
|
|
67
|
+
"description": "The source provides no expiry, repeat-request or disclosure policy. Obtain the actual product and service contract before deciding what the interface should say or do. This is an unresolved requirement, not an inferred security rule.",
|
|
68
|
+
"icon": "decision"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"id": "focus-recovery",
|
|
72
|
+
"label": "Accessible recovery",
|
|
73
|
+
"kind": "behavior",
|
|
74
|
+
"origin": "proposed",
|
|
75
|
+
"requirementIds": [
|
|
76
|
+
"reset-focus"
|
|
77
|
+
],
|
|
78
|
+
"summary": "Announce errors and guide keyboard focus.",
|
|
79
|
+
"description": "Proposed accessible recovery should explain failures to screen-reader users and support keyboard correction and retry. Exact focus destinations, announcement behavior and implementation checks remain to be defined and tested.",
|
|
80
|
+
"icon": "check"
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"edges": [
|
|
84
|
+
{
|
|
85
|
+
"id": "request-success",
|
|
86
|
+
"from": "address-entry",
|
|
87
|
+
"to": "confirmation",
|
|
88
|
+
"label": "Success",
|
|
89
|
+
"origin": "proposed",
|
|
90
|
+
"requirementIds": [
|
|
91
|
+
"reset-confirmation"
|
|
92
|
+
]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"id": "request-failure",
|
|
96
|
+
"from": "address-entry",
|
|
97
|
+
"to": "recoverable-error",
|
|
98
|
+
"label": "Failure",
|
|
99
|
+
"origin": "proposed",
|
|
100
|
+
"requirementIds": [
|
|
101
|
+
"reset-error-retry"
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"id": "retry",
|
|
106
|
+
"from": "recoverable-error",
|
|
107
|
+
"to": "address-entry",
|
|
108
|
+
"label": "Retry",
|
|
109
|
+
"origin": "proposed",
|
|
110
|
+
"requirementIds": [
|
|
111
|
+
"reset-error-retry"
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"id": "expiry-decision",
|
|
116
|
+
"from": "address-entry",
|
|
117
|
+
"to": "expiry-policy",
|
|
118
|
+
"label": "Resolve policy",
|
|
119
|
+
"origin": "unknown",
|
|
120
|
+
"requirementIds": [
|
|
121
|
+
"reset-expiry"
|
|
122
|
+
]
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"id": "focus-requirement",
|
|
126
|
+
"from": "recoverable-error",
|
|
127
|
+
"to": "focus-recovery",
|
|
128
|
+
"label": "Accessible feedback",
|
|
129
|
+
"origin": "proposed",
|
|
130
|
+
"requirementIds": [
|
|
131
|
+
"reset-focus"
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
"requirements": [
|
|
136
|
+
{
|
|
137
|
+
"id": "reset-entry",
|
|
138
|
+
"text": "The synthetic source includes an address-entry screen.",
|
|
139
|
+
"origin": "observed",
|
|
140
|
+
"sourceIds": [
|
|
141
|
+
"sample-brief"
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"id": "reset-confirmation",
|
|
146
|
+
"text": "The synthetic source includes a confirmation screen; its actual transition is proposed.",
|
|
147
|
+
"origin": "observed",
|
|
148
|
+
"sourceIds": [
|
|
149
|
+
"sample-brief"
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"id": "reset-error-retry",
|
|
154
|
+
"text": "Proposed: preserve the entered address after a failed request and allow retry.",
|
|
155
|
+
"origin": "proposed"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"id": "reset-expiry",
|
|
159
|
+
"text": "Unknown: expiry policy and treatment of repeated requests require a product/security decision.",
|
|
160
|
+
"origin": "unknown"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"id": "reset-focus",
|
|
164
|
+
"text": "Proposed: focus and announced errors must support keyboard and screen-reader recovery.",
|
|
165
|
+
"origin": "proposed"
|
|
166
|
+
}
|
|
167
|
+
],
|
|
168
|
+
"findings": [
|
|
169
|
+
{
|
|
170
|
+
"id": "decide-request-contract",
|
|
171
|
+
"message": "No actual API contract or account-disclosure policy has been supplied.",
|
|
172
|
+
"severity": "blocking",
|
|
173
|
+
"status": "open"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"id": "design-error-state",
|
|
177
|
+
"message": "Recovery and accessible error presentation are proposals; no inspected frame supports them.",
|
|
178
|
+
"severity": "warning",
|
|
179
|
+
"status": "open"
|
|
180
|
+
}
|
|
181
|
+
],
|
|
182
|
+
"presentation": {
|
|
183
|
+
"fontFamily": "Inter"
|
|
184
|
+
},
|
|
185
|
+
"summary": "Request reset instructions and recover from failure.",
|
|
186
|
+
"description": "This unapproved planning fixture is grounded only in the synthetic brief. It illustrates the proposed reset flow without claiming inspected Penpot frames, actual application behavior or owner agreement. Request policy, recovery and accessibility behavior remain explicit decisions and verification work."
|
|
187
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Synthetic reset-password source
|
|
2
|
+
|
|
3
|
+
This is illustrative fixture text, not a Penpot inspection or approved product
|
|
4
|
+
requirement. It supplies reproducible local source bytes for the map examples.
|
|
5
|
+
|
|
6
|
+
The sample includes an address-entry screen and a confirmation screen.
|
|
7
|
+
The intended user goal is to request password-reset instructions.
|
|
8
|
+
No API, expiry policy, error recovery or focus behavior is established here.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@penpair/web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "The penpair command for Penpot on the web (design.penpot.app or your team's own): guided setup, a safe write protocol, skills for AI agents. Includes everything in @penpair/core.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"access": "public"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@penpair/core": "0.
|
|
51
|
+
"@penpair/core": "0.4.0"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
54
|
"build": "tsc -p tsconfig.json",
|