reflection-projection
v0.5.0
Published
Neutral evidence projection and immutable bundles for Reflection: schemas, readiness, validity, decisions, release diffs, and a bundle reader and writer.
Maintainers
Readme
reflection-projection
The neutral contract between a project that proves a design against its implementation and anything that shows the result: reflection-check-ui, the release portal, a CLI. It has no knowledge of Figma, Penpot, a component framework or Discord.
pnpm add reflection-projectionA provider turns its own evidence into a Projection. The reader never needs to know where it came from.
What is in a projection
| Part | What it says |
| --- | --- |
| requirements | Everything that must be proven, whether or not a comparison exists. Readiness is derived, never stored |
| comparisons | One check of a design reference against a rendered result: proof per layer, artifacts with roles and hashes, a verdict, optional measurements, the reference approval |
| snapshots | The design data something was proven against. Several can coexist, so a full sync date never hides an older proof-source date |
| runs | Engine, runner, inputs[] and result hashes, so validity can be computed when the evidence is read |
| decisions | Human decisions, bound to content (verdicts, reference hashes, capture policies, the required set), never to a run |
| release, delta | The release manifest and what changed since the previous release |
| subjects | Optional facts about a component family or page: label, description, link to the design source, a change note in the provider's words |
Rules the schema enforces
- Five signals stay separate: proof (
passed,failed,not-run,unsupported), readiness (derived), validity (computed on read), reference approval, review (decisions). - A requirement may name required implementations. Then each must have a comparison and pass; a missing one leaves the item not proven (a failure still reads as failing).
- Coverage never appears in proof. A required layer that is
not-runorunsupportedcan never make a requirementproven. - A bucket the provider has no concept of is
null, never 0.requiredalways equals the sum of the buckets. - An approval that holds or lapsed says who recorded it:
human,delegated(a person's words, written down by an agent, withby,recordedByand the words) oragent. Onlyagentis not a person's approval, and only a legacy reference approval may be agent-recorded. - Artifact paths are relative and may not contain
... - Ids are unique and every reference resolves (requirement, run, snapshot, decision).
Functions
deriveReadiness,summarizeReadiness,summarizeProjection: the one place readiness is counted.computeValidity(recorded, current):current,stalewith the exact changed inputs,invalid,never-runoroffline. Pure. The caller hashes the current inputs with the engine'shashReportInputs.buildDecisionBinding,evaluateDecision:holds,carried-forward(identical results on a rebuilt bundle),lapsedwith named causes, orwithdrawn.diffProjections(previous, current): what differs between two releases. Subjects and required items added, removed or updated (a reference counts as updated only when both releases recorded a hash and the hashes differ, or one had a reference and the other none), plus regressed, fixed, still failing and newly enrolled comparisons. Pure, from recorded data only, separate from verification outcomes.comparisonOutcome,countComparisons: the outcome of a comparison from its proof layers only, and comparison counts in their own unit.projectFromReflectionReport: the native provider. The engine cannot declare required items, so its inventory isexecuted-onlyand coverage is a lower bound.
Bundles
A release is published as an immutable bundle: manifest.json (project, release, generator, every file's path, kind, sha256 and size, and a bundleHash over all of them), projection.json (the entry), the artifacts it points at, and optional source/ and analysis files. Paths are relative with / separators; only images and text are allowed (no SVG or HTML), and _raw content is refused.
openBundle(source, { verifyFiles })reads a bundle from anyBundleSource(a directory, an HTTP origin, memory) and never throws for bad content. A bundle that cannot be trusted as a whole comes backrejected(missing or invalid manifest, unsupported schema version, changed manifest or projection, wrong project). One with a missing, unreadable, tampered or undeclared file comes backopenedwithproblemsandunusablePaths, so the inventory stays visible and only that evidence is withheld.toIntegrityFailuresfeedscomputeValidity.verifyBundleFilereads one declared file and checks its hash; a viewer calls it when it loads an image.writeBundleandcreateDirectorySourceare Node-only and live inreflection-projection/node. The writer streams files, fills in missing artifact hashes, refuses to overwrite, refuses text that holds a local path or an obvious credential, and renames a finished temporary directory into place.foldNotes,countNotesandnoteEventSchema: per-family notes as an append-only event log (added, resolved, retracted). A note never changes an outcome.buildArchiveSummaryandarchiveSummarySchema: what remains after a release leaves its slot (counts, decision, snapshot dates, notes at exit).
Writing a provider: see docs/provider-guide.md.
Hosting the viewer
The built viewer ships in viewer/ as static files with relative paths: copy the folder to any base path, put bundles and an index.json beside it, and optionally a reflection-config.json and a decision API. releaseIndexSchema, recordDecisionRequestSchema, decisionListSchema and recordDecision are the shapes and the server-side helper. See docs/hosting.md.
Conventions
Property names are camelCase, matching the engine's report. Ids, enum values, file and folder names are kebab-case (needs-design, changes-required, canonical-json).
JSON Schema
schema/projection.v1.schema.json is generated from the Zod schema (pnpm schema) so providers in other repositories can validate without importing this package. schema/release-index.v1.schema.json, schema/decision-request.v1.schema.json and schema/decision-list.v1.schema.json do the same for hosts. It covers structure only. Integrity rules (unique ids, resolving references, relative paths, decision rules) need the Zod schema. A test fails if the committed file drifts from the Zod schema.
Fixtures
tests/fixtures holds four shapes: a real native report, two samples mapped from real projects, and an independent project (screenshots, browsers as adapters). The samples carry only the comparisons and requirements that were really read. The test builder adds clearly named placeholder/ requirements to reach their real totals, so the counts can be asserted without inventing detail.
