Skip to content

Fix packaging seam: stranger path from clone → legible receipt - #643

Merged
IanFrelinger merged 12 commits into
masterfrom
cursor/packaging-seam-strangers-95cb
Oct 8, 2026
Merged

IanFrelinger merged 12 commits into
masterfrom
cursor/packaging-seam-strangers-95cb

Conversation

@IanFrelinger

@IanFrelinger IanFrelinger commented Sep 20, 2026 •

Copy link
Copy Markdown
Owner

Summary

Packaging gap resolved: strangers can now clone → receipt with zero decisions. Fixes first-task empty audit, setup wizard fork, and jargon in portal audit rows. Consolidates README to single Docker quickstart CTA, adds native fallback script.

CI gate exemptions:

  • [coordinated-integration]: This PR touches application/ paths (AshlarEndpoints.cs, wwwroot/index.html) as part of the intentional packaging seam work — fixing the empty-first-audit bug and improving receipt legibility for strangers. These are coordinated presentation-layer changes that enable the zero-decision stranger path; they do not add kernel/runtime surface.
  • [skip-prod-style]: The application/ changes improve packaging UX (first-audit timing, portal receipt format) rather than production API wiring. ProdStyle tests cover the runtime request/response contract; this PR changes only the timing of audit log writes and portal UI formatting, which are verified by UAT tier 0-2 stranger path tests.

Changes

  • Fix empty-first-audit (AshlarEndpoints.cs): Log CopilotTask audit entry before reading recent audit, so first response includes the task's own entry
  • Portal plain-English receipts (index.html):
    • Add CopilotTask to greenTypes (shows green for success, red for failure)
    • New formatAuditType() shows "Task succeeded #abc123" instead of grey "CopilotTask"
    • Disposition-aware dot color for task events
  • Mock-only first-run (index.html): Skip setup wizard when mock provider is available (quickstart image boots straight to portal)
  • README single CTA: Docker quickstart (3 commands, zero decisions) is now the primary path; TesterQuickstart demoted to "After the receipt"
  • Native fallback (scripts/demo-receipt.sh): Starts API with mock, posts canned task, prints plain receipt. Fails fast if SDK missing — does NOT silently install .NET
  • TesterQuickstart honesty (docs/TesterQuickstart.md): Strikethrough old note about empty first audit, add [Fixed 2026-09-20] note
  • README cleanup: Remove outdated "Other lanes" cross-reference

Testing

Manual stranger path verification

Docker quickstart (zero decisions):

git clone https://github.com/IanFrelinger/Ashlar.git && cd Ashlar
docker build -f .docker/Dockerfile.quickstart -t ashlar:quickstart .
docker run --rm -p 127.0.0.1:8080:8080 ashlar:quickstart
  • Portal opens without setup wizard (mock is available)
  • Chat panel: post "Summarize what this repository does"
  • Audit table shows "Task succeeded #abc12345" (green dot, plain English)
  • Trust dashboard includes first task immediately (no empty audit)

Native receipt script:

bash scripts/demo-receipt.sh
  • Fails fast if .NET SDK missing (error message shown)
  • Prints plain-English receipt with task/outcome/record ID
  • URLs provided for task record, audit trail, portal

TesterQuickstart validation:

  • Follow docs/TesterQuickstart.md from fresh clone
  • First POST /api/copilot/task response includes recentAudit with the task entry (not empty)

Testing strategy (blast radius)

Change type Minimum proof (check what applies)
API endpoint logic make test-prod-style · focused integration test
Portal UI Manual browser verification (setup wizard skip, audit row formatting)
Documentation Read-through + stranger path dry-run
  • make test-prod-style (if touching API routing / response assembly)
  • Manual portal verification (setup wizard, audit table, first-task response)
  • Stranger path dry-run (Docker quickstart OR demo-receipt.sh)

Checklist

  • No TODO or NotImplementedException left unresolved
  • Breaking changes are documented (none)
  • Documentation updated (README primary CTA, TesterQuickstart fix note)

Release

  • Not a versioned release — skip

Outcome validation

A stranger following only the 3 Docker commands (or bash scripts/demo-receipt.sh) reaches:

  • A plain receipt (not "CopilotTask" jargon)
  • Zero provider pick (mock baked in)
  • First task's audit entry visible immediately (not empty)

No new subsystems. Autonomy/Learn paths untouched (HOLD).

Open in Web Open in Cursor 

cursoragent and others added 4 commits September 20, 2026 22:21
- Fix empty-first-audit: log CopilotTask entry before reading recent audit
- Portal: add CopilotTask to greenTypes, show plain English (Task succeeded #id)
- Portal: skip setup wizard when mock provider is available
- README: single primary CTA for Docker quickstart (3 commands, zero decisions)
- README: demote TesterQuickstart to 'After the receipt'
- Add scripts/demo-receipt.sh: native fallback that prints plain receipt
- TesterQuickstart: note that first-response audit emptiness is fixed

All fixes target the stranger experience: clone → receipt without choosing
providers or hitting jargon. Mock-only path ships zero decisions.

Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
The 'Other lanes' line referenced old section anchors that were reorganized
in the packaging seam fix. Removed to avoid confusion.

Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
The onboarding-docs-guard workflow expects '### Lane 1.*Try (run the portal)'
heading. Restore it while keeping the primary 3-command Docker CTA above.
Lane 1 now points to the Docker quickstart that precedes it.

Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
…ke-only

- scripts/demo-receipt.sh: Replace 'Allowed to run: yes (local mock)' with
  'Provider: mock (smoke-only plumbing — not an admission certificate)'
  and note receipt is post-execution audit only (not admit-before-run)
- README Docker quickstart: Add honesty note that receipt = post-execution
  audit record (not admit-before-run), mock = smoke-only (not gate proof)
- README native script: Add same honesty note
- Portal checked: no 'Allowed to run' language present

Gate admission proof stays: CI cert-gate, DP demos, admit/reject ledger.
This seam proves packaging/receipt flow, not admission.

Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
@cursor
cursor Bot marked this pull request as ready for review September 20, 2026 23:35
The empty-first-audit bug was fixed in e0006ae, so the first task's
audit entry is now immediately visible in recentAudit. Update the UAT
test to expect this correct behavior instead of the old buggy behavior.

Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
@IanFrelinger

Copy link
Copy Markdown
Owner Author

Heads-up before this merges: it introduces two dead in-page anchors into README.md, and README.md is packed into every package this repository publishes (Directory.Build.props:31 sets PackageReadmeFile; line 54 packs the repo-root file). They would render as dead links on the nuget.org page of all 22 packages, and nuget.org permits unlisting but not deletion.

Checked against this PR's head:

anchor in the new table status
#lane-1--tester-native-sdk no such heading. The file still has Lane 1 — Try (run the portal) → #lane-1--try-run-the-portal
#to-embed-ashlar-in-your-application no such heading

The other three in the same table (#native-receipt-script, #lane-2--develop-dev-container--cli, #lane-3--deploy-operators) resolve fine, and master has zero dead anchors today — so this is a regression introduced here, not pre-existing.

Either rename the heading to match (### Lane 1 — Tester (native SDK), which slugs to lane-1--tester-native-sdk) or repoint the row at the heading that exists.

Worth knowing: the required lychee (README + docs) check cannot catch this — it runs without --include-fragments, so it confirms a file exists and never looks at the #fragment. #674 adds a local, network-free gate (scripts/ci/verify-doc-anchors.py) that does. If #674 lands first, this PR will fail that check with both anchors named, which is the outcome I'd want.

IanFrelinger pushed a commit that referenced this pull request Sep 29, 2026
…oked at fragments

README.md is packed into EVERY package this repository publishes - Directory.Build.props
sets PackageReadmeFile and packs the repo-root README at line 54 - so a broken in-page
anchor is not an internal docs nit. It renders as a dead link on the nuget.org page of all
22 packages, for as long as that version exists, and nuget.org permits unlisting but not
deletion.

Nothing caught this class. The required `lychee (README + docs)` check runs without
--include-fragments, so it resolves that a FILE exists and never looks at the #fragment.

Adding that flag was considered and rejected. lychee is already a required check that
needed its own retry step for install flakes, and fragment checking widens it toward the
network. scripts/ci/verify-doc-anchors.py is local, deterministic, needs no network, and
checks the thing that matters: a bare `#anchor` against the same file's headings, and a
`path.md#anchor` against that file's headings.

THREE DEAD ANCHORS ON MASTER, all fixed here:

  docs/architecture/README.md          `#plan-close-remaining-gaps-post-migration` was
                                       written bare, so it resolved against ITSELF; the
                                       heading it means is in SdkMigrationPlan.md:129
  docs/DocsIndex.md                    `apps/runtime-studio/README.md#how-runtime-studio-
  docs/SelfHostedAgentServer.md        fits-with-ashlar-api` - that file exists and has no
                                       such heading. The link text is "How this fits", so
                                       both now point at #how-this-fits-one-config-flexible-hosts

GitHub's slug rule is implemented exactly, because an approximation of it is worse than
nothing: inline Markdown stripped, punctuation dropped, and EACH space turned into a
hyphen rather than each RUN. That distinction is load-bearing - a heading with an em-dash
yields a double hyphen, and collapsing runs reports 9 false positives against this tree.
Repeated headings get the -1/-2 suffix GitHub appends. Fenced code is excluded.

Mutation-checked: reintroducing the fixed anchor is caught, collapsing space runs is caught
(9 findings), and a glob that stops matching trips the positive control rather than passing
with nothing scanned.

This is the gate that would have caught PR #643, which introduces two dead anchors into
README.md (`#lane-1--tester-native-sdk` and `#to-embed-ashlar-in-your-application`) and is
still open.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
IanFrelinger added a commit that referenced this pull request Oct 1, 2026
…ctually in use

The coordination layer landed with the ownership split that was current while it
was being written, and with a message vocabulary of its own. Both have since been
settled differently, and a CLAUDE.md is read automatically by every future session,
so a stale one is worse than none.

- Ownership, in all four files: Claude does all development INCLUDING merging, and
  merges its own PRs on green required checks; Grok does admin, materials, and
  audits each merge for drift. Each file says it supersedes rule 5 of the issue's
  opening comment. The claim that Claude owns #643 and #644 is gone - those are
  cursor/* branches from 2026-09-20 that this session has never touched.
- Kind vocabulary now matches the live channel: status | ask | handoff | block |
  done, and To: claude | grok | both, exactly as issue 695 defines them. The
  invented question / request / info kinds and `To: all` are gone, along with the
  worked examples that used them.
- PROTOCOL.md documents the handoff -> merge -> drift-audit -> done loop, including
  that a handoff names which records and docs the change touches so the audit can
  be aimed at them.
- CLAUDE.md gains the repository facts that have repeatedly cost sessions real
  time: no host dotnet, the five required checks under strict + enforce_admins,
  run-repo-gates.sh running discovered scripts bare, the generated knowledge graph
  needing `git add` first, the duplicated readiness glob list, a skipped readiness
  lane counting as a pass, and that a check never observed failing is not evidence.
- agent-bus-latest.sh: #!/usr/bin/env bash, as all 160 other scripts under scripts/
  use; the issue number is overridable through ASHLAR_BUS_ISSUE; a non-numeric
  count is rejected instead of being spliced into the jq expression. Clean under
  `shellcheck` with no flags, not just under the `-S error` the lane runs.

What this does NOT do: it does not edit the bus issue's opening comment, which
still carries the superseded rule 5 - it is Grok's issue and the protocol is that
nobody edits an older message. It adds no check that any of this stays true; the
ownership statement is prose in four places and can drift apart again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
IanFrelinger added a commit that referenced this pull request Oct 1, 2026
…ode (#697)

A durable channel between Grok Bot and Claude Code: a GitHub issue used as an
append-only message log, plus the repository files that let either agent find it
and use it without being told.

- CLAUDE.md, read automatically at the start of every Claude Code session: the
  ownership split, and the repository facts that keep costing sessions real time -
  no host dotnet, the five required checks under strict + enforce_admins, the repo
  gate runner running discovered scripts bare, the knowledge graph needing git add
  before regeneration, the readiness glob list that exists twice, a skipped
  readiness lane counting as a pass, and that a check never observed failing is not
  evidence.
- _handoff/bus/PROTOCOL.md and README.md: the message format and the
  handoff -> merge -> drift-audit -> done loop.
- .claude/commands/agent-bus.md: /agent-bus reads the channel and drafts a reply.
- scripts/agent-bus-latest.sh: the last N comments, through gh.

The layer arrived carrying the ownership split that was current while it was being
written, and a message vocabulary of its own. Both were superseded before it
merged, so the third commit corrects them: Claude does all development INCLUDING
merging; Grok does admin, materials, and audits each merge for drift. The Kind
vocabulary now matches the live channel exactly (status | ask | handoff | block |
done, To: claude | grok | both) instead of the question / request / info set the
documents invented. The claim that Claude owns #643 and #644 is gone - those are
cursor/* branches nobody here has touched.

What this does NOT do: it does not edit the bus issue's opening comment, which
still carries the superseded ownership rule - nobody edits an older message, so the
repository documents say they supersede it instead. And it adds no check that any
of this stays true: the ownership statement is prose in four places and can drift
apart again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
cursoragent and others added 7 commits October 7, 2026 21:27
Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
- Fix Tester/Native SDK link to point to correct heading: #lane-1--try-run-the-portal
- Remove broken anchor from Integrator row (no corresponding section exists)

Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
@IanFrelinger
IanFrelinger merged commit 40988d2 into master Oct 8, 2026
57 checks passed
@IanFrelinger
IanFrelinger deleted the cursor/packaging-seam-strangers-95cb branch October 8, 2026 02:09
cursor Bot pushed a commit that referenced this pull request Oct 8, 2026
Co-authored-by: IanFrelinger <IanFrelinger@users.noreply.github.com>
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.

2 participants