@mnstry/atelier 0.2.0-alpha.4 → 0.2.0-alpha.5

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 (53) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +38 -12
  3. package/contracts/public-api-baseline.json +57 -0
  4. package/docs/assurance-controls.md +39 -0
  5. package/docs/atelier-runtime.md +15 -0
  6. package/docs/blocks/claims.md +15 -9
  7. package/docs/design.md +12 -6
  8. package/docs/install.md +26 -4
  9. package/docs/knowledge-graph.md +8 -4
  10. package/docs/local-services.md +101 -0
  11. package/docs/release-engineering.md +75 -10
  12. package/docs/repo-boundary-guard.md +12 -2
  13. package/docs/upgrade.md +25 -2
  14. package/fixtures/projects/sample-workspace/content/source.html.kg.json +4 -1
  15. package/fixtures/projects/source-formats-workspace/content/data.json.kg.json +4 -1
  16. package/fixtures/projects/source-formats-workspace/content/logo.png.kg.json +4 -1
  17. package/fixtures/projects/source-formats-workspace/content/metrics.csv.kg.json +4 -1
  18. package/fixtures/projects/source-formats-workspace/content/pipeline.yaml.kg.json +4 -1
  19. package/package.json +12 -5
  20. package/skills/claude/atelier-local-service/SKILL.md +47 -0
  21. package/skills/claude/atelier-public-boundary/SKILL.md +31 -0
  22. package/skills/codex/atelier-local-service/SKILL.md +47 -0
  23. package/skills/codex/atelier-public-boundary/SKILL.md +31 -0
  24. package/src/boundary/content-rules.mjs +278 -20
  25. package/src/boundary/policy.mjs +150 -60
  26. package/src/cli/execute-command.mjs +36 -0
  27. package/src/cli/run.mjs +17 -7
  28. package/src/collaboration/event-ledger.mjs +365 -0
  29. package/src/collaboration/index.mjs +17 -0
  30. package/src/collaboration/proposals.mjs +265 -65
  31. package/src/commands/attestation.mjs +20 -6
  32. package/src/commands/disclosure.mjs +133 -0
  33. package/src/commands/distribution.mjs +2 -1
  34. package/src/commands/extension-pack.mjs +2 -1
  35. package/src/commands/init.mjs +2 -1
  36. package/src/commands/server.mjs +1 -4
  37. package/src/disclosure/content-scan.mjs +193 -0
  38. package/src/egress/check.mjs +7 -38
  39. package/src/egress/forbidden-egress.mjs +32 -18
  40. package/src/graph/graph.mjs +112 -314
  41. package/src/graph/knowledge-graph.mjs +94 -18
  42. package/src/harness/context-client.mjs +9 -1
  43. package/src/index.mjs +12 -0
  44. package/src/project/config.mjs +66 -7
  45. package/src/project/file-class.mjs +14 -0
  46. package/src/project/package-root.mjs +10 -0
  47. package/src/project/path-match.mjs +38 -15
  48. package/src/project/private-state.mjs +110 -0
  49. package/src/server/local-sidecar.mjs +81 -59
  50. package/src/server/security.mjs +89 -4
  51. package/src/server/server.mjs +3 -2
  52. package/src/support/feedback-report.mjs +4 -3
  53. package/src/upgrade/upgrade.mjs +2 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,67 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.0-alpha.5
4
+
5
+ - Harden boundary enforcement so path globs use segment-aware matching, an
6
+ explicitly empty or malformed content-rule policy is invalid, staged and
7
+ pushed binary evidence is scanned within bounded budgets, incomplete Git
8
+ reads fail closed, linked worktrees install hooks in the correct Git common
9
+ directory, and `boundary audit` defaults to the current working tree with an
10
+ explicit `--head` snapshot mode.
11
+ - Consolidate graph classification in one canonical engine. Markdown without a
12
+ `kg` block is now represented as `unclassified` with a private audience and
13
+ diagnostics; empty, partial, or malformed declarations remain blocking.
14
+ Generated projection directories remain derived from the file-class manifest
15
+ so graph validation and generated-only upgrade recovery cannot drift apart.
16
+ - Bind release egress verification to the exact `npm pack` inventory, including
17
+ test-shaped paths that are actually published, and make the legacy egress
18
+ checker a thin delegate to the canonical scanner. Packed fixture-suppression
19
+ markers are refused and reviewed local-computed suppressions are counted.
20
+ - Harden `atelier dev` so it binds only to loopback, requires a generated
21
+ `atelier.manifest.json`, serves only enrolled safe static files after
22
+ realpath validation, and applies host, fetch-site, origin, method, and nonce
23
+ checks to the relevant read and mutation routes.
24
+ - Make collaboration records fail closed with typed corrupt-record results,
25
+ bounded ledger reads, POSIX no-follow and cross-platform state-leaf identity
26
+ validation, content-bound event identifiers, write locking, explicit
27
+ compaction, and one-pass proposal-list materialization. Compatibility
28
+ snapshots are best-effort projections of committed events rather than a
29
+ second authority. Proposal authority now follows declared capabilities and
30
+ apply endpoints rather than action-like words, and the never-released
31
+ provider-analysis experiment was removed before it became part of a
32
+ published API.
33
+ - Render expected project and JSON failures as typed, actionable CLI messages
34
+ without stacks by default; set `ATELIER_DEBUG=1` to include diagnostic stacks.
35
+ - Strengthen release proof with negative-control mutations and a bare consumer
36
+ that installs without publisher overrides, validates its dependency tree,
37
+ and imports every declared package export. A candidate is packed once, bound
38
+ by SHA-256, and passed unchanged through tarball audit, consumer, and branded
39
+ distribution gates. The trusted-publishing workflow publishes that same
40
+ retained, audited tarball rather than repacking the source directory.
41
+ - Pin every JavaScript subpath and named export from `v0.2.0-alpha.4` in a
42
+ registry-verified compatibility baseline with immutable tag-commit and
43
+ public-artifact provenance. Release tooling refuses removals, provenance
44
+ drift, and binding modified source to an already-tagged package version.
45
+ - Add a portable `atelier disclosure check` command that scans tracked or
46
+ staged consumer content, requires private denylist coverage by default, and
47
+ refuses tracked repository-local denylist files. Portable and repository
48
+ sweeps now detect the full bounded family of private-key headers and refuse
49
+ binary or invalid-UTF-8 evidence instead of omitting it. Fork sweeps require
50
+ the trusted denylist secret and cannot fall back to the untrusted checkout.
51
+ Repository release sweeps also inspect every bounded blob introduced by the
52
+ commit range, so content added and deleted before the final tree cannot
53
+ become public history unseen.
54
+ - Add public agent instructions and mirrored skills for extracting reusable
55
+ mechanisms from private implementations without carrying tenant material
56
+ into Atelier, plus a managed local-service contract for durable loopback
57
+ authoring and review tools.
58
+ - Document the client-zero adapter rule that exact package identity, installed
59
+ dependency resolution, CLI version, and `atelier.lock.json` must agree. This
60
+ prevents a stale sibling checkout from satisfying a current adapter proof.
61
+ - Declare the audited `fast-uri` pin as a direct runtime dependency so packed
62
+ offline consumer installs resolve the same dependency closure as the source
63
+ checkout.
64
+
3
65
  ## 0.2.0-alpha.4
4
66
 
5
67
  Presentation release. No contract changes and no runtime behaviour changes:
package/README.md CHANGED
@@ -48,7 +48,7 @@ governed projections
48
48
  You can see the complete loop in a disposable sample workspace:
49
49
 
50
50
  ```bash
51
- npm install --save-dev @mnstry/atelier@0.2.0-alpha.4
51
+ npm install --save-dev @mnstry/atelier@0.2.0-alpha.5
52
52
  npx mnstry-atelier init --fixture=sample-workspace --target ./sample
53
53
  npx mnstry-atelier graph --project ./sample/atelier.project.json
54
54
  npx mnstry-atelier project --project ./sample/atelier.project.json
@@ -146,6 +146,20 @@ best-effort publication.
146
146
  Because the checks are local and versioned with the work, the repository can
147
147
  prove its state in CI, on a laptop, or inside a larger toolchain.
148
148
 
149
+ Repositories that may contribute to a public or shared surface can add a
150
+ private, ignored disclosure denylist and scan either the tracked tree or the
151
+ exact staged index:
152
+
153
+ ```bash
154
+ npx mnstry-atelier disclosure check --staged
155
+ ```
156
+
157
+ The built-in structural pass catches machine-local paths, key material, and
158
+ secret-shaped assignments. A client-aware verdict additionally requires the
159
+ private denylist; the command fails closed when it is absent unless
160
+ `--structural-only` is chosen explicitly. Denylist patterns and matched text
161
+ never belong in the shared repository.
162
+
149
163
  ### 3. Collaboration becomes governed disclosure
150
164
 
151
165
  Collaboration is not equivalent to giving every participant every file. The
@@ -163,6 +177,11 @@ boundary; it does not silently make access decisions on your behalf.
163
177
  graph. The library exposes the same project, graph, validation, and projection
164
178
  primitives to code.
165
179
 
180
+ Consumer-owned authoring or review services that need a separate durable
181
+ lifecycle follow [the managed local-service contract](./docs/local-services.md).
182
+ That contract standardizes process ownership, private local state, and browser
183
+ recovery without putting a tenant's service details into Atelier.
184
+
166
185
  The shipped agent model is intentionally bounded: the Atelier can assemble
167
186
  session context, capability envelopes, and proposed changes, but it does not
168
187
  apply those proposals or grant direct write access. It is a local context and
@@ -234,16 +253,22 @@ one names the command that proves it.
234
253
 
235
254
  **Nothing leaves your machine, with one exception you can see.** There is no
236
255
  telemetry, no update check, no crash reporting, and no send path anywhere in
237
- the package. The exception: when no actor is configured, `boundary check` and
238
- `doctor` fall back to the `gh` CLI to resolve your GitHub login, which is an
239
- authenticated request to GitHub made with your own credentials. Set
240
- `MNSTRY_ATELIER_ACTOR` and that path is never taken. The only network client
256
+ the package. The exceptions are explicit: `boundary check` may invoke `gh api
257
+ user` after no declared actor matches an explicit `--actor`,
258
+ `MNSTRY_ATELIER_ACTOR`, `GITHUB_ACTOR`, or a configured Git email; repository
259
+ identity checks may invoke `gh api repos/...` to resolve a canonical GitHub
260
+ identity. Those authenticated requests use your own `gh` credentials. A
261
+ recognized explicit actor prevents the boundary actor fallback; recorded
262
+ repository identities let identity checks keep working when the provider is
263
+ unavailable. The only network client
241
264
  refuses non-loopback URLs, the served pages carry a policy that authorizes no
242
- external origin, and a fail-closed gate scans the executable and markup files
243
- under `src/`, `bin/`, `scripts/`, and `examples/` for egress primitives. Two
244
- limits worth stating plainly: the gate does not read the `.json` and `.md`
245
- files under `templates/` and `skills/`, and it does not model
246
- `child_process`, which is why the `gh` fallback above does not trip it:
265
+ external origin, and release audit scans every executable or markup file in
266
+ the exact `npm pack` inventory for egress primitives. The standalone gate also
267
+ scans executable and markup files under `src/`, `bin/`, `scripts/`,
268
+ `templates/`, `examples/`, and `skills/`. Two limits worth stating plainly:
269
+ the egress control does not interpret data-only `.json` or `.md` files, and it
270
+ does not model `child_process`; the two reviewed `gh` paths above are therefore
271
+ documented exceptions rather than scanner detections:
247
272
 
248
273
  ```bash
249
274
  npm run egress:check
@@ -316,7 +341,7 @@ Node.js `>=22.18.0 <23` is required. Pin the prerelease while the package
316
341
  remains in alpha:
317
342
 
318
343
  ```bash
319
- npm install --save-dev @mnstry/atelier@0.2.0-alpha.4
344
+ npm install --save-dev @mnstry/atelier@0.2.0-alpha.5
320
345
  ```
321
346
 
322
347
  Then choose the path that matches what you are building:
@@ -328,11 +353,12 @@ Then choose the path that matches what you are building:
328
353
  - [Distribution contracts](./docs/distributions.md)
329
354
  - [Conformance and attestation](./docs/attestation.md)
330
355
  - [Continuity commitments](./docs/continuity.md)
356
+ - [Assurance controls and evidence map](./docs/assurance-controls.md)
331
357
  - [Upgrade notes](./docs/upgrade.md)
332
358
 
333
359
  ## Status and command reference
334
360
 
335
- Current package: `@mnstry/atelier@0.2.0-alpha.4`.
361
+ Current package: `@mnstry/atelier@0.2.0-alpha.5`.
336
362
 
337
363
  The alpha package is usable and contract-tested, but its library API may still
338
364
  change before a stable release. Pin the exact version in production toolchains.
@@ -0,0 +1,57 @@
1
+ {
2
+ "schema": "mnstry.atelier-public-api-baseline@v1",
3
+ "baselineTag": "v0.2.0-alpha.4",
4
+ "baselineCommit": "6fed5b9e1077b361e26b2b581ea67a55e7634963",
5
+ "baselineVersion": "0.2.0-alpha.4",
6
+ "publishedRegistryArtifact": {
7
+ "package": "@mnstry/atelier",
8
+ "version": "0.2.0-alpha.4",
9
+ "shasum": "9f67f5b7fabc748ec235bbe85587a71b5ad639c8",
10
+ "integrity": "sha512-mt2vWnFZtBAc8C+bzjcgrIPYRGgVOhFHm4SPDrnXvWgcdDY/G2aUY5KP6YPmjkRCMvewGMsH7Wg+8i63f1/onQ==",
11
+ "sha256": "a032971977d9fbd3b7adc94f204739d4202b1754d72a77cbc79f4c473850e531",
12
+ "entryCount": 265,
13
+ "verifiedAt": "2026-08-25"
14
+ },
15
+ "requiredSubpaths": [
16
+ ".",
17
+ "./cli",
18
+ "./project",
19
+ "./graph",
20
+ "./projection",
21
+ "./readiness",
22
+ "./readiness-protocols",
23
+ "./server",
24
+ "./harness",
25
+ "./support",
26
+ "./egress",
27
+ "./boundary",
28
+ "./upgrade",
29
+ "./attestation",
30
+ "./extension-packs",
31
+ "./analysis/adapter",
32
+ "./export-contract",
33
+ "./dry-run",
34
+ "./contracts/atelier-export.v1.schema.json",
35
+ "./fixtures/atelier-export/sample-studio-offer.v1.json"
36
+ ],
37
+ "requiredModuleExports": {
38
+ ".": ["ALLOWED_RUNTIME_TARGETS", "ATELIER_LOCK_SCHEMA", "ATELIER_MIGRATION_SCHEMA", "ATELIER_READINESS_SCHEMA", "BASE_MIGRATIONS", "BOUNDARY_POLICY_SCHEMA", "LOCAL_AUDIENCES", "MNSTRY_READINESS_PACK_SCHEMA", "OBJECT_CLASSES", "PROJECT_CONFIG_SCHEMA", "READINESS_PROTOCOL_IDS", "READINESS_PROTOCOL_SLUGS", "RUNTIME_OWNERS", "RUNTIME_VISIBILITIES", "analysisAdapterDryRun", "applyUpgrade", "buildAtelierLock", "buildGraph", "buildProjectProjection", "buildReadiness", "buildSupportBundlePreview", "bundledMnstryReadinessPackV1", "bundledReadinessPack", "bundledReadinessProtocols", "checkAtelierLock", "checkBoundaryPolicy", "checkForbiddenEgress", "contextEnvelope", "createAtelierSidecarServer", "createPromoteEvent", "getBundledReadinessProtocol", "installBoundaryHooks", "loadAtelierLock", "loadBoundaryPolicy", "planUpgrade", "protocolById", "resolveProjectConfig", "validateAtelierExportContract", "validateAtelierExportDryRun", "validateAtelierExportDryRunFile", "validateBoundaryPolicy", "validateJsonSchema", "validateMigrationRecord", "validateProjectConfigDoc", "validateSchemaShape", "validateSupportBundlePayload", "writeAtelierLock"],
39
+ "./cli": ["DEFAULT_BRAND", "buildCommandHelpText", "buildHelpText", "buildVersionText", "commandMap", "runCli"],
40
+ "./project": ["EXTERNAL_REPO_KIND", "LOCAL_OVERLAY_ENV", "LOCAL_OVERLAY_FILES", "LOCAL_OVERLAY_SCHEMA", "LOCAL_STATE_DIR", "PROJECT_CONFIG_ARG_PREFIX", "PROJECT_CONFIG_ENV", "PROJECT_CONFIG_SCHEMA", "SUPPORTED_IDENTITY_PROVIDERS", "asObject", "commandProject", "ensureLocalState", "firstString", "gitRemoteUrl", "isExternalRepo", "loadRepoAccess", "localOverlayCandidatePaths", "localStateRoot", "parseArgs", "parseRepoPathOverrides", "projectConfigArg", "readJson", "readLocalOverlay", "readProjectConfig", "remoteHost", "resolvePathValue", "resolveProjectConfig", "stripProjectConfigArgs", "validateProjectConfigDoc", "writeJson"],
41
+ "./graph": ["VALID_AUDIENCES", "VALID_RELATIONS", "buildGraph", "ignoredSidecarWarnings", "parseFrontmatterYaml", "runGraphCommand"],
42
+ "./projection": ["buildProjectProjection", "runProjectCommand"],
43
+ "./readiness": ["ATELIER_READINESS_SCHEMA", "buildReadiness", "runReadinessCommand", "stableReadinessForCheck", "summarizeGraph", "summarizeProjection"],
44
+ "./readiness-protocols": ["MNSTRY_READINESS_PACK_SCHEMA", "READINESS_PROTOCOL_IDS", "READINESS_PROTOCOL_SCHEMA", "READINESS_PROTOCOL_SLUGS", "READINESS_RUN_SCHEMA", "bundledMnstryReadinessPackV1", "bundledReadinessPack", "bundledReadinessProtocols", "getBundledReadinessProtocol", "protocolById"],
45
+ "./server": ["ATELIER_CAPABILITIES_SCHEMA", "ATELIER_CONTEXT_SCHEMA", "ATELIER_DOCTOR_SCHEMA", "ATELIER_PRESENCE_SCHEMA", "ATELIER_RESOLVE_SCHEMA", "ATELIER_SESSION_AUTH_SCHEMA", "createAtelierSidecarServer"],
46
+ "./harness": ["contextEnvelope", "runContextCommand"],
47
+ "./support": ["BANNED_KEY_PATTERNS", "BANNED_VALUE_PATTERNS", "DEFAULT_SUPPORT_FIELDS", "SUPPORT_BUNDLE_PREVIEW_SCHEMA", "buildSupportBundlePreview", "parseSupportBundleArgs", "readSupportBundleJson", "runSupportCommand", "supportBundlePreview", "validateSupportBundlePayload", "writeOrPrintSupportBundle"],
48
+ "./egress": ["DEFAULT_EGRESS_SCAN_PATHS", "LOCAL_COMPUTED_ALLOW_MARKER", "TEST_FIXTURE_ALLOW_MARKER", "checkForbiddenEgress", "discoverForbiddenEgressScanFiles", "forbiddenEgressFindingsForText"],
49
+ "./boundary": ["BOUNDARY_POLICY_SCHEMA", "DEFAULT_FORBIDDEN_PATHS", "LEGACY_PROMOTE_EVENT_SCHEMAS", "PRIVATE_AUDIENCES", "PROMOTE_EVENT_SCHEMA", "SEMANTIC_INITIALIZATION_DEFAULTS", "VALID_AUDIENCES", "VALID_AUTOCOMMIT", "VALID_BOUNDARY_MODES", "VALID_REPO_KINDS", "auditContentRules", "checkBoundaryPolicy", "checkPushContent", "createPromoteEvent", "diffFileSections", "installBoundaryHooks", "loadBoundaryPolicy", "projectBoundaryPolicyPath", "projectGovernanceLedgerPath", "resolveCurrentActor", "runBoundaryAuditCommand", "runBoundaryCheckCommand", "runBoundaryInstallHooksCommand", "runBoundaryPushCheckCommand", "runPromoteCommand", "semanticChangesInFile", "semanticFieldOnLine", "stagedPathsForProject", "validateBoundaryPolicy"],
50
+ "./upgrade": ["ATELIER_LOCK_SCHEMA", "ATELIER_MIGRATION_SCHEMA", "BASE_MIGRATIONS", "LOCK_FILE", "MIGRATION_CLASSES", "applyMigration", "applyUpgrade", "buildAtelierLock", "checkAtelierLock", "loadAtelierLock", "lockPathForProject", "planUpgrade", "runLockCommand", "runUpgradeCommand", "validateMigrationRecord", "writeAtelierLock"],
51
+ "./attestation": ["KEY_ENV_VAR", "LOCAL_KEY_FILE", "canonicalize", "generateKeyPair", "loadSigningKey", "payloadHashOf", "safeLabel", "signAttestation", "signDocument", "signingInput", "verifyAttestation", "verifyDocument", "verifyPayloadBinding"],
52
+ "./extension-packs": ["ATELIER_EXT_NAMESPACE", "EXTENSION_PACK_SCHEMA", "PROTOCOL_POSTURE_POINTS", "RESERVED_NAMESPACE", "RESERVED_NAMESPACE_PATTERN", "computePackDigest", "createProtocolRegistry", "loadExtensionPacks"],
53
+ "./analysis/adapter": ["analysisAdapterDryRun", "runAnalysisAdapterCommand"],
54
+ "./export-contract": ["ALLOWED_RUNTIME_TARGETS", "LOCAL_AUDIENCES", "OBJECT_CLASSES", "RUNTIME_OWNERS", "RUNTIME_VISIBILITIES", "validateAtelierExportContract", "validateJsonSchema", "validateSchemaShape"],
55
+ "./dry-run": ["main", "validateAtelierExportDryRun", "validateAtelierExportDryRunFile"]
56
+ }
57
+ }
@@ -0,0 +1,39 @@
1
+ # Assurance controls and evidence map
2
+
3
+ This ledger maps public trust claims to the control that enforces them, the
4
+ test that challenges the control, and the limit that remains. It describes the
5
+ source tree; a release decision must additionally record the exact candidate
6
+ commit and packed-tarball digest.
7
+
8
+ | Claim | Enforcing control | Defensive evidence | Stated limit |
9
+ | --- | --- | --- | --- |
10
+ | Boundary rules cannot silently switch themselves off | `src/boundary/policy.mjs`, `src/boundary/content-rules.mjs`, and generated Git hooks | `boundary:test`; boundary case in `assurance:mutation-smoke` | Repository access remains the source read boundary; an audience label is not encryption |
11
+ | A clean boundary verdict uses complete evidence | Typed Git reads with diff and binary budgets; incomplete reads become blocking diagnostics | `test/boundary-content-rules.test.mjs` | Budgets intentionally refuse evidence too large to inspect rather than claiming it is clean |
12
+ | Graph classification has one meaning | `src/graph/knowledge-graph.mjs` is canonical; `src/graph/graph.mjs` adapts its result | `graph:test`; graph case in `assurance:mutation-smoke` | Unclassified Markdown is retained as private diagnostic material, not admitted as governed content |
13
+ | The package has no undisclosed runtime egress path | Canonical forbidden-egress scanner plus exact packed-file inventory in `release:audit` | egress tests, marker-inventory test, and egress case in `assurance:mutation-smoke` | Data-only files are not interpreted; reviewed `gh` subprocess fallbacks are documented exceptions |
14
+ | Local review serves only generated publication output | Loopback-only bind, required `atelier.manifest.json`, realpath containment, enrolled safe types, POSIX no-follow plus cross-platform leaf type/identity validation for local state, and host/fetch-site/origin/method/nonce checks | `server:security:test`; sidecar case in `assurance:mutation-smoke` | The sidecar is a local review tool, not user authentication or runtime authorization |
15
+ | Collaboration cannot become a hidden apply path | Proposal authority is capability-derived; records are typed; POSIX ledger and snapshot leaves are no-follow, while every platform rejects redirected leaves and validates opened file identity when available; ledger reads are bounded, one-pass for lists, and corrupt tails fail closed | `collaboration:test` and ledger ceiling/performance tests | Collaboration remains copy-only proposal metadata; snapshots are rebuildable projections and Git review owns source changes |
16
+ | Expected operator failures are actionable without leaking internals | Typed project/JSON diagnostics and the CLI execution wrapper | `test/cli-brand.test.mjs` | Unexpected stacks require the operator to opt in with `ATELIER_DEBUG=1` |
17
+ | Published APIs do not disappear silently | Tag-derived subpath and named-export baseline plus version/tag identity refusal | `public-api:compat`; `test/public-api-compat.test.mjs` | Additive API checks do not decide whether a new version number is appropriate |
18
+ | The published artifact is the artifact tested | `release:candidate` packs once, binds SHA-256, sends that exact archive through allowlist/content audit, bare-consumer install, all-export import, and branded distribution smoke, then the trusted-publishing workflow retains and publishes that same tarball path | `release:audit`, `consumer:smoke`, `distribution:smoke`, `assurance:mutation-smoke`, `publish-workflow.test.mjs` | Passing gates does not publish, deploy, or constitute an external reviewer’s approval |
19
+
20
+ The release-blocking command is `npm run prepublishOnly`. It includes positive
21
+ regression suites and deliberately broken local fixtures. The latter prove
22
+ that boundary, graph, egress, sidecar, and distribution controls still refuse
23
+ their named failure modes; they do not exercise a live abuse path.
24
+
25
+ ## Exact-candidate evidence
26
+
27
+ At candidate cut, retain all of the following together:
28
+
29
+ 1. the Git commit SHA and a clean working-tree check;
30
+ 2. the `npm pack --json` inventory and tarball SHA-256;
31
+ 3. outputs from syntax, contracts, public-API compatibility, migrations, repository disclosure,
32
+ release audit, full tests, mutation smoke, bare consumer, and distribution
33
+ smoke;
34
+ 4. a defensive review tied to that same commit and digest; and
35
+ 5. explicit human decisions for versioning, publication, deployment, or any
36
+ external communication.
37
+
38
+ Evidence for a different commit or a dirty tree is not evidence for the
39
+ candidate.
@@ -32,3 +32,18 @@ The default package posture is no telemetry, no external network egress, no
32
32
  runtime mutation, no browser apply endpoint, and no model-assisted analysis execution.
33
33
  Provider analysis output may only enter as proposed `atelier-claim@v1` records
34
34
  until explicitly reviewed by the project owner.
35
+
36
+ `atelier dev` is narrower than a general static server. It refuses non-loopback
37
+ bind hosts, requires a generated `atelier.manifest.json`, and publishes only
38
+ manifest-enrolled HTML, script, style, and image files that remain inside the
39
+ workspace after realpath resolution. Hidden paths, local state, secret-shaped
40
+ names, symlinks, unknown file types, and unenrolled files are unavailable.
41
+ Reads validate the loopback host and fetch metadata; mutations additionally
42
+ require an allowed method, exact same origin, and the session nonce.
43
+
44
+ Collaboration endpoints are copy-only: they create or review proposal records;
45
+ they do not apply source changes. Authority is derived from declared
46
+ capabilities and apply endpoints, never inferred from action-like prose. A
47
+ partially corrupt ledger returns typed incomplete evidence and blocks a clean
48
+ claim. Ledger reads and records are bounded, appends are locked, and retention
49
+ changes happen only through explicit compaction.
@@ -3,16 +3,22 @@ one names the command that proves it.
3
3
 
4
4
  **Nothing leaves your machine, with one exception you can see.** There is no
5
5
  telemetry, no update check, no crash reporting, and no send path anywhere in
6
- the package. The exception: when no actor is configured, `boundary check` and
7
- `doctor` fall back to the `gh` CLI to resolve your GitHub login, which is an
8
- authenticated request to GitHub made with your own credentials. Set
9
- `MNSTRY_ATELIER_ACTOR` and that path is never taken. The only network client
6
+ the package. The exceptions are explicit: `boundary check` may invoke `gh api
7
+ user` after no declared actor matches an explicit `--actor`,
8
+ `MNSTRY_ATELIER_ACTOR`, `GITHUB_ACTOR`, or a configured Git email; repository
9
+ identity checks may invoke `gh api repos/...` to resolve a canonical GitHub
10
+ identity. Those authenticated requests use your own `gh` credentials. A
11
+ recognized explicit actor prevents the boundary actor fallback; recorded
12
+ repository identities let identity checks keep working when the provider is
13
+ unavailable. The only network client
10
14
  refuses non-loopback URLs, the served pages carry a policy that authorizes no
11
- external origin, and a fail-closed gate scans the executable and markup files
12
- under `src/`, `bin/`, `scripts/`, and `examples/` for egress primitives. Two
13
- limits worth stating plainly: the gate does not read the `.json` and `.md`
14
- files under `templates/` and `skills/`, and it does not model
15
- `child_process`, which is why the `gh` fallback above does not trip it:
15
+ external origin, and release audit scans every executable or markup file in
16
+ the exact `npm pack` inventory for egress primitives. The standalone gate also
17
+ scans executable and markup files under `src/`, `bin/`, `scripts/`,
18
+ `templates/`, `examples/`, and `skills/`. Two limits worth stating plainly:
19
+ the egress control does not interpret data-only `.json` or `.md` files, and it
20
+ does not model `child_process`; the two reviewed `gh` paths above are therefore
21
+ documented exceptions rather than scanner detections:
16
22
 
17
23
  ```bash
18
24
  npm run egress:check
package/docs/design.md CHANGED
@@ -12,12 +12,16 @@ proves it — because a design document that cannot be checked is marketing.
12
12
 
13
13
  ## 1. A repository with an ontology
14
14
 
15
- A small structured header turns a file into a node: front matter on
15
+ A small structured header turns a file into a governed node: front matter on
16
16
  Markdown, or a `.kg.json` sidecar beside any other format — JSON, YAML,
17
17
  CSV, media, anything — which the kit enrolls without ever parsing the
18
18
  foreign format. The header declares identity (`kg.id`), type, status,
19
19
  audience, and relations to other nodes.
20
20
 
21
+ Markdown without a `kg` block is still counted by the canonical graph engine,
22
+ but only as private `unclassified` material with a diagnostic. Once a `kg`
23
+ block is present, partial or malformed declarations are blocking errors.
24
+
21
25
  The graph builder compiles the repository into a knowledge graph,
22
26
  deterministically: same tree in, same graph out, and `--check` mode fails
23
27
  when a generated graph has drifted from its sources. There is no import
@@ -92,14 +96,16 @@ atelier lock check --project ./atelier.project.json
92
96
  The same governed workspace projects two ways.
93
97
 
94
98
  For humans: a generated review surface, served by a sidecar that binds to
95
- loopback only. The served pages carry a policy that authorizes no external
96
- origin, and the only network client in the package refuses non-loopback
97
- URLs.
99
+ loopback only. It requires a generated publication manifest and serves only
100
+ enrolled safe static files after realpath validation. The served pages carry a
101
+ policy that authorizes no external origin, and the only network client in the
102
+ package refuses non-loopback URLs.
98
103
 
99
104
  For agents: session-bound context and capability envelopes that hand an
100
105
  agent harness a governed view of the workspace — what exists, what it may
101
- look at, what it may propose. Proposals are recorded as metadata; there
102
- are no browser apply endpoints and no write authority to grant. Context
106
+ look at, what it may propose. Proposals are recorded as typed copy-only
107
+ metadata; capability declarations expose no apply endpoint, source write,
108
+ execution, or Git authority. Context
103
109
  without authority. Neutral Claude and Codex skill wrappers ship in the
104
110
  package, so a harness can do readiness review work against the workspace
105
111
  without a single line of custom glue.
package/docs/install.md CHANGED
@@ -30,19 +30,19 @@ The registry is the distribution channel of record, as `docs/continuity.md`
30
30
  commits:
31
31
 
32
32
  ```bash
33
- npm install --save-dev @mnstry/atelier@0.2.0-alpha.4
33
+ npm install --save-dev @mnstry/atelier@0.2.0-alpha.5
34
34
  ```
35
35
 
36
36
  Installing from the matching Git tag resolves to the same reviewed commit:
37
37
 
38
38
  ```bash
39
- npm install --save-dev "git+https://github.com/MNSTRY/atelier.git#v0.2.0-alpha.4"
39
+ npm install --save-dev "git+https://github.com/MNSTRY/atelier.git#v0.2.0-alpha.5"
40
40
  ```
41
41
 
42
42
  Or over SSH:
43
43
 
44
44
  ```bash
45
- npm install --save-dev "git+ssh://git@github.com/MNSTRY/atelier.git#v0.2.0-alpha.4"
45
+ npm install --save-dev "git+ssh://git@github.com/MNSTRY/atelier.git#v0.2.0-alpha.5"
46
46
  ```
47
47
 
48
48
  Keep the `@mnstry/` scope — see the command-form note above for why the
@@ -57,6 +57,24 @@ The workspace `atelier.lock.json` should record the resolved version or Git
57
57
  SHA from the install. Treat the tag or version as the friendly handle and the
58
58
  SHA as the review authority.
59
59
 
60
+ ### Adapter runners must bind package identity
61
+
62
+ An early downstream adapter exposed a subtle failure mode worth making a
63
+ general rule: a wrapper that scans arbitrary sibling checkouts and accepts the
64
+ first matching binary can validate against an archived tree while appearing
65
+ current. Adapter and distribution runners must therefore:
66
+
67
+ 1. declare one exact `@mnstry/atelier` version in their package manifest;
68
+ 2. prefer the installed `node_modules/@mnstry/atelier` package over incidental
69
+ sibling checkouts;
70
+ 3. accept an explicit local checkout only when its package name and version
71
+ match the declared dependency;
72
+ 4. run `atelier --version` and `atelier lock check` as part of adapter proof;
73
+ 5. fail closed when the declared version, resolved package, and lock disagree.
74
+
75
+ This rule binds which Atelier implementation ran. It does not make generated
76
+ output authoritative or grant runtime mutation.
77
+
60
78
  Use one private domain repository per user:
61
79
 
62
80
  ```text
@@ -103,7 +121,11 @@ atelier init --template shared-project --target ./project-alpha --actor tenant-u
103
121
 
104
122
  `--actor` rewrites the copied boundary policy actor entry and binds it to the
105
123
  local Git email when available. Use `--github-login` or `--git-email` to set
106
- those values explicitly during onboarding.
124
+ those values explicitly during onboarding. At check time, a declared actor is
125
+ resolved in this order: recognized `--actor`/`MNSTRY_ATELIER_ACTOR`/
126
+ `GITHUB_ACTOR`, configured Git email, then a reviewed `gh api user` fallback.
127
+ An explicit value that is not declared in the policy does not authenticate an
128
+ actor and therefore does not suppress later resolution attempts.
107
129
 
108
130
  Then update:
109
131
 
@@ -7,16 +7,20 @@ projection readiness.
7
7
 
8
8
  ## Source Rules
9
9
 
10
- - Markdown documents use front matter.
10
+ - Markdown documents may use front matter. A document with no `kg` block is
11
+ represented as `unclassified`, assigned the fail-closed `private` audience,
12
+ and reported diagnostically rather than silently treated as governed.
11
13
  - Non-Markdown sources use adjacent `.kg.json` sidecars.
12
- - `kg.id` is required and stable.
13
- - `kg.audience` is required.
14
+ - Once a Markdown `kg` block exists, `kg.id` and `kg.audience` are required;
15
+ empty, partial, and malformed declarations are blocking errors.
14
16
  - `kg.visibility` is invalid in local source metadata.
15
17
  - Declared relations emit semantic edges.
16
18
 
17
19
  ## Source formats
18
20
 
19
- The graph is sidecar-first: Markdown front matter is the only inline metadata
21
+ The graph has one canonical classification engine in
22
+ `src/graph/knowledge-graph.mjs`; the older `graph.mjs` surface is a compatibility
23
+ adapter over it, not a second classifier. Markdown front matter is the only inline metadata
20
24
  format the kit reads, and every other file becomes a first-class node through
21
25
  an adjacent `<file>.kg.json` sidecar
22
26
  (`contracts/knowledge-source-sidecar.v1.schema.json`). This is how any format
@@ -0,0 +1,101 @@
1
+ # Managed local services
2
+
3
+ Atelier-backed repositories sometimes need a local authoring, review, or
4
+ preview service that writes repository-owned state. The service may be
5
+ specialized; its lifecycle and data-boundary behavior should not be improvised.
6
+
7
+ This contract applies to consumer services other than `atelier dev`. It does
8
+ not change the Atelier sidecar's own lifecycle.
9
+
10
+ ## Atelier sidecar reference boundary
11
+
12
+ The built-in `atelier dev` sidecar is the reference for its request and
13
+ publication boundary, not for the managed lifecycle below. It binds only to a
14
+ literal loopback host and refuses startup without a valid generated
15
+ `atelier.manifest.json`. Static reads are limited to manifest-enrolled,
16
+ supported file types after realpath containment; hidden, state, secret-shaped,
17
+ symlinked, unknown, and unenrolled paths are denied. API reads require a trusted
18
+ loopback host and `Sec-Fetch-Site: same-origin` or `none`; `same-site` and
19
+ cross-site requests are refused. Mutations additionally require an
20
+ allowed method, exact expected origin, and the session nonce. Its collaboration
21
+ records are copy-only proposals, not an apply channel.
22
+
23
+ ## Kit and adapter boundary
24
+
25
+ The portable Atelier layer owns these invariants:
26
+
27
+ - bind to loopback only;
28
+ - expose explicit `start`, `status`, and `stop` operations;
29
+ - detach only when the user asked for a service that survives an agent command;
30
+ - identify the running process with both a random runtime identifier and its
31
+ process ID;
32
+ - refuse to adopt, overwrite, or stop a process whose identity cannot be
33
+ proven;
34
+ - keep runtime records, logs, drafts, and recovery copies in ignored local
35
+ storage with owner-only permissions;
36
+ - make writes atomic and keep a failed queued write from poisoning later saves;
37
+ - keep unsaved browser work available when the service disappears;
38
+ - provide an explicit snapshot export and a retry path;
39
+ - use no telemetry, remote dependency, or external send path.
40
+
41
+ The consuming repository owns its service name, port, executable, state schema,
42
+ content, command names, and user-facing recovery copy. None of those adapter
43
+ details belong in the public Atelier kit.
44
+
45
+ ## Lifecycle contract
46
+
47
+ ### Start
48
+
49
+ 1. Resolve an explicit loopback port and ignored runtime directory.
50
+ 2. Probe the service health endpoint.
51
+ 3. If a managed instance answers with the recorded runtime identifier and PID,
52
+ report it as already running.
53
+ 4. If anything else owns the port, refuse to take it over.
54
+ 5. Generate a fresh runtime identifier, start the child without a shell, write
55
+ a mode-0600 runtime record, and wait for health to echo both identifiers.
56
+ 6. If health never proves ownership, stop only the child just created and
57
+ report the ignored operational log.
58
+
59
+ ### Status
60
+
61
+ Status is healthy only when the runtime record, health response, runtime
62
+ identifier, PID, service identity, and loopback address agree. A responding
63
+ port without that proof is occupied, not adopted.
64
+
65
+ ### Stop
66
+
67
+ Stop only the PID whose health response matches the recorded runtime identifier
68
+ and PID. Refuse on disagreement. After a clean stop, remove only the generated
69
+ runtime record. Never kill by port, process name, or broad pattern.
70
+
71
+ Managed start survives a terminal or agent command. It does not imply operating
72
+ system startup. Installing an OS-level service is a separate system change and
73
+ requires explicit user authorization.
74
+
75
+ ## Authoring-state contract
76
+
77
+ - The canonical template may be tracked; the live draft must be ignored unless
78
+ a reviewed workflow explicitly promotes a sanitized artifact.
79
+ - Live state and runtime metadata use owner-only permissions.
80
+ - Browser autosave is a recovery layer, not a substitute for the canonical
81
+ local file.
82
+ - A lost server must produce a persistent, actionable message naming the exact
83
+ restart command, the retained browser state, the snapshot option, and Retry.
84
+ - Conflict responses remain fail-closed. Do not silently overwrite a newer
85
+ file or reconcile divergent tabs automatically.
86
+
87
+ ## Required evidence
88
+
89
+ A consumer implementation is not complete until tests prove:
90
+
91
+ 1. start is idempotent and survives the launching command;
92
+ 2. status refuses an unowned listener;
93
+ 3. stop is bound to runtime identifier and PID;
94
+ 4. a stopped server leaves the exact in-browser draft intact;
95
+ 5. restart plus Retry persists that draft;
96
+ 6. a refused filesystem write does not break later valid saves;
97
+ 7. private state and runtime files are ignored and owner-readable only; and
98
+ 8. a fresh checkout can discover the commands through its agent instructions.
99
+
100
+ Use synthetic fixtures for public Atelier tests. Tenant-specific proof remains
101
+ in the tenant repository.