Skip to content

fix(effort-graph): clarify Citation and Blob behavior - #226

Merged
tonyketcham merged 8 commits into
mainfrom
toeknee/fix-citation-blob-review-5e3f
Jul 26, 2026
Merged

tonyketcham merged 8 commits into
mainfrom
toeknee/fix-citation-blob-review-5e3f

Conversation

@tonyketcham

@tonyketcham tonyketcham commented Jul 26, 2026 •

Copy link
Copy Markdown
Collaborator

Follow-up to the Citation and Blob work in #224 and #225.

What this PR changes

  • Adds Citations as the records used to refer to outside sources.
  • Lets a Citation optionally point to a Blob, which stores large content such as a document, JSON, or image.
  • Ensures these links stay within the same Effort and covers the behavior in the planner, writer, CLI, and GraphQL.
  • Updates skills, reference material, and example records so the workflow is explained in direct language.

How to attach a source

  1. Save large content with WriteBlob when needed.
  2. Create a WriteCitation for the URL or source.
  3. Create the Finding, Decision, Issue, Constraint, or Risk with cites: ["<citation-id>"].

Create the Citation before the record that uses it; citations cannot be added later.

Validation

  • pnpm -F @flatbread/effort-graph test (104 passed)
  • pnpm exec ava packages/flatbread/src/cli/effort.test.ts packages/flatbread/src/graphql/liveServerEffortGraph.test.ts (15 passed)
  • pnpm lint
  • pnpm skills:check

Capture three Findings from a stack review of #224/#225: stale skill/Constraint
mutation counts, conflicting Decisions on how Blobs are cited, and same-effort /
Effort.cites holes around the new cites surface.

Change-Id: I3f59480248af6c7e49396a0a651802970f1c6f39
Address review blockers and follow-ups on the Citation/Blob stack:
- Skill hero teaches 8 collections / 15 mutations + cite create-order
- Supersede mutation-enum Constraint to fifteen (WriteCitation/WriteBlob)
- Roll up Blob naming Decision and Issue to cites→Citation→optional Blob
- Enforce same-effort for cites and Citation.blob; drop CreateEffort.cites
- Fix relations() Effort membership; default records omit blob
- Teach cite workflow in effort-modeling / grill-with-efforts
- Add planner, writer, CLI, and live GraphQL cite/blob coverage

Change-Id: I11e65dc7c1390e1c2d3b6c946ebdecffe3d16605
@tonyketcham
tonyketcham marked this pull request as ready for review July 26, 2026 02:05
@mergify

mergify Bot commented Jul 26, 2026 •

Copy link
Copy Markdown
Contributor

Queued — the merge queue status continues in this comment ↓.

Rewrite the Citation and Blob documentation in plain language. Explain the
record types, source workflow, and links directly instead of relying on
internal terms such as epistemic records, homogeneous refs, or retro-linking.

Keep installed skill copies and the dogfooded Decision and Issue aligned with
the source skills.

Change-Id: If2114f6509df1a0222014d9690e039faefcc86dc
@tonyketcham tonyketcham changed the title fix(effort-graph): align Citation+Blob contracts after stack review fix(effort-graph): clarify Citation and Blob behavior Jul 26, 2026

@cursor cursor 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.

Stale comment

Review verdict

REQUEST_CHANGES — consensus HIGH on stale journal finding fnd-cites… plus CreateEffort/cites contract stickiness, and two+ independent HIGHs (opaque same-effort errors, missing writer/CLI foreign-blob negatives, undocumented Citation.blob same-Effort rule).

Adversarial DAG (4 perspectives + judge) on 91aec60...1559fd9. Models: HIGH=grok-4.5, MED/LOW=composer-2.5.

Must-fix before merge

  1. Invalidate/supersede active finding fnd-cites-and-citation-blob-skip-same-effort-checks (still teaches pre-fix behavior).
  2. Make same-effort errors specific (cites target ${id}… / Citation.blob ${id}…), not bare 'Different effort'.
  3. Keep CreateEffort .strict() but make cites rejection loud end-to-end (domain error + CLI pin); resolve Effort preset still advertising cites.
  4. Add writer + CLI negatives for foreign Citation.blob; document blob same-Effort in skill reference.

Coverage plan

  1. HIGH writer.test.ts — WriteCitation rejects blob from another effort (negative)
  2. HIGH cli/effort.test.ts — CreateEffort+cites rejected at handleEffortWrite (negative)
  3. HIGH cli/effort.test.ts — WriteCitation foreign blob rejected (negative)
  4. MED strengthen schemas Zod path assert; live GraphQL foreign reject; relations(effortA, effortB) throw / effort-root no-throw
  5. LOW planner mixed-list cites edge

Reviewer scoreboard

reviewer verdict signal
correctness-and-contracts REQUEST_CHANGES strong
test-coverage-robustness REQUEST_CHANGES strongest
effort-graph-contracts REQUEST_CHANGES strong
docs-and-positioning REQUEST_CHANGES good
Open in Web View Automation 

Sent by Cursor Automation: Flatbread PR Review

Comment thread packages/effort-graph/src/planner.ts Outdated
Comment thread packages/effort-graph/src/planner.ts Outdated
Comment thread packages/effort-graph/src/schemas.ts
Comment thread packages/effort-graph/src/__tests__/writer.test.ts
Comment thread packages/flatbread/src/cli/effort.test.ts
Comment thread packages/effort-graph/skills/effort-graph/reference.md
tonyketcham and others added 2 commits July 25, 2026 19:37
Apply a direct, newcomer-friendly writing style to every agent output,
including responses, plans, PR descriptions, commits, documentation, and
code comments. Require a brief explanation whenever a Flatbread-specific term
is necessary.

Co-authored-by: Cursor <cursoragent@cursor.com>
Change-Id: Ia151e3589b3dcc602cf566f05940243ff116e4d8
Make cross-Effort Citation and Blob errors identify the failing field and id.
Reject CreateEffort cites with a direct CLI error, remove the stale Effort
cites reference, document the Blob ownership rule, and add writer and CLI
regression coverage. Record that the earlier missing-validation Finding is now
invalidated.

Co-authored-by: Cursor <cursoragent@cursor.com>
Change-Id: I9d9531e5e8ae75e6b48113fbfc6c5fc9b7180a51

@cursor cursor 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.

Stale comment

Review verdict

REQUEST_CHANGES — consensus HIGH that CreateEffort + cites still silently succeeds on planMutation / writer.mutate while schema, CLI, and docs claim rejection.

Same-Effort cites / Citation.blob checks, clearer errors, foreign-blob negatives, and skill reference.md look solid. The remaining contract hole is the library write path: createEffortGraphWriter().mutate takes input: any and calls planMutation without EffortGraphMutationSchema, so programmatic/GraphQL callers can still pass cites and have them dropped.

Chunk-bound feedback (priority)

  1. HIGH planner.ts CreateEffort branch — reject 'cites' in input (same message as CLI) or parse the mutation schema before planning.
  2. MED CreateEffortSchema.strict() / CLI pre-parse guard — move enforcement to planner/writer so CLI is not the only fail-closed path.
  3. MED Active Findings that still teach direct Blob cites or “13 mutations / 6 primitives” — invalidate or supersede so recall matches current skills.

Coverage plan

  • writer.test.ts — negative: writer.mutate({ type:'CreateEffort', cites:[...] }) rejects; Effort file has no cites
  • planner.test.ts — negative: planMutation(CreateEffort + cites) throws actionable CreateEffort does not accept cites
  • liveServerEffortGraph.test.ts — negative: live-bridge CreateEffort+cites fails closed (non-CLI path)
  • schemas.test.ts — edge: failure text for CreateEffort+cites is actionable, not only opaque unrecognized_keys

Reviewer scoreboard

  • correctness-and-contracts: 5 findings, 3 coverage gaps, signal:HIGH
  • test-coverage-robustness: 2 findings, 3 coverage gaps, signal:HIGH
  • docs-and-positioning: 6 findings, 4 coverage gaps, signal:HIGH
  • cli-and-runtime: 3 findings, 4 coverage gaps, signal:MED
  • effort-graph-citation-invariants: 3 findings, 3 coverage gaps, signal:MED

Prior threads: same-Effort errors, foreign-blob tests, and skill reference updates look addressed; CreateEffort stickiness remains partially open on the writer path.

Open in Web View Automation 

Sent by Cursor Automation: Flatbread PR Review

Comment thread packages/effort-graph/src/planner.ts
Comment thread packages/effort-graph/src/schemas.ts
Comment thread packages/flatbread/src/cli/effort.ts
Comment thread packages/effort-graph/skills/effort-graph/SKILL.md Outdated
Comment thread packages/effort-graph/skills/effort-graph/glossary.md Outdated
tonyketcham and others added 2 commits July 25, 2026 19:50
Fail closed for direct planner and writer callers instead of silently dropping an unsupported CreateEffort relation.

Tests: pnpm exec ava packages/effort-graph/src/__tests__/planner.test.ts packages/effort-graph/src/__tests__/writer.test.ts
Co-authored-by: Cursor <cursoragent@cursor.com>
Change-Id: Ie64f029651430b3b638849edd5774f9904fcbfaa
Document same-Effort Citation and Blob links in the source and installed
skills. Invalidate stale Findings and record that CreateEffort cites remains
a programmatic-writer follow-up.

Co-authored-by: Cursor <cursoragent@cursor.com>
Change-Id: I695834471a811abca6b06595bfaf81d72332db5d
Base automatically changed from toeknee/blob-collection-cites-1b07 to main July 26, 2026 02:51
@tonyketcham

Copy link
Copy Markdown
Collaborator Author

@Mergifyio queue

@mergify

mergify Bot commented Jul 26, 2026 •

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • ✅ Entered queue — 2026-07-26 02:54 UTC · Rule: owner-bypass · triggered by @tonyketcham with the @mergifyio queue command
  • ✅ Checks passed · in-place
  • ✅ Merged — 2026-07-26 02:57 UTC · at 9554679ecdfd0a672e76470fc305cfb050e2a330

This pull request spent 3 minutes 18 seconds in the queue, including 2 minutes 57 seconds running CI.

Required conditions to merge
  • author = tonyketcham
  • check-success = build (20.x, ubuntu-latest)
  • check-success = build (22.x, ubuntu-latest)
  • check-success = integration-nextjs (20.x, macos-latest)
  • check-success = integration-nextjs (20.x, ubuntu-latest)
  • check-success = integration-nextjs (20.x, windows-latest)
  • check-success = integration-nextjs (22.x, macos-latest)
  • check-success = integration-nextjs (22.x, ubuntu-latest)
  • check-success = integration-nextjs (22.x, windows-latest)
  • check-success = integration-sveltekit (20.x, macos-latest)
  • check-success = integration-sveltekit (20.x, ubuntu-latest)
  • check-success = integration-sveltekit (20.x, windows-latest)
  • check-success = integration-sveltekit (22.x, macos-latest)
  • check-success = integration-sveltekit (22.x, ubuntu-latest)
  • check-success = integration-sveltekit (22.x, windows-latest)
  • check-success = lint (20.x, ubuntu-latest)
  • check-success = lint (22.x, ubuntu-latest)
  • check-success = test (20.x, ubuntu-latest)
  • check-success = test (22.x, ubuntu-latest)

@mergify mergify Bot added the queued label Jul 26, 2026
@tonyketcham
tonyketcham merged commit bc2fda7 into main Jul 26, 2026
20 checks passed
@tonyketcham
tonyketcham deleted the toeknee/fix-citation-blob-review-5e3f branch July 26, 2026 02:57
@mergify mergify Bot removed the queued label Jul 26, 2026

@cursor cursor 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.

Review verdict

REQUEST_CHANGES — Consensus HIGH on a stale CreateEffort-enforcement Finding, plus independent HIGHs on Citation/Blob silent-drop (planner/schema) and missing live-bridge coverage of documented same-Effort / CreateEffort rejects.

Prior CreateEffort+cites silent-drop on planner/writer is closed at HEAD (planMutation throws). Remaining blockers are contract honesty + fail-closed Citation/Blob + GraphQL negative coverage.

Chunk-bound feedback (priority)

  1. HIGH Stale Finding still says planner/writer CreateEffort/cites enforcement is a follow-up — rewrite or supersede.
  2. HIGH WriteCitation/WriteBlob still Zod-strip unknown edge keys; planner deletes them — apply .strict() / throw like CreateEffort.
  3. HIGH Live GraphQL writer never asserts CreateEffort+cites, foreign cite, or foreign Citation.blob rejects.
  4. MED effort-modeling skill omits Issue from cites create list; relations() silently filters foreign cite targets.

Coverage plan

  • liveServerEffortGraph.test.ts — negative CreateEffort+cites, foreign blob, foreign cite; positive Finding→Citation resolve
  • schemas.test.ts / planner.test.ts / writer.test.ts — WriteCitation/WriteBlob + cites reject
  • effort.test.ts — WriteCitation+cites CLI error; relations not-in-effort / foreign-cite edge

Reviewer scoreboard

  • correctness-and-contracts: 3 findings, signal:HIGH
  • test-coverage-robustness: 5 findings, signal:HIGH
  • docs-and-positioning: 2 findings, signal:HIGH
  • effort-graph-citation-blob: 4 findings, signal:MED
  • cli-and-runtime: 1 finding, signal:MED

Models: Grok 4.5 High (HIGH), Composer 2.5 (MED/LOW).

Open in Web View Automation 

Sent by Cursor Automation: Flatbread PR Review

- fnd-skill-and-hard-constraint-still-teach-13-mutatio--gvg2btns0q7rp0eq
---

The skills and related Decision, Issue, and Constraint now describe eight record types, fifteen mutations, and the Citation-to-optional-Blob path. Direct Blob citations are not supported. Cross-Effort `cites` and `Citation.blob` links are rejected. `CreateEffort` rejects `cites` when callers use the CLI or mutation schema; planner and writer enforcement remains a follow-up so programmatic callers cannot silently drop the field. This Finding replaces the prior audits and retrospective where their earlier claims no longer match the current contract.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

HIGH (consensus) — This active Finding says CreateEffort rejects cites only via CLI/mutation schema and that "planner and writer enforcement remains a follow-up." At HEAD, planMutation already throws CreateEffort does not accept cites… and writer tests cover it. Agent-facing memory that invents remaining work will send follow-up PRs at a closed gap.

Minimal fix: Rewrite the body to state CLI, schema, planner, and writer all reject CreateEffort/cites (or supersede with a Finding that does).

if (EPISTEMIC_CREATE.has(kind)) assertCites(get, raw.effort, raw.cites);
const fm: Record<string, unknown> = {
...raw,
id,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

HIGH — For Citation/Blob creates, mistaken cites / edge keys are never validated (EPISTEMIC_CREATE skips these kinds), then silently deleted before write. Callers get a successful mutate with the mistake dropped — the same silent-drop class just closed for CreateEffort.

Minimal fix: Throw EffortGraphValidationError when those keys are present on Citation/Blob creates (CreateEffort posture).

...common,
slug: z.string().optional(),
})
.strict();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

HIGH — Only CreateEffortSchema is .strict(). WriteCitationSchema / WriteBlobSchema still Zod-strip unrecognized keys such as cites / derives_from, so CLI parse can hide the mistake before the planner ever sees it.

Minimal fix: Apply .strict() (or an explicit reject) on WriteCitation/WriteBlob, and add schema/CLI negative tests.

t.deepEqual(response.data?.allBlobs, [{ id: blobId, title: 'Payload' }]);
}
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

HIGH — New live-bridge coverage is Citation→Blob happy-path shape only. Documented rejects (CreateEffort+cites, foreign cite, foreign Citation.blob) and Finding→Citation resolve after commit are unexercised on server.effortGraph.writer / GraphQL, so bridge/ref regressions would not fail CI.

Minimal fix: Add parallel negative mutates plus a positive allFindings { cites { id } } resolve.

if ('cites' in input)
throw new EffortGraphValidationError(
'CreateEffort does not accept cites; create the Effort before its Citations.'
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

HIGH (coverage) — CreateEffort/cites reject is closed in planner/writer/CLI unit tests, but the no-Zod live-server writer path still lacks an assertion for this contract.

Minimal fix: In liveServerEffortGraph.test.ts, assert server.effortGraph.writer.mutate({ type: 'CreateEffort', …, cites: [...] }) throws the planner message.

`role` when needed.
3. **Create the record** — pass `cites: ["<cit-id>"]` when creating the
Finding, Decision, Constraint, or Risk. You cannot add a citation later,
so create the Citation first.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MED — External-evidence step 3 lists Finding/Decision/Constraint/Risk but omits Issue, which schemas/cites[] allow. Agents following this skill will under-use Issue citations.

Minimal fix: Add Issue to the create list; sync via pnpm skills:sync into packages/effort-graph/skills/….

source?.kind === 'effort' && fromId === effortId
? true
: source?.frontmatter.effort === effortId;
if (!source || !sourceInEffort)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MED — Happy path covers Effort-as-relations-root empty cites; foreign cite targets are filtered with no anomaly when target.frontmatter.effort !== effortId. Corrupt/pre-fix data under-counts silently.

Minimal fix: Assert not-in-effort when fromId is another Effort; add a seeded foreign-cite case and either surface an anomaly/filtered-count hint or document intentional defensive filtering.

throw new EffortGraphValidationError(
'CreateEffort does not accept cites; create the Effort before its Citations.'
);
const input = EffortGraphMutationSchema.parse(raw);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

MED — CLI fail-closes CreateEffort+cites with a clear error, but WriteCitation+cites still succeeds after Zod strip until schemas/planner reject. Once Write* schemas are strict (or CLI mirrors this guard), assert a discoverable validation error at the write handler.

@cursor cursor Bot mentioned this pull request Jul 26, 2026
5 of 8 tasks
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