Skip to content

Commit 1eba67d

Browse files
committed
Bump @julian/openspec-adversary to 2.3.0 and add add-facet-visibility-to-manifest specs, tasks, and adversarial review artifacts
1 parent 68d14f4 commit 1eba67d

17 files changed

Lines changed: 1164 additions & 4 deletions

File tree

facets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
"viper-plans": "0.2.0",
44
"cowsay": "0.2.0",
55
"@julian/review-openspec-design": "1.1.0",
6-
"@julian/openspec-adversary": "2.2.1"
6+
"@julian/openspec-adversary": "2.3.0"
77
}
88
}

facets.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
"kind": "registry",
77
"registry": "https://api.facet.cafe"
88
},
9-
"version": "2.2.1",
10-
"integrity": "sha256:c89f3a38e0deade748ab63c6e8d74ae65eee717fa2ccd8cc69ebca96c0caf189",
9+
"version": "2.3.0",
10+
"integrity": "sha256:12f91506d77467081816cd89412828df91a25d2de2ab897803a7dbc468dc1c1b",
1111
"assets": [
1212
{
1313
"scope": "project",
@@ -27,7 +27,7 @@
2727
{
2828
"scope": "project",
2929
"type": "agent",
30-
"name": "opencode-adversary"
30+
"name": "openspec-adversary"
3131
},
3232
{
3333
"scope": "project",
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
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
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
## MODIFIED Requirements
2+
3+
### Requirement: A facet manifest schema is published as part of the protocol
4+
5+
The shape of a facet manifest (`facet.json`) SHALL be published as a normative schema. Any system that produces a facet manifest SHALL produce one conforming to the published schema. Any system that consumes a facet manifest SHALL validate it against the published schema before treating any value as trusted. The schema SHALL define the required fields, the permitted shapes for skills/agents/commands, the accepted facet identity grammar, the optional privacy declaration, and the rules for unrecognized fields.
6+
7+
A facet identity name SHALL be either an unscoped name (`<slug>`) or a scoped name (`@<scope>/<slug>`). Each `slug` and `scope` component SHALL satisfy the same component grammar: it MUST be at least 2 characters and at most 64 characters, MUST start with a lowercase ASCII letter, MUST end with a lowercase ASCII letter or ASCII digit, MUST contain only lowercase ASCII letters, ASCII digits, and hyphens, and MUST NOT contain consecutive hyphens. Uppercase letters, non-ASCII characters, underscores, dots, spaces, plus signs, tildes, emoji, and any other character outside the component grammar SHALL be rejected rather than normalized. A facet manifest whose `name` is malformed SHALL be rejected as invalid. Asset names SHALL remain independently validated as local asset identifiers and SHALL NOT become scoped names.
8+
9+
The facet manifest schema SHALL define an optional top-level `private` field. When present, `private` SHALL be a boolean. `private: true` SHALL declare that the author intends the facet to be published as private. `private: false` and an omitted `private` field SHALL both declare the default public publishing intent. Values of any non-boolean type SHALL be rejected rather than treated as unknown extension data or coerced to booleans.
10+
11+
The facet manifest schema SHALL NOT document unsupported composition or server-reference fields as part of the current user-facing manifest contract. Current user-facing manifest documentation SHALL describe only supported manifest behavior and SHALL use the manifest specification page as the canonical place for facet-name grammar and manifest privacy semantics.
12+
13+
#### Scenario: A producer emits a manifest conforming to the published schema
14+
15+
- **WHEN** a system produces a `facet.json` for distribution
16+
- **THEN** the produced manifest SHALL satisfy every requirement of the published schema
17+
- **AND** another facet-compatible system SHALL accept the manifest after validating it
18+
19+
#### Scenario: A consumer accepts valid unscoped facet identities
20+
21+
- **WHEN** a system receives a `facet.json` whose `name` is `ab`, `cowsay`, `julian`, `admin-tester`, `apple-b34r`, or `f-o-s-s-o`
22+
- **THEN** the system SHALL accept the facet identity as valid
23+
- **AND** the accepted identity SHALL remain the facet's canonical name without normalization
24+
25+
#### Scenario: A consumer accepts a valid scoped facet identity
26+
27+
- **WHEN** a system receives a `facet.json` whose `name` is `@julian/cowsay`
28+
- **THEN** the system SHALL accept the facet identity as valid
29+
- **AND** both scoped identity components SHALL satisfy the same component grammar as unscoped facet names
30+
- **AND** the scoped identity SHALL remain the facet's canonical name
31+
32+
#### Scenario: A consumer accepts a private publishing declaration
33+
34+
- **WHEN** a system receives a `facet.json` containing `private: true`
35+
- **THEN** the system SHALL accept the privacy declaration as schema-valid
36+
- **AND** the validated manifest SHALL preserve `private: true` as the facet's publishing intent
37+
38+
#### Scenario: A consumer accepts public-by-default manifests
39+
40+
- **WHEN** a system receives a `facet.json` where `private` is omitted or set to `false`
41+
- **THEN** the system SHALL accept the manifest as schema-valid when all other schema requirements are satisfied
42+
- **AND** the manifest SHALL be interpreted as public for publishing intent
43+
44+
#### Scenario: A consumer rejects invalid slug components
45+
46+
- **WHEN** a system receives a `facet.json` whose `name` is empty, `a`, `z`, `A`, `Cowsay`, `1abc`, `-abc`, `abc-`, `abc--def`, `abc_def`, `abc.def`, `abc def`, `éclair`, `gооgle` with Cyrillic homoglyphs, or any component longer than 64 characters
47+
- **THEN** the system SHALL reject the manifest as invalid
48+
- **AND** the system SHALL surface a structured error indicating that the facet identity is malformed
49+
50+
#### Scenario: A consumer rejects malformed scoped facet identities
51+
52+
- **WHEN** a system receives a `facet.json` whose `name` is `@scope`, `@/name`, `@scope/`, `@scope/name/extra`, or `scope/name`
53+
- **THEN** the system SHALL reject the manifest as invalid
54+
- **AND** the system SHALL surface a structured error indicating that the facet identity is malformed
55+
56+
#### Scenario: A consumer rejects a non-boolean privacy declaration
57+
58+
- **WHEN** a system receives a `facet.json` whose `private` field is a string, number, object, array, or null
59+
- **THEN** the system SHALL reject the manifest as invalid
60+
- **AND** the system SHALL surface a structured error indicating that `private` must be a boolean
61+
62+
#### Scenario: A consumer rejects a manifest that violates the published schema
63+
64+
- **WHEN** a system receives a `facet.json` that omits a required field or contains a field with the wrong type
65+
- **THEN** the system SHALL reject the manifest as invalid
66+
- **AND** the system SHALL surface a structured error indicating which constraint was violated
67+
68+
#### Scenario: A consumer tolerates unrecognized fields
69+
70+
- **WHEN** a system receives a `facet.json` containing a field not defined in the schema
71+
- **THEN** the system SHALL accept the manifest as valid
72+
- **AND** the system SHALL preserve the unknown field if it later re-emits the manifest

0 commit comments

Comments
 (0)