|
| 1 | +## MODIFIED Requirements |
| 2 | + |
| 3 | +### Requirement: Valid facet manifests are accepted |
| 4 | + |
| 5 | +The system SHALL accept a facet manifest that conforms to the manifest schema. A valid manifest has a name, a version, and at least one text asset (skills, agents, commands, or composed facets). The name SHALL be either an unscoped kebab-case facet identity (`name`) or a scoped facet identity (`@scope/name`). All three text asset types — skills, agents, and commands — use the same descriptor model: a map of asset name to a descriptor with a required description and optional platform metadata. Descriptors SHALL NOT contain prompt references — prompt content is inferred from the file-path convention. Skills use the Agent Skills directory convention `skills/<name>/SKILL.md`. Agents and commands use the flat file convention `agents/<name>.md` and `commands/<name>.md` respectively. All three descriptor types SHALL require a `description` field. Asset names SHALL remain local kebab-case identifiers and SHALL NOT be scoped facet identities. |
| 6 | + |
| 7 | +The system SHALL accept and preserve an optional top-level `private` boolean in a valid manifest. `private: true` SHALL identify that the author intends the facet to be private when published. `private: false` and omission SHALL preserve public-by-default behavior for existing projects. |
| 8 | + |
| 9 | +#### Scenario: Minimal valid manifest with a skill |
| 10 | + |
| 11 | +- **WHEN** an author provides a manifest with a name, version, and a single skill descriptor that includes a description |
| 12 | +- **THEN** the system SHALL accept the manifest |
| 13 | + |
| 14 | +#### Scenario: Valid manifest with a scoped facet identity |
| 15 | + |
| 16 | +- **WHEN** an author provides a manifest whose `name` is `@julian/cowsay`, with a version and a single skill descriptor that includes a description |
| 17 | +- **THEN** the system SHALL accept the manifest |
| 18 | + |
| 19 | +#### Scenario: Manifest with all sections |
| 20 | + |
| 21 | +- **WHEN** an author provides a manifest with identity fields, skill descriptors with descriptions, agent descriptors with descriptions, command descriptors with descriptions, composed facets, and server references |
| 22 | +- **THEN** the system SHALL accept the manifest |
| 23 | + |
| 24 | +#### Scenario: Manifest with only composed facets is valid |
| 25 | + |
| 26 | +- **WHEN** an author provides a manifest with `name`, `version`, and a `facets` section but no local skills, agents, or commands |
| 27 | +- **THEN** the system SHALL accept the manifest |
| 28 | + |
| 29 | +#### Scenario: Private manifest is accepted and preserved |
| 30 | + |
| 31 | +- **WHEN** an author provides a valid manifest containing `private: true` |
| 32 | +- **THEN** the system SHALL accept the manifest |
| 33 | +- **AND** the loaded manifest data SHALL preserve `private: true` |
| 34 | + |
| 35 | +#### Scenario: Public-by-default manifests remain valid |
| 36 | + |
| 37 | +- **WHEN** an author provides a valid manifest with `private` omitted or set to `false` |
| 38 | +- **THEN** the system SHALL accept the manifest |
| 39 | +- **AND** downstream tooling SHALL interpret the manifest as public for publishing intent |
| 40 | + |
| 41 | +### Requirement: Invalid facet manifests are rejected with actionable errors |
| 42 | + |
| 43 | +The system SHALL reject a facet manifest that does not conform to the manifest schema. Each error SHALL identify the location of the problem (field path) and describe what was expected, so the author can fix it without guessing. |
| 44 | + |
| 45 | +#### Scenario: Missing required identity field |
| 46 | + |
| 47 | +- **WHEN** an author provides a manifest without a `name` or `version` field |
| 48 | +- **THEN** the system SHALL reject the manifest |
| 49 | +- **AND** the error SHALL identify which required field is missing |
| 50 | + |
| 51 | +#### Scenario: No text assets |
| 52 | + |
| 53 | +- **WHEN** an author provides a manifest with identity fields and server references but no skills, agents, commands, or composed facets |
| 54 | +- **THEN** the system SHALL reject the manifest |
| 55 | +- **AND** the error SHALL indicate that at least one text asset is required |
| 56 | + |
| 57 | +#### Scenario: Agent missing its description |
| 58 | + |
| 59 | +- **WHEN** an author defines an agent without a `description` field |
| 60 | +- **THEN** the system SHALL reject the manifest |
| 61 | +- **AND** the error SHALL identify the agent by name and the missing field |
| 62 | + |
| 63 | +#### Scenario: Selective facets entry with no asset selection |
| 64 | + |
| 65 | +- **WHEN** an author writes a selective facets entry with `name` and `version` but no `skills`, `agents`, or `commands` |
| 66 | +- **THEN** the system SHALL reject the manifest |
| 67 | +- **AND** the error SHALL indicate that at least one asset type must be selected |
| 68 | + |
| 69 | +#### Scenario: Server reference object without image field |
| 70 | + |
| 71 | +- **WHEN** an author writes a server reference as an object but omits the `image` field |
| 72 | +- **THEN** the system SHALL reject the manifest |
| 73 | +- **AND** the error SHALL identify the server by name |
| 74 | + |
| 75 | +#### Scenario: Non-boolean privacy declaration |
| 76 | + |
| 77 | +- **WHEN** an author provides a manifest whose top-level `private` field is not a boolean |
| 78 | +- **THEN** the system SHALL reject the manifest |
| 79 | +- **AND** the error SHALL identify `private` and state that a boolean value was expected |
| 80 | + |
| 81 | +### Requirement: Authors can build a facet locally for validation and inspection |
| 82 | + |
| 83 | +The system SHALL compile a facet project into a build output directory. The build command SHALL read the manifest, validate it, verify that every declared asset file exists, is non-empty, and contains no YAML front matter, resolve all file-based prompts to their content, run all validation checks, assemble the resolved output into a deterministic compressed archive, compute content hashes, and write the archive and build manifest to a `dist/` directory. The build command SHALL NOT modify the manifest or any content files. The build command SHALL NOT be interactive — it SHALL behave identically in all environments. |
| 84 | + |
| 85 | +The build output SHALL contain a compressed archive (`.facet` file) with the manifest and all text asset files with prompts resolved to their final string content, and a build manifest (`build-manifest.json`) recording content hashes. If the source manifest contains `private`, the embedded manifest in the archive SHALL contain the same boolean value. If the source manifest omits `private`, the build output SHALL preserve omission and SHALL NOT inject a default field. For a scoped facet identity, whose name renders as a nested path under `dist/`, the system SHALL create any required parent directories under `dist/` before writing the built archive. The build-output write boundary SHALL create parent directories for any slash-containing archive path, so the same fix also repairs the pre-existing failure for any nested archive filename. |
| 86 | + |
| 87 | +The build command SHALL render its progress as a step-by-step display, showing each pipeline stage as it completes — including the archive assembly stage. On success, the system SHALL display the archive contents listing and the archive content hash. On failure, the system SHALL indicate which stage failed and display errors with their field paths, and SHALL suggest running the editing command to fix the issues. After the display exits, the system SHALL print a brief plain-text summary to stdout — including the content hash — so it persists in terminal scroll-back. |
| 88 | + |
| 89 | +#### Scenario: Successful build of a valid facet |
| 90 | + |
| 91 | +- **WHEN** the author runs the build command in a directory with a valid manifest, all referenced files exist, and no files contain front matter |
| 92 | +- **THEN** the system SHALL write a compressed archive and build manifest to `dist/` |
| 93 | +- **AND** the archive SHALL contain the facet manifest and all text asset files with prompts resolved to their string content |
| 94 | +- **AND** the build manifest SHALL contain the archive content hash and per-asset content hashes |
| 95 | +- **AND** the system SHALL display the archive contents and content hash |
| 96 | +- **AND** the system SHALL print a brief success summary to stdout including the content hash |
| 97 | + |
| 98 | +#### Scenario: Successful build preserves private publishing intent |
| 99 | + |
| 100 | +- **WHEN** the author runs the build command for a valid manifest containing `private: true` |
| 101 | +- **THEN** the built archive SHALL contain an embedded manifest with `private: true` |
| 102 | +- **AND** verification of the built archive SHALL treat that value as part of the manifest content |
| 103 | + |
| 104 | +#### Scenario: Successful build preserves public-by-default omission |
| 105 | + |
| 106 | +- **WHEN** the author runs the build command for a valid manifest that omits `private` |
| 107 | +- **THEN** the built archive SHALL contain an embedded manifest with `private` omitted |
| 108 | +- **AND** the archive SHALL remain publishable as a public facet when all other requirements are satisfied |
| 109 | + |
| 110 | +#### Scenario: Successful build of a scoped facet identity |
| 111 | + |
| 112 | +- **WHEN** the author runs the build command for a valid facet whose name is `@julian/cowsay` |
| 113 | +- **THEN** the system SHALL write the built archive under `dist/` without failing on the scoped name separator |
| 114 | +- **AND** the archive SHALL contain `facet.json` at the archive root with `name` set to `@julian/cowsay` |
| 115 | +- **AND** the archive's internal asset paths SHALL continue to be derived from asset names, not from the facet identity |
| 116 | + |
| 117 | +#### Scenario: Build-output write boundary creates parent directories for a nested archive path |
| 118 | + |
| 119 | +- **WHEN** the build-output write boundary writes an archive whose filename renders as a nested path under `dist/` (for example a scoped `@scope/name` identity, or any other slash-containing archive filename) |
| 120 | +- **THEN** the system SHALL create the required parent directories under `dist/` before writing the archive |
| 121 | +- **AND** the write SHALL NOT fail with a missing-directory error |
| 122 | + |
| 123 | +#### Scenario: Build fails on invalid manifest |
| 124 | + |
| 125 | +- **WHEN** the author runs the build command and the manifest fails schema validation |
| 126 | +- **THEN** the system SHALL report the validation errors with field paths |
| 127 | +- **AND** the system SHALL suggest running the editing command to fix the issues |
| 128 | +- **AND** the system SHALL NOT write any output to `dist/` |
| 129 | + |
| 130 | +#### Scenario: Build fails on missing asset file |
| 131 | + |
| 132 | +- **WHEN** the author runs the build command and any asset references a file that does not exist |
| 133 | +- **THEN** the system SHALL report which file is missing and which asset references it |
| 134 | +- **AND** the system SHALL suggest running the editing command to fix the issues |
| 135 | +- **AND** the system SHALL NOT write any output to `dist/` |
| 136 | + |
| 137 | +#### Scenario: Build fails on file containing front matter |
| 138 | + |
| 139 | +- **WHEN** the build command encounters a content file containing YAML front matter |
| 140 | +- **THEN** the build SHALL fail with an error identifying the file and indicating that front matter must be removed |
| 141 | + |
| 142 | +#### Scenario: Build fails on empty content file |
| 143 | + |
| 144 | +- **WHEN** the author runs the build command and a content file referenced by the manifest is empty (zero bytes or only whitespace) |
| 145 | +- **THEN** the system SHALL report which file is empty and which asset references it |
| 146 | +- **AND** the system SHALL suggest running the editing command to add content |
| 147 | +- **AND** the system SHALL NOT write any output to `dist/` |
| 148 | + |
| 149 | +#### Scenario: Build with no manifest |
| 150 | + |
| 151 | +- **WHEN** the author runs the build command in a directory with no manifest |
| 152 | +- **THEN** the system SHALL report that no manifest was found |
| 153 | + |
| 154 | +#### Scenario: Build cleans previous output |
| 155 | + |
| 156 | +- **WHEN** the author runs the build command and a `dist/` directory already exists from a previous build |
| 157 | +- **THEN** the system SHALL remove the previous `dist/` directory before writing new output |
0 commit comments