@plasius/gpu-demo-viewer 0.3.0 → 0.4.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/CHANGELOG.md +30 -0
- package/CONTRIBUTING.md +32 -0
- package/NFR.md +14 -0
- package/README.md +67 -0
- package/SECURITY.md +17 -0
- package/diagnostics/assets.js +7 -0
- package/diagnostics/index.js +20 -0
- package/diagnostics/panel.js +88 -0
- package/diagnostics/source.js +39 -0
- package/docs/adrs/adr-0007-consented-curated-showcase-diagnostics.md +42 -0
- package/docs/adrs/adr-0008-public-compliance-artifact-contract.md +60 -0
- package/docs/adrs/index.md +3 -0
- package/docs/consented-diagnostics.md +82 -0
- package/legal/CLA.md +25 -0
- package/legal/CORPORATE_CLA.md +57 -0
- package/legal/INDIVIDUAL_CLA.md +91 -0
- package/package.json +12 -5
- package/scripts/verify-public-package.cjs +50 -12
package/CHANGELOG.md
CHANGED
|
@@ -18,6 +18,34 @@ The format is based on Keep a Changelog and this project adheres to SemVer.
|
|
|
18
18
|
- **Security**
|
|
19
19
|
- (placeholder)
|
|
20
20
|
|
|
21
|
+
## [0.4.1] - 2026-10-23
|
|
22
|
+
|
|
23
|
+
- **Added**
|
|
24
|
+
- Approved unsigned legal templates and security/contribution policies in the npm artifact, with fail-closed compliance checks, pinned template hashes and regression tests.
|
|
25
|
+
|
|
26
|
+
- **Changed**
|
|
27
|
+
- (placeholder)
|
|
28
|
+
|
|
29
|
+
- **Fixed**
|
|
30
|
+
- (placeholder)
|
|
31
|
+
|
|
32
|
+
- **Security**
|
|
33
|
+
- (placeholder)
|
|
34
|
+
|
|
35
|
+
## [0.4.0] - 2026-10-21
|
|
36
|
+
|
|
37
|
+
- **Added**
|
|
38
|
+
- Source-owned curated showcase diagnostics with integrity-pinned public assets, remote access checks, explicit consent, accessible preview/copy, and fail-closed provenance; no client-pixel capture or diagnostic transport.
|
|
39
|
+
|
|
40
|
+
- **Changed**
|
|
41
|
+
- (placeholder)
|
|
42
|
+
|
|
43
|
+
- **Fixed**
|
|
44
|
+
- (placeholder)
|
|
45
|
+
|
|
46
|
+
- **Security**
|
|
47
|
+
- (placeholder)
|
|
48
|
+
|
|
21
49
|
## [0.3.0] - 2026-10-21
|
|
22
50
|
|
|
23
51
|
- **Added**
|
|
@@ -353,3 +381,5 @@ The format is based on Keep a Changelog and this project adheres to SemVer.
|
|
|
353
381
|
[0.2.2]: https://github.com/Plasius-LTD/gpu-demo-viewer/releases/tag/v0.2.2
|
|
354
382
|
[0.2.3]: https://github.com/Plasius-LTD/gpu-demo-viewer/releases/tag/v0.2.3
|
|
355
383
|
[0.3.0]: https://github.com/Plasius-LTD/gpu-demo-viewer/releases/tag/v0.3.0
|
|
384
|
+
[0.4.0]: https://github.com/Plasius-LTD/gpu-demo-viewer/releases/tag/v0.4.0
|
|
385
|
+
[0.4.1]: https://github.com/Plasius-LTD/gpu-demo-viewer/releases/tag/v0.4.1
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Contributing to @plasius/gpu-demo-viewer
|
|
2
|
+
|
|
3
|
+
This workspace utility exists to accelerate validation across the Plasius
|
|
4
|
+
`gpu-*` packages.
|
|
5
|
+
|
|
6
|
+
## Local Development
|
|
7
|
+
|
|
8
|
+
### Prerequisites
|
|
9
|
+
|
|
10
|
+
- Node.js 24 (`nvm use`)
|
|
11
|
+
- npm
|
|
12
|
+
|
|
13
|
+
### Validate
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm run lint
|
|
17
|
+
npm test
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Demo
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm run demo
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Then open `http://localhost:8000/gpu-demo-viewer/`.
|
|
27
|
+
|
|
28
|
+
## Expectations
|
|
29
|
+
|
|
30
|
+
- Keep the viewer aligned with the real package demos; do not let the manifest drift.
|
|
31
|
+
- Add or update tests when browser target paths or shared showcase assets change.
|
|
32
|
+
- Update `README.md` and `CHANGELOG.md` whenever demo behavior or structure changes.
|
package/NFR.md
CHANGED
|
@@ -34,3 +34,17 @@ entry surfaces.
|
|
|
34
34
|
## Model library review
|
|
35
35
|
|
|
36
36
|
Inherits `gpu-demo.scene-fidelity.enabled` with a localhost-only fixture override. Model changes abort prior work and release its GPU resources. Downloads use trusted reviewed hosts, no redirects, strict byte/hash limits and bounded concurrency. Preserve source licences. Keep missing downloads and renderer defects visible. Keyboard, touch, reduced-motion and 320px layouts must remain usable.
|
|
37
|
+
|
|
38
|
+
## Consented diagnostics
|
|
39
|
+
|
|
40
|
+
Task #42 inherits `feedback.game-diagnostics.enabled` and the host-evaluated
|
|
41
|
+
`feedback.game-diagnostics.attach` capability. The separate diagnostics mount
|
|
42
|
+
has no local/query override. Source-owned native mounts use four SRI-pinned
|
|
43
|
+
public baseline assets from published shared 1.3.0; fallback or unqualified
|
|
44
|
+
surfaces are ineligible. No scene/canvas/DOM/debug snapshot crosses the
|
|
45
|
+
diagnostics boundary. Timing is unknown rather than synthetic precision.
|
|
46
|
+
No automatic collection, diagnostic request, cache, storage or analytics is
|
|
47
|
+
permitted. Explicit preview/copy must remain keyboard accessible at 320px;
|
|
48
|
+
consent/access changes and disposal cancel pending work. Preserve the ordinary
|
|
49
|
+
structured-only reporting path on denial or rollback. Requirements and evidence
|
|
50
|
+
are recorded in [the design](docs/consented-diagnostics.md) and ADR 0007.
|
package/README.md
CHANGED
|
@@ -11,9 +11,76 @@ A browser workshop for inspecting source models with the Plasius GPU renderer,
|
|
|
11
11
|
plus a workspace launcher for the `gpu-*` package demos. The workshop provides
|
|
12
12
|
camera gestures, progressive rendering, quality controls and model credits.
|
|
13
13
|
|
|
14
|
+
## Optional consented renderer diagnostics
|
|
15
|
+
|
|
16
|
+
Hosts can mount the fixed public baseline harbour and an accessible optional
|
|
17
|
+
diagnostics panel through the focused subpath:
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
import { mountDiagnosticShowcase } from '@plasius/gpu-demo-viewer/feedback-diagnostics';
|
|
21
|
+
|
|
22
|
+
const viewer = await mountDiagnosticShowcase({
|
|
23
|
+
root: document.getElementById('scene'),
|
|
24
|
+
feedbackRoot: document.getElementById('feedback'),
|
|
25
|
+
resolveAccess: async () => {
|
|
26
|
+
const decisions = await readCurrentRemoteAccess(); // host source-of-truth evaluator
|
|
27
|
+
return {
|
|
28
|
+
featureEnabled: decisions.flags['feedback.game-diagnostics.enabled'] === true,
|
|
29
|
+
capabilityGranted: decisions.capabilities['feedback.game-diagnostics.attach'] === true,
|
|
30
|
+
sceneEnabled: decisions.flags['gpu-demo.scene-fidelity.enabled'] === true,
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
// On a pushed access/flag change: viewer.refreshAccess();
|
|
35
|
+
// On route exit: viewer.destroy(); remount after changing the scene rollout.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Approved routes are exactly `/gpu-demo`, `/gpu-demo/`, and the workspace
|
|
39
|
+
`/gpu-demo-viewer/showcase/` (including its `index.html`). The API accepts no
|
|
40
|
+
surface ID, existing runtime, model, renderer loader or provenance override.
|
|
41
|
+
Only the fixed four integrity-pinned procedural public assets and a live native
|
|
42
|
+
WebGPU frame are eligible. Open model-library studies, generator and
|
|
43
|
+
`/player-system` are excluded. This does not add controls to the existing demo
|
|
44
|
+
launcher or grant a product capability; downstream site integration is tracked
|
|
45
|
+
in site#1677.
|
|
46
|
+
|
|
47
|
+
Consent starts unchecked. Preview and copy both verify current remote access;
|
|
48
|
+
copy also verifies that the surface still matches the reviewed packet. Only
|
|
49
|
+
coarse renderer/backend/viewport fields and closed codes leave this module;
|
|
50
|
+
synthetic timing stays unknown. Nothing is automatically captured, sent,
|
|
51
|
+
logged or stored. Clipboard denial leaves a selectable read-only preview.
|
|
52
|
+
Disabling `feedback.game-diagnostics.enabled` restores structured-only reporting.
|
|
53
|
+
See [the design and validation contract](docs/consented-diagnostics.md) and
|
|
54
|
+
[ADR 0007](docs/adrs/adr-0007-consented-curated-showcase-diagnostics.md).
|
|
55
|
+
|
|
14
56
|
The npm package includes the viewer source, manifest and build-time acquisition
|
|
15
57
|
helper and typed composite layout definitions. Model binaries are downloaded separately; they are not bundled in npm.
|
|
16
58
|
|
|
59
|
+
## Package compliance documents
|
|
60
|
+
|
|
61
|
+
The npm artifact includes `LICENSE`, `SECURITY.md`, `CONTRIBUTING.md` and the
|
|
62
|
+
unsigned [CLA guide](legal/CLA.md), [Individual CLA](legal/INDIVIDUAL_CLA.md)
|
|
63
|
+
and [Corporate CLA](legal/CORPORATE_CLA.md) templates from the approved schema
|
|
64
|
+
baseline. Only package-name references are adapted. These documents describe
|
|
65
|
+
contribution and reporting policies; model-specific credits and licences remain
|
|
66
|
+
with their existing catalogue records.
|
|
67
|
+
|
|
68
|
+
Run `npm ci`, `npm run build`, `npm test`, `npm run test:coverage` and
|
|
69
|
+
`npm run pack:check` to validate the contract. The pack check requires non-empty
|
|
70
|
+
regular compliance files and a real `legal/` directory, then verifies their
|
|
71
|
+
presence in the actual npm dry-run manifest. SHA-256 checks pin the exact bytes
|
|
72
|
+
of all three templates to schema commit `d8f8eb430c77b8a98da496a3d8382d73d6297394`
|
|
73
|
+
after package-name substitution. Future legal changes require explicit review
|
|
74
|
+
of the approved baseline, pinned digests and regression expectations together.
|
|
75
|
+
CI and the approved CD path run this check. It fails on missing documents,
|
|
76
|
+
omitted package entries, symlinks, altered template terms or unexpected legal
|
|
77
|
+
files in the artifact. The package allowlist names each legal template individually.
|
|
78
|
+
|
|
79
|
+
Signed agreements and contributor acceptance records belong in the approved
|
|
80
|
+
access-controlled system outside source control. Never add them to this
|
|
81
|
+
repository, package or public build artifacts. See [ADR 0008](docs/adrs/adr-0008-public-compliance-artifact-contract.md)
|
|
82
|
+
for the packaging decision and release checks.
|
|
83
|
+
|
|
17
84
|
## Run the model workshop
|
|
18
85
|
|
|
19
86
|
Use Node.js 24 or later, npm, and a WebGPU-capable browser on localhost or HTTPS.
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
We currently support the latest major version of this project. Older versions may not receive security updates.
|
|
6
|
+
|
|
7
|
+
## Reporting a Vulnerability
|
|
8
|
+
|
|
9
|
+
If you discover a security vulnerability, please report it privately by emailing us at [security@plasius.co.uk](mailto:security@plasius.co.uk). Please do not create a public issue for security-related matters.
|
|
10
|
+
|
|
11
|
+
## Response Timeline
|
|
12
|
+
|
|
13
|
+
We aim to acknowledge your report within 2 business days and to provide a more detailed response (including next steps and, if applicable, a timeline for a fix) within 7 business days.
|
|
14
|
+
|
|
15
|
+
## Disclosure Policy
|
|
16
|
+
|
|
17
|
+
We request that you give us the opportunity to address the vulnerability before publicly disclosing it. We will coordinate with you on public disclosure once a fix is available and deployed.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Reviewed procedural public baseline from @plasius/gpu-shared@1.3.0.
|
|
2
|
+
export const showcaseAssetIntegrity = Object.freeze({
|
|
3
|
+
"brigantine": "sha384-iK6Q3rfU7L0mtjE/pgOJWrAaS0X56xrnmomRuGQkHaA24TvKra4BffwwDjhOxaNG",
|
|
4
|
+
"lighthouse": "sha384-rm8vGSiRziQ4V3IAFGJNiZqEzyvEpJDg/FvZNa2MxOrThSQ9HYIEVGzz9dN0S8Qb",
|
|
5
|
+
"harbor-dock": "sha384-4FJzP1Rk0Ll0IokVbzBWpY06m6zfWAUeALPC7Lh7refibUKF3Am+JWStJSlcC7cV",
|
|
6
|
+
"shoreline": "sha384-/hcbf3/xM+bdGaDnQliQ2r45WoCmZ769s1fpKneZ6QhIZGTDPGH2YNDQjKKP3MMO"
|
|
7
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createCuratedShowcaseSource } from './source.js';
|
|
2
|
+
import { createFeedbackPanel } from './panel.js';
|
|
3
|
+
|
|
4
|
+
export async function mountDiagnosticShowcase(options) {
|
|
5
|
+
const keys=['root','feedbackRoot','resolveAccess'];
|
|
6
|
+
if(!options || Object.getPrototypeOf(options)!==Object.prototype ||
|
|
7
|
+
Reflect.ownKeys(options).length!==keys.length || keys.some(key=>!Object.hasOwn(options,key)) ||
|
|
8
|
+
typeof options.resolveAccess!=='function')throw new TypeError('Invalid diagnostics mount options.');
|
|
9
|
+
const pathname=globalThis.location?.pathname;
|
|
10
|
+
if(!['/gpu-demo','/gpu-demo/','/gpu-demo-viewer/showcase/','/gpu-demo-viewer/showcase/index.html'].includes(pathname)) {
|
|
11
|
+
throw new TypeError('This route is not registered for diagnostics.');
|
|
12
|
+
}
|
|
13
|
+
let access;
|
|
14
|
+
try {access=await options.resolveAccess();}catch {access=undefined;}
|
|
15
|
+
const source=await createCuratedShowcaseSource({root:options.root,sceneEnabled:access?.sceneEnabled===true});
|
|
16
|
+
try {
|
|
17
|
+
const panel=createFeedbackPanel({root:options.feedbackRoot,source,resolveAccess:options.resolveAccess,initialAccess:access});
|
|
18
|
+
return Object.freeze({refreshAccess:panel.refreshAccess,destroy(){panel.destroy();source.destroy();}});
|
|
19
|
+
} catch {source.destroy();throw new Error('Diagnostics controls could not be mounted.');}
|
|
20
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { parseFeedbackGameDiagnostics } from '@plasius/gpu-shared/feedback-diagnostics';
|
|
2
|
+
|
|
3
|
+
const available = value => value?.featureEnabled===true && value?.capabilityGranted===true && value?.sceneEnabled===true;
|
|
4
|
+
|
|
5
|
+
// Source is private to the public mount; this internal seam permits hostile-data
|
|
6
|
+
// and race tests without making arbitrary registrations a supported public API.
|
|
7
|
+
export function createFeedbackPanel({root,source,resolveAccess,initialAccess,document=globalThis.document,
|
|
8
|
+
copy=text=>globalThis.navigator.clipboard.writeText(text)}) {
|
|
9
|
+
const make=(tag,text)=>{const e=document.createElement(tag);if(text)e.textContent=text;return e;};
|
|
10
|
+
const section=make('section'),heading=make('h2','Optional renderer diagnostics');
|
|
11
|
+
const help=make('p','Share coarse renderer health only. No image, page content, names, locations or device identity is collected. Nothing is sent automatically.');
|
|
12
|
+
const label=make('label'),consent=make('input');consent.type='checkbox';consent.checked=false;
|
|
13
|
+
label.append(consent,make('span','I consent to preview and copy renderer diagnostics.'));
|
|
14
|
+
const prepare=make('button','Preview diagnostics'),copyButton=make('button','Copy diagnostics');
|
|
15
|
+
prepare.type=copyButton.type='button';copyButton.disabled=true;
|
|
16
|
+
const previewLabel=make('label','Diagnostics preview'),preview=make('textarea');
|
|
17
|
+
preview.readOnly=true;preview.value='';preview.rows=12;previewLabel.append(preview);
|
|
18
|
+
const status=make('p','Diagnostics are optional. Select consent to prepare a preview.');
|
|
19
|
+
status.setAttribute('role','status');status.setAttribute('aria-live','polite');
|
|
20
|
+
const style=make('style',`[data-feedback-diagnostics] {box-sizing:border-box;max-width:42rem;padding:1rem;color:#f4f7fb;background:#152234;font:1rem/1.5 system-ui;overflow-wrap:anywhere}
|
|
21
|
+
[data-feedback-diagnostics] label {display:block;min-height:44px;margin:.75rem 0}
|
|
22
|
+
[data-feedback-diagnostics] textarea {box-sizing:border-box;display:block;width:100%;max-width:100%;color:#f4f7fb;background:#101925;font:0.85rem/1.5 monospace}
|
|
23
|
+
[data-feedback-diagnostics] input {margin-right:.5rem}
|
|
24
|
+
[data-feedback-diagnostics] button {min-height:44px;margin:.25rem;padding:.5rem;color:#101925;background:#d7e7fa;border:2px solid #a3c6ed;border-radius:.25rem}
|
|
25
|
+
[data-feedback-diagnostics] :focus-visible {outline:3px solid #ffce64;outline-offset:3px}
|
|
26
|
+
[data-feedback-diagnostics] button:disabled {color:#526071;background:#d7e7fa}`);
|
|
27
|
+
section.setAttribute('data-feedback-diagnostics','');
|
|
28
|
+
section.hidden=!available(initialAccess);
|
|
29
|
+
section.append(style,heading,help,label,prepare,copyButton,previewLabel,status);root.append(section);
|
|
30
|
+
let revision=0,destroyed=false,text='';
|
|
31
|
+
function clear(message) {
|
|
32
|
+
revision++;text='';preview.value='';copyButton.disabled=true;
|
|
33
|
+
if(message)status.textContent=message;
|
|
34
|
+
}
|
|
35
|
+
function revoke(message) {consent.checked=false;section.hidden=true;clear(message);}
|
|
36
|
+
const consentChanged=()=>clear('Consent changed. Prepare a new preview before copying.');
|
|
37
|
+
async function permitted(token) {
|
|
38
|
+
try {
|
|
39
|
+
const decision=await resolveAccess();
|
|
40
|
+
if(destroyed || token!==revision || !consent.checked)return false;
|
|
41
|
+
if(!available(decision)){revoke('Diagnostics are unavailable. Ordinary bug reporting remains available.');return false;}
|
|
42
|
+
return true;
|
|
43
|
+
} catch {
|
|
44
|
+
if(!destroyed && token===revision)revoke('Diagnostics access could not be verified. Try again later.');
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function preparePreview() {
|
|
49
|
+
clear();const token=revision;
|
|
50
|
+
if(destroyed || !consent.checked){status.textContent='Select consent before preparing diagnostics.';return;}
|
|
51
|
+
if(!await permitted(token))return;
|
|
52
|
+
try {
|
|
53
|
+
const packet=await source.observe(true,()=>!destroyed && token===revision && consent.checked);
|
|
54
|
+
if(destroyed || token!==revision || !consent.checked)return;
|
|
55
|
+
if(!packet){revoke('This surface is not eligible for diagnostics.');return;}
|
|
56
|
+
text=JSON.stringify(parseFeedbackGameDiagnostics(packet),null,2);preview.value=text;
|
|
57
|
+
copyButton.disabled=false;status.textContent='Preview ready. Review these exact fields before copying.';
|
|
58
|
+
} catch {if(!destroyed && token===revision)revoke('Diagnostics could not be prepared safely.');}
|
|
59
|
+
}
|
|
60
|
+
async function copyPreview() {
|
|
61
|
+
if(destroyed || !text || !consent.checked)return;
|
|
62
|
+
const token=++revision;
|
|
63
|
+
if(!await permitted(token))return;
|
|
64
|
+
try {
|
|
65
|
+
const packet=await source.observe(true,()=>!destroyed && token===revision && consent.checked);
|
|
66
|
+
if(destroyed || token!==revision || !consent.checked)return;
|
|
67
|
+
if(!packet || JSON.stringify(parseFeedbackGameDiagnostics(packet),null,2)!==text){
|
|
68
|
+
clear('The surface changed. Prepare and review a new preview.');return;
|
|
69
|
+
}
|
|
70
|
+
// No await between the last consent check and invoking the explicit copy.
|
|
71
|
+
await copy(text);
|
|
72
|
+
if(!destroyed && token===revision)status.textContent='Diagnostics copied. Paste them only where you choose.';
|
|
73
|
+
} catch {if(!destroyed && token===revision)status.textContent='Copy unavailable. Select the preview text and copy it manually.';}
|
|
74
|
+
}
|
|
75
|
+
consent.addEventListener('change',consentChanged);
|
|
76
|
+
prepare.addEventListener('click',preparePreview);copyButton.addEventListener('click',copyPreview);
|
|
77
|
+
return Object.freeze({
|
|
78
|
+
async refreshAccess() {
|
|
79
|
+
revoke('Access changed. Select consent and prepare a new preview.');const token=revision;
|
|
80
|
+
try {
|
|
81
|
+
const decision=await resolveAccess();
|
|
82
|
+
if(!destroyed && token===revision)section.hidden=!available(decision);
|
|
83
|
+
} catch { /* Missing remote decisions leave the controls hidden. */ }
|
|
84
|
+
},
|
|
85
|
+
destroy() {if(destroyed)return;destroyed=true;revoke();consent.removeEventListener('change',consentChanged);
|
|
86
|
+
prepare.removeEventListener('click',preparePreview);copyButton.removeEventListener('click',copyPreview);section.remove();},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { showcaseAssetIntegrity } from './assets.js';
|
|
2
|
+
|
|
3
|
+
// Internal mount seam for tests. The public entrypoint never accepts loaders or
|
|
4
|
+
// an existing runtime. Registration is a consequence of this fixed source mount.
|
|
5
|
+
export async function createCuratedShowcaseSource({root,sceneEnabled,
|
|
6
|
+
loadShared=()=>import('@plasius/gpu-shared'),
|
|
7
|
+
loadRenderer=()=>import('@plasius/gpu-renderer')}) {
|
|
8
|
+
let destroyed=false, runtime;
|
|
9
|
+
if(sceneEnabled===true) {
|
|
10
|
+
const shared=await loadShared();
|
|
11
|
+
const integrity=Object.fromEntries(Object.entries(showcaseAssetIntegrity).map(
|
|
12
|
+
([key,digest])=>[String(shared.resolveShowcaseAssetUrl(key)),digest]));
|
|
13
|
+
runtime=await shared.mountGpuShowcase({root,focus:'integrated',
|
|
14
|
+
packageName:'@plasius/gpu-demo-viewer',
|
|
15
|
+
__featureFlags:{'gpu-demo.scene-fidelity.enabled':true,gpu_showcase_realistic_models_v1:false,
|
|
16
|
+
'gpu.model.conversion.enabled':false},gltfLoadOptions:{integrity}});
|
|
17
|
+
}
|
|
18
|
+
function eligible() {
|
|
19
|
+
const state=runtime?.state;
|
|
20
|
+
return !destroyed && state?.assetCatalog?.mode==='modeled-baseline' &&
|
|
21
|
+
state.assetCatalog.fallbackReason===null && state.rendererUnavailable!==true &&
|
|
22
|
+
state.nativeRenderer?.backend==='webgpu-raster' && state.nativeRenderer.submittedFrames>0;
|
|
23
|
+
}
|
|
24
|
+
return Object.freeze({
|
|
25
|
+
async observe(consent,isCurrent=()=>true) {
|
|
26
|
+
if(consent!==true || !isCurrent() || !eligible())return null;
|
|
27
|
+
const {createFeedbackGameDiagnosticSnapshot}=await loadRenderer();
|
|
28
|
+
if(!isCurrent() || !eligible())return null;
|
|
29
|
+
const frame=runtime.state.nativeRenderer;
|
|
30
|
+
// Never pass the frame, canvas, telemetry, raw errors or other scene state
|
|
31
|
+
// across the renderer diagnostics boundary. Synthetic timing stays unknown.
|
|
32
|
+
return createFeedbackGameDiagnosticSnapshot({featureEnabled:true,capabilityGranted:true,
|
|
33
|
+
consentConfirmed:true,surfaceId:'site.gpu-demo',renderer:'webgpu',backend:'browser',
|
|
34
|
+
viewportWidth:frame.width,viewportHeight:frame.height,frameRate:undefined,frameTimeMs:undefined,
|
|
35
|
+
featureIds:['renderer.frame-loop'],counters:[],errorCodes:[]});
|
|
36
|
+
},
|
|
37
|
+
destroy() { if(destroyed)return;destroyed=true;runtime?.destroy();runtime=undefined; },
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# ADR 0007: Consented diagnostics from a source-owned curated showcase
|
|
2
|
+
|
|
3
|
+
Status: accepted for Task gpu-demo-viewer#42, Story site#1671, Feature site#1665.
|
|
4
|
+
|
|
5
|
+
The shared registration contract and renderer bucketing API do not establish
|
|
6
|
+
that a caller's arbitrary canvas or scene is curated. The open model library
|
|
7
|
+
can contain private or unqualified assets. Existing debug snapshots contain
|
|
8
|
+
coordinates, names and broad runtime state.
|
|
9
|
+
|
|
10
|
+
The new `feedback-diagnostics` package subpath owns a fixed baseline showcase
|
|
11
|
+
mount. Its public API accepts only render/control roots and a remote access
|
|
12
|
+
resolver. Source registration is fixed to `site.gpu-demo` on exact approved
|
|
13
|
+
routes; generator, `/player-system`, model-library and arbitrary runtime
|
|
14
|
+
injection are excluded. Four procedural public shared-package assets are
|
|
15
|
+
integrity-pinned to the published 1.3.0 release. Missing assets, fallback,
|
|
16
|
+
unsubmitted frames, unavailable renderers and destroyed mounts fail closed.
|
|
17
|
+
The raw runtime stays in a closure. Only explicit native backend and viewport
|
|
18
|
+
numbers reach the released renderer bucketing helper. Synthetic timing is
|
|
19
|
+
reported as unknown. The resulting packet is validated by the shared parser.
|
|
20
|
+
|
|
21
|
+
The host resolves `feedback.game-diagnostics.enabled`, capability
|
|
22
|
+
`feedback.game-diagnostics.attach`, and `gpu-demo.scene-fidelity.enabled`.
|
|
23
|
+
Publishing does not grant access. No environment or query override exists.
|
|
24
|
+
Explicit consent and preview precede observation. Copy rechecks access and
|
|
25
|
+
surface eligibility, and requires a packet identical to the reviewed preview.
|
|
26
|
+
Revocation, access refresh and disposal invalidate pending asynchronous work.
|
|
27
|
+
Disable the diagnostics flag to roll back; ordinary structured reports remain.
|
|
28
|
+
Hosts must call `refreshAccess()` on pushed control changes and destroy on route
|
|
29
|
+
exit. Remount after changing the scene rollout decision.
|
|
30
|
+
|
|
31
|
+
Accepting caller-supplied IDs/provenance or filtering generic debug snapshots
|
|
32
|
+
was rejected because neither proves a curated source. Adding capture or
|
|
33
|
+
transport was rejected because the Feature prohibits client pixels. The new
|
|
34
|
+
boundary exposes an accessible optional preview/copy UI and performs no upload,
|
|
35
|
+
storage, diagnostic logging or automatic collection.
|
|
36
|
+
|
|
37
|
+
Tests cover denial/allow/rollback, exact routes, source provenance, immutable
|
|
38
|
+
schema output, forbidden fields, race cancellation and lifetime. Browser checks
|
|
39
|
+
cover explicit user flow, mobile/keyboard access and network/cache isolation.
|
|
40
|
+
Release uses PR CI followed by exact-main `cd.yml` in `production`; verify the
|
|
41
|
+
npm artifact before downstream site#1677 adopts it. No backend or secret mapping
|
|
42
|
+
changes occur in this static package release.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# ADR 0008: Public compliance artifact contract
|
|
2
|
+
|
|
3
|
+
Status: Accepted 2026-10-23
|
|
4
|
+
|
|
5
|
+
## Context
|
|
6
|
+
|
|
7
|
+
Project Task gpu-demo-viewer#35 under operational task site#847 requires the
|
|
8
|
+
schema-template legal baseline and package-level guarantees. The previous
|
|
9
|
+
verifier allowed publication without security/contribution policies or legal
|
|
10
|
+
templates. This is repository-operational compliance maintenance; it changes no
|
|
11
|
+
product Feature, remotely controlled behaviour or entitlement. Flags and
|
|
12
|
+
capabilities are N/A for this packaging-only task.
|
|
13
|
+
|
|
14
|
+
## Decision
|
|
15
|
+
|
|
16
|
+
Reuse the three unsigned templates from @plasius/schema main
|
|
17
|
+
`d8f8eb430c77b8a98da496a3d8382d73d6297394`, substituting only the package name.
|
|
18
|
+
Preserve Apache-2.0 package licensing and existing model-specific licences.
|
|
19
|
+
Include SECURITY.md and CONTRIBUTING.md and explicitly list each legal template
|
|
20
|
+
in package.json. Do not include a broad legal directory glob. Signed agreements
|
|
21
|
+
and acceptance records stay outside source control in the approved restricted
|
|
22
|
+
system; they are never package inputs.
|
|
23
|
+
|
|
24
|
+
The Node-built-in verifier checks metadata for non-empty regular compliance
|
|
25
|
+
files and a real legal directory. It pins SHA-256 digests of all three adapted
|
|
26
|
+
templates to exact approved bytes before invoking a bounded npm dry-run. Future
|
|
27
|
+
legal changes require reviewed baseline/digest and test updates together;
|
|
28
|
+
non-empty truncation, rewording or added terms must fail. It then
|
|
29
|
+
requires all six documents in the manifest and rejects any unapproved legal
|
|
30
|
+
entry. It does not read private contributor records. Its root argument permits
|
|
31
|
+
isolated test fixtures without mutating the working checkout. CI and CD invoke
|
|
32
|
+
the same pack check; no new runtime dependency or public runtime API is needed.
|
|
33
|
+
|
|
34
|
+
## Alternatives
|
|
35
|
+
|
|
36
|
+
Repository-only documents would not satisfy the requested artifact baseline.
|
|
37
|
+
Including all of legal/ would make accidental document additions package inputs.
|
|
38
|
+
Checking source presence alone would miss package allowlist regressions. A new
|
|
39
|
+
shared package is unnecessary for these local filesystem checks.
|
|
40
|
+
|
|
41
|
+
## Tests and NFR implications
|
|
42
|
+
|
|
43
|
+
Requirements-derived regressions remove, empty, symlink or omit each required
|
|
44
|
+
document and exercise actual npm dry-runs. Tampering regressions truncate,
|
|
45
|
+
reword and append to every template, and independently pin their approved hashes.
|
|
46
|
+
Positive fixtures prove the complete contract passes, while synthetic unlisted records stay excluded or fail packing.
|
|
47
|
+
Tests never create actual agreements or personal information. Source/helper
|
|
48
|
+
coverage, frozen install, audit, build and package checks establish reproducible
|
|
49
|
+
and maintainable validation. Viewer runtime, browser/GPU behaviour, accessibility,
|
|
50
|
+
SEO and performance are unchanged; no browser qualification or Azure secretref
|
|
51
|
+
change applies. Existing NFR.md remains the runtime baseline.
|
|
52
|
+
|
|
53
|
+
## Release and rollback
|
|
54
|
+
|
|
55
|
+
Deliver through PR, successful CI, protected main and the existing cd.yml
|
|
56
|
+
production/OIDC prepare-publish route. Verify a fresh package version and compare
|
|
57
|
+
all required document bytes with the released source and sealed tarball. Do not
|
|
58
|
+
manually promote changelog sections or publish locally. Correct packaging defects
|
|
59
|
+
through an ordinary forward release; never roll back by publishing private
|
|
60
|
+
records or restoring fail-open validation. No site consumer deployment is needed.
|
package/docs/adrs/index.md
CHANGED
|
@@ -9,3 +9,6 @@
|
|
|
9
9
|
|
|
10
10
|
- [ADR 0005: Build-time model acquisition subpath](adr-0005-build-time-model-acquisition-subpath.md)
|
|
11
11
|
- [ADR 0006: Composite study consumer](adr-0006-composite-study-consumer.md)
|
|
12
|
+
- [ADR 0007: Consented curated showcase diagnostics](adr-0007-consented-curated-showcase-diagnostics.md)
|
|
13
|
+
|
|
14
|
+
- [ADR 0008: Public compliance artifact contract](adr-0008-public-compliance-artifact-contract.md)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Consented showcase diagnostics
|
|
2
|
+
|
|
3
|
+
Design for gpu-demo-viewer#42, Story site#1671, Feature site#1665.
|
|
4
|
+
|
|
5
|
+
Only a mount owned by this package can register `site.gpu-demo`. A new focused
|
|
6
|
+
entrypoint will mount the fixed baseline harbour using the published shared
|
|
7
|
+
runtime, four integrity-pinned procedural public assets, and the native renderer.
|
|
8
|
+
It will retain the runtime privately. It will accept no caller-provided surface
|
|
9
|
+
ID, provenance, scene, model, renderer loader, snapshot, warning or URL. Open
|
|
10
|
+
model-library studies, generator, arbitrary canvases and `/player-system` remain
|
|
11
|
+
ineligible. Asset failure, fallback rendering, no submitted frame, disposal or
|
|
12
|
+
unknown provenance disables diagnostics.
|
|
13
|
+
|
|
14
|
+
The host supplies a fresh remote decision for `feedback.game-diagnostics.enabled`,
|
|
15
|
+
`feedback.game-diagnostics.attach`, and `gpu-demo.scene-fidelity.enabled`.
|
|
16
|
+
Missing decisions deny access. This package adds no service endpoint or local
|
|
17
|
+
production override. The panel requires explicit unchecked consent and a preview
|
|
18
|
+
action before reading observations. Copy rechecks remote access; consent changes,
|
|
19
|
+
refresh, disposal and races clear or invalidate pending work. Normal structured
|
|
20
|
+
reporting is independent. Rollback disables the diagnostics flag.
|
|
21
|
+
|
|
22
|
+
Only native renderer/backend and coarse viewport buckets are observed. Timing is
|
|
23
|
+
unknown because existing showcase telemetry includes synthetic stress values.
|
|
24
|
+
No raw scene/debug snapshot is passed to the renderer helper. That released helper
|
|
25
|
+
constructs the closed packet, then the shared parser validates it. Preview is
|
|
26
|
+
read-only text; copying is an explicit clipboard operation. No automatic capture,
|
|
27
|
+
upload, download, browser storage, cache entry, analytics or log is introduced.
|
|
28
|
+
|
|
29
|
+
Alternatives: accepting any source-tagged object would permit forged provenance;
|
|
30
|
+
using `render_game_to_text` would disclose scene details; collecting images would
|
|
31
|
+
violate the Feature. This narrow mount adds a supported validation surface rather
|
|
32
|
+
than assuming every existing demo is eligible. Site integration/reconstruction is
|
|
33
|
+
the separate downstream site#1677.
|
|
34
|
+
|
|
35
|
+
Validation: tests derive from deny/allow/rollback/provenance/consent/lifetime
|
|
36
|
+
requirements, with changed-source LCOV, static package checks and real browser
|
|
37
|
+
keyboard/320px/no-pixel network/storage/cache checks. Release only via PR CI and
|
|
38
|
+
exact-main `cd.yml` in `production`, then verify npm artifact and provenance.
|
|
39
|
+
|
|
40
|
+
## Dependency and compatibility decision
|
|
41
|
+
|
|
42
|
+
The direct shared dependency changes from `^1.2.0` (locked 1.2.0) to exact 1.3.0.
|
|
43
|
+
This adopts the published diagnostics contract verified under shared#101 and
|
|
44
|
+
fixes the bytes used by the four SRI entries. The renderer remains locked to
|
|
45
|
+
0.2.54, with its existing compatible manifest range. Shared 1.3.0 brings its
|
|
46
|
+
declared model-conversion dependency graph; this mount explicitly disables
|
|
47
|
+
conversion and lazily loads the shared runtime only for a positive scene
|
|
48
|
+
decision. No unrelated direct dependency is updated. Package audits and
|
|
49
|
+
signature/attestation verification cover the new locked graph. A future shared
|
|
50
|
+
version requires an explicit asset/hash compatibility review rather than
|
|
51
|
+
silently accepting changed assets.
|
|
52
|
+
|
|
53
|
+
## Browser qualification — 21 October 2026
|
|
54
|
+
|
|
55
|
+
An isolated in-app Chromium tab mounted the actual published shared/native
|
|
56
|
+
WebGPU renderer, with the four SRI-pinned assets. The local harness supplied
|
|
57
|
+
test access decisions only; no production controls changed. Keyboard activation
|
|
58
|
+
prepared the closed packet; explicit Copy reported success. No-consent preview
|
|
59
|
+
was denied. Revoking access immediately before Copy cleared preview and consent;
|
|
60
|
+
unchecking consent and disposal also removed retained diagnostics. A 320px-wide
|
|
61
|
+
panel had no horizontal overflow. This is actual narrow-container validation,
|
|
62
|
+
not an emulated 320px device viewport or a full multi-browser qualification.
|
|
63
|
+
|
|
64
|
+
The harness trapped canvas export/readback and display capture. It recorded
|
|
65
|
+
four public-asset fetches at mount, zero later fetches, zero non-GET requests,
|
|
66
|
+
zero request bodies and zero pixel reads. Resource entries stayed at 36 across
|
|
67
|
+
preview/copy/revocation; localStorage, sessionStorage, Cache Storage and IndexedDB
|
|
68
|
+
stayed empty. This combines browser observations with source/invariant tests;
|
|
69
|
+
it does not claim arbitrary third-party host code cannot perform network I/O.
|
|
70
|
+
No Chrome/Firefox/Safari cross-browser pass is inferred. Clipboard denial has a
|
|
71
|
+
tested selectable-preview fallback.
|
|
72
|
+
|
|
73
|
+
NFR disposition: security/privacy checked by integrity, closed packet, no-pixel,
|
|
74
|
+
rollback and race tests plus browser isolation evidence; accessibility checked
|
|
75
|
+
for labels, keyboard activation, live status, visible focus, contrast and 44px
|
|
76
|
+
action targets; performance checked through lazy loading and absence of new
|
|
77
|
+
sampling loops; reliability/reproducibility checked by clean install, build,
|
|
78
|
+
asset hashes and lifetime tests; maintainability/testability checked by ADR,
|
|
79
|
+
focused public entrypoint and changed-source LCOV; observability uses fixed
|
|
80
|
+
user-visible status messages without raw diagnostics logging. SEO is N/A for a
|
|
81
|
+
package subpath that creates no public route. Backend sensitive-environment
|
|
82
|
+
mapping is N/A because no backend or Azure resource changes are made.
|
package/legal/CLA.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Contributor License Agreements (CLA)
|
|
2
|
+
|
|
3
|
+
To protect the intellectual property of this project and ensure clarity of rights, all contributors must sign a Contributor License Agreement (CLA) before their first contribution.
|
|
4
|
+
|
|
5
|
+
## Which CLA should I sign?
|
|
6
|
+
|
|
7
|
+
- **Individual CLA**: If you are contributing personally and not on behalf of an employer, sign the [Individual CLA](INDIVIDUAL_CLA.md).
|
|
8
|
+
- **Corporate CLA**: If you are contributing as part of your work for a company, the company should sign the [Corporate CLA](CORPORATE_CLA.md).
|
|
9
|
+
|
|
10
|
+
## How to sign
|
|
11
|
+
|
|
12
|
+
1. Download the appropriate CLA file (Individual or Corporate).
|
|
13
|
+
2. Fill in the required details, sign, and date it.
|
|
14
|
+
3. Email a PDF copy of the signed document to **[contributors@plasius.co.uk](mailto:contributors@plasius.co.uk)** with subject: `CLA – Individual` or `CLA – Corporate`.
|
|
15
|
+
|
|
16
|
+
## Registry
|
|
17
|
+
|
|
18
|
+
Signed agreements and acceptance records are stored in an access-controlled
|
|
19
|
+
system outside source control. They must never be committed to a repository,
|
|
20
|
+
included in a package, or copied into issues, pull requests, build logs, or
|
|
21
|
+
other public artifacts.
|
|
22
|
+
|
|
23
|
+
## Questions?
|
|
24
|
+
|
|
25
|
+
If you have any questions about which CLA to sign or how the process works, please email **[contributors@plasius.co.uk](mailto:contributors@plasius.co.uk)**.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Corporate Contributor License Agreement (CLA)
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
This Corporate Contributor License Agreement ("Agreement") is intended to protect the intellectual property rights of the contributors and the project, ensure clear licensing terms for contributions, and maintain trust within the community. By signing this Agreement, the corporation agrees to the terms that facilitate the use, distribution, and modification of contributions under the project's licensing framework.
|
|
6
|
+
|
|
7
|
+
## Agreement
|
|
8
|
+
|
|
9
|
+
1. **Representation of Authority**
|
|
10
|
+
The undersigned individual represents and warrants that they have the full legal authority to enter into this Agreement on behalf of the corporation named below ("Corporation") and to grant the rights contained herein.
|
|
11
|
+
|
|
12
|
+
2. **Grant of Copyright License**
|
|
13
|
+
The Corporation hereby grants to the project maintainers and users a perpetual, worldwide, non-exclusive, royalty-free, irrevocable copyright license to use, reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute the contributions submitted to the project.
|
|
14
|
+
|
|
15
|
+
3. **Grant of Patent License**
|
|
16
|
+
The Corporation hereby grants to the project maintainers and users a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license under any patent claims that are necessarily infringed by the contributions to make, use, sell, offer for sale, import, and otherwise dispose of the contributions or derivative works thereof.
|
|
17
|
+
|
|
18
|
+
4. **Warranties and Representations**
|
|
19
|
+
The Corporation represents and warrants that:
|
|
20
|
+
|
|
21
|
+
- The contributions are the original work of the Corporation or that the Corporation has sufficient rights to grant the licenses herein.
|
|
22
|
+
- The submission of the contributions does not violate any agreements or rights of third parties.
|
|
23
|
+
|
|
24
|
+
5. **No Revocation**
|
|
25
|
+
This license is granted on a perpetual basis and cannot be revoked, provided that the terms of this Agreement are met.
|
|
26
|
+
|
|
27
|
+
6. **Governing Law**
|
|
28
|
+
This Agreement shall be governed by and construed in accordance with the laws of the United Kingdom, without regard to its conflict of laws principles.
|
|
29
|
+
|
|
30
|
+
7. **Execution**
|
|
31
|
+
|
|
32
|
+
This Agreement is effective upon signature by the authorized representative of the Corporation. Please sign and date this document, then email a scanned PDF copy to [contributors@plasius.co.uk](mailto:contributors@plasius.co.uk).
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
### **@plasius/gpu-demo-viewer**
|
|
37
|
+
|
|
38
|
+
**Corporation Legal Name:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
39
|
+
|
|
40
|
+
**Authorized Representative:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
41
|
+
|
|
42
|
+
**Title:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
43
|
+
|
|
44
|
+
**Email:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
45
|
+
|
|
46
|
+
**Date:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
47
|
+
|
|
48
|
+
**Signature:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## How to Sign
|
|
53
|
+
|
|
54
|
+
- Download this file as a template.
|
|
55
|
+
- Fill in the Corporation’s legal name, authorized representative, title, email, date, and provide a signature.
|
|
56
|
+
- Sign and date the document.
|
|
57
|
+
- Send a scanned copy of the signed Agreement to [contributors@plasius.co.uk](mailto:contributors@plasius.co.uk).
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Individual Contributor License Agreement (CLA)
|
|
2
|
+
|
|
3
|
+
**Project:** @plasius/gpu-demo-viewer (Plasius LTD)
|
|
4
|
+
**Version:** 1.0 — 2025‑09‑12
|
|
5
|
+
**Contact:** [contributors@plasius.co.uk](mailto:contributors@plasius.co.uk)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Definitions
|
|
10
|
+
|
|
11
|
+
- **"You"** (or **"Contributor"**) means the individual signing this CLA and submitting Contributions to the Project.
|
|
12
|
+
- **"Contribution"** means any original work of authorship, including code, documentation, data, designs, or feedback that You submit to the Project in any form (e.g., pull request, issue comment, email, file upload).
|
|
13
|
+
- **"Project"** means the @plasius/gpu-demo-viewer repositories and related materials owned or managed by **Plasius LTD**.
|
|
14
|
+
|
|
15
|
+
## 2. Copyright License Grant
|
|
16
|
+
|
|
17
|
+
You hereby grant to Plasius LTD a **perpetual, worldwide, non‑exclusive, transferable, sublicensable, royalty‑free, irrevocable** copyright license to:
|
|
18
|
+
|
|
19
|
+
- use, reproduce, publicly display, publicly perform, modify, create derivative works of, and
|
|
20
|
+
- distribute Contributions in source and object form,
|
|
21
|
+
- and to **sublicense** these rights under any terms Plasius LTD chooses, including proprietary or open‑source licenses.
|
|
22
|
+
|
|
23
|
+
## 3. Patent License Grant
|
|
24
|
+
|
|
25
|
+
You hereby grant to Plasius LTD and its sublicensees a **perpetual, worldwide, non‑exclusive, transferable, royalty‑free, irrevocable** patent license to **make, have made, use, offer to sell, sell, import, and otherwise transfer** the Contribution and derivative works thereof, where such license applies only to patent claims that You **own or control** and that would be infringed by Your Contribution or its combination with the Project.
|
|
26
|
+
|
|
27
|
+
## 4. Moral Rights & Attribution
|
|
28
|
+
|
|
29
|
+
To the maximum extent permitted by applicable law, You **waive** and agree not to assert any moral rights (e.g., rights of attribution or integrity) in or to the Contribution against Plasius LTD. Plasius LTD may, but is not required to, credit You.
|
|
30
|
+
|
|
31
|
+
## 5. Representations & Warranties
|
|
32
|
+
|
|
33
|
+
You represent that:
|
|
34
|
+
|
|
35
|
+
1. **Originality / Rights:** Each Contribution is Your original creation, or You have sufficient rights to submit it and grant the licenses above.
|
|
36
|
+
2. **No Confidential Info:** Contributions **do not** include confidential information or trade secrets of any third party.
|
|
37
|
+
3. **No Infringement:** To the best of Your knowledge, Contributions do not infringe any third‑party IP rights.
|
|
38
|
+
4. **Employment / Contractor Status:** If Your employer or a third party might claim rights in Your Contribution, You have obtained **written permission** to make the Contribution and grant these licenses (attach or reference below), or Your Contribution is made **outside the scope** of your employment and without using your employer’s confidential information or resources.
|
|
39
|
+
5. **Compliance:** You will follow the Project’s policies (e.g., Code of Conduct, Security Policy) and applicable laws.
|
|
40
|
+
|
|
41
|
+
## 6. Third‑Party Code
|
|
42
|
+
|
|
43
|
+
If Your Contribution includes code, data, or other material from a third party, You will **identify the material and its license** in the pull request or submission, and ensure it is **compatible** with the Project’s licensing model. You will not submit material subject to terms that require the Project to disclose proprietary source code (e.g., certain copyleft obligations) unless the Project has **pre‑approved** such inclusion in writing.
|
|
44
|
+
|
|
45
|
+
## 7. Scope & Duration
|
|
46
|
+
|
|
47
|
+
- This CLA covers **all past and future** Contributions You submit to the Project, unless and until You provide written notice to **revoke** it.
|
|
48
|
+
- Revocation is **not retroactive**: rights granted for prior Contributions remain in effect.
|
|
49
|
+
|
|
50
|
+
## 8. Disclaimer
|
|
51
|
+
|
|
52
|
+
THE CONTRIBUTION IS PROVIDED “AS IS” WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON‑INFRINGEMENT.
|
|
53
|
+
|
|
54
|
+
## 9. Governing Law & Jurisdiction
|
|
55
|
+
|
|
56
|
+
This CLA is governed by the **laws of England and Wales**, and the courts of England and Wales shall have **exclusive jurisdiction** over any dispute arising out of or relating to it.
|
|
57
|
+
|
|
58
|
+
## 10. Entire Agreement
|
|
59
|
+
|
|
60
|
+
This CLA is the entire agreement between You and Plasius LTD regarding Contributions. It supersedes any prior discussions relating to Contributions. If any provision is held unenforceable, the remaining provisions remain in full force.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 11. Contributor Information & Signature
|
|
65
|
+
|
|
66
|
+
By signing below, You agree to the terms of this CLA for Your Contributions to the Project.
|
|
67
|
+
|
|
68
|
+
**Full Name:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
69
|
+
|
|
70
|
+
**Email:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
71
|
+
|
|
72
|
+
**GitHub Handle:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
73
|
+
|
|
74
|
+
**Address (optional):** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
75
|
+
|
|
76
|
+
**Employer (if applicable):** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
77
|
+
|
|
78
|
+
**If employed:** ☐ I confirm Contributions are made outside the scope of employment **or** ☐ I have attached my employer’s written permission.
|
|
79
|
+
|
|
80
|
+
**Signature:** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
81
|
+
|
|
82
|
+
**Date (YYYY‑MM‑DD):** \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_
|
|
83
|
+
|
|
84
|
+
_Electronic signatures are accepted. You may type your name in the Signature field and email a PDF copy._
|
|
85
|
+
|
|
86
|
+
**Submission:** Please email the signed CLA to **[contributors@plasius.co.uk](mailto:contributors@plasius.co.uk)** with subject line: `CLA – Individual – <GitHubHandle>`.
|
|
87
|
+
|
|
88
|
+
**(Optional) Attachments / Notes:**
|
|
89
|
+
|
|
90
|
+
- Employer permission letter (if required)
|
|
91
|
+
- Third‑party license disclosures (if any)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plasius/gpu-demo-viewer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Root validation viewer for Plasius gpu-* demos.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"./model-library/studies": {
|
|
24
24
|
"types": "./model-library/studies.d.ts",
|
|
25
25
|
"default": "./model-library/studies.js"
|
|
26
|
-
}
|
|
26
|
+
},
|
|
27
|
+
"./feedback-diagnostics": "./diagnostics/index.js"
|
|
27
28
|
},
|
|
28
29
|
"files": [
|
|
29
30
|
"assets/",
|
|
@@ -39,7 +40,13 @@
|
|
|
39
40
|
"main.js",
|
|
40
41
|
"styles.css",
|
|
41
42
|
"viewer-manifest.js",
|
|
42
|
-
"model-library/"
|
|
43
|
+
"model-library/",
|
|
44
|
+
"diagnostics/",
|
|
45
|
+
"SECURITY.md",
|
|
46
|
+
"CONTRIBUTING.md",
|
|
47
|
+
"legal/CLA.md",
|
|
48
|
+
"legal/INDIVIDUAL_CLA.md",
|
|
49
|
+
"legal/CORPORATE_CLA.md"
|
|
43
50
|
],
|
|
44
51
|
"engines": {
|
|
45
52
|
"node": ">=24"
|
|
@@ -51,7 +58,7 @@
|
|
|
51
58
|
"lint": "npm run typecheck",
|
|
52
59
|
"pack:check": "node scripts/verify-public-package.cjs",
|
|
53
60
|
"prepublishOnly": "npm run build && npm run pack:check",
|
|
54
|
-
"typecheck": "node --check index.js && node --check main.js && node --check viewer-manifest.js && node --check showcase/index.js && node --check showcase/main.js && node --check wavefront/main.js && node --check model-library/main.js && node --check model-library/controller.js && node --check model-library/scenes.js && node --check model-library/acquire.js && node --check model-library/rollout.js && node --check model-library/studies.js",
|
|
61
|
+
"typecheck": "node --check index.js && node --check main.js && node --check viewer-manifest.js && node --check showcase/index.js && node --check showcase/main.js && node --check wavefront/main.js && node --check model-library/main.js && node --check model-library/controller.js && node --check model-library/scenes.js && node --check model-library/acquire.js && node --check model-library/rollout.js && node --check model-library/studies.js && node --check diagnostics/index.js && node --check diagnostics/source.js && node --check diagnostics/panel.js && node --check diagnostics/assets.js",
|
|
55
62
|
"test": "node --test",
|
|
56
63
|
"models:download": "node scripts/acquire-model-library.mjs",
|
|
57
64
|
"models:dev": "vite --config model-library/vite.config.js",
|
|
@@ -59,7 +66,7 @@
|
|
|
59
66
|
},
|
|
60
67
|
"dependencies": {
|
|
61
68
|
"@plasius/gpu-renderer": "^0.2.54",
|
|
62
|
-
"@plasius/gpu-shared": "
|
|
69
|
+
"@plasius/gpu-shared": "1.3.0"
|
|
63
70
|
},
|
|
64
71
|
"devDependencies": {
|
|
65
72
|
"c8": "^11.0.0",
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
const fs = require("node:fs");
|
|
2
2
|
const os = require("node:os");
|
|
3
|
+
const { createHash } = require("node:crypto");
|
|
3
4
|
const path = require("node:path");
|
|
4
5
|
const { spawnSync } = require("node:child_process");
|
|
5
6
|
|
|
6
|
-
const
|
|
7
|
+
const complianceFiles = [
|
|
8
|
+
"LICENSE",
|
|
9
|
+
"SECURITY.md",
|
|
10
|
+
"CONTRIBUTING.md",
|
|
11
|
+
"legal/CLA.md",
|
|
12
|
+
"legal/INDIVIDUAL_CLA.md",
|
|
13
|
+
"legal/CORPORATE_CLA.md"
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
// Approved schema d8f8eb430c77b8a98da496a3d8382d73d6297394, with only
|
|
17
|
+
// @plasius/schema replaced by @plasius/gpu-demo-viewer. Hash exact bytes.
|
|
18
|
+
const approvedTemplates = {
|
|
19
|
+
"legal/CLA.md": "8e7de8348013f65a551d9a3179d4927cdce4ae15497ba209a0cf2c1098ba489c",
|
|
20
|
+
"legal/INDIVIDUAL_CLA.md": "6ce945a06ee88d3c3103a6094123465440d8e9890a84956f257555cc9994fb39",
|
|
21
|
+
"legal/CORPORATE_CLA.md": "f56606b1a8a563ca1bae67a9335f32ced1ce3827dec500bc28617de604c66608"
|
|
22
|
+
};
|
|
7
23
|
|
|
8
24
|
function assert(condition, message) {
|
|
9
25
|
if (!condition) {
|
|
@@ -11,14 +27,15 @@ function assert(condition, message) {
|
|
|
11
27
|
}
|
|
12
28
|
}
|
|
13
29
|
|
|
14
|
-
function readJson(relativePath) {
|
|
30
|
+
function readJson(repoRoot, relativePath) {
|
|
15
31
|
return JSON.parse(fs.readFileSync(path.join(repoRoot, relativePath), "utf8"));
|
|
16
32
|
}
|
|
17
33
|
|
|
18
|
-
function packDryRunFiles() {
|
|
34
|
+
function packDryRunFiles(repoRoot) {
|
|
19
35
|
const result = spawnSync("npm", ["pack", "--dry-run", "--json"], {
|
|
20
36
|
cwd: repoRoot,
|
|
21
37
|
encoding: "utf8",
|
|
38
|
+
timeout: 30000,
|
|
22
39
|
env: {
|
|
23
40
|
...process.env,
|
|
24
41
|
npm_config_cache:
|
|
@@ -38,8 +55,8 @@ function packDryRunFiles() {
|
|
|
38
55
|
return packInfo.files.map((file) => file.path).sort();
|
|
39
56
|
}
|
|
40
57
|
|
|
41
|
-
function
|
|
42
|
-
const packageJson = readJson("package.json");
|
|
58
|
+
function verifyPublicPackage(repoRoot = path.resolve(__dirname, "..")) {
|
|
59
|
+
const packageJson = readJson(repoRoot, "package.json");
|
|
43
60
|
|
|
44
61
|
assert(packageJson.name === "@plasius/gpu-demo-viewer", "package name must remain scoped");
|
|
45
62
|
assert(packageJson.private !== true, "public package must not set private=true");
|
|
@@ -51,11 +68,24 @@ function main() {
|
|
|
51
68
|
assert(packageJson.repository?.url?.includes("Plasius-LTD/gpu-demo-viewer"), "repository metadata is required");
|
|
52
69
|
assert(packageJson.exports?.["."] === "./viewer-manifest.js", "viewer manifest must be the package root export");
|
|
53
70
|
|
|
54
|
-
|
|
71
|
+
// Inspect metadata before packing; never read contributor acceptance records.
|
|
72
|
+
const legalDirectory = fs.lstatSync(path.join(repoRoot, "legal"));
|
|
73
|
+
assert(legalDirectory.isDirectory(), "legal must be a real directory");
|
|
74
|
+
for (const file of complianceFiles) {
|
|
75
|
+
const stat = fs.lstatSync(path.join(repoRoot, file));
|
|
76
|
+
assert(stat.isFile() && stat.size > 0, `${file} must be a non-empty regular file`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for (const [file, expected] of Object.entries(approvedTemplates)) {
|
|
80
|
+
const digest = createHash("sha256").update(fs.readFileSync(path.join(repoRoot, file))).digest("hex");
|
|
81
|
+
assert(digest === expected, `${file} must match approved schema template`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const files = packDryRunFiles(repoRoot);
|
|
55
85
|
const fileSet = new Set(files);
|
|
56
86
|
const requiredFiles = [
|
|
57
87
|
"CHANGELOG.md",
|
|
58
|
-
|
|
88
|
+
...complianceFiles,
|
|
59
89
|
"README.md",
|
|
60
90
|
"assets/brigantine.gltf",
|
|
61
91
|
"docs/adrs/index.md",
|
|
@@ -73,6 +103,10 @@ function main() {
|
|
|
73
103
|
}
|
|
74
104
|
|
|
75
105
|
for (const file of files) {
|
|
106
|
+
assert(
|
|
107
|
+
!file.startsWith("legal/") || complianceFiles.includes(file),
|
|
108
|
+
`package tarball contains unapproved legal document: ${file}`
|
|
109
|
+
);
|
|
76
110
|
assert(!file.startsWith("node_modules/"), `package tarball must not include ${file}`);
|
|
77
111
|
assert(!file.startsWith("tests/"), `package tarball must not include ${file}`);
|
|
78
112
|
assert(!file.startsWith(".git/"), `package tarball must not include ${file}`);
|
|
@@ -82,9 +116,13 @@ function main() {
|
|
|
82
116
|
process.stdout.write("Public package contract verified.\n");
|
|
83
117
|
}
|
|
84
118
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
119
|
+
module.exports = { verifyPublicPackage };
|
|
120
|
+
|
|
121
|
+
if (require.main === module) {
|
|
122
|
+
try {
|
|
123
|
+
verifyPublicPackage();
|
|
124
|
+
} catch (error) {
|
|
125
|
+
process.stderr.write(`${error.message}\n`);
|
|
126
|
+
process.exitCode = 1;
|
|
127
|
+
}
|
|
90
128
|
}
|