@nextcommerce/campaigns-os 1.33.0 → 1.37.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +42 -13
- package/CHANGELOG.md +129 -0
- package/README.md +42 -20
- package/compatibility.json +1 -1
- package/contracts/agent-relevant-change-policy.v1.json +1 -0
- package/contracts/fixtures/progress/observation.v0.json +89 -0
- package/contracts/fixtures/runtime-recipe/accept/current.json +3 -5
- package/contracts/fixtures/runtime-recipe/accept/minimal.json +3 -5
- package/contracts/fixtures/runtime-recipe/reject/advisory-enforcement.json +3 -5
- package/contracts/fixtures/runtime-recipe/reject/allowlist-without-hosts.json +3 -5
- package/contracts/fixtures/runtime-recipe/reject/committed-output-claim.json +3 -5
- package/contracts/fixtures/runtime-recipe/reject/engines-disagreement-warns.json +3 -5
- package/contracts/fixtures/runtime-recipe/reject/lifecycle-scripts-enabled.json +3 -5
- package/contracts/fixtures/runtime-recipe/reject/missing-required-field.json +3 -5
- package/contracts/fixtures/runtime-recipe/reject/unknown-kind.json +3 -5
- package/contracts/fixtures/runtime-recipe/reject/unknown-network-policy.json +3 -5
- package/contracts/fixtures/runtime-recipe/reject/unknown-output-check.json +3 -5
- package/contracts/fixtures/runtime-recipe/reject/unknown-revision.json +2 -4
- package/contracts/fixtures/runtime-recipe/reject/unknown-step-id.json +3 -5
- package/contracts/fixtures/runtime-recipe/reject/unperformable-check-skipped.json +3 -5
- package/contracts/fixtures/runtime-recipe/reject/unpinned-lockfile.json +3 -5
- package/contracts/release-ledger.json +614 -0
- package/contracts/runtime-recipe.campaigns-os-node-v1.json +3 -5
- package/contracts/supported-surface.json +23 -6
- package/demo/apollo-v0/NOTICE.txt +51 -0
- package/demo/apollo-v0/assets/css/demo.css +2 -0
- package/demo/apollo-v0/assets/css/landing/tokens.css +35 -0
- package/demo/apollo-v0/assets/css/next-core.css +16124 -0
- package/demo/apollo-v0/assets/images/1x1_1.svg +19 -0
- package/demo/apollo-v0/assets/images/1x1_2.svg +19 -0
- package/demo/apollo-v0/assets/images/affirm-logo.svg +24 -0
- package/demo/apollo-v0/assets/images/apple-pay-logo.svg +4 -0
- package/demo/apollo-v0/assets/images/bancontact-logo.svg +1 -0
- package/demo/apollo-v0/assets/images/cc-visa.svg +28 -0
- package/demo/apollo-v0/assets/images/cc_amex.svg +20 -0
- package/demo/apollo-v0/assets/images/cc_discover.svg +21 -0
- package/demo/apollo-v0/assets/images/cc_master.svg +22 -0
- package/demo/apollo-v0/assets/images/credit-card-flags.svg +38 -0
- package/demo/apollo-v0/assets/images/demo-inline-40788e52a7c75b78.svg +1 -0
- package/demo/apollo-v0/assets/images/demo-inline-686e73c8840a0f0a.svg +1 -0
- package/demo/apollo-v0/assets/images/google-pay-logo.svg +7 -0
- package/demo/apollo-v0/assets/images/guarantee-badge.png +0 -0
- package/demo/apollo-v0/assets/images/icon-dollar.svg +5 -0
- package/demo/apollo-v0/assets/images/icon-guarantee.svg +5 -0
- package/demo/apollo-v0/assets/images/icon-shipping.svg +5 -0
- package/demo/apollo-v0/assets/images/icons8-lock-24_1icons8-lock-24.png +0 -0
- package/demo/apollo-v0/assets/images/ideal-logo.svg +30 -0
- package/demo/apollo-v0/assets/images/klarna-logo.svg +9 -0
- package/demo/apollo-v0/assets/images/landing/_shared/16x9.svg +19 -0
- package/demo/apollo-v0/assets/images/landing/_shared/1x1_1.svg +19 -0
- package/demo/apollo-v0/assets/images/landing/_shared/4x3.svg +19 -0
- package/demo/apollo-v0/assets/images/landing/_shared/arrow-right.svg +6 -0
- package/demo/apollo-v0/assets/images/landing/_shared/cta-guarantee-icon.png +0 -0
- package/demo/apollo-v0/assets/images/landing/benefits-2/benefits-2-icon-1.svg +8 -0
- package/demo/apollo-v0/assets/images/landing/benefits-2/benefits-2-icon-2.svg +10 -0
- package/demo/apollo-v0/assets/images/landing/benefits-2/benefits-2-icon-3.svg +13 -0
- package/demo/apollo-v0/assets/images/landing/benefits-2/benefits-2-icon-4.svg +11 -0
- package/demo/apollo-v0/assets/images/landing/benefits-2/benefits-2-quote.svg +6 -0
- package/demo/apollo-v0/assets/images/landing/benefits-2/benefits-2-verified.svg +10 -0
- package/demo/apollo-v0/assets/images/landing/bottomcta-1/check-bullet.svg +5 -0
- package/demo/apollo-v0/assets/images/landing/faq-1/faq-chevron.svg +6 -0
- package/demo/apollo-v0/assets/images/landing/footer-1/footer-logo.png +0 -0
- package/demo/apollo-v0/assets/images/landing/guarantee-1/guarantee-1-badge.svg +8 -0
- package/demo/apollo-v0/assets/images/landing/hero-1/icon-check.svg +5 -0
- package/demo/apollo-v0/assets/images/landing/hero-1/icon-star.svg +6 -0
- package/demo/apollo-v0/assets/images/landing/hero-1/icon-verified.svg +6 -0
- package/demo/apollo-v0/assets/images/landing/icons-5/icon-batteries.svg +7 -0
- package/demo/apollo-v0/assets/images/landing/icons-5/icon-cuff-checking.svg +6 -0
- package/demo/apollo-v0/assets/images/landing/icons-5/icon-dual-user.svg +5 -0
- package/demo/apollo-v0/assets/images/landing/icons-5/icon-fda-cleared.svg +5 -0
- package/demo/apollo-v0/assets/images/landing/icons-5/icon-heartbeat.svg +17 -0
- package/demo/apollo-v0/assets/images/landing/icons-5/icon-lcd-display.svg +10 -0
- package/demo/apollo-v0/assets/images/landing/icons-5/icon-movement-error.svg +7 -0
- package/demo/apollo-v0/assets/images/landing/icons-5/icon-portable.png +0 -0
- package/demo/apollo-v0/assets/images/landing/icons-5/icon-reading-memory.svg +6 -0
- package/demo/apollo-v0/assets/images/landing/icons-5/icon-wrist-comfort.svg +5 -0
- package/demo/apollo-v0/assets/images/landing/ingredients-3/ingredients-3-card-1.jpg +0 -0
- package/demo/apollo-v0/assets/images/landing/ingredients-3/ingredients-3-card-2.jpg +0 -0
- package/demo/apollo-v0/assets/images/landing/ingredients-3/ingredients-3-card-3.jpg +0 -0
- package/demo/apollo-v0/assets/images/landing/ingredients-3/ingredients-3-card-4.jpg +0 -0
- package/demo/apollo-v0/assets/images/landing/ingredients-3/ingredients-3-promise-1.png +0 -0
- package/demo/apollo-v0/assets/images/landing/ingredients-3/ingredients-3-promise-2.png +0 -0
- package/demo/apollo-v0/assets/images/landing/ingredients-3/ingredients-3-promise-3.png +0 -0
- package/demo/apollo-v0/assets/images/landing/ingredients-3/ingredients-3-promise-4.png +0 -0
- package/demo/apollo-v0/assets/images/landing/ingredients-3/ingredients-3-promise-5.png +0 -0
- package/demo/apollo-v0/assets/images/landing/ingredients-3/ingredients-3-promise-6.png +0 -0
- package/demo/apollo-v0/assets/images/landing/nav-1/flag-us.png +0 -0
- package/demo/apollo-v0/assets/images/landing/reviews-3/star-card.svg +3 -0
- package/demo/apollo-v0/assets/images/landing/reviews-3/star-lg.svg +3 -0
- package/demo/apollo-v0/assets/images/landing/reviews-3/star-sm.svg +3 -0
- package/demo/apollo-v0/assets/images/landing/reviews-3/verified.svg +10 -0
- package/demo/apollo-v0/assets/images/landing/testimonials-2/testimonials-2-reactions.svg +9 -0
- package/demo/apollo-v0/assets/images/landing/testimonials-2/testimonials-2-stars.svg +6 -0
- package/demo/apollo-v0/assets/images/link-logo.svg +1 -0
- package/demo/apollo-v0/assets/images/next-dark.svg +8 -0
- package/demo/apollo-v0/assets/images/paypal-logo.svg +5 -0
- package/demo/apollo-v0/assets/images/paypal-txt.svg +8 -0
- package/demo/apollo-v0/assets/images/paypal.svg +22 -0
- package/demo/apollo-v0/assets/images/sepa-logo.svg +275 -0
- package/demo/apollo-v0/assets/images/twint-logo.svg +1 -0
- package/demo/apollo-v0/assets/images/united-states-flag-icon.webp +0 -0
- package/demo/apollo-v0/assets/images/upsell-payment-logos.svg +38 -0
- package/demo/apollo-v0/assets/images/usps.png +0 -0
- package/demo/apollo-v0/checkout/index.html +1370 -0
- package/demo/apollo-v0/landing/index.html +1836 -0
- package/demo/apollo-v0/provenance.json +342 -0
- package/demo/apollo-v0/receipt/index.html +292 -0
- package/demo/apollo-v0/upsell-bundle-stepper/index.html +401 -0
- package/docs/activation-and-evidence.md +37 -0
- package/docs/demo-preview.md +63 -0
- package/docs/diagnostics.md +55 -0
- package/docs/orientation-contract-reference.md +3 -1
- package/docs/progress-snapshots.md +142 -0
- package/docs/qa-and-test-orders.md +26 -0
- package/docs/runtime-readiness.md +3 -3
- package/docs/sdk-storage-compatibility.md +19 -0
- package/docs/supported-surface.md +14 -1
- package/docs/versioning.md +1 -1
- package/package.json +22 -8
- package/schemas/campaign-runtime-build-context.v0.schema.json +42 -0
- package/schemas/campaigns-os-progress-snapshot.v0.schema.json +370 -0
- package/skills/next-campaigns-build/SKILL.md +17 -1
- package/skills/next-campaigns-os/SKILL.md +19 -3
- package/skills/next-campaigns-os-setup/SKILL.md +17 -1
- package/skills/next-campaigns-polish/SKILL.md +18 -2
- package/skills/next-campaigns-qa/SKILL.md +24 -8
- package/skills.json +5 -5
- package/src/cli.mjs +96 -6
- package/src/consent.mjs +2 -2
- package/src/demo-artifact.mjs +97 -0
- package/src/demo.mjs +85 -0
- package/src/diagnostic.mjs +101 -0
- package/src/install-mode.mjs +13 -1
- package/src/progress-node.mjs +177 -0
- package/src/progress.mjs +133 -0
- package/src/sdk-storage-compatibility.mjs +359 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Minimal progress observations
|
|
2
|
+
|
|
3
|
+
Candidate release **1.36.0** adds the portable `@nextcommerce/campaigns-os/progress`
|
|
4
|
+
export and `schemas/campaigns-os-progress-snapshot.v0.schema.json`. The currently
|
|
5
|
+
published install example does not include this feature. Progress is a compact
|
|
6
|
+
observation of the existing lifecycle, not a second workflow or proof of readiness.
|
|
7
|
+
|
|
8
|
+
`next --packet <packet>` records the canonical picker result after the same doctor
|
|
9
|
+
checks that supply its continuation and gates. Agents run `next` after setup,
|
|
10
|
+
assembly, polish and preview deployment so those committed stage reports become
|
|
11
|
+
visible. The CLI `build` command prepares inputs and runs doctor; it does not build
|
|
12
|
+
or deploy the campaign. Preview's existing stage is `deploy`. Arbitrary edits are
|
|
13
|
+
not tracked. `qa run --packet <packet>` observes its successfully committed or
|
|
14
|
+
unchanged QA report before the existing closeout: ready QA closes its run once,
|
|
15
|
+
blocked QA keeps it open. A progress delivery cannot close a run.
|
|
16
|
+
|
|
17
|
+
## What is shared
|
|
18
|
+
|
|
19
|
+
The strict v0 object carries its schema, package version, observation timestamp,
|
|
20
|
+
producer (`next` or `qa`), opaque progress stream and sequence, prior snapshot ID,
|
|
21
|
+
content digest, Map ID and separate revision/spec/build hashes. Six independent
|
|
22
|
+
stage records retain observed status and explicit build binding. Continuation
|
|
23
|
+
retains the canonical stage, blocked/divergent flags, fixed action IDs and gate
|
|
24
|
+
states. Preview carries only presence and a hash of the URL. An optional QA block
|
|
25
|
+
retains the exact verdict ID, disposition (including `ready_with_exceptions`),
|
|
26
|
+
binding and publication state. Publication failure does not invalidate a locally
|
|
27
|
+
retained verdict; recovery uses `qa publish`, without repeating an order.
|
|
28
|
+
|
|
29
|
+
No commands, prompts, free text, content, local paths, URLs, query strings,
|
|
30
|
+
credentials, order values or customer payloads enter the wire. Unknown vocabulary
|
|
31
|
+
becomes a fixed `unknown` marker and cannot imply a passing continuation. A
|
|
32
|
+
stage's observed `completed` status is a ledger claim, not independent verification.
|
|
33
|
+
Only matching fingerprints carry `matching`; absent or unverifiable binding is
|
|
34
|
+
`unconfirmed`. A current local output hash never proves a deployment is current.
|
|
35
|
+
|
|
36
|
+
The identity algorithms are deliberately different:
|
|
37
|
+
|
|
38
|
+
- `map-store-v1` retains the original saved Map hash. A fresh Map fetch records
|
|
39
|
+
that hash and the fetched local semantic baseline in Build Context intake.
|
|
40
|
+
Saved revision alignment is `aligned` only while the local spec still matches
|
|
41
|
+
that baseline and the context names this packet and Map. Existing contexts,
|
|
42
|
+
offline caches and local exports without that provenance remain `unconfirmed`.
|
|
43
|
+
The saved hash may still be retained as identity; it alone proves no alignment.
|
|
44
|
+
- `campaign-spec-material-v1` hashes recursively key-sorted JSON after removing
|
|
45
|
+
top-level `spec_identity`, `slug`, `map_id` and `saved_at`, as existing
|
|
46
|
+
`specMaterialHash` does. It includes lifecycle and parent Map fields that the
|
|
47
|
+
saved Map producer excludes. It must never be compared as a Map-store hash.
|
|
48
|
+
Assembly Report `identity.spec_hash` is a raw-byte hash and is not this value.
|
|
49
|
+
- `sha256-manifest/v1` is the existing doctor's output fingerprint: SHA-256 of
|
|
50
|
+
the sorted relative-path and file-SHA-256 manifest under the built route.
|
|
51
|
+
Reported assembly/QA binding uses the doctor's actual observed output and its
|
|
52
|
+
recorded-fingerprint comparison. Missing output remains nullable/unconfirmed.
|
|
53
|
+
|
|
54
|
+
Different Map revisions, local specs, builds, packet/context/report bindings and
|
|
55
|
+
endpoint scopes have independent streams. Completed stages cannot be combined
|
|
56
|
+
across them. A progress stream is independent of a run-session ID.
|
|
57
|
+
|
|
58
|
+
## Capture and delivery
|
|
59
|
+
|
|
60
|
+
Sanitized immutable snapshots are written under the target repository's
|
|
61
|
+
`.campaign-runtime/progress/` before any request. Allocation uses an exclusive
|
|
62
|
+
local lock with a process owner. Dead owners are recovered through an exclusive
|
|
63
|
+
recovery claim and an atomic rename; a live process is never evicted. An ownerless
|
|
64
|
+
crash gap is recoverable after ten seconds. If recovery itself is interrupted,
|
|
65
|
+
capture fails closed: stop all Campaigns OS writers for that target, then remove
|
|
66
|
+
the abandoned `.allocation-lock` directory in the affected progress scope before
|
|
67
|
+
retrying `next`. Do not remove a lock while a writer is active.
|
|
68
|
+
|
|
69
|
+
An unchanged projection reuses its ID, timestamp and sequence. Identity
|
|
70
|
+
changes start a new stream. Each local scope retains at most 32 snapshots and
|
|
71
|
+
separate remit metadata; retention can leave an incomplete history. There is no
|
|
72
|
+
daemon. A later observation retries its current pending delivery; old pending
|
|
73
|
+
snapshots remain in the bounded local history, without background sends.
|
|
74
|
+
|
|
75
|
+
`--no-write` disables both capture and delivery. `--no-remit` keeps capture local.
|
|
76
|
+
`--no-run-session` does not start a session. A missing/invalid Map ID keeps the
|
|
77
|
+
observation local with `map_id_missing`; a missing campaign key similarly yields
|
|
78
|
+
`campaign_key_missing`. Capture or delivery failures never alter the lifecycle
|
|
79
|
+
result or exit status.
|
|
80
|
+
Capture may wait up to 1.5 seconds for allocation. Delivery is awaited within
|
|
81
|
+
its separate two-second network budget. Unchanged lifecycle results mean the
|
|
82
|
+
command's output and status remain unchanged; these bounded waits can add latency.
|
|
83
|
+
|
|
84
|
+
The planned ops receiver is `POST /api/progress`. Destination precedence is an
|
|
85
|
+
explicit `--proxy-base`, then the bound Build Context's `intake.proxy_base`, then
|
|
86
|
+
the canonical NEXT endpoint only when there is no source binding. An invalid or
|
|
87
|
+
foreign source binding fails closed, including a context without a nonempty
|
|
88
|
+
matching packet pointer. An explicit endpoint override remains independent of
|
|
89
|
+
that context, and cannot confirm its saved revision.
|
|
90
|
+
|
|
91
|
+
HTTPS and plain HTTP loopback are accepted;
|
|
92
|
+
userinfo, query, fragment and other protocols are refused. Redirects are refused.
|
|
93
|
+
The existing campaign-key resolver supplies `X-Campaign-Key`; keys never enter
|
|
94
|
+
snapshots or metadata.
|
|
95
|
+
|
|
96
|
+
The same telemetry on/off choice governs sharing. Canonical delivery defaults on;
|
|
97
|
+
explicit off, malformed environment/configuration and scope mismatch keep delivery
|
|
98
|
+
off. Consent off still permits the sanitized local capture and sends no request.
|
|
99
|
+
Noncanonical progress delivery requires an explicit matching scoped file
|
|
100
|
+
opt-in (`telemetry on --proxy-base <endpoint>`). Unlike existing Run Record remit,
|
|
101
|
+
unscoped environment ON cannot bypass scope for progress; it yields
|
|
102
|
+
`scoped_consent_required`. Minimal stage observations are intended to be visible
|
|
103
|
+
in Workspace. This producer does not implement the receiver or Workspace UI.
|
|
104
|
+
|
|
105
|
+
Delivery uses a total two-second budget, at most one initial request and one retry
|
|
106
|
+
for transport errors, 429 or 5xx. Both requests use identical canonical JSON bytes,
|
|
107
|
+
ID and timestamp. A response body is bounded to 4 KiB. A 2xx or 409 succeeds only
|
|
108
|
+
with `{ "ok": true, "snapshot_id": "<id>", "digest": "<same-id>" }`. Other
|
|
109
|
+
400/401/403/409 answers and nonmatching acknowledgments remain failed; a conflict
|
|
110
|
+
never silently counts as stored. Response error text is never copied to metadata.
|
|
111
|
+
|
|
112
|
+
## Portable consumption
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
import {
|
|
116
|
+
verifyProgressSnapshot, groupProgressHistories, progressStorageKey,
|
|
117
|
+
} from '@nextcommerce/campaigns-os/progress';
|
|
118
|
+
|
|
119
|
+
const checked = await verifyProgressSnapshot(snapshot);
|
|
120
|
+
const histories = await groupProgressHistories(snapshots);
|
|
121
|
+
const key = progressStorageKey(snapshot, scopeHash);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The export uses standard Web Crypto and TextEncoder; it has no Node, filesystem
|
|
125
|
+
or network dependency. `validateProgressSnapshot` checks bounded strict shape and
|
|
126
|
+
binding invariants; `verifyProgressSnapshot` also verifies the content digest.
|
|
127
|
+
`snapshot_id` hashes recursively key-sorted JSON of every field except itself.
|
|
128
|
+
Canonical transport JSON includes the ID, with no whitespace or newline.
|
|
129
|
+
The exported schema and supported example fixture agree byte-for-byte in tests.
|
|
130
|
+
|
|
131
|
+
`groupProgressHistories` accepts at most 256 snapshots, groups whole observations
|
|
132
|
+
by complete identity plus stream, removes exact duplicate IDs and sorts sequences.
|
|
133
|
+
Groups are `conflicted`, `incomplete`, `unconfirmed` or `observed`. It neither
|
|
134
|
+
chooses a lifecycle stage nor merges completion claims. `observed` confers no
|
|
135
|
+
receiver trust or readiness. Invalid members are rejected with fixed reason codes.
|
|
136
|
+
|
|
137
|
+
The planned immutable receiver key is
|
|
138
|
+
`progress:v0:<scope-hex>:<map-id>:<revision-hex>:<stream>:<sequence>:<digest-hex>`.
|
|
139
|
+
`progressStorageKey` returns null without a valid shape, scope hash, Map or saved
|
|
140
|
+
revision. A key match identifies scope; it is not authentication or trust. The
|
|
141
|
+
receiver must verify the digest and authorized Map scope and stamp its own trust.
|
|
142
|
+
Unknown, incomplete or conflicted histories must never yield a ready workspace.
|
|
@@ -1689,3 +1689,29 @@ meta assertions to avoid duplicating their values into the verdict.
|
|
|
1689
1689
|
Older verdicts lacking this assertion were not checked. Consumers must retain
|
|
1690
1690
|
run/time/spec-hash context and segregate server-stamped untrusted submissions;
|
|
1691
1691
|
a trusted submission attests the runner, not execution or resource identity.
|
|
1692
|
+
|
|
1693
|
+
### Playwright updates and consumer installs
|
|
1694
|
+
|
|
1695
|
+
After installing or updating Campaigns OS, run `npx campaigns-os qa install-browser`
|
|
1696
|
+
from the campaign project (or `campaigns-os qa install-browser` for a global
|
|
1697
|
+
installation). This resolves the same Playwright package as QA and polish capture.
|
|
1698
|
+
A project's own `npx playwright install` can resolve a different version and install
|
|
1699
|
+
a different Chromium build. Campaigns OS is an optional-dependency owner, not a
|
|
1700
|
+
Playwright peer dependency: npm may share a compatible copy or install a nested one.
|
|
1701
|
+
The consumer project's lockfile determines its installed version; this repository's
|
|
1702
|
+
lockfile only controls checkout builds.
|
|
1703
|
+
|
|
1704
|
+
CI reports independent types, unit, contracts, and browser lanes under the existing
|
|
1705
|
+
required `check` status. `npm run check:browser` requires working Chromium and fails
|
|
1706
|
+
on launch errors. `npm run check:consumer` installs the packed package into fresh
|
|
1707
|
+
projects with a shared Playwright, an older conflicting version, and `latest`, then
|
|
1708
|
+
installs and launches Campaigns OS's Chromium. These checks use local fixture pages;
|
|
1709
|
+
they do not place merchant orders. `npm run check` remains the browser-free contributor
|
|
1710
|
+
check; run the browser commands separately after installing Chromium.
|
|
1711
|
+
|
|
1712
|
+
Dependency PRs must include any required release-ledger entries. If the set of
|
|
1713
|
+
install-script dependencies changes, update the runtime recipe's exact expectation,
|
|
1714
|
+
advance its revision and the supported-surface/package patch version, and regenerate
|
|
1715
|
+
the runtime-readiness guide and fixtures. The v1 recipe still uses exact agreement:
|
|
1716
|
+
removing a dependency does not authorize silently reinterpreting that field as an
|
|
1717
|
+
allowlist. Dependabot groups minor/patch updates; major API upgrades remain separate.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
How a checkout of this repository at one commit becomes a usable installed runtime, and how a consumer decides whether a prepared one is still trustworthy. Everything below is generated from `contracts/runtime-recipe.campaigns-os-node-v1.json`, which is the only authority for these values.
|
|
10
10
|
|
|
11
|
-
Recipe kind `campaigns-os-node-v1`, revision `1.0.
|
|
11
|
+
Recipe kind `campaigns-os-node-v1`, revision `1.0.2`, validated by `schemas/campaigns-os-runtime-recipe.v1.schema.json` (`Campaigns OS Runtime Recipe v1`). Supported surface at generation time: `1.37.1`.
|
|
12
12
|
|
|
13
13
|
## What this is
|
|
14
14
|
|
|
@@ -65,7 +65,7 @@ npm ci --ignore-scripts --no-audit --fund=false
|
|
|
65
65
|
|
|
66
66
|
Working directory `target_root`, stdin `closed`, lifecycle scripts `disabled`, bounded by `install_seconds`.
|
|
67
67
|
|
|
68
|
-
ci rather than install, so the lockfile is authoritative and the tree is reproducible. --ignore-scripts is the load-bearing flag: it suppresses every dependency lifecycle script and the target's own prepare.
|
|
68
|
+
ci rather than install, so the lockfile is authoritative and the tree is reproducible. --ignore-scripts is the load-bearing flag: it suppresses every dependency lifecycle script and the target's own prepare. No dependency in the resolved tree declares an install script. The exact list in target_expectations remains a reviewed expectation: additions and removals require a recipe revision, so existing v1 consumers retain the same agreement semantics. --no-audit and --fund=false remove two network- and output-side effects that are not part of preparing a runtime.
|
|
69
69
|
|
|
70
70
|
### build
|
|
71
71
|
|
|
@@ -170,7 +170,7 @@ What this revision assumes about the target, stated as values a checker can comp
|
|
|
170
170
|
| Lockfile | `package-lock.json`, version `3`, integrity pinned `true` |
|
|
171
171
|
| Script `build:spec` | `tsc -p campaign-spec/tsconfig.build.json` |
|
|
172
172
|
| Script `prepare` | `npm run build:spec` |
|
|
173
|
-
| Dependencies declaring an install script |
|
|
173
|
+
| Dependencies declaring an install script | none |
|
|
174
174
|
|
|
175
175
|
## Bounds
|
|
176
176
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# SDK storage compatibility before a bump
|
|
2
|
+
|
|
3
|
+
Run the read-only source scanner from a campaign repository before changing its SDK pin:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npx campaigns-os sdk storage-check --target . --target-sdk 0.4.38 --manifest /path/to/campaign-cart/docs/compatibility/storage-migrations.v1.json --scope campaigns/spring,shared --json
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Omit `--json` for the concise human report. Exit 0 means source-compatible; exit 2 means incompatible or unknown; invalid arguments or manifests exit 1. No merchant files or pins are rewritten. This is independent of doctor's built HTML markup check.
|
|
10
|
+
|
|
11
|
+
The manifest is generated and owned by Campaign Cart, from its storage registry. The scanner has no independent SDK key list and fetches no remote code. Supply the generated `storage-migrations.v1.json` from the SDK contract change (campaign-cart #102); until that change is published, this command does **not** imply a released SDK tag contains that file. The report records the full file SHA-256, SDK version, supported target range, registry/extractor/input digest, and Git provenance. When the supplied bytes equal their repository HEAD blob, provenance is `verified-git-blob` with commit and repository path. Proposed, modified, or copied manifests are labeled `unverified-local-file`; the label never certifies a release. Review/pin SDK provenance separately before acting on findings. Targets outside the manifest's supported SDK range report unknown.
|
|
12
|
+
|
|
13
|
+
`--target` must name the Git root. `--scope` is mandatory: comma-separated literal repository-relative directory/file paths; use `.` only when the complete repository is intended. Add shared JavaScript directories explicitly. `--exclude` uses the same syntax and records explicit exclusions. Archives receive no implicit exemption. Only Git-tracked `.html`, `.htm`, `.js`, `.mjs`, and `.cjs` files in the selected scope are scanned, using current working-tree bytes and per-file digests; untracked files and built dependencies are outside this evidence. A selected HTML page's local script outside the selected files reports unknown. Relative scripts affected by an HTML `<base href>` also report unknown; review their actual dependency paths. Remote SDK and third-party scripts are not fetched or analyzed.
|
|
14
|
+
|
|
15
|
+
Acorn parses JavaScript ASTs; parse5 identifies executable inline HTML scripts and source offsets. Findings inventory storage area, operation, key, file/line/column, reason, and SDK-owned public replacement when supplied. The scanner recognizes direct `localStorage`/`sessionStorage`, `window`/`globalThis`/`self` properties, simple constant browser-global/storage aliases and storage destructuring, literal `getItem`/`setItem`/`removeItem` calls (including bracket method notation), property access/assignment/deletion, and lexical constant string indirection. Comments, ordinary strings, JSON script blocks and public store calls do not become storage reads. A literal legacy SDK key at or after its manifest migration boundary is incompatible. Guessed prefixes cannot establish compatibility.
|
|
16
|
+
|
|
17
|
+
Dynamic storage keys, unresolved storage methods, shadowed storage names, missing migration release evidence, unsupported target versions, and JavaScript parse failures report unknown. This bounded analysis does not execute merchant code or prove computed keys correct. It does not follow arbitrary data flow, dynamic imports, event-handler attributes, generated code or runtime-loaded script graphs. Inspect unresolved findings and include all campaign sources in scope; a clean result is only static tracked source compatibility evidence. Browser behavior, order creation, tracking and analytics still require their own proof, especially where multiple campaigns share an origin. Use the SDK public store API where the manifest recommends it; do not invent a prefix-first merchant repair.
|
|
18
|
+
|
|
19
|
+
Storage `length` property reads are unaffected metadata (`storage-metadata-read`). Storage `key()` enumeration, extracted method references, and mutations of reserved members remain unknown; enumeration cannot prove an SDK key lookup safe. Git discovery failures return one bounded CLI error. Local script diagnostics retain repository-relative spellings from HTML source, including `../` paths; excluded/outside sources are not read. The Git root and operator target are compared by filesystem device/inode identity, so supported case aliases and symlinks can name the same root. Source containment uses realpaths below the Git root without case folding. Extra positional CLI arguments are rejected so an accidental scope or version value cannot silently disappear.
|
|
@@ -14,7 +14,8 @@ implementation detail, however stable it looks.
|
|
|
14
14
|
| Surface | Contract | Change discipline |
|
|
15
15
|
|---|---|---|
|
|
16
16
|
| `schemas/*.schema.json` (all of them) | The portable contract catalog: CampaignSpec, Design Source Package, Build Packet, Build Context, Assembly Report, Doctor Output, sidecar-bundle conformance, Run Record, Workflow Finding, Build Brief, Source-HTML Manifest, Tooling Orientation, Release Ledger, QA Verdict, the QA Verdict sidecar projection, Runtime Recipe, and the legacy-migration inventory/plan/receipt trio. | Hashed. Any content change requires updating the recorded hash **and** bumping `surface_version` in the same PR. A shape change that alters meaning gets a new schema-version const — one version identifier must never cover two shapes (the 2026-08 assembly-report drift is the incident this rule encodes). Additions to an open `v0` schema are expected and consumers must tolerate unknown fields; the security-sensitive legacy-migration schemas are closed, so additions there require a new lineage. 1.28.0 (RL entry `surface_version: 1.28.0`, breaking) removed the two required Build Packet booleans `qa.test_orders_allowed` and `qa.sandbox_test_card_confirmed` (nothing read them; test orders run from `--test-order <mode>` alone), added `local-serve` to the `deploy.target` enum, and added the optional `remit_result` / `remit_base_kind` fields to the Run Record. 1.30.0 (additive) added the optional `data_layer` record to the QA Verdict's `test_orders[]` entries — the order's `dl_purchase` reading (#325). 1.33.0 (additive) added the optional `qa_verdict_publish` block to the Run Record — which verdict was posted to the QA portal, by `qa run` or `qa publish`, and what the portal answered, in the `remit_result` vocabulary (#328). |
|
|
17
|
-
| CLI commands: `start`, `prepare-build`, `build`, `polish`, `checkpoint`, `page-kit`, `spec`, `doctor`, `bundle`, `next`, `theme`, `tooling`, `install-skills`, `install-agent-context`, `validate-assembly-report`, `telemetry`, `standardize`, `qa`, `findings`, `run-record`, `run` | Scriptable entry points. The founding list (1.0.0) was the argv surface Campaigns Agent's remit fixture pins; 1.25.0 adds the partner entry path the public guides instruct — `install-skills` (skill install), `tooling status` (preflight), `next --packet` (the runtime cursor) — plus `theme`, `install-agent-context`, `validate-assembly-report`, and `telemetry`, since consent is part of the partner contract. `validate-build-packet`, formerly an undocumented and unsupported alias of `doctor`, was removed in 1.25.0+agent.7 (RL-0036) and now gets the unknown-command error; use `doctor`. `standardization-report`, a supported but redundant second spelling of `standardize` — same flags, same output, same exit codes — was removed in 1.27.0 and now gets the same unknown-command error; use `standardize`. Removing a supported command is a breaking change and is why that release moved the minor. `bundle check` validates the canonical JSON readback set and makes QA required only under `--require-qa`. `polish capture` owns page-load evidence production. `checkpoint waive` currently accepts four registered gates: `page_kit.store_profile`, `page_kit.sdk_version`, `polish.hidden_eager_media`, and `built_output.upsell_selector_scope`. `page-kit sync` (added in 1.29.0) writes the CampaignSpec's Store Profile fields and SDK pin into the target's `_data/campaigns.json` entry — the repair the first two gates name — and is the only `page-kit` subcommand. `spec derive` (added in 1.31.0) is the reverse write for the repo-derived field class (#432): the target's SDK pin, page routes and analytics ids into the packet's local CampaignSpec; it is the only `spec` subcommand, and the `page_kit.sdk_version.repo_newer` advisory names it; its `--write-map` flag (1.33.0+agent.2) also records the derived pin in the saved Map's Build hints field through the proxy Worker, never moving a Map pin backwards. `qa publish` (added in 1.33.0) posts an already-stored verdict to the QA portal without a re-run or an order, refusing a stale `spec_hash` or a verdict its Run Record already records as published (#328). Within Polish, only the broader Source Freshness waiver remains on its existing report lane; theme and QA decisions also retain their existing lanes. | Any change to this list — adding, renaming, or removing a command — bumps `surface_version` in the same PR, and since 1.25.0 `check-supported-surface.mjs --base` enforces that (before, only hashed and named entries owed a bump, so `checkpoint` landed unbumped). Subcommands, registered gates, and flags may grow freely beneath a listed command. Removing a listed command from dispatch fails the gate outright. Do not infer support for an unregistered checkpoint from the top-level command. |
|
|
17
|
+
| CLI commands: `start`, `prepare-build`, `build`, `polish`, `checkpoint`, `page-kit`, `spec`, `doctor`, `bundle`, `next`, `theme`, `tooling`, `install-skills`, `install-agent-context`, `validate-assembly-report`, `telemetry`, `standardize`, `qa`, `findings`, `run-record`, `run`, `sdk`, `demo` | Scriptable entry points. The founding list (1.0.0) was the argv surface Campaigns Agent's remit fixture pins; 1.25.0 adds the partner entry path the public guides instruct — `install-skills` (skill install), `tooling status` (preflight), `next --packet` (the runtime cursor) — plus `theme`, `install-agent-context`, `validate-assembly-report`, and `telemetry`, since consent is part of the partner contract. `validate-build-packet`, formerly an undocumented and unsupported alias of `doctor`, was removed in 1.25.0+agent.7 (RL-0036) and now gets the unknown-command error; use `doctor`. `standardization-report`, a supported but redundant second spelling of `standardize` — same flags, same output, same exit codes — was removed in 1.27.0 and now gets the same unknown-command error; use `standardize`. Removing a supported command is a breaking change and is why that release moved the minor. `bundle check` validates the canonical JSON readback set and makes QA required only under `--require-qa`. `polish capture` owns page-load evidence production. `checkpoint waive` currently accepts four registered gates: `page_kit.store_profile`, `page_kit.sdk_version`, `polish.hidden_eager_media`, and `built_output.upsell_selector_scope`. `page-kit sync` (added in 1.29.0) writes the CampaignSpec's Store Profile fields and SDK pin into the target's `_data/campaigns.json` entry — the repair the first two gates name — and is the only `page-kit` subcommand. `spec derive` (added in 1.31.0) is the reverse write for the repo-derived field class (#432): the target's SDK pin, page routes and analytics ids into the packet's local CampaignSpec; it is the only `spec` subcommand, and the `page_kit.sdk_version.repo_newer` advisory names it; its `--write-map` flag (1.33.0+agent.2) also records the derived pin in the saved Map's Build hints field through the proxy Worker, never moving a Map pin backwards. `qa publish` (added in 1.33.0) posts an already-stored verdict to the QA portal without a re-run or an order, refusing a stale `spec_hash` or a verdict its Run Record already records as published (#328). Within Polish, only the broader Source Freshness waiver remains on its existing report lane; theme and QA decisions also retain their existing lanes. | Any change to this list — adding, renaming, or removing a command — bumps `surface_version` in the same PR, and since 1.25.0 `check-supported-surface.mjs --base` enforces that (before, only hashed and named entries owed a bump, so `checkpoint` landed unbumped). Subcommands, registered gates, and flags may grow freely beneath a listed command. Removing a listed command from dispatch fails the gate outright. Do not infer support for an unregistered checkpoint from the top-level command. |
|
|
18
|
+
| `sdk storage-check` and `docs/sdk-storage-compatibility.md` | Read-only AST compatibility report for explicitly scoped tracked campaign HTML/JS before an SDK bump; consumes the supplied SDK-owned manifest and records its SHA-256 and verified or unverified local Git provenance. Incompatible and unknown findings exit 2; a clean scan is static source evidence only. | Additive supported CLI and named documentation; no automatic merchant integration repair. |
|
|
18
19
|
| `bin/campaigns-os.mjs` (`campaigns-os`) | The CLI entry itself. | Declared in `package.json` `bin`; the gate fails if it disappears. |
|
|
19
20
|
| Package export `./campaign-spec` | The versioned campaign-spec rule registry, consumed as `@nextcommerce/campaigns-os` (pinned by consumers' lockfiles; lockstep policy — ADR-003 in the ops repo). | Behavior-guarded from the consumer side by their contract tests; the export path itself is gated here. |
|
|
20
21
|
| Package exports `./commercial-journey` and `./commercial-parity` | Portable scenario planning, response normalization, contract-governed source extraction, Exact-only parity comparison, and deterministic QA assertion serialization. These modules own no network transport and do not calculate prices locally. | Consumers execute descriptors through a supported calculate transport, then pass captured envelopes into the pure normalizer. Existing export paths are gated and may not be renamed or removed without a breaking surface change. |
|
|
@@ -81,3 +82,15 @@ the package a consumer installs."
|
|
|
81
82
|
the PR body — downstream pins (Campaigns Agent context spine, ops-repo
|
|
82
83
|
`public-contracts.manifest.json`) update on their own cadence against a
|
|
83
84
|
version they can see move.
|
|
85
|
+
|
|
86
|
+
Candidate 1.36.0 adds the portable `./progress` export, its strict v0 JSON schema,
|
|
87
|
+
[progress observation reference](progress-snapshots.md), and supported example
|
|
88
|
+
fixture. Observations preserve canonical continuation and separate Map/spec/build
|
|
89
|
+
identities; consumers must not treat history presence or scope-key matching as
|
|
90
|
+
readiness or trust.
|
|
91
|
+
|
|
92
|
+
Candidate 1.37.0 adds the `demo` CLI command, [offline sample reference](demo-preview.md),
|
|
93
|
+
a hashed `demo/apollo-v0/provenance.json` and named attribution notice. The command
|
|
94
|
+
exclusively creates a new target with validated inert pages. Its internal static
|
|
95
|
+
files are covered by the provenance output hashes; they are not independent
|
|
96
|
+
consumer interfaces. No campaign proof or session authority is granted.
|
package/docs/versioning.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This repo uses independent compatibility versions:
|
|
4
4
|
|
|
5
|
-
- package version: `1.
|
|
5
|
+
- package version: `1.34.0` — equals `surface_version` in
|
|
6
6
|
`contracts/supported-surface.json` (`check:supported-surface` enforces it)
|
|
7
7
|
and is the version published to the npm registry; `+agent.N` changelog
|
|
8
8
|
sections are same-surface changes and are not published on their own
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextcommerce/campaigns-os",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.37.1",
|
|
4
4
|
"description": "Toolkit for agent-assisted NEXT campaign builds.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -47,7 +47,12 @@
|
|
|
47
47
|
"./schemas/campaigns-os-legacy-migration-inventory.v0.schema.json": "./schemas/campaigns-os-legacy-migration-inventory.v0.schema.json",
|
|
48
48
|
"./schemas/campaigns-os-legacy-provisioning-plan.v0.schema.json": "./schemas/campaigns-os-legacy-provisioning-plan.v0.schema.json",
|
|
49
49
|
"./schemas/campaigns-os-legacy-provisioning-receipt.v0.schema.json": "./schemas/campaigns-os-legacy-provisioning-receipt.v0.schema.json",
|
|
50
|
-
"./package.json": "./package.json"
|
|
50
|
+
"./package.json": "./package.json",
|
|
51
|
+
"./progress": {
|
|
52
|
+
"import": "./src/progress.mjs",
|
|
53
|
+
"default": "./src/progress.mjs"
|
|
54
|
+
},
|
|
55
|
+
"./schemas/campaigns-os-progress-snapshot.v0.schema.json": "./schemas/campaigns-os-progress-snapshot.v0.schema.json"
|
|
51
56
|
},
|
|
52
57
|
"scripts": {
|
|
53
58
|
"campaigns-os": "node ./bin/campaigns-os.mjs",
|
|
@@ -60,7 +65,7 @@
|
|
|
60
65
|
"prepare": "npm run build:spec",
|
|
61
66
|
"check:spec": "node --test \"campaign-spec/test/**/*.test.ts\"",
|
|
62
67
|
"check": "npm run check:provenance && npm run check:workflows && npm run check:changelog-structure && npm run build:spec && npm run check:tests && npm run check:spec && npm run check:fixtures && npm run check:legacy-migration && npm run check:spec-conformance && npm run check:private-strings && npm run check:template-doctrine && npm run check:slot-manifest && npm run check:skill-versions && npm run check:cart-readiness && npm run check:sidecar-bundle && npm run check:supported-surface && npm run check:release-ledger && npm run check:runtime-recipe && npm run check:orientation-docs && npm run check:runtime-docs && npm run check:pack -- --skip-prepare",
|
|
63
|
-
"check:tests": "node
|
|
68
|
+
"check:tests": "node ./scripts/check-tests.mjs",
|
|
64
69
|
"check:legacy-migration": "node ./scripts/check-legacy-migration.mjs",
|
|
65
70
|
"check:fixtures": "node ./scripts/check-fixtures.mjs",
|
|
66
71
|
"check:spec-conformance": "node ./scripts/check-campaign-spec-conformance.mjs",
|
|
@@ -80,7 +85,10 @@
|
|
|
80
85
|
"check:runtime-recipe": "node ./scripts/check-runtime-recipe.mjs",
|
|
81
86
|
"check:runtime-docs": "node ./scripts/generate-runtime-readiness.mjs --check",
|
|
82
87
|
"generate:runtime-docs": "node ./scripts/generate-runtime-readiness.mjs --write",
|
|
83
|
-
"check:sidecar-bundle": "node ./bin/campaigns-os.mjs bundle check --packet contracts/fixtures/sidecar-bundle/production-shaped/campaign-runtime.build.json --require-qa --json"
|
|
88
|
+
"check:sidecar-bundle": "node ./bin/campaigns-os.mjs bundle check --packet contracts/fixtures/sidecar-bundle/production-shaped/campaign-runtime.build.json --require-qa --json",
|
|
89
|
+
"check:browser": "node ./scripts/check-tests.mjs --browser",
|
|
90
|
+
"check:consumer": "node ./scripts/check-playwright-consumer.mjs",
|
|
91
|
+
"check:contracts": "npm run check:provenance && npm run check:workflows && npm run check:changelog-structure && npm run check:fixtures && npm run check:legacy-migration && npm run check:spec-conformance && npm run check:private-strings && npm run check:template-doctrine && npm run check:slot-manifest && npm run check:skill-versions && npm run check:cart-readiness && npm run check:sidecar-bundle && npm run check:supported-surface && npm run check:release-ledger && npm run check:runtime-recipe && npm run check:orientation-docs && npm run check:runtime-docs"
|
|
84
92
|
},
|
|
85
93
|
"engines": {
|
|
86
94
|
"node": ">=20.19.0"
|
|
@@ -88,11 +96,11 @@
|
|
|
88
96
|
"dependencies": {
|
|
89
97
|
"acorn": "^8.18.0",
|
|
90
98
|
"ajv": "^8.20.0",
|
|
91
|
-
"parse5": "^
|
|
92
|
-
"yaml": "^2.9.
|
|
99
|
+
"parse5": "^8.0.1",
|
|
100
|
+
"yaml": "^2.9.1"
|
|
93
101
|
},
|
|
94
102
|
"optionalDependencies": {
|
|
95
|
-
"playwright": "^1.
|
|
103
|
+
"playwright": "^1.63.0"
|
|
96
104
|
},
|
|
97
105
|
"devDependencies": {
|
|
98
106
|
"typescript": "^5.9.3"
|
|
@@ -130,6 +138,12 @@
|
|
|
130
138
|
"CONTEXT.md",
|
|
131
139
|
"compatibility.json",
|
|
132
140
|
"AGENTS.md",
|
|
133
|
-
"CHANGELOG.md"
|
|
141
|
+
"CHANGELOG.md",
|
|
142
|
+
"docs/sdk-storage-compatibility.md",
|
|
143
|
+
"docs/activation-and-evidence.md",
|
|
144
|
+
"docs/diagnostics.md",
|
|
145
|
+
"docs/progress-snapshots.md",
|
|
146
|
+
"demo",
|
|
147
|
+
"docs/demo-preview.md"
|
|
134
148
|
]
|
|
135
149
|
}
|
|
@@ -24,6 +24,48 @@
|
|
|
24
24
|
},
|
|
25
25
|
"description": "Context-relative reference to the normalized Design Source Package. sha256 hashes the exact artifact bytes; material_fingerprint drives freshness gates."
|
|
26
26
|
},
|
|
27
|
+
"intake": {
|
|
28
|
+
"type": "object",
|
|
29
|
+
"additionalProperties": true,
|
|
30
|
+
"properties": {
|
|
31
|
+
"saved_map_revision": {
|
|
32
|
+
"anyOf": [
|
|
33
|
+
{
|
|
34
|
+
"type": "null"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"type": "object",
|
|
38
|
+
"additionalProperties": false,
|
|
39
|
+
"required": [
|
|
40
|
+
"map_id",
|
|
41
|
+
"hash",
|
|
42
|
+
"algorithm",
|
|
43
|
+
"local_spec_material_hash"
|
|
44
|
+
],
|
|
45
|
+
"properties": {
|
|
46
|
+
"map_id": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"minLength": 1
|
|
49
|
+
},
|
|
50
|
+
"hash": {
|
|
51
|
+
"type": [
|
|
52
|
+
"string",
|
|
53
|
+
"null"
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"algorithm": {
|
|
57
|
+
"const": "map-store-v1"
|
|
58
|
+
},
|
|
59
|
+
"local_spec_material_hash": {
|
|
60
|
+
"type": "string",
|
|
61
|
+
"pattern": "^sha256:[0-9a-f]{64}$"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
27
69
|
"spec": {
|
|
28
70
|
"type": "object",
|
|
29
71
|
"required": ["path", "hash", "active_pages"],
|