Skip to content

docs(#6407): adopt deterministic entity context staging - #7080

Open
ifireball wants to merge 4 commits into
fullsend-ai:mainfrom
ifireball:codex/adr-entity-context-staging
Open

docs(#6407): adopt deterministic entity context staging#7080
ifireball wants to merge 4 commits into
fullsend-ai:mainfrom
ifireball:codex/adr-entity-context-staging

Conversation

@ifireball

@ifireball ifireball commented Sep 7, 2026

Copy link
Copy Markdown
Member

Summary

  • adopt ADR 0107 for deterministic, filtered entity-context snapshots before the harness pre-script
  • define a versioned normative v1 contract with schemas, canonical serialization, stable record keys, and explicit private-data cleanup
  • make issue/PR bodies, comments, and reviews self-contained attributed records while keeping mutable thread resolution state separate
  • store each conversation turn once under chronologically sortable filenames, enabling cat records/*.md assembly with a stable prefix for prompt caching
  • provide lightweight per-thread order files that reference the same records without duplicating content
  • expose the same relative-path contract to host scripts and the sandbox through FULLSEND_CONTEXT_DIR, outside the repository clone and retained run artifacts
  • update the living architecture, security threat model, and ADR 0017 cross-reference

Rationale

Issue #6407 identifies repeated ad-hoc forge calls as non-deterministic and token-intensive. This ADR records the architecture for collecting the handled issue or change proposal once, filtering untrusted content before agent consumption, and sharing the resulting snapshot across scripts and runtimes.

The record/state split means resolution changes do not rewrite unchanged comments. Chronological record names keep prior turns byte-identical when ordinary new replies append, allowing runtimes to reuse provider prompt caches without storing duplicate concatenated views. Current mutable state is supplied afterward.

This is the design decision for #6407; implementation and token-cost measurement remain follow-up work, so this PR does not close the issue.

Verification

  • make lint
  • repository check json hook for all v1 JSON Schemas

Relates to #6407.

Record a runner-owned, filtered entity snapshot that is available before the pre-script and exposed through predictable paths outside the repository clone.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Assisted-by: Codex (gpt-5.6-sol)
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Document deterministic filtered entity-context staging

📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Adopt ADR 0107 for deterministic, filtered entity snapshots before harness pre-scripts.
• Define a versioned context tree shared across host scripts and sandbox agents.
• Align architecture, credential isolation, and threat-model documentation with the new contract.
Diagram

graph TD
  FC["Forge Client"] -->|"fetches entity"| RUN["Run Orchestrator"] -->|"assembles snapshot"| FIL["Filter Pipeline"] -->|"writes filtered files"| CTX[("Context Tree")] -->|"FULLSEND_CONTEXT_DIR"| HS["Host Scripts"]
  CTX -->|"digest-verified context"| UP["Sandbox Upload"] -->|"read-only context"| AG["Agent Runtime"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. On-demand forge reads
  • ➕ Always retrieves the latest entity state
  • ➕ Avoids snapshot startup and storage costs
  • ➖ Produces non-deterministic views during a run
  • ➖ Requires repeated network calls and additional tokens
  • ➖ Weakens centralized filtering and credential isolation
2. Single bundled context file
  • ➕ Provides a simpler staging and transfer contract
  • ➕ Makes snapshot publication naturally atomic
  • ➖ Encourages agents to consume irrelevant content
  • ➖ Reduces per-record provenance and selective access
  • ➖ Makes large logs, reviews, and comments harder to navigate
3. Stage context inside the clone
  • ➕ Simplifies path sharing with repository-oriented tooling
  • ➕ May avoid a separate sandbox upload location
  • ➖ Risks accidental staging or commits of generated input
  • ➖ Blurs the trust boundary between repository and forge content
  • ➖ Allows repository operations to mutate or remove context

Recommendation: The proposed runner-owned, filtered, per-record snapshot is the strongest approach because it combines deterministic inputs, selective agent reads, provenance, and credential isolation. Keeping it outside the clone and verifying manifest digests before sandbox upload preserves the trust boundary; implementations should retain explicit freshness validation before forge mutations.

Files changed (4) +110 / -0

Documentation (4) +110 / -0
0017-credential-isolation-for-sandboxed-agents.mdCross-reference the standardized entity-prefetch model +3/-0

Cross-reference the standardized entity-prefetch model

• Links the credential-isolation ADR to ADR 0107 as the default prefetch model for handled entity content.

docs/ADRs/0017-credential-isolation-for-sandboxed-agents.md

0107-deterministic-filtered-entity-context-staging.mdDefine deterministic filtered entity-context staging +100/-0

Define deterministic filtered entity-context staging

• Records the accepted architecture for fetching, filtering, manifesting, and staging immutable entity snapshots before pre-scripts. It specifies the versioned file tree, shared FULLSEND_CONTEXT_DIR contract, integrity checks, read-only sandbox exposure, and operational consequences.

docs/ADRs/0107-deterministic-filtered-entity-context-staging.md

architecture.mdAdd entity-context staging to the living architecture +5/-0

Add entity-context staging to the living architecture

• Documents the runner's pre-script snapshot step and the shared host-to-sandbox relative-path contract, with a link to ADR 0107.

docs/architecture.md

security-threat-model.mdConnect input sanitization controls to ADR 0107 +2/-0

Connect input sanitization controls to ADR 0107

• Links the threat model's input-sanitization guidance to the deterministic filtering and finding-disclosure decision in ADR 0107.

docs/problems/security-threat-model.md

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 7, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 1:08 PM UTC · Completed 1:26 PM UTC

Commit: 64bd0d5 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $5.09

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

Site preview

Preview: https://36defd79-site.fullsend-ai.workers.dev

Commit: 2e9ff4836b0b6817a66f94141f9af27225ee95f8

@qodo-code-review

qodo-code-review Bot commented Sep 7, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Private forge data enters run artifacts ✓ Resolved 🐞 Bug ⛨ Security
Description
The decision stores bodies, comments, reviews, diffs, and logs beneath <run-dir>/context without
requiring deletion or exclusion from retained artifacts. Private-entity runs therefore leave
filtered but still confidential content in a directory the repository documents as
artifact-uploaded, reaching artifact retention whenever the run directory is collected.
Code

docs/ADRs/0107-deterministic-filtered-entity-context-staging.md[R48-51]

+The snapshot is written outside the repository clone. Host-side pre- and
+post-scripts receive `FULLSEND_CONTEXT_DIR` pointing to
+`<run-dir>/context`; inside the sandbox the same variable points to
+`/sandbox/workspace/context`. Fullsend uploads that directory after sandbox
Relevance

●●● Strong

Security-critical private data requires explicit artifact exclusion or cleanup before retention.

PR-#5328

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new tree explicitly includes entity bodies, discussions, diffs, and check logs under the run
directory. Existing security guidance says prefetched private data outlives the agent and requires
security-critical cleanup, while contributor guidance states that the run directory is uploaded as a
CI artifact; ADR 0107 specifies neither cleanup nor artifact exclusion.

docs/ADRs/0107-deterministic-filtered-entity-context-staging.md[48-75]
docs/ADRs/0017-credential-isolation-for-sandboxed-agents.md[68-72]
docs/ADRs/0017-credential-isolation-for-sandboxed-agents.md[102-104]
docs/contributing/go-code.md[452-457]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Define the lifecycle and retention boundary for staged entity context containing private forge data.

## Issue Context
Require cleanup after the last authorized host consumer, specify behavior on failures and cancellation, and either exclude context from run artifacts or define explicit access-controlled retention. Preserve diagnostics without retaining full private bodies and logs unnecessarily.

## Fix Focus Areas
- docs/ADRs/0107-deterministic-filtered-entity-context-staging.md[48-75]
- docs/ADRs/0107-deterministic-filtered-entity-context-staging.md[94-100]
- docs/ADRs/0017-credential-isolation-for-sandboxed-agents.md[102-104]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Identical inputs produce different trees ✓ Resolved 🐞 Bug ≡ Correctness
Description
index.json must include the snapshot time while the ADR also promises byte-identical trees for
identical forge responses. Fetching the same response at different times changes that required
timestamp, so the central determinism guarantee fails unless time is derived canonically or excluded
from the tree.
Code

docs/ADRs/0107-deterministic-filtered-entity-context-staging.md[R78-81]

+`index.json` is the authoritative, versioned manifest. It identifies the forge,
+repository, entity kind and ID, snapshot time/revision, schema version, and an
+ordered entry for every staged file with source ID and URL, author, timestamps,
+media type, byte count, SHA-256 digest, and filtering/truncation status.
Relevance

●●● Strong

The required acquisition timestamp directly contradicts byte-identical output for identical
responses.

PR-#5328

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The manifest is required to contain snapshot time, while the following paragraph says identical
forge responses produce byte-identical trees. A run-specific acquisition time necessarily changes
the manifest bytes even when every forge response is unchanged.

docs/ADRs/0107-deterministic-filtered-entity-context-staging.md[78-85]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Reconcile the required snapshot timestamp with the guarantee that identical forge responses produce byte-identical context trees.

## Issue Context
Define a canonical source for the timestamp, weaken the guarantee to exclude acquisition metadata, or separate non-deterministic run metadata from the deterministic snapshot.

## Fix Focus Areas
- docs/ADRs/0107-deterministic-filtered-entity-context-staging.md[78-85]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Implementers can diverge on snapshots ✓ Resolved 📜 Skill insight ⚙ Maintainability
Description
The Decision section of ADR 0107 embeds the authoritative v1 directory tree, exact paths,
field-level index.json schema, ordering, metadata, and digest behavior instead of linking to a
versioned artifact under docs/normative/. When runner, forge-adapter, and sandbox implementations
adopt this prose independently, they have no machine-checkable conformance target for schemas or
canonical serialization and can diverge.
Code

docs/ADRs/0107-deterministic-filtered-entity-context-staging.md[R78-81]

+`index.json` is the authoritative, versioned manifest. It identifies the forge,
+repository, entity kind and ID, snapshot time/revision, schema version, and an
+ordered entry for every staged file with source ID and URL, author, timestamps,
+media type, byte count, SHA-256 digest, and filtering/truncation status.
Relevance

●● Moderate

Normative-contract concerns are often accepted, but implementation-link requests have also been
rejected.

PR-#5016
PR-#2743

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
ADR 0107 introduces a field-, path-, ordering-, and byte-level v1 compatibility contract directly in
its Decision section, but does not link or add an entity-context normative tree. ADR 0015 and
compliance rule 1525847 require ADRs introducing such contracts to link a versioned specification
under docs/normative/<topic>/v<major>/, establishing that the inline contract lacks the required
normative artifact.

docs/ADRs/0107-deterministic-filtered-entity-context-staging.md[56-85]
docs/ADRs/0015-normative-specifications-directory.md[29-55]
Skill: writing-adrs

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description

Move the detailed entity-context directory and manifest contract into a versioned normative specification, and update ADR 0107 to link to it rather than defining the contract inline.

## Issue Context

Create an appropriate artifact such as `docs/normative/entity-context/v1/README.md`. Preserve and formalize the complete directory layout, schemas, canonical serialization and ordering, path-safe stable-ID encoding, filtering status values, field-level `index.json` contents, metadata, digest coverage, and compatibility rules there, while keeping ADR 0107 focused on the architectural decision and rationale.

## Fix Focus Areas

- docs/ADRs/0107-deterministic-filtered-entity-context-staging.md[56-85]
- docs/ADRs/0015-normative-specifications-directory.md[39-55]
- docs/normative[1-1]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 67 rules
Review mode: ⚖️ Balanced: Although the diff is documentation-only, it defines security-sensitive runtime architecture and contracts for filtering, sandbox boundaries, manifests, and credential isolation, warranting a careful review.

Grey Divider

Tip of the day
💡 Did you know, you can tweak Display preferences with a live preview to see your comment before it ships

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread docs/ADRs/0107-deterministic-filtered-entity-context-staging.md Outdated
Comment thread docs/ADRs/0107-deterministic-filtered-entity-context-staging.md Outdated
Comment thread docs/ADRs/0107-deterministic-filtered-entity-context-staging.md
@codecov

codecov Bot commented Sep 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 7, 2026

Copy link
Copy Markdown

Risk Assessment: moderate (2/5)

Details

Docs-only normative spec addition with no source or CI changes; prior score of 2 preserved — Tier 2 confirms architecture.md high-churn and multi-author merge-conflict risk flagged in prior assessment, with all other signals unchanged.

Previous run

Risk Assessment: moderate (2/5)

Details

Docs-only ADR addition with no source or CI changes; score elevated slightly above low by docs/architecture.md being a high-churn, multi-author file that creates merge-conflict risk.

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 7, 2026

Copy link
Copy Markdown

Review

Findings

Medium

  • [internal-consistency] docs/normative/entity-context/v1/README.md:168 — The Compatibility section states consumers "must ignore unknown object properties within v1" and "Adding an optional record kind or property is compatible." However, every JSON Schema in the specification (index.schema.json, entity.schema.json, check.schema.json, commits.schema.json, thread-state.schema.json) sets additionalProperties: false on every object definition. A consumer validating against these schemas would reject any document containing a property added in a later compatible v1 revision, breaking the stated forward-compatibility contract. The two normative claims — "ignore unknown properties" and additionalProperties: false — cannot both be true simultaneously.
    Remediation: Either (a) remove additionalProperties: false from all schema objects so consumers can accept v1-compatible additions without schema violation; or (b) change the Compatibility section to state that adding any property is a breaking change requiring v2, aligning the prose with the schemas; or (c) add explicit guidance that the schemas are producer-side contracts only and that consumers must strip additionalProperties constraints before validation.

Low

  • [code-organization] docs/normative/entity-context/v1/README.md:122 — In the "Canonical bytes" section, the paragraph about attacker-controlled strings passing through the filter pipeline (lines 122–123) is placed between the introductory sentence ending "filter.status is:" (line 120) and the bullet list defining the filter.status values (lines 125–128). This breaks the semantic connection between the introduction and its enumeration.
    Remediation: Move lines 122–123 to immediately after the bullet list (after the rejected entry), so the bullet list follows directly from "filter.status is:".

Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run

Review

Findings

Medium

  • [internal-consistency] docs/ADRs/0107-deterministic-filtered-entity-context-staging.md:84 — (a) The determinism claim "identical forge responses produce byte-identical trees" is potentially contradicted by the "snapshot time/revision" field in index.json. If "snapshot time" is derived from the runner's wall clock rather than from forge response data, two assemblies of the same forge data at different times would produce different index.json files, breaking the byte-identical guarantee. The ADR does not clarify the source. (b) The text states "Entries use canonical ordering and zero-padded ordinals plus forge-stable IDs" without qualification, but the directory tree shows ordinal prefixes only on comments and reviews, not on checks. The discrepancy between the general statement and the selective application in the diagram is real.
    Remediation: Clarify whether "snapshot time" is derived from forge response data (preserving determinism) or from the runner clock (excluded from the byte-identical guarantee). Clarify that ordinal prefixes apply to flat-file collections (comments, reviews) but not to per-entity subdirectories (checks), or align the diagram with the text.

Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR

fullsend-ai-review[bot]

This comment was marked as outdated.

Separate immutable record content from mutable thread state, move the byte-level contract into a normative v1 specification, and define cleanup outside retained run artifacts.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Assisted-by: Codex (gpt-5.6-sol)
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 8, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 11:21 AM UTC · Ended 11:27 AM UTC

Commit: 9a0d4f6 · View workflow run →

Include immutable attribution in each conversation record and define canonical whole-conversation and per-thread views whose normal reply path preserves the existing byte prefix.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Assisted-by: Codex (gpt-5.6-sol)
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 8, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 11:28 AM UTC · Ended 11:32 AM UTC

Commit: 2e9ff48 · View workflow run →

Store each attributed conversation record once, name records for chronological glob concatenation, and use lightweight thread order files for thread-specific assembly.

Signed-off-by: Barak Korren <bkorren@redhat.com>
Assisted-by: Codex (gpt-5.6-sol)
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 8, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 11:34 AM UTC · Completed 11:53 AM UTC

Commit: 0395379 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $5.22

@fullsend-ai-review fullsend-ai-review 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.

See the review comment for full details.

## Compatibility

Consumers must reject an unsupported `schema_version` or `filter_version`; they
must ignore unknown object properties within v1. Adding an optional record kind

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] internal-consistency

The Compatibility section states consumers "must ignore unknown object properties within v1" and "Adding an optional record kind or property is compatible." However, every JSON Schema in the specification sets additionalProperties: false on every object definition. A consumer validating against these schemas would reject any document containing a property added in a later compatible v1 revision, breaking the stated forward-compatibility contract.

Suggested fix: Either (a) remove additionalProperties: false from all schema objects, or (b) change the Compatibility section to state that adding any property is a breaking change requiring v2, or (c) add explicit guidance that the schemas are producer-side contracts only.

applies size bounds, Unicode safety normalization, secret/sensitive-data
redaction, and injection scanning in that order. `filter.status` is:

All attacker-controlled strings in JSON metadata pass through the same pipeline

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] code-organization

In the Canonical bytes section, the paragraph about attacker-controlled strings (lines 122-123) is placed between the introductory sentence ending "filter.status is:" and the bullet list defining its values (lines 125-128), breaking the semantic connection.

Suggested fix: Move lines 122-123 to immediately after the bullet list so it follows directly from "filter.status is:".

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

Labels

risk/moderate PR risk: moderate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant