Skip to content

Add versioned build-manifest, lockfile, and archive-plan schemas with exact facetVersion/lockfileVersion dispatch and supplementary files support - #435

Merged
eXamadeus merged 1 commit into
mainfrom
julian/07-20-add_versioned_build-manifest_lockfile_and_archive-plan_schemas_with_exact_facetversion___lockfileversion_dispatch_and_supplementary_files_support
Jul 23, 2026
Merged

Add versioned build-manifest, lockfile, and archive-plan schemas with exact facetVersion/lockfileVersion dispatch and supplementary files support#435
eXamadeus merged 1 commit into
mainfrom
julian/07-20-add_versioned_build-manifest_lockfile_and_archive-plan_schemas_with_exact_facetversion___lockfileversion_dispatch_and_supplementary_files_support

Conversation

@eXamadeus

@eXamadeus eXamadeus commented Jul 20, 2026

Copy link
Copy Markdown
Member

Why

Skills and commands share one logical namespace (design D9), meaning a facet cannot declare a skill and a command with the same name. Previously, the build pipeline permitted this cross-type name sharing. This change enforces the shared namespace at both the schema and build-pipeline levels, while keeping agents as a separate namespace that may freely share names with skills or commands.

This is part of the broader support-non-asset-files work (tasks 1.1–3.3 are now complete), which introduces supplementary file declarations (files arrays at the top level and per skill), a pure archive-plan derivation, versioned build-manifest and lockfile schemas with exact version dispatch, and duplicate JSON member rejection across all security-relevant documents.

Details

Archive plan (planArchiveEntries): A new pure operation derives the complete, deterministically sorted set of tagged archive entries from manifest data. It classifies entries as manifest, primary-asset, skill-companion, or archive-only, and enforces the full portable path grammar (traversal, absolute paths, backslashes, control bytes, empty segments, forbidden characters, Windows reserved device names, trailing dot/space) plus whole-set collision detection (exact duplicates, Unicode normalization aliases, case-fold aliases, file/directory prefix conflicts, and supplementary-vs-primary collisions). Build collection, hashing, verification, and installation all consume this one operation so membership sets cannot drift apart.

Versioned schemas with exact dispatch: LegacyBuildManifestSchema (pinned to facetVersion: 0.1, assets map) and CurrentBuildManifestSchema (pinned to facetVersion: 0.2, archive: "archive.tar.gz" literal, files map) replace the previous permissive BuildManifestSchema. parseBuildManifestDocument dispatches by exact equality — a malformed 0.2 document fails as 0.2 and is never reinterpreted as 0.1. The same pattern applies to lockfiles: LegacyLockfileSchema (pinned to lockfileVersion: 1, identity-only asset entries) and CurrentLockfileSchema (pinned to lockfileVersion: 0.2, per-materialized-file integrity records with strict lexicographic ordering). Note that 0.2 < 1 numerically, so dispatch must use exact equality, not ordering.

Legacy facet-manifest schema: LegacyFacetManifestSchema freezes the pre-0.2 rules — multi-segment asset names, no shared skill/command namespace, no supplementary files declarations — for use only when verifying legacy 0.1 archives. The current FacetManifestSchema now enforces single-segment asset names, the shared skill/command namespace, and delegates supplementary path validation to planArchiveEntries so a manifest that validates here always yields a valid archive plan.

Duplicate JSON member rejection: findDuplicateJsonMembers scans already-parsed JSON text for duplicate object member names (decoding escape sequences before comparison) and is applied before schema validation in all three document validators. JSON.parse's last-member-wins collapse would otherwise let two parsers see different declarations in one document.

The outer-tar layout constants (INNER_ARCHIVE_NAME, BUILD_MANIFEST_NAME) are moved to build-manifest.ts as the single source of truth and re-exported from content-hash.ts to avoid an import cycle.

The existing permissive BuildManifestSchema, LockfileSchema, and LOCKFILE_VERSION exports are retained but marked deprecated for removal after downstream consumers migrate to the versioned parsers.

Verification

New focused test suites cover all legal and illegal states: archive-plan.test.ts (path grammar, declaration-site rules, collision classes), build-manifest-versions.test.ts (schema acceptance/rejection, exact dispatch, duplicate member and invalid JSON failures), lockfile-versions.test.ts (legacy and current schemas, dispatch edge cases including the 0.2 < 1 numeric ordering trap), and duplicate-json-members.test.ts (scanner correctness and integration with facet-manifest validators). The build-pipeline test is corrected to assert that a skill/command name collision fails and adds a separate passing case for an agent sharing a name with a skill.


Note

Medium Risk
Touches integrity and manifest validation contracts (shared skill/command namespace, legacy vs current dispatch, duplicate-JSON rejection); behavior changes are largely gated by tests but archive verification still uses legacy manifest rules until the consumer bridge lands.

Overview
Introduces the protocol layer for non-asset archive members and strict 0.1 / 0.2 wire formats, ahead of consumer-bridge and producer work still open in the change plan.

Manifest & membership: Current FacetManifestSchema now accepts top-level and per-skill files, validates asset names as single segments, and rejects skill/command name collisions (agents stay a separate namespace). A frozen LegacyFacetManifestSchema keeps multi-segment names and permissive skill/command sharing for legacy 0.1 verification only. planArchiveEntries is the single pure derivation of sorted, tagged inner-archive paths (manifest, primary assets, skill companions, archive-only) with portable path grammar and collision rules; the current manifest narrow delegates to it so validation and future build/verify paths stay aligned.

Versioned artifacts: Split legacy vs current build manifests (assets @ 0.1 vs files @ 0.2 with pinned archive: "archive.tar.gz") and lockfiles (alpha 1 vs 0.2 with sorted per-file integrity records). parseBuildManifestDocument and parseLockfileDocument dispatch on exact version equality (no cross-version reinterpretation). findDuplicateJsonMembers runs before schema validation on facet manifests, build manifests, and lockfiles.

Exports & verification path: Public API expands with archive-plan types, version constants, parsers, and legacy validators. validateFacetArchive now validates embedded facet.json via validateLegacyFacetManifest (explicit legacy-only behavior for the existing verifier). Engine build-pipeline test updated: skill+command same name fails; agent+skill same name still passes.

Reviewed by Cursor Bugbot for commit 90a0704. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features
    • Added support for supplementary files at the facet and skill level.
    • Added version-aware parsing for build manifests and lockfiles, including legacy compatibility.
    • Added archive planning with deterministic ordering and collision detection.
  • Bug Fixes
    • Rejects unsafe paths, duplicate JSON members, invalid placements, and conflicting asset names.
    • Prevents ambiguous skill and command names while allowing valid agent name sharing.
  • Validation
    • Provides clearer, structured errors for unsupported versions and malformed archive contents.

@changeset-bot

changeset-bot Bot commented Jul 20, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 90a0704

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5bcfbacd-cfe3-47a0-9dfc-5d1ee5460789

📥 Commits

Reviewing files that changed from the base of the PR and between 1bbf0c2 and 90a0704.

📒 Files selected for processing (19)
  • openspec/changes/support-non-asset-files/tasks.md
  • packages/engine/src/__tests__/build-pipeline.test.ts
  • packages/protocol/src/__tests__/archive-plan.test.ts
  • packages/protocol/src/__tests__/build-manifest-versions.test.ts
  • packages/protocol/src/__tests__/duplicate-json-members.test.ts
  • packages/protocol/src/__tests__/facet-manifest.test.ts
  • packages/protocol/src/__tests__/lockfile-versions.test.ts
  • packages/protocol/src/build/archive-plan.ts
  • packages/protocol/src/build/content-hash.ts
  • packages/protocol/src/index.ts
  • packages/protocol/src/integrity/validate-archive.ts
  • packages/protocol/src/loaders/build-manifest.ts
  • packages/protocol/src/loaders/facet.ts
  • packages/protocol/src/loaders/lockfile.ts
  • packages/protocol/src/loaders/validate.ts
  • packages/protocol/src/schemas/build-manifest.ts
  • packages/protocol/src/schemas/facet-manifest-legacy.ts
  • packages/protocol/src/schemas/facet-manifest.ts
  • packages/protocol/src/schemas/lockfile.ts

📝 Walkthrough

Walkthrough

The protocol adds deterministic archive planning for primary, companion, and supplementary files, with portable-path and collision validation. Facet manifests now distinguish current and legacy naming rules and support supplementary files. Duplicate JSON members are rejected before schema validation. Build manifests and lockfiles gain version-specific schemas, exact-version parsers, structured failures, and expanded public exports. Embedded archive validation uses the legacy facet schema, while engine tests cover updated cross-namespace naming behavior.

Sequence Diagram(s)

sequenceDiagram
  participant BuildPipeline
  participant FacetManifestSchema
  participant planArchiveEntries
  participant ArchiveWriter
  BuildPipeline->>FacetManifestSchema: validate facet manifest
  FacetManifestSchema->>planArchiveEntries: validate and derive archive entries
  planArchiveEntries-->>FacetManifestSchema: ordered entries or errors
  FacetManifestSchema-->>BuildPipeline: validation result
  BuildPipeline->>ArchiveWriter: write planned archive entries
Loading
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch julian/07-20-add_versioned_build-manifest_lockfile_and_archive-plan_schemas_with_exact_facetversion___lockfileversion_dispatch_and_supplementary_files_support

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

eXamadeus commented Jul 20, 2026

Copy link
Copy Markdown
Member Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2dbd6c3f2b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (!record) continue
for (const key of Object.keys(record)) {
const check = validateAssetName(key)
const check = validateAssetNameSegment(key)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve legacy names in the still-0.1 build pipeline

runBuildPipeline still emits facetVersion: 0.1 and loads manifests through validateFacetManifest (packages/engine/src/loaders/facet.ts:34), so this current-only single-segment check rejects existing legacy-valid names such as viper-plans/planning before they can be built. The new legacy schema is only used by archive verification, not by the producer; route the 0.1 producer through the legacy validator or defer this restriction until it emits 0.2 artifacts.

Useful? React with 👍 / 👎.

Comment on lines 14 to 18
const SkillDescriptor = type({
description: 'string',
'adapters?': type.Record('string', 'unknown'),
'files?': 'string[]',
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Do not accept supplementary files until the builder archives them

A manifest with skills.<name>.files now validates successfully, but the active build path calls collectArchiveEntries, which only adds facet.json and conventional primary prompts (packages/protocol/src/build/content-hash.ts:39-58), then writes a 0.1 manifest. Consequently declared companion files are silently omitted from the emitted archive while facet.json advertises them; either include these files via the archive plan or reject the declarations until the 0.2 producer is enabled.

Useful? React with 👍 / 👎.

Comment thread packages/protocol/src/build/archive-plan.ts
Comment thread packages/protocol/src/schemas/lockfile.ts
@greptile-apps

greptile-apps Bot commented Jul 20, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces the protocol foundation for archive format 0.2: versioned build-manifest and lockfile schemas with exact version dispatch, a new planArchiveEntries derivation as the single shared archive membership oracle, duplicate JSON-member rejection on all security-sensitive documents, and the shared skill/command namespace enforcement at both schema and build-pipeline levels.

  • Archive plan (planArchiveEntries): A pure, deterministic operation that classifies entries as manifest, primary-asset, skill-companion, or archive-only; enforces the full portable path grammar; and detects six classes of set-level collision. All build/hash/verify stages are expected to consume this one operation (build output and 0.2 verification are still future work in tasks 3.4+).
  • Versioned schemas: LegacyBuildManifestSchema/CurrentBuildManifestSchema (pinned facetVersion: 0.1/0.2) and LegacyLockfileSchema/CurrentLockfileSchema (pinned lockfileVersion: 1/0.2) replace the previous permissive schemas; exact-equality dispatch in parseBuildManifestDocument and parseLockfileDocument ensures a malformed 0.2 document never falls back to 0.1 rules.
  • Schema tightening: FacetManifestSchema now requires single-segment asset names, rejects skill/command name collisions, and validates supplementary files paths through the shared archive-plan derivation; LegacyFacetManifestSchema freezes the pre-0.2 rules for legacy archive verification only.

Confidence Score: 5/5

Safe to merge. The protocol changes are carefully scoped — legacy 0.1 archive verification is preserved, new versioned parsers use exact dispatch with no cross-version fallback, and the archive plan is backed by comprehensive test coverage of all path grammar and collision classes.

The core design — exact version dispatch, single-source archive membership derivation, duplicate JSON member rejection — is correctly implemented throughout. Tests cover legal and illegal states comprehensively, including edge cases like the 0.2 < 1 numeric ordering trap, Unicode normalization aliases, Windows device name segments, and every collision class. The known open items (step 6b own allowlist, resolvePromptsFromMap spreading files, case-sensitive site-top-level-under-skills) are pre-existing and already documented in prior review comments.

No files require special attention beyond what was flagged in earlier review rounds.

Reviews (6): Last reviewed commit: "Add versioned build-manifest, lockfile, ..." | Re-trigger Greptile

)
continue
}
if (declared.split('/')[0] === 'skills') {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The site-top-level-under-skills check is case-sensitive (=== 'skills'), but the rest of the collision system uses the case-insensitive collisionKey(). A top-level supplementary path like 'Skills/review/doc.md' or 'SKILLS/review/doc.md' slips past this declaration-site check entirely. On a case-insensitive filesystem (macOS, Windows) those paths land in the same directory as the skill files, defeating the "skill companions belong in the owning skill's files array" invariant without any error. collisionKey is already in scope and costs nothing here.

Suggested change
if (declared.split('/')[0] === 'skills') {
if (collisionKey(declared.split('/')[0]) === 'skills') {

@eXamadeus
eXamadeus force-pushed the julian/07-13-add_openspec_proposal_for_non-asset_file_support_in_facet_archives branch from 2eada07 to 69b1df3 Compare July 22, 2026 21:29
@eXamadeus
eXamadeus force-pushed the julian/07-20-add_versioned_build-manifest_lockfile_and_archive-plan_schemas_with_exact_facetversion___lockfileversion_dispatch_and_supplementary_files_support branch from 2dbd6c3 to fef9bb7 Compare July 22, 2026 21:29

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fef9bb7b03

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +172 to +180
if (data.files.length === 0) {
return ctx.mustBe('an asset entry with at least one materialized file record')
}
for (let i = 0; i < data.files.length; i++) {
const record = data.files[i] as (typeof data.files)[number]
const pathCheck = validateAssetName(record.path)
if (!pathCheck.ok) {
return ctx.mustBe(`file path "${record.path}" ${pathCheck.reason}`)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce lockfile file ownership against each asset

A 0.2 lockfile currently accepts any nonempty, path-safe files list for every asset. For example, an agent named reviewer can list README.md or skills/other/SKILL.md, and it can omit agents/reviewer.md; a skill can likewise claim another skill's companion. parseLockfileDocument will therefore treat a lockfile that cannot reproduce the declared asset state as valid, allowing archive-only or another asset's files to become owned by the wrong asset once consumers use these records. Require agents/commands to contain exactly their conventional primary path and skills to contain their own primary path plus only descendants of their own skill directory.

Useful? React with 👍 / 👎.

)
continue
}
if (declared.split('/')[0] === 'skills') {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject case-folded top-level skill paths

On a case-insensitive supported filesystem, a declaration such as files: ["Skills/review/notes.md"] resolves beneath the skills/review directory but passes this exact-case check (and does not collide with skills/review/SKILL.md). It is consequently classified as archive-only instead of requiring the owning skill's files declaration, bypassing the ownership/declaration-site rule. Compare the first component with skills using the same portable case-folding policy used for archive collisions.

Useful? React with 👍 / 👎.

@eXamadeus
eXamadeus force-pushed the julian/07-20-add_versioned_build-manifest_lockfile_and_archive-plan_schemas_with_exact_facetversion___lockfileversion_dispatch_and_supplementary_files_support branch from fef9bb7 to 6a969ca Compare July 22, 2026 22:01
@eXamadeus
eXamadeus force-pushed the julian/07-13-add_openspec_proposal_for_non-asset_file_support_in_facet_archives branch from 69b1df3 to 673386f Compare July 22, 2026 22:01

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6a969ca927

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

* There is NO fallback between versions: a malformed `0.2` manifest fails
* as a `0.2` schema violation and is never reinterpreted as `0.1`.
*/
export function parseBuildManifestDocument(bytes: Uint8Array | string): ParseBuildManifestResult {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Route archive parsing through duplicate-aware validation

parseBuildManifestDocument is the only build-manifest path that invokes findDuplicateJsonMembers; parseFacetArchive, which feeds validateFacetArchive, still calls JSON.parse and the permissive BuildManifestSchema directly. Consequently, a submitted .facet with duplicate security-relevant members such as assets or integrity is accepted with JavaScript's last-member-wins interpretation, despite the new duplicate-member protection. Reuse this parser (or run the same scan) in parseFacetArchive before schema validation so archive verification enforces the promised rule.

Useful? React with 👍 / 👎.

Comment thread packages/protocol/src/build/content-hash.ts
@eXamadeus
eXamadeus force-pushed the julian/07-13-add_openspec_proposal_for_non-asset_file_support_in_facet_archives branch from 673386f to f5e650e Compare July 23, 2026 00:03
@eXamadeus
eXamadeus force-pushed the julian/07-20-add_versioned_build-manifest_lockfile_and_archive-plan_schemas_with_exact_facetversion___lockfileversion_dispatch_and_supplementary_files_support branch from 6a969ca to a3ab253 Compare July 23, 2026 00:04
@eXamadeus
eXamadeus force-pushed the julian/07-13-add_openspec_proposal_for_non-asset_file_support_in_facet_archives branch from f5e650e to 43cb4de Compare July 23, 2026 00:04
@eXamadeus
eXamadeus force-pushed the julian/07-20-add_versioned_build-manifest_lockfile_and_archive-plan_schemas_with_exact_facetversion___lockfileversion_dispatch_and_supplementary_files_support branch 2 times, most recently from 1ba7c8d to b6ee73c Compare July 23, 2026 00:48
@eXamadeus
eXamadeus force-pushed the julian/07-13-add_openspec_proposal_for_non-asset_file_support_in_facet_archives branch from 43cb4de to a17d95c Compare July 23, 2026 00:48

eXamadeus commented Jul 23, 2026

Copy link
Copy Markdown
Member Author

Merge activity

  • Jul 23, 2:25 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 23, 2:27 AM UTC: Graphite rebased this pull request as part of a merge.
  • Jul 23, 2:27 AM UTC: @eXamadeus merged this pull request with Graphite.

@eXamadeus
eXamadeus changed the base branch from julian/07-13-add_openspec_proposal_for_non-asset_file_support_in_facet_archives to graphite-base/435 July 23, 2026 02:25
@eXamadeus
eXamadeus changed the base branch from graphite-base/435 to main July 23, 2026 02:25
… exact `facetVersion`/`lockfileVersion` dispatch and supplementary `files` support
@eXamadeus
eXamadeus force-pushed the julian/07-20-add_versioned_build-manifest_lockfile_and_archive-plan_schemas_with_exact_facetversion___lockfileversion_dispatch_and_supplementary_files_support branch from b6ee73c to 90a0704 Compare July 23, 2026 02:26
@eXamadeus
eXamadeus merged commit 98d6750 into main Jul 23, 2026
6 of 7 checks passed
@eXamadeus
eXamadeus deleted the julian/07-20-add_versioned_build-manifest_lockfile_and_archive-plan_schemas_with_exact_facetversion___lockfileversion_dispatch_and_supplementary_files_support branch July 23, 2026 02:27

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 90a0704. Configure here.

`file records sorted by path: "${record.path}" must sort after "${previous}" with no duplicates`,
)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lockfile allows case-fold duplicates

Medium Severity

CurrentLockfileSchema only enforces strict lexicographic ordering and exact string inequality between adjacent files paths. Two records whose paths differ only by portable case (for example Skills/review/SKILL.md and skills/review/SKILL.md) can both pass validation.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 90a0704. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant