@mnstry/atelier 0.2.0-alpha.3 → 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 (55) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +280 -230
  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 +34 -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 +13 -6
  20. package/skills/claude/atelier-local-service/SKILL.md +47 -0
  21. package/skills/claude/atelier-open/SKILL.md +6 -5
  22. package/skills/claude/atelier-public-boundary/SKILL.md +31 -0
  23. package/skills/codex/atelier-local-service/SKILL.md +47 -0
  24. package/skills/codex/atelier-open/SKILL.md +6 -5
  25. package/skills/codex/atelier-public-boundary/SKILL.md +31 -0
  26. package/src/boundary/content-rules.mjs +278 -20
  27. package/src/boundary/policy.mjs +150 -60
  28. package/src/cli/execute-command.mjs +36 -0
  29. package/src/cli/run.mjs +17 -7
  30. package/src/collaboration/event-ledger.mjs +365 -0
  31. package/src/collaboration/index.mjs +17 -0
  32. package/src/collaboration/proposals.mjs +265 -65
  33. package/src/commands/attestation.mjs +20 -6
  34. package/src/commands/disclosure.mjs +133 -0
  35. package/src/commands/distribution.mjs +2 -1
  36. package/src/commands/extension-pack.mjs +2 -1
  37. package/src/commands/init.mjs +2 -1
  38. package/src/commands/server.mjs +1 -4
  39. package/src/disclosure/content-scan.mjs +193 -0
  40. package/src/egress/check.mjs +7 -38
  41. package/src/egress/forbidden-egress.mjs +32 -18
  42. package/src/graph/graph.mjs +112 -314
  43. package/src/graph/knowledge-graph.mjs +94 -18
  44. package/src/harness/context-client.mjs +9 -1
  45. package/src/index.mjs +12 -0
  46. package/src/project/config.mjs +66 -7
  47. package/src/project/file-class.mjs +14 -0
  48. package/src/project/package-root.mjs +10 -0
  49. package/src/project/path-match.mjs +38 -15
  50. package/src/project/private-state.mjs +110 -0
  51. package/src/server/local-sidecar.mjs +81 -59
  52. package/src/server/security.mjs +89 -4
  53. package/src/server/server.mjs +3 -2
  54. package/src/support/feedback-report.mjs +4 -3
  55. package/src/upgrade/upgrade.mjs +2 -1
@@ -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.3
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.3"
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.3"
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.
@@ -10,16 +10,23 @@ a location, never the matched content.
10
10
  ### release:audit
11
11
 
12
12
  `npm run release:audit` (`scripts/check-release-tarball.mjs`) audits the exact
13
- tarball `npm pack` would publish:
13
+ tarball `npm pack` would publish. `npm run release:candidate` packs once and
14
+ passes the same archive and expected SHA-256 through this audit and both
15
+ consumer smokes:
14
16
 
15
17
  - Package metadata: name, license, exposed CLI bins, and a mandatory `files`
16
18
  allowlist in `package.json`.
17
19
  - Tarball allowlist: every packed path must match a known-good pattern; any
18
- unexpected file fails the audit.
20
+ unexpected file fails the audit. The extracted archive inventory must match
21
+ the `npm pack --json` inventory exactly.
19
22
  - Content scan: every packed file is scanned against committed structural
20
23
  patterns (absolute user paths, machine-local temp paths, agent-local state
21
24
  paths, key material, secret-like assignments) and against the maintainer-held
22
25
  denylist described below.
26
+ - Egress scan: the canonical egress control receives the exact `npm pack`
27
+ inventory and inspects every packed executable or markup file, including a
28
+ test-shaped path if one is ever admitted to the artifact. Packed test-fixture
29
+ suppression markers are refused; reviewed local-computed markers are counted.
23
30
  - Version drift: `CHANGELOG.md` must contain a `## <version>` heading and
24
31
  `README.md` must mention the version. The expected version and tarball name
25
32
  are derived from `package.json`, never hardcoded.
@@ -27,6 +34,15 @@ tarball `npm pack` would publish:
27
34
  Exit codes: `0` clean, `1` findings, `2` configuration error (for example an
28
35
  unavailable denylist without explicit acknowledgment).
29
36
 
37
+ `release:candidate` additionally requires a clean tree, records the candidate
38
+ commit and tarball digest, and refuses a version already bound to a different
39
+ tagged commit. It is a release-evidence command, not a publication command.
40
+ When `ATELIER_RELEASE_OUTPUT_DIR` is set, it atomically retains the verified
41
+ tarball, npm-pack metadata, and a machine-readable receipt. The trusted
42
+ publishing workflow runs `prepublishOnly` explicitly with that output directory,
43
+ re-verifies the retained digest, and publishes the retained tarball path rather
44
+ than repacking the source checkout.
45
+
30
46
  ### repo:check
31
47
 
32
48
  `npm run repo:check` (`scripts/check-repo-disclosure.mjs`) sweeps the whole
@@ -43,6 +59,27 @@ Git-tracked tree, not just the tarball:
43
59
  Exit codes match `release:audit`: `0` clean, `1` findings, `2` configuration or
44
60
  usage error.
45
61
 
62
+ ### disclosure check
63
+
64
+ `atelier disclosure check` is the portable consumer-facing content gate. It
65
+ scans every tracked text file by default or the exact staged index with
66
+ `--staged`, never follows tracked symlinks, and reports labels plus locations
67
+ without echoing matched content. `--untrusted` suppresses finding details.
68
+
69
+ The command loads private patterns from `ATELIER_DENYLIST_JSON`, an explicit
70
+ `--denylist` path, or ignored
71
+ `.atelier-local/disclosure-denylist.json`. A repository-local denylist is
72
+ refused if it is tracked or not covered by `.gitignore`. Missing private
73
+ patterns are a configuration failure unless `--structural-only` explicitly
74
+ acknowledges the reduced verdict. Public text-only packaging can also use
75
+ `--fail-on-binary`; Atelier's own tarball audit separately refuses packed
76
+ binary files.
77
+
78
+ The public Atelier repository keeps the stronger `repo:check` identity and
79
+ commit-message controls. The portable command exists so consumer repositories
80
+ can enforce the same public/private content boundary without inheriting
81
+ MNSTRY-specific commit identities.
82
+
46
83
  ### Commit-identity gate
47
84
 
48
85
  Part of `repo:check --commits`. Commit authors must match a hardcoded
@@ -65,6 +102,17 @@ changelog and the migration registry honest about breaking changes:
65
102
  - Every registered migration record is re-validated against the migration
66
103
  record contract.
67
104
 
105
+ ### public-api:compat
106
+
107
+ `npm run public-api:compat` compares every package subpath and named JavaScript
108
+ export published by `v0.2.0-alpha.4` with the current package. Removing one
109
+ fails closed. It also rejects modified source that retains the already-tagged
110
+ baseline version, independently of the release-candidate check. The baseline
111
+ records and verifies its tag commit and the public npm artifact identity; the
112
+ published archive was independently checked to contain all 20 subpaths and 212
113
+ named exports. This is runtime JavaScript shape continuity, not a promise about
114
+ function signatures, types, or behavior.
115
+
68
116
  ### egress:check
69
117
 
70
118
  `npm run egress:check` (`atelier egress check`) scans package runtime paths for
@@ -75,8 +123,22 @@ paths; this gate is the mechanical check behind that claim.
75
123
 
76
124
  `npm run consumer:smoke` (`scripts/consumer-smoke.mjs`) packs the real tarball,
77
125
  installs it offline into a throwaway consumer project with lifecycle scripts
78
- disabled, and imports the public API to validate a sample export. It proves the
79
- tarball is installable and functional exactly as a consumer receives it.
126
+ disabled and without copying the publisher's `overrides`, checks the installed
127
+ dependency tree, imports every declared JavaScript export, parses every
128
+ declared JSON export, and validates a sample export through both API and CLI.
129
+ It proves the tarball is installable and functional exactly as a bare consumer
130
+ receives it from disk. The offline smoke deliberately warms the locked registry
131
+ dependency closure first; it does not prove that a not-yet-published version
132
+ resolves from a cold or live registry.
133
+
134
+ ### assurance:mutation-smoke
135
+
136
+ `npm run assurance:mutation-smoke` runs local, synthetic negative controls for
137
+ the boundary, graph, packed and direct egress, sidecar, and distribution
138
+ families. Every fixture introduces one named failure and must be refused by the
139
+ terminal CLI or release command where one exists. This is part of
140
+ `prepublishOnly`; a control that stops detecting its failure mode blocks the
141
+ release even if positive-path tests remain green.
80
142
 
81
143
  ### Egress-marker inventory
82
144
 
@@ -105,7 +167,7 @@ maintainer-reviewed before entering the list.
105
167
  Four jobs run on pushes to `main` and on pull requests, and all four are
106
168
  required status checks:
107
169
 
108
- - `test`: syntax check (`node --check`, not a type system), the full test suite, contract checks, `egress:check`, and
170
+ - `test`: syntax check (`node --check`, not a type system), the full test suite (including isolated consumer disclosure-command proofs), contract checks, `egress:check`, `assurance:mutation-smoke`, and
109
171
  `migrations:check`. This job sets `ATELIER_ALLOW_MISSING_DENYLIST=1` scoped
110
172
  to the job only — denylist assertions belong to the secret lane.
111
173
  - `consumer-smoke`: warms the npm cache with `npm ci` (the offline tarball
@@ -127,11 +189,14 @@ the only safe block.
127
189
 
128
190
  To clear a fork pull request, a maintainer verifies the head SHA and dispatches
129
191
  the `fork-sweep` workflow with the pull-request number and that SHA. The
130
- workflow runs the trusted scanner from `main` against the fork's tree checked
131
- out as data — it never installs or executes anything from the untrusted tree —
132
- re-verifies that the head SHA has not moved, and posts a `secret-sweep` check
133
- run on the SHA. The newest check run with that name supersedes the earlier
134
- failure for branch protection.
192
+ workflow pins the trusted scanner checkout to the protected default branch and
193
+ runs it against the fork checked out as data — it never installs or executes
194
+ anything from the untrusted tree. It requires an open PR whose base repository
195
+ and branch are the protected default, pins the base and head SHAs from GitHub,
196
+ scans the complete bounded base-to-head object range while waiving only
197
+ repository-specific commit identity, re-verifies that the head SHA has not
198
+ moved, and posts a `secret-sweep` check run on the SHA. The newest check run
199
+ with that name supersedes the earlier failure for branch protection.
135
200
 
136
201
  `release:audit` never runs against untrusted code (`npm pack` executes
137
202
  lifecycle scripts); it re-runs on the push build of the merge commit. No
@@ -170,12 +170,22 @@ machine for weeks.
170
170
  - `pre-push` runs `atelier boundary push-check` — git writes the ref updates to
171
171
  the hook's stdin, and only that range is judged. A brand-new branch is diffed
172
172
  against the empty tree, so nothing slips through unscanned.
173
- - `atelier boundary audit` scans the whole tree and **reports without blocking**,
174
- listing both matches and declared exceptions with their reasons.
173
+ - `atelier boundary audit` scans the current working tree by default and
174
+ **reports without blocking**, listing matches, incomplete-read diagnostics,
175
+ and declared exceptions with their reasons. Use `--head` for a committed
176
+ snapshot. The output names its source so a dirty tree cannot be mistaken for
177
+ `HEAD` evidence.
175
178
 
176
179
  If the guard cannot work out which repo it is running in, it fails closed. A
177
180
  guard that silently judges nothing is worse than one that stops you.
178
181
 
182
+ Path scopes are segment-aware globs: `*` does not cross `/`, `**` does, and
183
+ patterns are matched against normalized repository-relative paths. Explicitly
184
+ declaring `contentRules: []` is invalid; omit the field to receive defaults.
185
+ Git diff output and binary reads have per-file and aggregate budgets. A failed,
186
+ truncated, oversized, or unparsable evidence read produces a blocking
187
+ completeness diagnostic rather than a partial clean verdict.
188
+
179
189
  ### Declaring an exception
180
190
 
181
191
  Exceptions live in the boundary policy, not in the guard script. A repo-specific
package/docs/upgrade.md CHANGED
@@ -5,6 +5,38 @@ workspace between Atelier package releases. The flow is local-only: it does not
5
5
  provision repositories, contact a Git host, mutate the MNSTRY runtime, or write
6
6
  through a browser view.
7
7
 
8
+ ## Upgrading to 0.2.0-alpha.5
9
+
10
+ This release hardens public/private boundary enforcement, local serving,
11
+ collaboration-ledger integrity, disclosure review, and release provenance.
12
+ Documents valid against `0.2.0-alpha.0` remain contract-compatible, but some
13
+ previously tolerated unsafe or ambiguous states now fail closed.
14
+
15
+ - Projects using `atelier dev` must provide a generated
16
+ `atelier.manifest.json`; only enrolled, safe, realpath-validated static files
17
+ are served, and the sidecar accepts loopback traffic only.
18
+ - Empty or malformed content-rule policies, incomplete Git reads, corrupt or
19
+ oversized collaboration ledgers, and unsafe manifest entries are now
20
+ blocking errors with typed CLI diagnostics.
21
+ - Run `atelier disclosure check` before sharing tracked or staged content. A
22
+ private denylist is required by default and must remain outside the public
23
+ repository.
24
+ - Release candidates are packed once, SHA-256-bound, and the exact audited
25
+ tarball is the artifact sent through npm trusted publishing.
26
+
27
+ Re-run the boundary, disclosure, graph, readiness, and lock checks below after
28
+ updating. If `atelier dev` previously served files without a manifest, generate
29
+ and review the manifest before restarting it.
30
+
31
+ ## Upgrading to 0.2.0-alpha.4
32
+
33
+ This is a presentation release. There are no contract changes and no runtime
34
+ behaviour changes: documents valid against `0.2.0-alpha.0` remain valid, and
35
+ `npm run contract:compat` is clean against the same epoch baseline. The README,
36
+ package metadata, and public documentation now describe the Atelier as a
37
+ repository substrate for people, agents, teams, and tools. Upgrading is a
38
+ dependency bump.
39
+
8
40
  ## Upgrading to 0.2.0-alpha.3
9
41
 
10
42
  No contract changes and no runtime behaviour changes: documents valid against
@@ -85,7 +117,7 @@ For registry installs, pin the exact version and record the resolved version
85
117
  in the lockfile:
86
118
 
87
119
  ```bash
88
- npm install --save-dev @mnstry/atelier@0.2.0-alpha.3
120
+ npm install --save-dev @mnstry/atelier@0.2.0-alpha.5
89
121
  npx mnstry-atelier lock write --project ./atelier.project.json
90
122
  ```
91
123
 
@@ -93,7 +125,7 @@ For Git installs, pin the release tag rather than a branch, so the lock file
93
125
  records exactly what was reviewed:
94
126
 
95
127
  ```bash
96
- npm install --save-dev "git+https://github.com/MNSTRY/atelier.git#v0.2.0-alpha.3"
128
+ npm install --save-dev "git+https://github.com/MNSTRY/atelier.git#v0.2.0-alpha.5"
97
129
  npx mnstry-atelier lock write --project ./atelier.project.json
98
130
  ```
99
131
 
@@ -1,5 +1,6 @@
1
1
  {
2
- "assetFilename": "source.html",
2
+ "schema": "mnstry.source-sidecar@v1",
3
+ "asset": "source.html",
3
4
  "title": "Sample Source",
4
5
  "summary": "Neutral non-Markdown source with durable sidecar identity.",
5
6
  "tags": [
@@ -8,6 +9,8 @@
8
9
  "kg": {
9
10
  "id": "sample-workspace:source-html",
10
11
  "type": "source",
12
+ "domain": "sample",
13
+ "lifecycle": "source",
11
14
  "status": "active",
12
15
  "audience": "private",
13
16
  "relations": {}