Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions SESSION.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
## AI tools used

- ChatGPT/Codex in the local repo workspace.

## Prompts and instructions

List the prompts or instructions you gave to AI tools during the challenge.
- Reviewed the current citation rendering flow: how `answer.evidence` is resolved, where inline markers render, how source metadata is attached, and where visibility checks happen.
- Asked for the smallest clean fix in `lib/citations.ts` only, without changing React components or redesigning the data model.
- Asked to verify assumptions against the actual TypeScript types and fixtures.
- Ran the full challenge validation with `npm test` and `npm run build`.


## AI outputs accepted

Summarize the AI outputs, edits, commands, or recommendations you accepted.
- Updated `resolveCitations` to use the viewer context before adding citations.
- Counted unavailable evidence when evidence/source lookup fails or the viewer cannot use the evidence.
- Kept citation grouping and numbering based on the first visible evidence item in `answer.evidence` order.
- Applied evidence redactions before excerpts are returned to the UI.
- Kept all UI components unchanged.


## Manual work

Summarize the parts you wrote, changed, reviewed, or corrected manually.
- Reviewed the changed resolver against `data/types.ts` and `data/fixtures.ts`.
- Verified that `Answer.asOf`, `Source.requiredGroups`, `EvidenceChunk.validFrom`, optional `validUntil`, optional `redactions`, and the redaction field names matched the implementation.
- Ran `npm test`, `npm run typecheck`, and `npm run build`.


## Discarded AI output

Summarize any AI suggestions you intentionally did not use and why.
- Did not move citation safety logic into React components.
- Did not redesign the data model or add new behavior beyond the citation safety fix.
- Did not add extra tests because the existing citation tests covered the requested behavior.


## Notes

Do not include secrets, access tokens, private credentials, or personal data. Redact anything sensitive before submission.
- The first focused test attempt failed because dependencies were not installed yet. After dependencies were available, tests and build passed.
7 changes: 6 additions & 1 deletion SUBMISSION.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
## What changed?

Fixed citation resolution in `lib/citations.ts` so only evidence the current viewer can use is rendered. The resolver now checks source/evidence visibility before grouping citations, counts unavailable evidence references, only assigns inline citation numbers after checks pass, and redacts restricted excerpt text before it reaches the UI.

## What did you test?

- `npm test`
- `npm run build`

## Session log

- [ ] `SESSION.md` is completed.
- [x] `SESSION.md` is completed.


## Final commit SHA

3b242ae3fb6840768a72d7cb085313d674dc504c
45 changes: 36 additions & 9 deletions lib/citations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,17 @@ export function canViewSource(source: Source, context: ViewerContext): boolean {
}

if (source.visibility === "internal") {
return context.role === "admin" && context.isInternalEmployee;
if (context.role !== "admin" || !context.isInternalEmployee) {
return false;
}
}

if (source.region !== "global" && source.region !== context.region) {
return false;
}

if (!source.requiredGroups.every((group) => context.groups.includes(group))) {
return false;
}

return true;
Expand All @@ -42,36 +52,53 @@ export function canViewSource(source: Source, context: ViewerContext): boolean {
export function canUseEvidence(
evidence: EvidenceChunk,
source: Source,
context: ViewerContext
context: ViewerContext,
asOf: string
): boolean {
if (evidence.status !== "verified") {
return false;
}

if (evidence.validFrom > asOf) {
return false;
}

if (evidence.validUntil && evidence.validUntil < asOf) {
return false;
}

return canViewSource(source, context);
}

function redactExcerpt(excerpt: string, evidence: EvidenceChunk, context: ViewerContext): string {
return (evidence.redactions ?? []).reduce((safeExcerpt, redaction) => {
if (redaction.visibleToGroups.some((group) => context.groups.includes(group))) {
return safeExcerpt;
}

return safeExcerpt.replaceAll(redaction.text, redaction.replacement);
}, excerpt);
}

export function resolveCitations(
answer: Answer,
evidenceChunks: EvidenceChunk[],
allSources: Source[],
context: ViewerContext
): CitationResolution {
void context;

const evidenceById = new Map(evidenceChunks.map((evidence) => [evidence.id, evidence]));
const sourcesById = new Map(allSources.map((source) => [source.id, source]));
const citationBySourceId = new Map<string, ResolvedCitation>();
const citations: ResolvedCitation[] = [];
const evidenceToCitationNumber: Record<string, number> = {};
let unavailableCount = 0;

// BUG: the legacy resolver trusts retrieval output and groups every matching
// evidence ID. It misses source policy, time windows, redactions, and unavailable counts.
for (const reference of answer.evidence) {
const evidence = evidenceById.get(reference.evidenceId);
const source = evidence ? sourcesById.get(evidence.sourceId) : undefined;

if (!evidence || !source) {
if (!evidence || !source || !canUseEvidence(evidence, source, context, answer.asOf)) {
unavailableCount += 1;
continue;
}

Expand All @@ -93,12 +120,12 @@ export function resolveCitations(

citation.evidence.push({
id: evidence.id,
excerpt: evidence.excerpt,
excerpt: redactExcerpt(evidence.excerpt, evidence, context),
updatedAt: evidence.updatedAt,
confidence: reference.confidence
});
evidenceToCitationNumber[evidence.id] = citation.citationNumber;
}

return { citations, unavailableCount: 0, evidenceToCitationNumber };
return { citations, unavailableCount, evidenceToCitationNumber };
}