motionloom 2.0.0 → 2.2.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.
Files changed (64) hide show
  1. package/.agents/skills/motionloom/SKILL.md +14 -0
  2. package/.claude/skills/motionloom.md +5 -0
  3. package/.codex/skills/motionloom.md +11 -0
  4. package/AGENTS.md +17 -0
  5. package/CHANGELOG.md +68 -0
  6. package/CODE_OF_CONDUCT.md +19 -0
  7. package/CONTRIBUTING.md +65 -0
  8. package/README.md +193 -134
  9. package/ROADMAP.md +36 -0
  10. package/SECURITY.md +28 -0
  11. package/SKILL.md +57 -9
  12. package/SUPPORT.md +23 -0
  13. package/agent-card.json +42 -6
  14. package/agent-surfaces.json +79 -0
  15. package/bin/motionloom.mjs +33 -5
  16. package/docs/AGENT-INTEGRATION.md +47 -0
  17. package/docs/CHECKLIST.md +2 -1
  18. package/docs/STATUS.md +33 -0
  19. package/docs/audits/2.1.0-deep-stress-evaluation.md +97 -0
  20. package/docs/audits/ci-replay-remediation-2026-08-13.md +33 -0
  21. package/docs/audits/data/2.1.0-deep-stress-6900.json +329 -0
  22. package/docs/audits/data/deep-stress-latest.json +329 -0
  23. package/docs/audits/external-project-corpus-2026-08-13.md +26 -0
  24. package/docs/releases/2.1.0.md +23 -0
  25. package/docs/releases/2.2.0.md +35 -0
  26. package/docs/releases/npm-publish-from-workstation.md +6 -6
  27. package/examples/agent-consumer/README.md +18 -0
  28. package/examples/agent-consumer/fixture-manifest.json +82 -0
  29. package/package.json +69 -28
  30. package/references/agent-interoperability.md +29 -0
  31. package/references/intelligence-core.md +5 -1
  32. package/schemas/agent-surfaces.schema.json +78 -0
  33. package/schemas/project-memory.schema.json +180 -0
  34. package/schemas/remediation-history.schema.json +23 -0
  35. package/schemas/scene-manifest.schema.json +1 -0
  36. package/schemas/visual-truth.schema.json +80 -0
  37. package/scripts/analyze.py +56 -0
  38. package/scripts/capture-runtime-telemetry.py +119 -0
  39. package/scripts/devlab.py +126 -0
  40. package/scripts/discovery.py +257 -0
  41. package/scripts/docs-audit.py +112 -0
  42. package/scripts/eval-intelligence.py +23 -0
  43. package/scripts/eval-projects.py +156 -0
  44. package/scripts/intelligence.py +106 -6
  45. package/scripts/pr.py +151 -0
  46. package/scripts/prepack-clean.mjs +37 -0
  47. package/scripts/project-memory.py +483 -0
  48. package/scripts/project_memory_loader.py +31 -0
  49. package/scripts/quality-gate.py +43 -3
  50. package/scripts/release-verify.py +52 -0
  51. package/scripts/remediation-learning.py +326 -0
  52. package/scripts/render.py +65 -0
  53. package/scripts/report.py +60 -2
  54. package/scripts/review-hook.py +13 -2
  55. package/scripts/skill-doctor.py +12 -2
  56. package/scripts/to-dotlottie.mjs +26 -20
  57. package/scripts/visual-truth.py +310 -0
  58. package/src/core/analyzer.py +174 -25
  59. package/src/output/browser-review-smoke/manifest.json +1 -0
  60. package/src/output/browser-review-smoke/visual-truth.json +68 -0
  61. package/tests/evals/intelligence-cases.json +10 -0
  62. package/tests/evals/project-corpus.json +51 -0
  63. package/tests/scripts/run_tests.py +111 -1
  64. package/tests/scripts/test_project_memory.py +129 -0
package/package.json CHANGED
@@ -1,13 +1,21 @@
1
1
  {
2
2
  "name": "motionloom",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "type": "module",
5
- "description": "MotionLoom: project-aware animation Skill with graph, provenance, Motion IR, runtime telemetry, DSSE-compatible signed attestation, external evidence verification and Dev Lab review.",
5
+ "packageManager": "pnpm@11.20.0",
6
+ "description": "MotionLoom: project-aware animation Skill with Agent interoperability, graph, provenance, Motion IR, runtime telemetry, Visual Truth, Remediation Learning, DSSE-compatible signed attestation, external evidence verification and Dev Lab review.",
7
+ "author": "lenhonbp",
6
8
  "bin": {
7
9
  "motionloom": "bin/motionloom.mjs"
8
10
  },
9
11
  "files": [
10
12
  "README.md",
13
+ "CHANGELOG.md",
14
+ "ROADMAP.md",
15
+ "CONTRIBUTING.md",
16
+ "CODE_OF_CONDUCT.md",
17
+ "SECURITY.md",
18
+ "SUPPORT.md",
11
19
  "SKILL.md",
12
20
  "LICENSE",
13
21
  "agent-card.json",
@@ -23,7 +31,13 @@
23
31
  "project-context.example.json",
24
32
  "tests/evals",
25
33
  "tests/scripts/run_tests.py",
26
- "tests/scripts/test_attestation.py"
34
+ "tests/scripts/test_attestation.py",
35
+ "tests/scripts/test_project_memory.py",
36
+ ".agents",
37
+ ".claude",
38
+ ".codex",
39
+ "AGENTS.md",
40
+ "agent-surfaces.json"
27
41
  ],
28
42
  "keywords": [
29
43
  "animation",
@@ -35,7 +49,16 @@
35
49
  "gsap",
36
50
  "framer-motion",
37
51
  "runtime-evidence",
38
- "developer-tools"
52
+ "developer-tools",
53
+ "project-memory",
54
+ "motion-ir",
55
+ "provenance",
56
+ "attestation",
57
+ "browser-review",
58
+ "dev-lab",
59
+ "visual-truth",
60
+ "remediation-learning",
61
+ "agent-interoperability"
39
62
  ],
40
63
  "repository": {
41
64
  "type": "git",
@@ -53,35 +76,53 @@
53
76
  "python": ">=3.11"
54
77
  },
55
78
  "scripts": {
56
- "prepack": "find . -type d -name __pycache__ -prune -exec rm -rf {} + && find . -type f \\( -name '*.pyc' -o -name '*.pyo' \\) -delete",
57
- "test": "python3 tests/scripts/run_tests.py",
58
- "validate": "python3 scripts/quality-gate.py --all",
59
- "doctor": "python3 scripts/skill-doctor.py --json",
60
- "report": "python3 scripts/report.py",
61
- "report:check": "python3 scripts/report-contract.py",
62
- "review": "python3 scripts/review-hook.py",
63
- "manifest": "python3 scripts/manifest.py",
64
- "intelligence": "python3 scripts/intelligence.py",
65
- "intelligence:registry": "python3 scripts/intelligence.py capabilities build --output capability-registry.json",
66
- "intelligence:registry:check": "python3 scripts/intelligence.py capabilities validate --path capability-registry.json",
67
- "intelligence:p1": "python3 scripts/intelligence.py",
68
- "quality:p1": "python3 scripts/quality-gate.py --require-intelligence --require-p1 --require-benchmark",
69
- "eval:intelligence": "python3 scripts/eval-intelligence.py",
70
- "benchmark:semantic": "python3 scripts/intelligence.py semantic-lint benchmark --task-dir artifacts/professional-review-e2e --iterations 25 --threshold-ms 500",
71
- "evidence:verify": "python3 scripts/evidence-verifier.py --scene-dir src/output/browser-review-smoke --task-dir artifacts/browser-review-smoke-task --runtime-evidence runtime-adapters/runtime-evidence.json --max-age-days 1 --output artifacts/browser-review-smoke-task/evidence-verifier-report.json",
72
- "attestation:build": "python3 scripts/attestation.py build",
73
- "attestation:verify": "python3 scripts/attestation-verifier.py",
74
- "attestation:policy": "python3 scripts/attestation.py validate-policy",
75
- "attestation:keygen": "python3 scripts/attestation-keygen.py",
76
- "quality:telemetry": "python3 scripts/quality-gate.py --scene browser-review-smoke --context artifacts/browser-review-smoke-task/project-context.json --task-dir artifacts/browser-review-smoke-task --require-browser-review --require-intelligence --require-p1 --require-benchmark --require-telemetry",
77
- "quality:attestation": "python3 scripts/quality-gate.py --scene browser-review-smoke --context artifacts/browser-review-smoke-task/project-context.json --task-dir artifacts/browser-review-smoke-task --require-browser-review --require-intelligence --require-p1 --require-benchmark --require-telemetry --require-attestation",
78
- "pack:dotlottie": "bash scripts/to-dotlottie.sh",
79
- "runtime:test": "node scripts/runtime-adapters.mjs"
79
+ "prepack": "node scripts/prepack-clean.mjs",
80
+ "test": "node bin/motionloom.mjs test",
81
+ "validate": "npm run quality:attestation",
82
+ "doctor": "node bin/motionloom.mjs doctor --json",
83
+ "docs:check": "python3 scripts/docs-audit.py",
84
+ "eval:projects": "python3 scripts/eval-projects.py --allow-insufficient",
85
+ "release:verify": "python3 scripts/release-verify.py",
86
+ "report": "node bin/motionloom.mjs report",
87
+ "report:check": "node bin/motionloom.mjs report-contract",
88
+ "review": "node bin/motionloom.mjs review-hook",
89
+ "devlab": "node bin/motionloom.mjs devlab",
90
+ "manifest": "node bin/motionloom.mjs manifest",
91
+ "intelligence": "node bin/motionloom.mjs intelligence",
92
+ "intelligence:registry": "node bin/motionloom.mjs intelligence capabilities build --output capability-registry.json",
93
+ "intelligence:registry:check": "node bin/motionloom.mjs intelligence capabilities validate --path capability-registry.json",
94
+ "intelligence:p1": "node bin/motionloom.mjs intelligence",
95
+ "quality:p1": "node bin/motionloom.mjs quality-gate --require-intelligence --require-p1 --require-benchmark",
96
+ "eval:intelligence": "node bin/motionloom.mjs eval-intelligence",
97
+ "audit:deep": "node bin/motionloom.mjs deep-audit --iterations 5000 --seed 20260813 --report docs/audits/data/deep-stress-latest.json",
98
+ "memory:init": "node bin/motionloom.mjs memory init --project-root .",
99
+ "memory:bootstrap": "node bin/motionloom.mjs analyze . --init-memory",
100
+ "memory:recover": "node bin/motionloom.mjs memory recover --project-root .",
101
+ "memory:validate": "node bin/motionloom.mjs memory validate --project-root . --json",
102
+ "memory:refresh": "node bin/motionloom.mjs memory refresh --project-root . --json",
103
+ "benchmark:semantic": "node bin/motionloom.mjs intelligence semantic-lint benchmark --task-dir artifacts/professional-review-e2e --iterations 25 --threshold-ms 500",
104
+ "evidence:verify": "node bin/motionloom.mjs evidence-verify --scene-dir src/output/browser-review-smoke --task-dir artifacts/browser-review-smoke-task --runtime-evidence runtime-adapters/runtime-evidence.json --max-age-days 1 --output artifacts/browser-review-smoke-task/evidence-verifier-report.json",
105
+ "attestation:build": "node bin/motionloom.mjs attestation build",
106
+ "attestation:verify": "node bin/motionloom.mjs verify-attestation",
107
+ "attestation:policy": "node bin/motionloom.mjs attestation validate-policy",
108
+ "attestation:keygen": "node bin/motionloom.mjs attestation-keygen",
109
+ "quality:telemetry": "node bin/motionloom.mjs quality-gate --scene browser-review-smoke --context artifacts/browser-review-smoke-task/project-context.json --task-dir artifacts/browser-review-smoke-task --require-browser-review --require-intelligence --require-p1 --require-benchmark --require-telemetry",
110
+ "quality:attestation": "node bin/motionloom.mjs quality-gate --scene browser-review-smoke --context artifacts/browser-review-smoke-task/project-context.json --task-dir artifacts/browser-review-smoke-task --require-browser-review --require-intelligence --require-p1 --require-benchmark --require-telemetry --require-attestation --require-visual-truth",
111
+ "pack:dotlottie": "node scripts/to-dotlottie.mjs",
112
+ "runtime:test": "node scripts/runtime-adapters.mjs",
113
+ "visual-truth:build": "node bin/motionloom.mjs visual-truth build",
114
+ "visual-truth:check": "node bin/motionloom.mjs visual-truth validate --root . --input src/output/browser-review-smoke/visual-truth.json",
115
+ "remediation:validate": "node bin/motionloom.mjs remediation-learning validate --history artifacts/remediation-history.jsonl --json",
116
+ "remediation:summary": "node bin/motionloom.mjs remediation-learning summary --history artifacts/remediation-history.jsonl --output artifacts/remediation-summary.json --json",
117
+ "discovery:check": "node bin/motionloom.mjs discovery check --root . --json",
118
+ "discovery:show": "node bin/motionloom.mjs discovery show --root . --json",
119
+ "install:matrix": "node bin/motionloom.mjs discovery install-matrix --root . --json"
80
120
  },
81
121
  "dependencies": {
82
122
  "@lottiefiles/dotlottie-web": "^0.79.0",
83
123
  "@napi-rs/canvas": "^1.0.5",
84
124
  "@rive-app/canvas": "^2.39.2",
125
+ "fflate": "^0.8.3",
85
126
  "framer-motion": "^13.1.0",
86
127
  "gsap": "^3.15.0",
87
128
  "react": "^19.2.8",
@@ -0,0 +1,29 @@
1
+ # Agent interoperability reference
2
+
3
+ Read this reference when installing MotionLoom into a new Agent environment or when adding a new discovery surface.
4
+
5
+ ## Contract hierarchy
6
+
7
+ 1. `SKILL.md` is the canonical workflow and must stay below the skill context budget.
8
+ 2. `agent-card.json` is the machine-readable capability and side-effect contract.
9
+ 3. `agent-surfaces.json` is the discovery/install/compatibility contract.
10
+ 4. `.agents/skills`, `.claude`, `.codex` and `AGENTS.md` are short routers that point to the canonical sources.
11
+ 5. `docs/AGENT-INTEGRATION.md` is user-facing installation and troubleshooting documentation.
12
+
13
+ Do not put divergent workflow rules into an Agent-specific file. Add reusable domain detail to `references/` or `docs/`, then update the canonical Skill navigation.
14
+
15
+ ## Discovery check output
16
+
17
+ The JSON result contains `status`, `source`, `surface_count`, `installation_count`, `errors` and `warnings`. `status=pass` means the local package has the expected files and contract values. It does not assert that the host project has been analyzed, that runtime dependencies are installed, that a candidate rendered correctly or that a user approved a change.
18
+
19
+ ## Adding a new Agent surface
20
+
21
+ Add one manifest entry with a safe relative path, a supported agent identifier, `canonical: SKILL.md` and either `load_mode: alias` or `load_mode: router`. Create a short file at that path. Add or update the installation/discovery test and run `motionloom discovery check --root . --json`, `python3 scripts/docs-audit.py` and the full test suite. Never silently overwrite an existing surface with a copied version of `SKILL.md`.
22
+
23
+ ## Source and version binding
24
+
25
+ When a user reports a discovery issue, capture the package version, source kind, resolved path, Git remote/commit where available and the discovery JSON. Treat a version mismatch as a structural problem, not as a runtime animation failure. Do not use network access in the check command; registry/Git availability belongs to the installation step.
26
+
27
+ ## Approval boundary
28
+
29
+ Discovery is deliberately orthogonal to approval. The discovery command can only tell an Agent how to load MotionLoom. It cannot transition an animation task to `ready_for_pr` or `confirmed`, and it cannot change `approval` from `false` to `true`.
@@ -13,8 +13,10 @@ Use this reference when an Agent needs to understand or extend MotionLoom's task
13
13
  | `replay-bundle.json` | `python3 scripts/intelligence.py replay capture --root <root> --task-dir <task>` | Captures clean-root artifact hashes and environment metadata; verification fails on mutation or omission. |
14
14
  | `semantic-lint-report.json` | `python3 scripts/intelligence.py semantic-lint build --task-dir <task>` | Reports intent, timing, easing, accessibility, performance and anti-pattern findings with severity, confidence and evidence. |
15
15
  | `semantic-lint-benchmark.json` | `python3 scripts/intelligence.py semantic-lint benchmark --task-dir <task>` | Measures in-process semantic-lint execution, rule coverage and p95 against a deterministic threshold; it is a performance contract, not visual approval. |
16
- | `runtime-telemetry.json` | `bash scripts/capture-runtime-telemetry.sh <scene> artifacts/<task-id>` | Records deterministic scrub-point observations, RAF timing, runtime state hashes and source/manifest/Motion IR bindings from the real adapter harness. |
16
+ | `runtime-telemetry.json` | `motionloom runtime-telemetry <scene> artifacts/<task-id>` | Records deterministic scrub-point observations, RAF timing, runtime state hashes and source/manifest/Motion IR bindings from the real adapter harness. The npm CLI is the cross-platform entrypoint; the legacy `.sh` wrapper remains for Unix compatibility. |
17
17
  | `evidence-verifier-report.json` | `python3 scripts/evidence-verifier.py --scene-dir <scene-dir> --task-dir <task> --runtime-evidence <path>` | Read-only external verification result for task/scene/path/hash/age integrity; `approval` is always `false`. |
18
+ | `visual-truth.json` | `motionloom visual-truth build|validate` | Baseline/candidate PNG hashes, dimensions, deterministic comparison signal, region-level review explanation and source/runtime/Motion IR provenance; `approval` is always `false`. |
19
+ | `remediation-history.jsonl` | `motionloom remediation-learning record-outcome|record-benchmark|summary` | Append-only, hash-chained user-confirmed corrections and deterministic benchmark runs; first-pass metrics guide future work but `approval` is always `false`. |
18
20
  | `attestation-statement.json` | `python3 scripts/attestation.py statement --scene-dir <scene-dir> --task-dir <task> --context <context>` | Derives canonical task/scene/source/manifest/Motion IR/evidence hash bindings before signing. |
19
21
  | `attestation.json` | `python3 scripts/attestation.py build --statement <statement> --private-key <key> --key-id <id>` | DSSE-compatible Ed25519 envelope over the versioned statement; `approval` is always `false`. |
20
22
  | `trust-policy.json` | `python3 scripts/attestation.py validate-policy --path <policy>` | Declares trusted keys, validity, rotation and fail-closed revocation behavior. |
@@ -71,6 +73,8 @@ python3 scripts/quality-gate.py \
71
73
  --context <project-context.json> \
72
74
  --task-dir artifacts/<task-id> \
73
75
  --require-browser-review --require-intelligence --require-p1 --require-benchmark --require-telemetry --require-attestation
76
+ python3 scripts/remediation-learning.py validate --history artifacts/remediation-history.jsonl --json
77
+ python3 scripts/remediation-learning.py summary --history artifacts/remediation-history.jsonl --output artifacts/remediation-summary.json --json
74
78
  python3 scripts/eval-intelligence.py
75
79
  ```
76
80
 
@@ -0,0 +1,78 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://motionloom.dev/schemas/agent-surfaces.schema.json",
4
+ "title": "MotionLoom Agent Surfaces",
5
+ "type": "object",
6
+ "required": ["schema_version", "name", "version", "canonical", "surfaces", "installations", "compatibility", "rules"],
7
+ "properties": {
8
+ "schema_version": {"const": "1.0"},
9
+ "name": {"const": "motionloom"},
10
+ "version": {"type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"},
11
+ "canonical": {
12
+ "type": "object",
13
+ "required": ["skill", "agent_card", "cli"],
14
+ "properties": {
15
+ "skill": {"const": "SKILL.md"},
16
+ "agent_card": {"const": "agent-card.json"},
17
+ "cli": {"const": "bin/motionloom.mjs"}
18
+ },
19
+ "additionalProperties": false
20
+ },
21
+ "surfaces": {
22
+ "type": "array",
23
+ "minItems": 4,
24
+ "items": {
25
+ "type": "object",
26
+ "required": ["id", "kind", "path", "canonical", "load_mode", "agents"],
27
+ "properties": {
28
+ "id": {"type": "string", "pattern": "^[a-z0-9-]+$"},
29
+ "kind": {"type": "string", "enum": ["agent-skill", "agent-instructions", "repository-guide"]},
30
+ "path": {"type": "string", "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$)).+$"},
31
+ "canonical": {"const": "SKILL.md"},
32
+ "load_mode": {"type": "string", "enum": ["alias", "router"]},
33
+ "agents": {"type": "array", "minItems": 1, "items": {"type": "string"}}
34
+ },
35
+ "additionalProperties": false
36
+ }
37
+ },
38
+ "installations": {
39
+ "type": "array",
40
+ "minItems": 3,
41
+ "items": {
42
+ "type": "object",
43
+ "required": ["id", "source_kind", "command", "verification", "provenance"],
44
+ "properties": {
45
+ "id": {"type": "string"},
46
+ "source_kind": {"type": "string", "enum": ["npm", "git", "local"]},
47
+ "command": {"type": "string"},
48
+ "verification": {"type": "string"},
49
+ "provenance": {"type": "string"}
50
+ },
51
+ "additionalProperties": false
52
+ }
53
+ },
54
+ "compatibility": {
55
+ "type": "object",
56
+ "required": ["operating_systems", "node", "python", "agents"],
57
+ "properties": {
58
+ "operating_systems": {"type": "array", "items": {"type": "string"}},
59
+ "node": {"type": "string"},
60
+ "python": {"type": "string"},
61
+ "agents": {"type": "array", "items": {"type": "string"}}
62
+ },
63
+ "additionalProperties": false
64
+ },
65
+ "rules": {
66
+ "type": "object",
67
+ "required": ["canonical_instruction_source", "no_surface_copy", "no_network_required_for_check", "approval_is_never_inferred"],
68
+ "properties": {
69
+ "canonical_instruction_source": {"const": "SKILL.md"},
70
+ "no_surface_copy": {"const": true},
71
+ "no_network_required_for_check": {"const": true},
72
+ "approval_is_never_inferred": {"const": true}
73
+ },
74
+ "additionalProperties": false
75
+ }
76
+ },
77
+ "additionalProperties": false
78
+ }
@@ -0,0 +1,180 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://motionloom.dev/schemas/project-memory.schema.json",
4
+ "title": "MotionLoom Project Memory",
5
+ "description": "Durable, relocatable project memory for recovering animation decisions and context across Agent sessions.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "schema_version",
10
+ "memory_id",
11
+ "created_at",
12
+ "updated_at",
13
+ "project",
14
+ "context",
15
+ "motion_principles",
16
+ "policies",
17
+ "decisions",
18
+ "rejected_patterns",
19
+ "remediation",
20
+ "freshness",
21
+ "recovery"
22
+ ],
23
+ "properties": {
24
+ "schema_version": { "const": "1.0" },
25
+ "memory_id": { "type": "string", "pattern": "^pm-[a-z0-9][a-z0-9._-]*$" },
26
+ "created_at": { "type": "string", "format": "date-time" },
27
+ "updated_at": { "type": "string", "format": "date-time" },
28
+ "project": {
29
+ "type": "object",
30
+ "additionalProperties": false,
31
+ "required": ["project_id", "name", "root_path", "repository"],
32
+ "properties": {
33
+ "project_id": { "type": "string", "minLength": 3 },
34
+ "name": { "type": "string", "minLength": 1 },
35
+ "root_path": { "type": "string", "minLength": 1 },
36
+ "repository": { "type": ["string", "null"] },
37
+ "package_name": { "type": ["string", "null"] }
38
+ }
39
+ },
40
+ "context": {
41
+ "type": "object",
42
+ "additionalProperties": false,
43
+ "required": ["path", "sha256", "schema_version"],
44
+ "properties": {
45
+ "path": { "type": "string", "minLength": 1 },
46
+ "sha256": { "type": ["string", "null"], "pattern": "^$|^[a-f0-9]{64}$" },
47
+ "schema_version": { "type": ["string", "null"] },
48
+ "generated_at": { "type": ["string", "null"] }
49
+ }
50
+ },
51
+ "motion_principles": {
52
+ "type": "object",
53
+ "additionalProperties": false,
54
+ "required": ["duration_ms", "easing", "rhythm", "reduced_motion", "notes"],
55
+ "properties": {
56
+ "duration_ms": { "type": ["number", "null"], "minimum": 0 },
57
+ "easing": { "type": ["string", "null"] },
58
+ "rhythm": { "type": ["string", "null"] },
59
+ "reduced_motion": { "type": ["string", "null"] },
60
+ "notes": { "type": "array", "items": { "type": "string" } }
61
+ }
62
+ },
63
+ "policies": {
64
+ "type": "object",
65
+ "additionalProperties": false,
66
+ "required": ["asset", "runtime"],
67
+ "properties": {
68
+ "asset": {
69
+ "type": "object",
70
+ "additionalProperties": false,
71
+ "required": ["authoritative_sources", "license_required", "unknown_asset_policy"],
72
+ "properties": {
73
+ "authoritative_sources": { "type": "array", "items": { "type": "string" } },
74
+ "license_required": { "type": "boolean" },
75
+ "unknown_asset_policy": { "type": "string", "enum": ["block", "review", "allow"] }
76
+ }
77
+ },
78
+ "runtime": {
79
+ "type": "object",
80
+ "additionalProperties": false,
81
+ "required": ["preferred_frameworks", "verified_runtimes", "browser_matrix"],
82
+ "properties": {
83
+ "preferred_frameworks": { "type": "array", "items": { "type": "string" } },
84
+ "verified_runtimes": { "type": "array", "items": { "type": "string" } },
85
+ "browser_matrix": { "type": "array", "items": { "type": "string" } }
86
+ }
87
+ }
88
+ }
89
+ },
90
+ "decisions": {
91
+ "type": "array",
92
+ "items": { "$ref": "#/$defs/decision" }
93
+ },
94
+ "rejected_patterns": {
95
+ "type": "array",
96
+ "items": { "$ref": "#/$defs/rejectedPattern" }
97
+ },
98
+ "remediation": {
99
+ "type": "array",
100
+ "items": { "$ref": "#/$defs/remediation" }
101
+ },
102
+ "freshness": {
103
+ "type": "object",
104
+ "additionalProperties": false,
105
+ "required": ["status", "checked_at", "context_hash", "project_fingerprint", "reason"],
106
+ "properties": {
107
+ "status": { "type": "string", "enum": ["fresh", "stale", "needs_context", "invalid"] },
108
+ "checked_at": { "type": "string", "format": "date-time" },
109
+ "context_hash": { "type": ["string", "null"], "pattern": "^$|^[a-f0-9]{64}$" },
110
+ "project_fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
111
+ "reason": { "type": "string", "minLength": 1 }
112
+ }
113
+ },
114
+ "recovery": {
115
+ "type": "object",
116
+ "additionalProperties": false,
117
+ "required": ["last_task_id", "next_actions"],
118
+ "properties": {
119
+ "last_task_id": { "type": ["string", "null"] },
120
+ "next_actions": { "type": "array", "items": { "type": "string" } },
121
+ "last_review_state": { "type": ["string", "null"] }
122
+ }
123
+ },
124
+ "integrity": {
125
+ "type": "object",
126
+ "additionalProperties": false,
127
+ "required": ["canonical_sha256"],
128
+ "properties": {
129
+ "canonical_sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
130
+ }
131
+ }
132
+ },
133
+ "$defs": {
134
+ "decision": {
135
+ "type": "object",
136
+ "additionalProperties": false,
137
+ "required": ["id", "recorded_at", "status", "summary", "rationale", "user_confirmed", "source_task_id", "evidence"],
138
+ "properties": {
139
+ "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
140
+ "recorded_at": { "type": "string", "format": "date-time" },
141
+ "status": { "type": "string", "enum": ["accepted", "rejected", "superseded"] },
142
+ "summary": { "type": "string", "minLength": 1 },
143
+ "rationale": { "type": "string" },
144
+ "user_confirmed": { "type": "boolean" },
145
+ "source_task_id": { "type": ["string", "null"] },
146
+ "evidence": { "type": "array", "items": { "type": "string" } }
147
+ }
148
+ },
149
+ "rejectedPattern": {
150
+ "type": "object",
151
+ "additionalProperties": false,
152
+ "required": ["id", "recorded_at", "pattern", "reason", "source_task_id"],
153
+ "properties": {
154
+ "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
155
+ "recorded_at": { "type": "string", "format": "date-time" },
156
+ "pattern": { "type": "string", "minLength": 1 },
157
+ "reason": { "type": "string" },
158
+ "source_task_id": { "type": ["string", "null"] }
159
+ }
160
+ },
161
+ "remediation": {
162
+ "type": "object",
163
+ "additionalProperties": false,
164
+ "required": ["id", "recorded_at", "issue_id", "summary", "root_cause", "resolution", "result", "correction_count", "rerun_scope", "user_confirmed", "source_task_id"],
165
+ "properties": {
166
+ "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
167
+ "recorded_at": { "type": "string", "format": "date-time" },
168
+ "issue_id": { "type": "string", "minLength": 1 },
169
+ "summary": { "type": "string", "minLength": 1 },
170
+ "root_cause": { "type": "string" },
171
+ "resolution": { "type": "string" },
172
+ "result": { "type": "string", "enum": ["pass", "fail", "partial", "unknown"] },
173
+ "correction_count": { "type": "integer", "minimum": 0 },
174
+ "rerun_scope": { "type": "array", "items": { "type": "string" } },
175
+ "user_confirmed": { "type": "boolean" },
176
+ "source_task_id": { "type": ["string", "null"] }
177
+ }
178
+ }
179
+ }
180
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/lenhonbp/MotionLoom/blob/main/schemas/remediation-history.schema.json",
4
+ "title": "MotionLoom remediation and benchmark history event",
5
+ "type": "object",
6
+ "additionalProperties": true,
7
+ "required": ["schema_version", "event_id", "event_type", "recorded_at", "previous_event_sha256", "event_sha256"],
8
+ "properties": {
9
+ "schema_version": {"const": "0.1"},
10
+ "event_id": {"type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{2,127}$"},
11
+ "event_type": {"type": "string", "enum": ["remediation_outcome", "benchmark_run"]},
12
+ "recorded_at": {"type": "string", "format": "date-time"},
13
+ "previous_event_sha256": {"type": ["string", "null"], "pattern": "^[a-f0-9]{64}$"},
14
+ "event_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
15
+ "user_confirmed": {"type": "boolean"},
16
+ "first_pass_accepted": {"type": "boolean"},
17
+ "correction_count": {"type": "integer", "minimum": 0},
18
+ "result": {"type": "string", "enum": ["pass", "fail", "partial", "unknown"]},
19
+ "status": {"type": "string", "enum": ["pass", "fail"]},
20
+ "p95_ms": {"type": "number", "minimum": 0},
21
+ "threshold_ms": {"type": "number", "exclusiveMinimum": 0}
22
+ }
23
+ }
@@ -11,6 +11,7 @@
11
11
  "category": {"type": "string", "minLength": 1},
12
12
  "file": {"type": "string", "minLength": 1, "pattern": "^(?!/)(?!.*\\.\\.).+$"},
13
13
  "runtime_evidence": {"type": "string", "minLength": 1, "pattern": "^(?!/)(?!.*\\.\\.).+$"},
14
+ "visual_truth": {"type": "string", "minLength": 1, "pattern": "^(?!/)(?!.*\\.\\.).+$"},
14
15
  "source_binding": {
15
16
  "type": "object",
16
17
  "required": ["kind", "source_path", "authority", "license", "sha256"],
@@ -0,0 +1,80 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/lenhonbp/MotionLoom/blob/main/schemas/visual-truth.schema.json",
4
+ "title": "MotionLoom Visual Truth Contract",
5
+ "type": "object",
6
+ "required": ["schema_version", "contract", "status", "scene", "frames", "comparison", "provenance", "review_boundary"],
7
+ "properties": {
8
+ "schema_version": {"const": "1.0"},
9
+ "contract": {"const": "motionloom-visual-truth"},
10
+ "status": {"enum": ["pass", "review_required"]},
11
+ "scene": {"type": "string", "minLength": 1},
12
+ "task_id": {"type": ["string", "null"]},
13
+ "frames": {
14
+ "type": "object",
15
+ "required": ["baseline", "candidate"],
16
+ "properties": {
17
+ "baseline": {"$ref": "#/$defs/frame"},
18
+ "candidate": {"$ref": "#/$defs/frame"}
19
+ },
20
+ "additionalProperties": false
21
+ },
22
+ "comparison": {
23
+ "type": "object",
24
+ "required": ["metric", "same_dimensions", "byte_identical", "changed", "interpretation"],
25
+ "properties": {
26
+ "metric": {"type": "string"},
27
+ "same_dimensions": {"type": "boolean"},
28
+ "byte_identical": {"type": "boolean"},
29
+ "changed": {"type": "boolean"},
30
+ "distance": {"type": "number", "minimum": 0},
31
+ "threshold": {"type": "number", "minimum": 0},
32
+ "interpretation": {"enum": ["equal", "review_required"]}
33
+ },
34
+ "additionalProperties": true
35
+ },
36
+ "regions": {"type": "array"},
37
+ "provenance": {
38
+ "type": "object",
39
+ "required": ["source_path", "source_sha256", "manifest_path", "manifest_sha256"],
40
+ "properties": {
41
+ "source_path": {"type": "string", "pattern": "^(?!/)(?!.*\\.\\.).+$"},
42
+ "source_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
43
+ "manifest_path": {"type": "string", "pattern": "^(?!/)(?!.*\\.\\.).+$"},
44
+ "manifest_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
45
+ "runtime_evidence_path": {"type": ["string", "null"]},
46
+ "runtime_evidence_sha256": {"type": ["string", "null"]},
47
+ "motion_ir_path": {"type": ["string", "null"]},
48
+ "motion_ir_sha256": {"type": ["string", "null"]}
49
+ },
50
+ "additionalProperties": true
51
+ },
52
+ "review_boundary": {
53
+ "type": "object",
54
+ "required": ["approval", "user_review_required", "decision"],
55
+ "properties": {
56
+ "approval": {"const": false},
57
+ "user_review_required": {"const": true},
58
+ "decision": {"const": "pending"}
59
+ },
60
+ "additionalProperties": true
61
+ }
62
+ },
63
+ "$defs": {
64
+ "frame": {
65
+ "type": "object",
66
+ "required": ["role", "percent", "path", "sha256", "bytes", "width", "height"],
67
+ "properties": {
68
+ "role": {"enum": ["baseline", "candidate"]},
69
+ "percent": {"type": "integer", "minimum": 0, "maximum": 100},
70
+ "path": {"type": "string", "pattern": "^(?!/)(?!.*\\.\\.).+$"},
71
+ "sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
72
+ "bytes": {"type": "integer", "minimum": 1},
73
+ "width": {"type": "integer", "minimum": 1},
74
+ "height": {"type": "integer", "minimum": 1}
75
+ },
76
+ "additionalProperties": true
77
+ }
78
+ },
79
+ "additionalProperties": true
80
+ }
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env python3
2
+ """Cross-platform project analyzer entrypoint.
3
+
4
+ This replaces the npm CLI's Bash-only analyzer path while preserving the
5
+ existing analyzer implementation and refreshing Project Memory when present.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ import json
12
+ import sys
13
+ from pathlib import Path
14
+
15
+ ROOT = Path(__file__).resolve().parents[1]
16
+ sys.path.insert(0, str(ROOT))
17
+
18
+ from src.core.analyzer import analyze # noqa: E402
19
+ from project_memory_loader import refresh_if_present # noqa: E402
20
+
21
+
22
+ def main() -> int:
23
+ parser = argparse.ArgumentParser(description="Analyze a host project and refresh MotionLoom Project Memory.")
24
+ parser.add_argument("project_root", nargs="?", default=".")
25
+ parser.add_argument("--output")
26
+ parser.add_argument("--init-memory", action="store_true", help="Create .motionloom/project-memory.json if it does not exist")
27
+ parser.add_argument("--max-files", type=int, default=2500, help="Maximum files to inspect")
28
+ parser.add_argument("--max-bytes", type=int, default=25_000_000, help="Maximum file bytes to inspect")
29
+ parser.add_argument("--max-seconds", type=float, default=10.0, help="Maximum traversal time")
30
+ parser.add_argument("--ignore-dir", action="append", default=[], help="Directory name to skip; repeatable")
31
+ parser.add_argument("--ignore-glob", action="append", default=[], help="Relative path glob to skip; repeatable")
32
+ args = parser.parse_args()
33
+ root = Path(args.project_root).expanduser().resolve()
34
+ if not root.is_dir():
35
+ parser.error(f"project root is not a directory: {root}")
36
+ context_path = Path(args.output).expanduser().resolve() if args.output else root / "project-context.json"
37
+ context = analyze(
38
+ str(root),
39
+ max_files=args.max_files,
40
+ max_bytes=args.max_bytes,
41
+ max_seconds=args.max_seconds,
42
+ ignore_dirs=args.ignore_dir or None,
43
+ ignore_globs=args.ignore_glob or None,
44
+ )
45
+ context_path.parent.mkdir(parents=True, exist_ok=True)
46
+ context_path.write_text(json.dumps(context, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
47
+ print(f"{context_path} written ({len(json.dumps(context, ensure_ascii=False))} bytes)")
48
+ memory_result = refresh_if_present(root, context_path, initialize=args.init_memory)
49
+ if memory_result:
50
+ print(json.dumps({"project_memory": memory_result}, ensure_ascii=False))
51
+ print("== MotionLoom analysis complete: review assumptions before generating ==")
52
+ return 0
53
+
54
+
55
+ if __name__ == "__main__":
56
+ raise SystemExit(main())