Skip to content

Add specs for artifact composition#836

Open
ogenstad wants to merge 1 commit intoinfrahub-developfrom
pog-artifact-composition-spec
Open

Add specs for artifact composition#836
ogenstad wants to merge 1 commit intoinfrahub-developfrom
pog-artifact-composition-spec

Conversation

@ogenstad
Copy link
Contributor

@ogenstad ogenstad commented Feb 18, 2026

Why

Provide specifications for INFP-504

What changed

Add Spec Kit specifications

Summary by CodeRabbit

  • Documentation
    • Added comprehensive specification for new artifact composition capability enabling dynamic content composition
    • Includes quality requirements checklist, user stories with acceptance criteria, security model, and implementation guidelines

@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

Walkthrough

A new specification directory structure is introduced containing documentation for artifact content composition via Jinja2 filters. The implementation adds a formal specification document outlining feature requirements, security models, functional changes, and success criteria for enabling inline artifact content and file object content through new Jinja2 filters. Accompanying this is a specification quality checklist document that tracks completion status against defined quality and readiness criteria.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add specs for artifact composition' directly and clearly summarizes the main change - adding specification documents for artifact composition functionality.
Description check ✅ Passed The description is minimal but covers the essential sections. It explains the why (INFP-504), what changed (Spec Kit specs), but lacks detail on behavioral changes, testing, and impact considerations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 18, 2026

Deploying infrahub-sdk-python with  Cloudflare Pages  Cloudflare Pages

Latest commit: f9ccc45
Status: ✅  Deploy successful!
Preview URL: https://7f27c33a.infrahub-sdk-python.pages.dev
Branch Preview URL: https://pog-artifact-composition-spe.infrahub-sdk-python.pages.dev

View logs

@ogenstad ogenstad force-pushed the pog-artifact-composition-spec branch from 13cefaa to f9ccc45 Compare February 19, 2026 08:29
@ogenstad ogenstad marked this pull request as ready for review February 19, 2026 11:32
@ogenstad ogenstad requested review from dgarros and wvandeun February 19, 2026 11:32
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@dev/specs/001-artifact-composition/checklists/requirements.md`:
- Around line 9-11: The checklist wrongly marks items as complete even though
the spec contains implementation details and is written for SDK implementers;
update the checklist in requirements.md by unchecking the four items at lines
shown (the items about "No implementation details", "Written for non-technical
stakeholders", "Success criteria are technology-agnostic", and "No
implementation details leak") and add a short note stating this is a technical
spec (not a pure PRD) calling out examples such as FR-001/006/010 naming
InfrahubClient/InfrahubClientSync, FR-012 file path
infrahub_sdk/template/exceptions.py, FR-013
client.object_store.get(identifier=storage_id), FR-002/007 naming
FilterDefinition/InfrahubFilters/Jinja2Template, and SC-005 referencing uv run
pytest tests/unit/ so reviewers understand the intentional deviation.
- Around line 34-36: The Markdown file ends with a Notes list but lacks a
trailing blank line; update
dev/specs/001-artifact-composition/checklists/requirements.md by adding a single
blank line after the final list item (the lines starting with "One open question
remains..." / "Ordering guarantee..." / "`from_json`/`from_yaml` existence...")
so there is an empty line at EOF, conforming to the guideline to add blank lines
before and after lists.

In `@dev/specs/001-artifact-composition/spec.md`:
- Around line 157-161: The Clarifications list at the end of the file lacks a
trailing blank line; update the final list in the "Clarifications" section (the
bullet list ending at the end of file) to include a blank line after the list so
the Markdown convention "Add blank lines before and after lists" is satisfied —
ensure there's exactly one empty line following the final list item and that any
preceding list start also has a blank line above it if missing.
- Around line 100-102: FR-007 is inconsistent with the three-context validation
model: registering artifact_content and file_object_content as trusted=False
will equate them with existing filters like safe and break the intended
Prefect-worker allowance; update the spec wording to mark FR-007 as provisional
and add a note that FilterDefinition must be extended (e.g., a new enum or flag)
to distinguish "worker-allowed" filters from general trusted/untrusted, and
reference artifact_content, file_object_content, FilterDefinition,
validate(restricted=True), safe, and JinjaTemplateOperationViolationError so
implementers know to avoid simply copying safe's trusted=False registration and
instead await the enum migration described in Open Questions.

Comment on lines +9 to +11
- [x] No implementation details (languages, frameworks, APIs)
- [x] Focused on user value and business needs
- [x] Written for non-technical stakeholders
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Four checklist items are marked complete but contradict the spec's content.

Line Item Counter-evidence in spec.md
9 [x] No implementation details (languages, frameworks, APIs) FR-001/006/010 name InfrahubClient/InfrahubClientSync; FR-012 names file path infrahub_sdk/template/exceptions.py; FR-013 names client.object_store.get(identifier=storage_id); FR-002/007 name FilterDefinition, InfrahubFilters, Jinja2Template.
11 [x] Written for non-technical stakeholders The spec is addressed entirely to SDK implementers, with Python class names, method signatures, and SDK module references throughout.
19 [x] Success criteria are technology-agnostic (no implementation details) SC-005 names uv run pytest tests/unit/; SC-004 names InfrahubClient; SC-002 names validate(restricted=True).
30 [x] No implementation details leak into specification Same evidence as line 9.

If this spec intentionally blends product requirements with technical design (a "technical spec" rather than a pure PRD), update the checklist criteria to reflect that, or uncheck these items and add a note explaining the intentional deviation.

Also applies to: 19-19, 29-30

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dev/specs/001-artifact-composition/checklists/requirements.md` around lines 9
- 11, The checklist wrongly marks items as complete even though the spec
contains implementation details and is written for SDK implementers; update the
checklist in requirements.md by unchecking the four items at lines shown (the
items about "No implementation details", "Written for non-technical
stakeholders", "Success criteria are technology-agnostic", and "No
implementation details leak") and add a short note stating this is a technical
spec (not a pure PRD) calling out examples such as FR-001/006/010 naming
InfrahubClient/InfrahubClientSync, FR-012 file path
infrahub_sdk/template/exceptions.py, FR-013
client.object_store.get(identifier=storage_id), FR-002/007 naming
FilterDefinition/InfrahubFilters/Jinja2Template, and SC-005 referencing uv run
pytest tests/unit/ so reviewers understand the intentional deviation.

Comment on lines +34 to +36
- One open question remains intentionally: whether to add a Python transform convenience SDK method (FR scope question flagged in Open Questions section, documented for planning phase).
- Ordering guarantee is explicitly out of scope and documented as a known limitation.
- `from_json`/`from_yaml` existence in the current filter set is flagged as an assumption to verify during planning.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing blank line after the Notes list.

The Notes list ends at line 36 (end of file) with no trailing blank line, violating the Markdown convention.

📝 Proposed fix
 - `from_json`/`from_yaml` existence in the current filter set is flagged as an assumption to verify during planning.
+

As per coding guidelines: "Add blank lines before and after lists in Markdown files."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- One open question remains intentionally: whether to add a Python transform convenience SDK method (FR scope question flagged in Open Questions section, documented for planning phase).
- Ordering guarantee is explicitly out of scope and documented as a known limitation.
- `from_json`/`from_yaml` existence in the current filter set is flagged as an assumption to verify during planning.
- One open question remains intentionally: whether to add a Python transform convenience SDK method (FR scope question flagged in Open Questions section, documented for planning phase).
- Ordering guarantee is explicitly out of scope and documented as a known limitation.
- `from_json`/`from_yaml` existence in the current filter set is flagged as an assumption to verify during planning.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dev/specs/001-artifact-composition/checklists/requirements.md` around lines
34 - 36, The Markdown file ends with a Notes list but lacks a trailing blank
line; update dev/specs/001-artifact-composition/checklists/requirements.md by
adding a single blank line after the final list item (the lines starting with
"One open question remains..." / "Ordering guarantee..." /
"`from_json`/`from_yaml` existence...") so there is an empty line at EOF,
conforming to the guideline to add blank lines before and after lists.

Comment on lines +100 to +102
- **FR-005**: Both `artifact_content` and `file_object_content` MUST raise `JinjaFilterError` when the input `storage_id` is null or empty, or when the object store cannot retrieve the content for any reason (not found, network failure, auth failure).
- **FR-006**: Both `artifact_content` and `file_object_content` MUST raise `JinjaFilterError` when invoked and no `InfrahubClient` was supplied to `Jinja2Template` at construction time. The error message MUST name the filter and explain that an `InfrahubClient` is required.
- **FR-007**: Both `artifact_content` and `file_object_content` MUST be registered with `trusted=False` in the `FilterDefinition` registry so that `validate(restricted=True)` blocks them in the computed attributes execution context (Infrahub API server). They are only permitted to execute on Prefect workers, where an `InfrahubClient` is available.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

FR-007 is internally inconsistent with the three-context validation model — mark as provisional.

FR-007 registers both new filters as trusted=False, but this puts them in the same bucket as safe (and similar currently-untrusted filters). User Story 4, Acceptance Scenario 3 explicitly requires that other trusted=False filters still raise JinjaTemplateOperationViolationError in the Prefect-worker context. With the current binary validate(restricted: bool), there is no way to simultaneously:

  • block artifact_content in the computed-attributes context ✓
  • allow artifact_content in the Prefect-worker context ✓
  • continue blocking safe in the Prefect-worker context ✓

The Open Questions section (line 151) correctly identifies the enum migration needed, but FR-007 reads as a final requirement rather than a provisional one. An implementer reading FR-007 in isolation could register the new filters identically to safe and still satisfy the wording — which would break US4/SC-002.

📝 Suggested wording to make FR-007 provisional
-- **FR-007**: Both `artifact_content` and `file_object_content` MUST be registered with `trusted=False` in the `FilterDefinition` registry so that `validate(restricted=True)` blocks them in the computed attributes execution context (Infrahub API server). They are only permitted to execute on Prefect workers, where an `InfrahubClient` is available.
+- **FR-007**: Both `artifact_content` and `file_object_content` MUST be blocked in the computed attributes execution context (Infrahub API server) and permitted in the Prefect-worker execution context. *Provisional implementation*: register with `trusted=False` so that the existing `validate(restricted=True)` blocks them initially. **This requirement depends on resolution of the "Validation level model" open question**, which must introduce a dedicated worker-context tag to distinguish these filters from currently-untrusted filters (e.g., `safe`) that must remain blocked even in the Prefect-worker context.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dev/specs/001-artifact-composition/spec.md` around lines 100 - 102, FR-007 is
inconsistent with the three-context validation model: registering
artifact_content and file_object_content as trusted=False will equate them with
existing filters like safe and break the intended Prefect-worker allowance;
update the spec wording to mark FR-007 as provisional and add a note that
FilterDefinition must be extended (e.g., a new enum or flag) to distinguish
"worker-allowed" filters from general trusted/untrusted, and reference
artifact_content, file_object_content, FilterDefinition,
validate(restricted=True), safe, and JinjaTemplateOperationViolationError so
implementers know to avoid simply copying safe's trusted=False registration and
instead await the enum migration described in Open Questions.

Comment on lines +157 to +161
- Q: Are `artifact_content` and `file_object_content` identical at the storage API level, or do they use different API paths / metadata handling? → A: Different implementations — `file_object_content` uses a different API path or carries different metadata handling than `artifact_content`.
- Q: Where are these filters permitted to execute, and what mechanism enforces the boundary? → A: Blocked in computed attributes (executed locally in the Infrahub API server, which uses `validate(restricted=True)`); permitted on Prefect workers, which have access to an `InfrahubClient`. The `trusted=False` registration enforces this boundary via the existing restricted-mode validation.
- Q: What exception class should filter-level errors (no client, retrieval failure) raise? → A: A new `JinjaFilterError` class that is a child of the existing `JinjaTemplateError` base class.
- Q: Should the SDK expose a convenience method for artifact content retrieval in Python transforms? → A: No new method — document `client.object_store.get(identifier=storage_id)` directly.
- Q: What should `from_json`/`from_yaml` do on malformed input? → A: Raise `JinjaFilterError` on malformed JSON or YAML input.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing blank line after the final list.

The Clarifications list ends at line 161 (end of file) without a trailing blank line, violating the project's Markdown convention.

📝 Proposed fix
 - Q: What should `from_json`/`from_yaml` do on malformed input? → A: Raise `JinjaFilterError` on malformed JSON or YAML input.
+

As per coding guidelines: "Add blank lines before and after lists in Markdown files."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- Q: Are `artifact_content` and `file_object_content` identical at the storage API level, or do they use different API paths / metadata handling? → A: Different implementations — `file_object_content` uses a different API path or carries different metadata handling than `artifact_content`.
- Q: Where are these filters permitted to execute, and what mechanism enforces the boundary? → A: Blocked in computed attributes (executed locally in the Infrahub API server, which uses `validate(restricted=True)`); permitted on Prefect workers, which have access to an `InfrahubClient`. The `trusted=False` registration enforces this boundary via the existing restricted-mode validation.
- Q: What exception class should filter-level errors (no client, retrieval failure) raise? → A: A new `JinjaFilterError` class that is a child of the existing `JinjaTemplateError` base class.
- Q: Should the SDK expose a convenience method for artifact content retrieval in Python transforms? → A: No new method — document `client.object_store.get(identifier=storage_id)` directly.
- Q: What should `from_json`/`from_yaml` do on malformed input? → A: Raise `JinjaFilterError` on malformed JSON or YAML input.
- Q: Are `artifact_content` and `file_object_content` identical at the storage API level, or do they use different API paths / metadata handling? → A: Different implementations — `file_object_content` uses a different API path or carries different metadata handling than `artifact_content`.
- Q: Where are these filters permitted to execute, and what mechanism enforces the boundary? → A: Blocked in computed attributes (executed locally in the Infrahub API server, which uses `validate(restricted=True)`); permitted on Prefect workers, which have access to an `InfrahubClient`. The `trusted=False` registration enforces this boundary via the existing restricted-mode validation.
- Q: What exception class should filter-level errors (no client, retrieval failure) raise? → A: A new `JinjaFilterError` class that is a child of the existing `JinjaTemplateError` base class.
- Q: Should the SDK expose a convenience method for artifact content retrieval in Python transforms? → A: No new method — document `client.object_store.get(identifier=storage_id)` directly.
- Q: What should `from_json`/`from_yaml` do on malformed input? → A: Raise `JinjaFilterError` on malformed JSON or YAML input.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dev/specs/001-artifact-composition/spec.md` around lines 157 - 161, The
Clarifications list at the end of the file lacks a trailing blank line; update
the final list in the "Clarifications" section (the bullet list ending at the
end of file) to include a blank line after the list so the Markdown convention
"Add blank lines before and after lists" is satisfied — ensure there's exactly
one empty line following the final list item and that any preceding list start
also has a blank line above it if missing.

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

Comments