@topy-ai/maggie 0.7.44 → 0.7.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-zh-TW.md +29 -6
- package/README.md +86 -12
- package/bin/maggie.js +207 -58
- package/bundled-contracts/google-integrations/capability-report-v2.schema.json +76 -0
- package/bundled-contracts/google-integrations/external-write-readback-v1.schema.json +36 -0
- package/bundled-contracts/maggie-deployment/deployer-delegation-v1.schema.json +20 -0
- package/bundled-contracts/maggie-deployment/release-profile-v1.schema.json +34 -0
- package/bundled-contracts/maggie-design/browser-capability-v1.schema.json +33 -0
- package/bundled-contracts/maggie-feedback/evidence-bundle-v1.schema.json +38 -0
- package/bundled-references/browser-inspection.md +17 -0
- package/bundled-references/google-integrations-runbook.md +8 -1
- package/bundled-skills/maggie-blog-bootstrap/SKILL.md +7 -7
- package/bundled-skills/maggie-clone/SKILL.md +21 -14
- package/bundled-skills/maggie-clone-to-template/SKILL.md +11 -11
- package/bundled-skills/maggie-clone-to-template/references/workflow.md +2 -2
- package/bundled-skills/maggie-content-localization/SKILL.md +10 -10
- package/bundled-skills/maggie-deployment/SKILL.md +57 -23
- package/bundled-skills/maggie-deployment/references/vps.md +4 -4
- package/bundled-skills/maggie-design/SKILL.md +12 -12
- package/bundled-skills/maggie-feedback/SKILL.md +23 -0
- package/bundled-skills/maggie-marketplace/SKILL.md +12 -12
- package/bundled-skills/maggie-ops/SKILL.md +28 -6
- package/bundled-skills/maggie-project-context/SKILL.md +1 -1
- package/bundled-skills/maggie-seo-geo/SKILL.md +6 -3
- package/bundled-skills/maggie-service-booking/SKILL.md +24 -24
- package/bundled-skills/maggie-social-share/SKILL.md +2 -2
- package/bundled-skills/maggie-template/SKILL.md +5 -5
- package/bundled-tools/clis/maggie_analytics.py +8 -0
- package/bundled-tools/clis/maggie_browser_audit.py +13 -2
- package/bundled-tools/clis/maggie_deployment.py +167 -6
- package/bundled-tools/clis/maggie_feedback.py +115 -1
- package/bundled-tools/clis/maggie_ops.py +33 -0
- package/bundled-tools/clis/maggie_release.py +124 -19
- package/bundled-tools/runtime/browser_capability.py +143 -0
- package/bundled-tools/runtime/external_write.py +122 -0
- package/bundled-tools/runtime/google_capabilities.py +37 -5
- package/package.json +1 -1
- package/references/browser-inspection.md +17 -0
- package/references/google-integrations-runbook.md +8 -1
|
@@ -34,6 +34,23 @@ The draft is written to `.maggie/feedback/`. It contains the Maggie version,
|
|
|
34
34
|
skill, run ID, phase, error fingerprint, expected/actual result, reproduction
|
|
35
35
|
steps, resolution, validation, and metadata-only screenshot references.
|
|
36
36
|
|
|
37
|
+
Attach bounded, privacy-safe evidence and relationships when a maintainer will
|
|
38
|
+
need to connect a report to a test, deployment, issue, or related run. Only
|
|
39
|
+
identifiers are stored; file contents, logs, credentials, and local paths are
|
|
40
|
+
never copied:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
maggie feedback collect --project . --summary "Adapter unavailable" \
|
|
44
|
+
--evidence-ref test:browser-capability:passed \
|
|
45
|
+
--evidence-ref report:browser-capability:v1 \
|
|
46
|
+
--relationship same-run=clone-001
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Evidence references are bounded and normalized into the
|
|
50
|
+
`maggie-feedback-evidence-bundle.v1` contract. The accepted kinds are
|
|
51
|
+
`test`, `report`, `screenshot`, `command`, `deployment`, `issue`, `commit`,
|
|
52
|
+
and `artifact`; relationships connect safe IDs such as feedback or run IDs.
|
|
53
|
+
|
|
37
54
|
If a draft is marked fixed with `--fixed` (or the supplied run report says
|
|
38
55
|
`fixed`), both `--resolution` and `--validation` are required. Feedback text
|
|
39
56
|
also scrubs common POSIX/home/temp and Windows absolute paths by default while
|
|
@@ -78,6 +95,12 @@ This writes `.maggie/feedback/batches/<batch-id>-review.json` under the
|
|
|
78
95
|
duplicate fingerprints/summaries, while retaining only redacted observations;
|
|
79
96
|
review the aggregate and each draft before submitting.
|
|
80
97
|
|
|
98
|
+
Batch review also emits a bounded `evidenceGraph` and
|
|
99
|
+
`remediationSuggestions`. The graph links feedback IDs to evidence IDs and
|
|
100
|
+
safe related references, while suggestions flag duplicate fingerprints,
|
|
101
|
+
missing batch indexes, shared evidence, or a batch with no validation
|
|
102
|
+
references. These are review aids, not automatic issue or memory writes.
|
|
103
|
+
|
|
81
104
|
Example:
|
|
82
105
|
|
|
83
106
|
{
|
|
@@ -37,18 +37,18 @@ API Pull integration, analytics, booking provider, or Maggie Ops backend.
|
|
|
37
37
|
## Commands
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
maggie tool maggie_marketplace.py list
|
|
41
|
+
maggie tool maggie_marketplace.py add \
|
|
42
42
|
https://www.aura.build/templates/medical-spa-landing-30 clone \
|
|
43
43
|
https://medical-spa-landing-30.aura.build/ \
|
|
44
44
|
--rename medical-spa-landing-001 --replace-id medical-spa-landing-30
|
|
45
|
-
|
|
45
|
+
maggie tool maggie_marketplace.py import \
|
|
46
46
|
--id medical-spa-landing-30 \
|
|
47
47
|
--template-url https://www.aura.build/templates/medical-spa-landing-30 \
|
|
48
48
|
--preview-url https://medical-spa-landing-30.aura.build/ \
|
|
49
49
|
--category spa --category medical-spa --tags premium --tags clinical
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
maggie tool maggie_marketplace.py validate marketplace/templates/medical-spa-landing-30
|
|
51
|
+
maggie tool maggie_marketplace.py apply \
|
|
52
52
|
--id medical-spa-landing-30 --project /path/to/astro-project
|
|
53
53
|
```
|
|
54
54
|
|
|
@@ -84,8 +84,8 @@ The workflow is persisted as `.maggie/marketplace-jobs/<template-id>.json` and
|
|
|
84
84
|
uses fail-closed checkpoints. Inspect or resume a job with:
|
|
85
85
|
|
|
86
86
|
```bash
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
maggie tool maggie_marketplace.py status <template-id>
|
|
88
|
+
maggie tool maggie_marketplace.py resume <template-id>
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
If generated assets are missing, the job stops at `WAITING_FOR_ASSETS`; cloned
|
|
@@ -114,16 +114,16 @@ or while an output image is reused across content occurrences.
|
|
|
114
114
|
sample only when the marketplace intentionally introduces a new contract:
|
|
115
115
|
|
|
116
116
|
```bash
|
|
117
|
-
|
|
117
|
+
maggie tool maggie_marketplace.py validate \
|
|
118
118
|
marketplace/templates/<template-id>
|
|
119
|
-
|
|
119
|
+
maggie tool maggie_marketplace.py validate \
|
|
120
120
|
marketplace/templates/<template-id> --sample marketplace/templates/<sample-id>
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
For a local export, pass the quoted HTML path as the preview argument:
|
|
124
124
|
|
|
125
125
|
```bash
|
|
126
|
-
|
|
126
|
+
maggie tool maggie_marketplace.py add \
|
|
127
127
|
https://www.aura.build/templates/medical-spa-landing-30 clone \
|
|
128
128
|
"/path/to/Medical Aesthetics & Wellness Landing Page Template.html" \
|
|
129
129
|
--rename medical-spa-landing-001 --category spa --category medical-spa \
|
|
@@ -197,7 +197,7 @@ manifest. A spinner, blank iframe, empty React root, loading skeleton, or page
|
|
|
197
197
|
without meaningful content is a failed clone and must not be packaged.
|
|
198
198
|
|
|
199
199
|
```bash
|
|
200
|
-
|
|
200
|
+
maggie tool maggie_clone.py extract \
|
|
201
201
|
"https://medical-spa-landing-30.aura.build/" \
|
|
202
202
|
--run-id marketplace-medical-spa-landing-001
|
|
203
203
|
```
|
|
@@ -301,7 +301,7 @@ redesign is explicitly requested.
|
|
|
301
301
|
### 10. Validate and apply
|
|
302
302
|
|
|
303
303
|
```bash
|
|
304
|
-
|
|
304
|
+
maggie tool maggie_marketplace.py validate \
|
|
305
305
|
marketplace/templates/medical-spa-landing-001
|
|
306
306
|
python3 scripts/validate_skills.py
|
|
307
307
|
git diff --check
|
|
@@ -38,13 +38,13 @@ Invoke it as:
|
|
|
38
38
|
Use the deterministic control-plane CLI for lifecycle gates:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
maggie tool maggie_ops.py --project . audit
|
|
42
|
+
maggie tool maggie_ops.py --project . preflight --write
|
|
43
|
+
maggie tool maggie_ops.py --project . status
|
|
44
|
+
maggie tool maggie_ops.py --project . verify
|
|
45
|
+
maggie tool maggie_ops.py --project . favicon-check \
|
|
46
46
|
--origin https://example.com
|
|
47
|
-
|
|
47
|
+
maggie tool maggie_ops.py --project . record sitemap-match \
|
|
48
48
|
--dry-run --quota-impact quota --idempotency-key match-2026-08-29-001
|
|
49
49
|
```
|
|
50
50
|
|
|
@@ -88,6 +88,14 @@ maggie ops google-capabilities --project . \
|
|
|
88
88
|
--report .maggie/google-capability-input.json
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
The input must use `maggie-google-capability-report.v2`: each row records the
|
|
92
|
+
redacted active account, the selected target (`property`, `container`,
|
|
93
|
+
`customer`, `project`, or `site`), and the exact scopes. Both account and target
|
|
94
|
+
must be explicitly verified, and `target.id` must equal `resource`. The command
|
|
95
|
+
prints these safe identifiers and scopes before any separate provider adapter
|
|
96
|
+
is allowed to perform a write. A v1 report is rejected because it cannot prove
|
|
97
|
+
that the browser/session is on the intended Google account and property.
|
|
98
|
+
|
|
91
99
|
The result separates `read`, `report`, `edit`, and `publish` for each
|
|
92
100
|
provider/resource. Write and publish remain `not_tested` until the operator
|
|
93
101
|
explicitly confirms the exact mutation and a successful read-back is captured.
|
|
@@ -164,6 +172,20 @@ Every mutation must validate the session, role, resource ownership/project
|
|
|
164
172
|
scope, input schema, legal state transition, and idempotency/correlation key.
|
|
165
173
|
Record actor, timestamp, previous state, next state, reason, and result.
|
|
166
174
|
|
|
175
|
+
For a GA4/GTM or other Google provider write, validate a hash-only
|
|
176
|
+
write/readback bundle before treating the operation as complete:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
maggie ops external-write-gate --project . \
|
|
180
|
+
--evidence .maggie/external-write-readback-input.json \
|
|
181
|
+
--output .maggie/external-write-readback.json
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The bundle requires one stable idempotency key across bounded retries, explicit
|
|
185
|
+
confirmation, successful readback fingerprints, an empty duplicate list, and
|
|
186
|
+
an empty orphaned-workspace list. It never stores provider payloads; an
|
|
187
|
+
incomplete or mismatched readback blocks the release gate.
|
|
188
|
+
|
|
167
189
|
### Operate
|
|
168
190
|
|
|
169
191
|
Use the dashboard or API to perform an explicitly requested operation. Show an
|
|
@@ -61,7 +61,7 @@ context. Product roles, OAuth scopes, and Cloud IAM are distinct evidence.
|
|
|
61
61
|
For the combined API Pull lifecycle, use the repository CLI in dry-run first:
|
|
62
62
|
|
|
63
63
|
```bash
|
|
64
|
-
|
|
64
|
+
maggie tool maggie.py api lifecycle --project .
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
The executing form can pull posts/updates, inspect rewrite queue/history and
|
|
@@ -125,7 +125,10 @@ maggie analytics release-gate --project . --environment staging \
|
|
|
125
125
|
|
|
126
126
|
Use `contracts/maggie-seo/gsc-readiness-v1.schema.json` as the evidence
|
|
127
127
|
boundary. Credentials and mutation scopes remain host-owned; a passing local
|
|
128
|
-
contract is not proof of property ownership or live readback.
|
|
128
|
+
contract is not proof of property ownership or live readback. If a GA4/GTM
|
|
129
|
+
write is part of the workflow, also pass hash-only
|
|
130
|
+
`.maggie/external-write-readback.json` evidence to the analytics release gate;
|
|
131
|
+
duplicate or orphaned provider objects fail closed.
|
|
129
132
|
|
|
130
133
|
## Freeze and compare a reviewed site
|
|
131
134
|
|
|
@@ -302,7 +305,7 @@ correct.
|
|
|
302
305
|
For a deterministic technical smoke check, run:
|
|
303
306
|
|
|
304
307
|
```bash
|
|
305
|
-
|
|
308
|
+
maggie tool site_audit.py https://example.com --crawl --json
|
|
306
309
|
```
|
|
307
310
|
|
|
308
311
|
This validates observable public output only. Strategy, AI visibility
|
|
@@ -350,7 +353,7 @@ enter the rewrite queue.
|
|
|
350
353
|
The deterministic local orchestration entry point is:
|
|
351
354
|
|
|
352
355
|
```bash
|
|
353
|
-
|
|
356
|
+
maggie tool maggie.py api lifecycle --project .
|
|
354
357
|
```
|
|
355
358
|
|
|
356
359
|
Use `--execute` only after reviewing the dry-run, and add `--allow-quota` for
|
|
@@ -80,66 +80,66 @@ provider research.
|
|
|
80
80
|
Run from the project root:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
|
-
|
|
83
|
+
maggie tool maggie_service_booking.py import \
|
|
84
84
|
"https://www.fresha.com/a/spa-chevy-chase-chevy-chase-4500-north-park-avenue-sbic60h4?pId=512061" \
|
|
85
85
|
--project .
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
maggie tool maggie_service_booking.py sync \
|
|
88
88
|
"https://www.fresha.com/a/spa-chevy-chase-chevy-chase-4500-north-park-avenue-sbic60h4?pId=512061" \
|
|
89
89
|
--project .
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
maggie tool maggie_service_booking.py sync-report --project .
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
maggie tool maggie_service_booking.py generate --project . --copy-data docs/service-page-copy.json
|
|
94
|
+
maggie tool maggie_service_booking.py validate --project .
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
maggie tool maggie_service_booking.py validate-copy \
|
|
97
97
|
--project . \
|
|
98
98
|
--service-id fresha:15510886 \
|
|
99
99
|
--copy-data docs/service-page-copy.json
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
maggie tool maggie_service_booking.py run \
|
|
102
102
|
"https://www.fresha.com/a/your-location" --project .
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
maggie tool maggie_service_booking.py inspect --project .
|
|
105
|
+
maggie tool maggie_service_booking.py status --project .
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
maggie tool maggie_service_booking.py convert-page \
|
|
108
108
|
src/pages/services/scalp-ritual.astro --project .
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
maggie tool maggie_service_booking.py match-pages \
|
|
111
111
|
--project . --pages-dir src/pages
|
|
112
112
|
|
|
113
113
|
# Apply only reviewed matches; do not accept the first candidate automatically.
|
|
114
|
-
|
|
114
|
+
maggie tool maggie_service_booking.py match-pages \
|
|
115
115
|
--project . --select 'fresha:15510886=/src/pages/lymphatic-drainage-massage-chevy-chase-md.astro'
|
|
116
116
|
|
|
117
117
|
# One service may intentionally have multiple reviewed pages; repeat --select.
|
|
118
|
-
|
|
118
|
+
maggie tool maggie_service_booking.py match-pages \
|
|
119
119
|
--project . \
|
|
120
120
|
--select 'fresha:15510886=/src/pages/lymphatic-drainage-massage-chevy-chase-md.astro' \
|
|
121
121
|
--select 'fresha:15510886=/src/pages/friendship-heights/lymphatic-drainage-massage.astro'
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
maggie tool maggie_service_booking.py polish \
|
|
124
124
|
--project . \
|
|
125
125
|
--service-id fresha:15510886 \
|
|
126
126
|
--page src/pages/lymphatic-drainage-massage-chevy-chase-md.astro \
|
|
127
127
|
--copy-data docs/service-page-copy.json
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
maggie tool maggie_service_booking.py validate-polish \
|
|
130
130
|
--project . --service-id fresha:15510886 \
|
|
131
131
|
--page src/pages/lymphatic-drainage-massage-chevy-chase-md.astro \
|
|
132
132
|
--copy-data docs/service-page-copy.json \
|
|
133
133
|
--rendered http://127.0.0.1:4323/lymphatic-drainage-massage-chevy-chase-md/
|
|
134
134
|
|
|
135
|
-
|
|
135
|
+
maggie tool maggie_service_booking.py category-audit \
|
|
136
136
|
--project . --rendered-dir /tmp/category-rendered
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
maggie tool maggie_service_booking.py category-context --project .
|
|
139
139
|
|
|
140
140
|
# Declare provider behavior, then validate it against the imported catalogue
|
|
141
141
|
# and a sanitized fixture before publishing service pages.
|
|
142
|
-
|
|
142
|
+
maggie tool maggie_service_booking.py capability-audit \
|
|
143
143
|
--project . \
|
|
144
144
|
--catalogue .maggie/booking/services.json \
|
|
145
145
|
--capabilities-file .maggie/booking/provider-capabilities.json \
|
|
@@ -147,11 +147,11 @@ python3 tools/clis/maggie_service_booking.py capability-audit \
|
|
|
147
147
|
|
|
148
148
|
# Answer whether provider-owned treatments are present using the same parser
|
|
149
149
|
# as import/sync; do not search the whole provider page for a name.
|
|
150
|
-
|
|
150
|
+
maggie tool maggie_service_booking.py catalogue-check \
|
|
151
151
|
"https://www.fresha.com/a/your-location" \
|
|
152
152
|
--provider fresha --treatment "Lymphatic drainage massage"
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
maggie tool maggie_service_booking.py retirement-audit \
|
|
155
155
|
--project . \
|
|
156
156
|
--catalogue .maggie/booking/services.json \
|
|
157
157
|
--evidence .maggie/booking/retirement-evidence.json
|
|
@@ -258,7 +258,7 @@ After the AI artifact is finalised, backfill only deterministic provenance
|
|
|
258
258
|
metadata with:
|
|
259
259
|
|
|
260
260
|
```bash
|
|
261
|
-
|
|
261
|
+
maggie tool maggie_service_booking.py category-hash \
|
|
262
262
|
--project . --copy-data docs/category-page-copy.json --apply
|
|
263
263
|
```
|
|
264
264
|
|
|
@@ -282,7 +282,7 @@ is `passed`.
|
|
|
282
282
|
Run the imported-fact gate before generating service or category copy:
|
|
283
283
|
|
|
284
284
|
```bash
|
|
285
|
-
|
|
285
|
+
maggie tool maggie_service_booking.py fact-audit \
|
|
286
286
|
--project . --backfill-source
|
|
287
287
|
```
|
|
288
288
|
|
|
@@ -466,7 +466,7 @@ never let a catch-all route render an unlisted fallback page.
|
|
|
466
466
|
|
|
467
467
|
Validate rendered sitemap output with:
|
|
468
468
|
|
|
469
|
-
|
|
469
|
+
maggie tool maggie_service_booking.py sitemap-audit \
|
|
470
470
|
--project . --index .maggie/rendered-sitemaps/sitemap.xml \
|
|
471
471
|
--sitemap-dir .maggie/rendered-sitemaps
|
|
472
472
|
|
|
@@ -482,7 +482,7 @@ the route.
|
|
|
482
482
|
|
|
483
483
|
Then audit the live route graph:
|
|
484
484
|
|
|
485
|
-
|
|
485
|
+
maggie tool maggie_service_booking.py route-audit \
|
|
486
486
|
--project . --base-url https://example.co.uk
|
|
487
487
|
|
|
488
488
|
This fetches every sitemap URL, requires HTTP 200, records internal inbound
|
|
@@ -22,9 +22,9 @@ and GEO. It is not a second content source of truth.
|
|
|
22
22
|
Create the reviewable channel contract before generating copy:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
|
|
25
|
+
maggie tool maggie_social_share.py plan content.json \
|
|
26
26
|
--channels linkedin,facebook --output .maggie/social-share-plan.json
|
|
27
|
-
|
|
27
|
+
maggie tool maggie_social_share.py validate .maggie/social-share-plan.json
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
The CLI does not generate copy or publish. It validates identity, canonical
|
|
@@ -20,11 +20,11 @@ publish marketplace entries.
|
|
|
20
20
|
Run from the AI CMO Skills repository, or use the equivalent installed tool:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
maggie tool maggie_marketplace.py list
|
|
24
|
+
maggie tool maggie_marketplace.py list --category spa --tag luxury
|
|
25
|
+
maggie tool maggie_marketplace.py suggest "premium London medical spa with editorial typography"
|
|
26
|
+
maggie tool maggie_marketplace.py inspect medical-spa-landing-001
|
|
27
|
+
maggie tool maggie_marketplace.py apply \
|
|
28
28
|
--id medical-spa-landing-001 --project /path/to/astro-project
|
|
29
29
|
```
|
|
30
30
|
|
|
@@ -13,6 +13,7 @@ from urllib.parse import urlsplit
|
|
|
13
13
|
import sys
|
|
14
14
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "runtime"))
|
|
15
15
|
from analytics_traffic import audit_events # noqa: E402
|
|
16
|
+
from external_write import validate as validate_external_write # noqa: E402
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
GA4_ID = re.compile(r"^G-[A-Z0-9]+$", re.I)
|
|
@@ -122,6 +123,12 @@ def release_gate(args: argparse.Namespace) -> int:
|
|
|
122
123
|
errors.append("gsc-evidence-schema")
|
|
123
124
|
elif args.require_gsc:
|
|
124
125
|
errors.append("gsc-evidence-required")
|
|
126
|
+
if args.write_readback:
|
|
127
|
+
write_readback, write_errors = load_json(Path(args.write_readback).resolve(), "external write readback")
|
|
128
|
+
errors.extend(write_errors)
|
|
129
|
+
write_result = validate_external_write(write_readback or {})
|
|
130
|
+
check("external-write-readback", write_result["passed"], "idempotency, readback, duplicate, and cleanup evidence", checks)
|
|
131
|
+
errors.extend(write_result["errors"])
|
|
125
132
|
if browser:
|
|
126
133
|
check("browser-schema", browser.get("schemaVersion") == "maggie-analytics-browser.v1", "versioned browser evidence", checks)
|
|
127
134
|
check("browser-render", browser.get("passed") is True and isinstance(browser.get("routes"), list) and bool(browser["routes"]), "routes rendered without a browser failure", checks)
|
|
@@ -191,6 +198,7 @@ def main() -> int:
|
|
|
191
198
|
parser.add_argument("--smoke-report", help="production smoke evidence for release-gate")
|
|
192
199
|
parser.add_argument("--gsc-evidence", help="versioned GSC readiness evidence for release-gate")
|
|
193
200
|
parser.add_argument("--require-gsc", action="store_true", help="require GSC readiness evidence in release-gate")
|
|
201
|
+
parser.add_argument("--write-readback", help="hash-only external write/readback evidence for release-gate")
|
|
194
202
|
parser.add_argument("--events", help="redacted JSON array of analytics events for traffic-audit")
|
|
195
203
|
args = parser.parse_args()
|
|
196
204
|
if args.command == "gsc-readiness":
|
|
@@ -10,6 +10,7 @@ from urllib.parse import urlparse
|
|
|
10
10
|
RUNTIME = Path(__file__).resolve().parents[1] / "runtime"
|
|
11
11
|
sys.path.insert(0, str(RUNTIME))
|
|
12
12
|
from browser_behavior import validate_samples
|
|
13
|
+
from browser_capability import discover_browser_adapter, require_browser_adapter
|
|
13
14
|
from localization_runner import checkpoint
|
|
14
15
|
|
|
15
16
|
|
|
@@ -108,10 +109,17 @@ def run_interactions(call, steps: list[dict]) -> list[dict]:
|
|
|
108
109
|
def audit(args):
|
|
109
110
|
if urlparse(args.url).scheme not in {"http", "https", "file"}:
|
|
110
111
|
raise ValueError("URL must use http, https or file")
|
|
111
|
-
if not args.required:
|
|
112
|
+
if not args.required and not args.check_browser:
|
|
112
113
|
raise ValueError("at least one --required selector is necessary")
|
|
113
114
|
output = args.output.resolve()
|
|
114
115
|
output.mkdir(parents=True, exist_ok=True)
|
|
116
|
+
capability = discover_browser_adapter(args.browse)
|
|
117
|
+
capability_path = args.capability_report.resolve() if args.capability_report else output / "browser-capability.json"
|
|
118
|
+
checkpoint(capability_path, capability)
|
|
119
|
+
if args.check_browser:
|
|
120
|
+
print(json.dumps(capability, indent=2))
|
|
121
|
+
return 0 if capability["status"] == "ready" else 1
|
|
122
|
+
require_browser_adapter(args.browse)
|
|
115
123
|
interactions = load_interactions(args.interactions)
|
|
116
124
|
def call(*command):
|
|
117
125
|
result = subprocess.run([str(args.browse), *command], capture_output=True, text=True, timeout=45)
|
|
@@ -120,7 +128,8 @@ def audit(args):
|
|
|
120
128
|
return result.stdout
|
|
121
129
|
report = {"schemaVersion": "maggie-browser-audit.v1", "url": args.url,
|
|
122
130
|
"passed": False, "viewports": [], "evidence": "browser-captured",
|
|
123
|
-
"interactionManifest": str(args.interactions.resolve()) if args.interactions else None
|
|
131
|
+
"interactionManifest": str(args.interactions.resolve()) if args.interactions else None,
|
|
132
|
+
"browserCapability": str(capability_path)}
|
|
124
133
|
try:
|
|
125
134
|
for index, viewport in enumerate(args.viewport or ["390x844", "768x1024", "1440x900"]):
|
|
126
135
|
width, height = [int(value) for value in viewport.split("x")]
|
|
@@ -158,6 +167,8 @@ def main():
|
|
|
158
167
|
parser.add_argument("url")
|
|
159
168
|
parser.add_argument("--browse", type=Path, required=True)
|
|
160
169
|
parser.add_argument("--output", type=Path, required=True, help="new directory for evidence")
|
|
170
|
+
parser.add_argument("--capability-report", type=Path, help="write the redacted browser adapter capability report here")
|
|
171
|
+
parser.add_argument("--check-browser", action="store_true", help="only check adapter capability; do not navigate or write page evidence")
|
|
161
172
|
parser.add_argument("--viewport", action="append")
|
|
162
173
|
parser.add_argument("--required", action="append", default=[])
|
|
163
174
|
parser.add_argument("--sticky", action="append", default=[])
|