Skip to content

fix(#2247): compare decoded text in shim drift detection#7

Closed
guyoron1 wants to merge 1220 commits into
mainfrom
agent/2247-fix-shim-stale-comparison
Closed

fix(#2247): compare decoded text in shim drift detection#7
guyoron1 wants to merge 1220 commits into
mainfrom
agent/2247-fix-shim-stale-comparison

Conversation

@guyoron1

Copy link
Copy Markdown
Owner

The stale-shim comparison in reconcile-repos.sh used managed_content_b64() which decoded base64, extracted managed content, then re-encoded to base64. Bash command substitution strips trailing newlines, so the re-encoded base64 could differ from the original even when the decoded text was identical. This caused false-positive drift detection, leading to bogus update PRs (e.g. PR fullsend-ai#2101) that removed the sentinel lines.

Replace the base64-to-base64 comparison with decoded text comparison: decode both sides, strip carriage returns, extract managed content via extract_managed_ content, and compare the resulting strings directly. For pre-sentinel shims (no sentinel found), fall back to comparing full decoded content.

Add a regression test that verifies logically identical content with different trailing newlines is not flagged as stale.

Note: pre-commit could not run in sandbox (shellcheck download blocked by network policy). The post-script runs pre-commit authoritatively on the runner.


Closes fullsend-ai#2247

Post-script verification

  • Branch is not main/master (agent/2247-fix-shim-stale-comparison)
  • Secret scan passed (gitleaks — cda8e5712200b8cf6e19be99722d6d33c4caabb7..HEAD)
  • Pre-commit hooks passed (authoritative run on runner)
  • Tests ran inside sandbox

Mirrored from upstream fullsend-ai#2254 for QualityFlow demo.

ralphbean and others added 30 commits June 5, 2026 14:21
- Split actions/cache into actions/cache/restore + actions/cache/save
  so stale cache entries get replaced when the upstream image changes
- Include image reference in cache key to avoid cross-image collisions
  when FULLSEND_SANDBOX_IMAGE is overridden
- Add restore-keys prefix matching for partial cache hits
- Track digest before/after pull to detect image changes and re-save
- Guard podman save with podman image exists to avoid hard failure
  when pull soft-fails
- Add -- before image arg in podman save for consistency with pull
- Add error handling on podman load for corrupted cache graceful
  degradation

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
…token-scope-logging

chore(mint): log requested and granted token scope
Replace the strict "immutable once accepted" policy with a nuanced one:
cross-references, short notes linking to newer ADRs, and typo fixes are
welcome on accepted ADRs. Substantial rewrites still require a new
superseding ADR. This stops agents from refusing to add navigational
links between related ADRs while still preventing old ADRs from becoming
evolving design documents (that role belongs to docs/architecture.md).

Updates both the ADR template and the writing-adrs skill.

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
fullsend-ai/.fullsend now references reusable workflows via @main
instead of @v0. This means:

- Pre-flight: fullsend-ai runs are now a signal that main is healthy
  before moving the v0 tag (new step E)
- Post-flight: fullsend-ai runs no longer tell us anything about v0
  resolution, so step C is replaced with an explanatory note and
  downstream verification is moved to step D with inline commands

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
- Rename heading to "Skip fullsend-ai repos" to match action-verb pattern
- Add rerun command template and prompt to step D for self-containment

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
Add AppID and InstallationID fields to GrantedScope and include them
in the "minted:" log line. This helps diagnose cross-org token scope
issues by revealing which GitHub App installation was used to create
the token.

Ref: fullsend-ai#1916

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
…jobs

Relative (./) paths in uses: resolve against the caller's repo, not the
repo that defines the reusable workflow. This breaks per-repo mode where
the caller is an external repo without the reusable-{stage}.yml files.

Restore fully-qualified fullsend-ai/fullsend/...@v0 references and add
a regression test to prevent re-introduction.

Signed-off-by: Wayne Sun <gsun@redhat.com>
…patch-paths

fix(workflows): use fully-qualified paths in reusable-dispatch stage jobs
…Phase 2 PR 2)

Implements recursive skill dependency resolution for the universal harness
access resolver (ADR-0038 Phase 2, PR 2 of 3).

Changes:
- Add ResolveRelativeURL for RFC 3986 relative URL resolution
- Add MaxDepth/MaxResources limits to ResolveOpts with explicit depth
  parameter threading through resolveTransitiveDeps (no mutable state)
- Cycle detection via inProgress DFS stack, diamond dedup via resolved map
- Conflicting SHA256 hashes for the same URL are detected and rejected
- Skills with dependencies: frontmatter are recursively resolved; policy
  references are fetched as leaf nodes (runtime semantics deferred)
- Rename resolveState.appended to inDeps for semantic clarity
- Standardize resolveURL error messages to consistent "%s: " prefix format
- Add explicit HTTPS-only scheme check in resolveURL as defense-in-depth
  for transitive dep URLs (fetch.FetchURL also enforces this)
- Wrap ParseFrontmatter errors with parentURL context in resolveTransitiveDeps
- 14 new transitive resolution tests: chain, diamond, cycle, depth limit,
  resource limit, allowlist, hash mismatch, relative URL, conflicting hashes,
  policy leaf, MaxDepth=0 disabled, default, overlap dedup, non-HTTPS scheme
- 4 new relurl tests: invalid percent-encoding, empty relRef, empty parentURL,
  parent URL with no path component
- Update stale pseudocode in design docs to reflect Phase 2 implementation

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Greg Allen <gallen@redhat.com>
…ork-check-token

fix(fullsend-ai#1532): use github.token for fork-check in dispatch
Allow overriding the number of prioritize jobs dispatched when
triggering the scheduler manually via workflow_dispatch. Falls back
to the PRIORITIZE_WIP_LIMIT repo variable, then to 5.

Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
…playwright-mcp

chore: add .playwright-mcp to .gitignore
Update AGENTS.md, CONTRIBUTING.md, docs/architecture.md,
skills/renumber-adr/SKILL.md, and skills/writing-adrs/SKILL.md to
distinguish minor annotations from substantial rewrites on accepted
ADRs, consistent with the updated template and writing-adrs skill.

Fix parallel structure in writing-adrs mistake table entries.

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
…w template

The shim-workflow-call.yaml template was missing the `---` YAML
document start marker, causing yamllint failures in enrolled repos
that enforce the `document-start` rule. Prepend `---` as the first
line of the template.

Also add a test assertion in TestShimWorkflowCallTemplateContent
to verify the marker is present.

Note: Go tests and pre-commit could not run in the sandbox due to
Go version mismatch (sandbox has 1.24.13, repo requires 1.26.0).
Manual verification of Go tests is required.

Closes fullsend-ai#1946
Prepend `---` to all 25 remaining scaffold YAML files (workflows,
actions, templates, policies, harness configs) that were missing
the yamllint document-start marker. Add TestAllScaffoldYAMLDocumentStartMarker
to prevent future regressions.

Addresses review feedback on fullsend-ai#1947

Signed-off-by: fullsend-fix <fullsend-code@users.noreply.github.com>
Refactor TestAllScaffoldYAMLDocumentStartMarker to use
WalkFullsendRepoAll instead of filepath.WalkDir + os.ReadFile.
This matches the established test pattern and validates the
embedded content that production code actually serves.

Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
Extract saveWorkflowRunDebugInfo from the triage phase so both triage
and unenrollment use the same code to fetch workflow logs, download
artifacts, and emit GitHub Actions annotations on failure.

In the unenrollment phase, find the most recent repo-maintenance run
after the CLI returns and capture its logs if it failed. This gives us
visibility into why the removal PR never appears.

Closes fullsend-ai#1960

Signed-off-by: Ralph Bean <rbean@redhat.com>
Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
…en scope

The minted token only covered enabled repos, so the reconcile script
couldn't access disabled repos during unenrollment. API calls failed
silently (2>/dev/null), causing the script to treat them as "already
unenrolled" and skip removal PR creation.

Also capture repo-maintenance workflow logs unconditionally in the e2e
test so silent-skip problems leave a debug trail even when the workflow
reports success.

Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
…nostics

- Replace two yq queries + bash concatenation with a single query that
  selects both enabled and disabled repos
- Return debugDir from saveWorkflowRunDebugInfo so callers can reference
  it in failure messages
- Consolidate the two removal-PR failure paths into one with conditional
  repo-maintenance run context
- Update test assertion to match the simplified yq query

Assisted-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
…eters

Split annotation prefix into annotationMsg (::notice::) for plain
messages and annotationFile (::notice ) for file-parameter annotations.
The previous code reused ::notice:: for both, producing malformed
annotations like ::notice::file=path::message instead of the correct
::notice file=path::message.

Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
…debug-logs

fix(fullsend-ai#1960): include disabled repos in repo-maintenance token scope
The added --- line pushed dispatch.yml to 392 lines, exceeding the
previous 391 cap.

Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
…aml-doc-start-marker

fix(fullsend-ai#1946): add YAML document start marker to shim workflow template
The fallback when merge-base fails silently reverted to CHANGED_FILES,
which re-introduces false positives after rebase. Align with the
post-code.sh fallback chain: warn, try origin/TARGET..HEAD, then
HEAD~1..HEAD.

Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
Remove path filters from pull_request trigger and add merge_group
trigger so the e2e job always reports a status. When no e2e-relevant
files changed, the job short-circuits after checking the PR file list
via the GitHub API.

This lets the e2e check be made a required status check without
blocking docs-only or other non-code PRs from the merge queue.

Push-to-main keeps its path filters since it doesn't gate the merge
queue.

Closes fullsend-ai#1987

Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
The sandbox image pinned Go 1.24.13 while go.mod requires 1.26.0.
This version mismatch prevented the code agent from compiling or
testing Go code, causing it to submit untested PRs (e.g. PR fullsend-ai#1016
shipped a duplicate map key that go build would have caught).

Update GO_VERSION from 1.24.13 to 1.26.0 and replace the SHA256
checksums for linux-amd64 and linux-arm64 archives. Checksums
sourced from docker-library/golang at the go1.26.0 release commit.

The sandbox image will rebuild automatically via the
sandbox-images.yml workflow on push to main.

Note: pre-commit could not run in-sandbox (exit 3) because the
gitleaks hook tried to auto-download a newer Go toolchain, which
is blocked by sandbox network policy. This is the same version
mismatch this commit fixes.

Closes fullsend-ai#1344
gopls 0.18.1 depends on golang.org/x/tools v0.30.x which fails to
compile under Go 1.26.0 (invalid array length in tokeninternal.go).
Bump to gopls 0.22.0, the latest release, which supports Go 1.26.

Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
    git %(contents:subject) skips leading blank lines, so a blank first
    line still picks up the first category header as .TagSubject. Using
    the tag name itself ensures .TagSubject == .Tag, which the goreleaser
    guard suppresses, producing a clean release title.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Hector Martinez <hemartin@redhat.com>
Opens /organizations/{org}/settings/installations/{id} instead of
/organizations/{org}/settings/apps/{slug}/advanced. The /advanced page
requires app owner access; org admins installing a third-party app need
the installation settings page to uninstall.

Falls back to /settings/installations list when the installation ID is
unavailable (e.g. ListOrgInstallations failed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Hector Martinez <hemartin@redhat.com>
maruiz93 and others added 25 commits June 12, 2026 12:24
…ract

- Distinguish what ADR 0017/0025 originally established (request bodies,
  response transformation) from the broader scope this ADR introduces
- Add implementation model Options subsection: language-agnostic process
  contract vs. Go interface
- Clarify the process contract is the runner's enforcement boundary;
  the Go interface is the recommended internal pattern for
  fullsend-maintained servers, not a runner requirement
- Scope experiment reference — experiment validated the flow, Go
  interface decision came from review discussion
- Update Consequences for Go interface pattern and process contract
  as enforcement boundary

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Marta Anon <manon@redhat.com>
End-to-end guide for creating new custom agents from scratch on
per-repo fullsend installations. Covers agent prompts, harness config,
sandbox policies, output schemas, pre/post scripts, GitHub Actions
workflows, slash-command dispatch, and troubleshooting.

Improvements over the source material:
- Fixed nested code block rendering (4-backtick outer fences)
- Added post-script security section (treat agent output as untrusted)
- Added glossary cross-references and Reference section
- Deduplicated with customizing-agents.md via cross-links

Addressed review feedback (PR fullsend-ai#1179):
- Removed explore/refine agent references (not upstream)
- Fixed install command (fullsend admin install <owner/repo>)
- Removed WIF secrets from prerequisites (part of installation)
- Replaced security model diagram with inline summary + link
- Removed Step 1 (config.yaml roles not yet extensible)
- Added target-repo checkout step and --target-repo flag
- Added MY_VAR to workflow env block
- Reduced permissions to least-privilege (contents:read, id-token:write)
- Added trigger instructions (UI and CLI) before dispatch workflow
- Extracted agent chaining to future guide
- Condensed debugging tips into troubleshooting table

Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Hector Martinez <hemartin@redhat.com>
docs(guides): add building custom agents guide
…ned-status-cleanup

fix(fullsend-ai#2149): finalize orphaned status comments on hard process termination
…d-cancel-context

fix(fullsend-ai#2148): thread signal-aware context into sandbox exec
feat(fetchsvc): runner-side runtime fetch service (Phase 4, PR 1)
…view

feat(harness): add base composition for harness inheritance (ADR-0045 PR 4/7)
…erver

docs: ADR 0046 — host-side API server design for sandboxed agents
…lgtm-no-findings

feat(review): use "Looks good to me" when no findings
Users must request mint enrollment before configuring fullsend, but
the getting started guide did not mention this step. Add it as step 1
with a note that ADR 0043 (public mint mode) will remove the manual
enrollment requirement once implemented.

Signed-off-by: Wayne Sun <gsun@redhat.com>
…tches remote

Use skopeo inspect to check the remote image digest (~1s) before
deciding whether to pull. When the locally loaded image (from cache)
already matches the remote, skip the pull, save, and cache upload
entirely. This avoids ~4.5 min of overhead on every run when the image
hasn't changed.

On cold cache or digest mismatch, behavior is unchanged: pull the new
image and update the cache. When skopeo cannot fetch the remote digest,
fall through to pull with a clear log message.

Relates-to: fullsend-ai#2222
Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com>
Signed-off-by: Ralph Bean <rbean@redhat.com>
…e-cache-digest-check

perf(fullsend-ai#2222): skip sandbox image pull when cached digest matches remote
…impl-questions

fix(fullsend-ai#2024): triage agent must not ask reporters implementation questions
…-prereq

docs: add mint enrollment prerequisite to getting started guide
…-claude-agents-md

chore(fullsend-ai#2088): consolidate agent instructions into AGENTS.md
Agents sometimes produce Signed-off-by trailers via `git commit -s`,
causing gitlint body-max-line-length failures because the bot noreply
email makes the trailer ~90 characters. DCO sign-off is a human
attestation of personhood — agents are not people, and the DCO app
already waives the check for bot authors (fullsend-ai#1449).

Changes:
- SKILL.md: add prominent prohibition against `git commit -s` and
  Signed-off-by trailers in the commit section (step 10b)
- post-code.sh: add section 3b that scans agent commits for
  Signed-off-by trailers and exits non-zero if found
- post-fix.sh: add section 2b with the same trailer check
- post-code-test.sh: add 5 test cases covering trailer detection
  (present, absent, empty body, mid-line mention, mixed trailers)

Note: `make lint` could not run due to network restrictions
preventing shellcheck installation. All scripts pass `bash -n`
syntax checking and the test suite (51 tests).

Closes fullsend-ai#2236
…acing questions

The HARD CONSTRAINT on line 146 required `action: "insufficient"` for
"ANY open questions or information gaps," which contradicted the question
classification rule (line 124) allowing implementation-facing questions
to proceed without `insufficient` unless they materially block triage.

Scope the HARD CONSTRAINT to user-facing questions and add an explicit
carve-out referencing the question classification rules, so the two
sections give consistent guidance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: fullsend-code <278716306+fullsend-ai-coder[bot]@users.noreply.github.com>
…cile-insufficient-rules

fix(fullsend-ai#2237): scope anti-premature-resolution rule to user-facing questions
…tall-cleanup-enrollment

fix(fullsend-ai#2017): unenroll repos during uninstall via repo-maintenance workflow
Remove stale "design exploration" framing from the "How to work in
this repo" section — the project now ships production Go code with
CI and deployments. Scope the options-with-trade-offs and target
audience bullets to problem documents specifically, where they
still apply.

Also fix stale ADR status guidance (related to fullsend-ai#1745): replace
references to removed Proposed/Undecided statuses with the current
three-status model (Accepted, Deprecated, Superseded).

Note: make lint could not run in the sandbox due to shellcheck
installation failure (network restriction). The post-script runs
an authoritative pre-commit check on the runner.

Closes fullsend-ai#2242
…-outdated-agents-md

docs(fullsend-ai#2242): prune outdated guidance from AGENTS.md
- Add Signed-off-by prohibition to fix-review/SKILL.md (incomplete-scope)
- Add variant-casing test to confirm case-sensitive matching (test-adequacy)
- Align success messages to em-dash pattern (success-message-consistency)

Addresses review feedback on fullsend-ai#2240
…gned-off-by

fix(fullsend-ai#2236): reject Signed-off-by trailers in agent commits
The stale-shim comparison in reconcile-repos.sh used
managed_content_b64() which decoded base64, extracted
managed content, then re-encoded to base64. Bash command
substitution strips trailing newlines, so the re-encoded
base64 could differ from the original even when the
decoded text was identical. This caused false-positive
drift detection, leading to bogus update PRs (e.g.
PR fullsend-ai#2101) that removed the sentinel lines.

Replace the base64-to-base64 comparison with decoded
text comparison: decode both sides, strip carriage
returns, extract managed content via extract_managed_
content, and compare the resulting strings directly.
For pre-sentinel shims (no sentinel found), fall back
to comparing full decoded content.

Add a regression test that verifies logically identical
content with different trailing newlines is not flagged
as stale.

Note: pre-commit could not run in sandbox (shellcheck
download blocked by network policy). The post-script
runs pre-commit authoritatively on the runner.

Closes fullsend-ai#2247
@guyoron1

Copy link
Copy Markdown
Owner Author

/fs quality

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 15, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 6:04 AM UTC · Completed 6:06 AM UTC
Commit: b906834 · View workflow run →

@guyoron1 guyoron1 closed this Jun 15, 2026
@fullsend-ai-review

Copy link
Copy Markdown

Review skipped — this PR is already closed.

The /fs-review command only reviews open pull requests.

Posted by fullsend post-review check

@github-actions

Copy link
Copy Markdown

QualityFlow Pipeline Summary

Stage Agent Status
1 STP Builder
2 STP Reviewer
3 STP Refiner
4 STD Builder
5 STD Reviewer
6 STD Refiner
7 Go Test Generator
8 Python Test Generator

Test Output

Type Count Location
Go/Ginkgo tier 1 8 files qf-tests/GH-2247/go/
Python/pytest tier 2 2 files qf-tests/GH-2247/python/

Issue: GH-2247


Generated by QualityFlow

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.

reconcile-repos.sh produces shim blob without sentinel, creating bogus update PR