Skip to content

docs: judge-ready documentation, plus three bugs it turned up#8

Merged
anchildress1 merged 35 commits into
mainfrom
docs/judge-ready
Jul 12, 2026
Merged

docs: judge-ready documentation, plus three bugs it turned up#8
anchildress1 merged 35 commits into
mainfrom
docs/judge-ready

Conversation

@anchildress1

Copy link
Copy Markdown
Owner

Rewrites the README, spec, and build plan for challenge judges, and corrects everywhere they had drifted from the shipped code. Auditing docs against the implementation surfaced three real bugs, each fixed in its own commit.

Bugs found while checking docs against code

PIPELINE_VERSION was broken. It hashes GET_DDL('FUNCTION', 'CHRONICLE_CARD(...)'), but the signature listed 19 VARCHARs against a 20-parameter function — HISTORY_SCOPE was added without updating the hash. GET_DDL resolves an exact overload, so on a warehouse with no leftover 19-arg version, every READ_REPO write fails to compile (both the Cortex path and the none path read that view). A fresh deploy would not have worked.

deploy.sh sourced .env wholesale — after an initial fix that made it read config at all. set -a; source .env exported SNOWFLAKE_PAT and GITHUB_TOKEN into the environment of a process that shells out to gcloud a dozen times, which is precisely what Secret Manager is on the critical path to prevent. It now reads its four non-secret keys by name. Verified: config resolves, secrets are absent from the process env.

PUBLIC_ORIGIN defaulted to a domain we don't own (commitchronicles.dev). Repointed to commitchronicles.anchildress1.dev.

Docs

The README leads with the three live cards, then makes the Snowflake case as its own section: external access, the SQL detector, the one Cortex call, the cost story. All diagrams are Mermaid (architecture, generation sequence, detector flow, job state) and validated.

The spec and build plan had drifted in ways that mattered to anyone reading them as the contract:

  • the nine Cortex keys were presented as the card payload — the payload is a 22-key camelCase object wrapping them
  • evidence is budgeted in commit lines (25%, floor 20, cap 140), not "~20 commits"
  • Cortex's output is verified in SQL before storage, and two labels are overwritten structurally
  • the none storyline never calls Cortex at all
  • status thresholds are literals in read_repo.sql, not DETECTOR_CONFIG entries
  • oversized repos are windowed, never rejected — AGENTS.md said otherwise
  • the gallery was cut; three landing-page examples cover it

Verification

make ai-checks green — 305 tests, lint, typecheck, build. shellcheck deploy.sh clean. All five Mermaid diagrams validated.

Not verified: PIPELINE_VERSION against the live warehouse. The MCP role can't see the CHRONICLES database, so the arity fix is proven by static analysis of the two signatures, not by a query.

🤖 Generated with Claude Code

GET_DDL resolves an exact overload. The hashed signature listed 19 VARCHARs
against a 20-parameter function, so every READ_REPO write — which selects
PIPELINE_VERSION on both the Cortex and the 'none' path — would fail to
compile on a warehouse that has no leftover 19-arg overload lying around.
HISTORY_SCOPE was added to the function without updating the hash.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
commitchronicles.dev is not a domain this project owns; the deployed site is
commitchronicles.anchildress1.dev. The fallback only bites when PUBLIC_ORIGIN
is unset, but when it does it mints README embeds pointing at someone else's
domain.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
Restructure to the 15-section layout, lead with the Snowflake case, and embed
the three live demo cards so the product is visible before any prose is read.

Replaces the ASCII architecture sketch with Mermaid (flowchart + sequence) and
corrects it against the shipped code: the detector's real thresholds, the
nine-key Cortex schema, evidence budgeted in lines rather than commits, the
500-commit ingest cap, and the cost guards that exist as opposed to the ones
the old copy implied.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
The spec had drifted from the warehouse in ways that matter to anyone reading
it as the contract:

- the nine Cortex keys were presented as the card payload; the payload is a
  22-key camelCase object that wraps them
- evidence is budgeted in commit *lines* (25%, floor 20, cap 140), not '~20
  commits' — squash bodies explode into line items first
- the detector's thresholds, tie-break order, and the 'none' path that never
  reaches Cortex at all were undocumented
- Cortex's output is verified in SQL before it is stored, and two labels are
  overwritten structurally; the old copy implied the prompt was the only guard
- status thresholds are literals in read_repo.sql, not DETECTOR_CONFIG entries
- the gallery never shipped; three landing-page examples cover it
- repo-size rejection does not exist — oversized histories are windowed

Adds routes, bucket layout, and the job state machine. ASCII architecture is
now Mermaid, alongside a state diagram for the generating/ready/failed cycle.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
The object table listed a pipeline that no longer matches the warehouse: it
was missing CHRONICLE_CARD, CARDS, CARD_PLOT, CARD_PAYLOAD, PIPELINE_VERSION,
STALE_CARDS, COMMIT_LINES, and DETECTOR_CONFIG, and still carried 'scripted'
against objects that have been deployed for two commits.

Also fills in the detector's real gates, the evidence budget in lines, the
SQL verification pass over Cortex's output, and the 'none' path. Marks the
gallery cut and the open items resolved. ASCII diagram is now Mermaid.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
They are windowed to the newest 500 commits and the card discloses the slice.
The gallery was cut, so the pre-generation rule now names the landing-page
examples it actually applies to.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
The value was already 0.4 in ai_functions.sql but no doc said so, which makes
it look like an oversight someone should 'fix' to 0. It is load-bearing: the
detector owns determinism, and a zero-temperature model writes the same flat
sentence about every repo.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
deploy.sh declared its own required vars with ${VAR:?} but relied on make to
source .env, so running it directly aborted on SNOWFLAKE_ACCOUNT. Config now
loads in the script, which is the only place that knows what it needs.

SNOWFLAKE_PAT is untouched: still mounted from Secret Manager at run time,
never passed on a gcloud command line.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
Sourcing .env exported SNOWFLAKE_PAT and GITHUB_TOKEN into the environment of
a process that shells out to gcloud a dozen times. Nothing leaked them, but
Secret Manager is on the critical path precisely so the PAT cannot reach a
command line, a shell history, or an audit log — and one careless
--set-env-vars edit would have undone that while looking correct in review.

deploy.sh needs four non-secret values. It now reads those four by name and
inhales nothing else.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
Copilot AI review requested due to automatic review settings July 12, 2026 14:28
@codecov

codecov Bot commented Jul 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copilot AI 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.

Pull request overview

Updates judge-facing documentation to match the shipped system, and fixes three implementation bugs uncovered during the doc/code audit (Snowflake PIPELINE_VERSION arity drift, safer deploy config handling, and correct PUBLIC_ORIGIN default).

Changes:

  • Repoint PUBLIC_ORIGIN default (and its test) to https://commitchronicles.anchildress1.dev.
  • Fix PIPELINE_VERSION to hash the correct CHRONICLE_CARD overload arity (20 params) and document why.
  • Adjust deploy flow to avoid exporting secrets from .env (Makefile stops sourcing; deploy.sh reads only named non-secret keys).

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/server/config.test.ts Updates expected default PUBLIC_ORIGIN in config tests.
src/server/config.ts Changes default PUBLIC_ORIGIN to the owned domain.
snowflake/schema.sql Fixes GET_DDL signature arity for CHRONICLE_CARD in PIPELINE_VERSION.
README.md Rewrites README for judges; aligns architecture, flow, and config docs with shipped behavior.
Makefile Stops sourcing .env during deploy; delegates config loading to deploy.sh.
docs/initial-design-spec.md Updates spec to describe the shipped system (job state, routing, detector/Cortex contract).
docs/build-plan.md Updates build plan to reflect delivered architecture and constraints.
deploy.sh Reads only specific non-secret config keys from .env instead of sourcing the whole file.
AGENTS.md Updates canonical guidance on oversized repos (windowed, not rejected) and examples.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread deploy.sh

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bc1c86fc28

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread deploy.sh Outdated
Comment thread deploy.sh Outdated
GitHub renders Mermaid with htmlLabels disabled, so the <b> and <small> tags
in node labels broke the parse and the diagrams showed as nothing. Parens in
node text are the other reliable way to kill it.

Labels are now plain text with <br/> only. The prose that was crammed into
them belongs in the paragraphs around them anyway.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
Ten numbered steps hid the only thing that matters about the flow: it reads
state before it spends, so the expensive path is entered on a genuine miss and
nowhere else. The branches — cached card, terminal failure, quota exhausted,
tab closed — are decisions, and a list cannot show a decision.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
Two bugs in the config loader, both caught in review.

Under 'set -euo pipefail' a grep that matches nothing returns 1, and a failing
command substitution in an assignment aborts the script. Any .env missing an
optional key — PUBLIC_ORIGIN, say — killed the deploy before the fallbacks
below could apply. Every key in the whitelist is optional at that layer; the
${VAR:?} guards further down are what make the required ones fatal.

DAILY_GENERATION_CAP was also dropped from the whitelist. It used to arrive via
make sourcing .env, so the deploy read 100; without it the script fell back to
its own 50 and silently halved the production cap.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
8,813 words across three docs, with the same arguments told two and three
times. Now 7,061.

The build plan was ~90% a second copy of the spec — same architecture diagram,
same detector list, same nine keys, same card design — so it is now only what
a plan is for: object status, timeline, open items, what got cut. 1,662 words
to 439.

Also gone: three separate sermons about temperature 0.4 where one line of fact
does the job, the queue cost rationale told twice, the 'why it wins' pitch
duplicated between spec and README, and an Acknowledgements section that
acknowledged nothing a reader needed.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
…cope

The date badges are the load-bearing ones: repo-created and last-commit are
what let a judge verify the entry was built inside the challenge window
without taking my word for it.

The two release badges render 'no releases' until v1.0.0 is tagged.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
legacy-smelter and save-the-sun both landed on lime — a relapse and a binge
wearing the same accent, which is the one thing the palette is supposed to
prevent. Each Cortex call sees one repo and cannot know what another chose, so
cross-card uniqueness was never enforceable at the model layer.

forem/forem replaces it and does more work than the card it displaces. 463
commits, storyline 'none', grey, Cortex never called: a team repo with
continuous CI has no personal arc for the detector to find, and the product
says so instead of inventing one. The honest-negative case is the proof the
other two cards are real.

Also drops the 'must not wear the same colour' claim, which the collision had
already falsified.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
…iagram

Three boxes hid the part that wins the prize. The chain GitHub -> external
access integration -> ingest -> detector -> scoring -> evidence selection ->
Cortex -> validation -> JSON is now explicit, including the two branches that
skip or reject the model: a 'none' storyline goes straight to the payload
without a Cortex call, and a card whose output fails SQL validation is never
written.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
The site had no footer at all. Adds copyright, the PolyForm licence it is
actually under, a Powered by Snowflake link, and icon-only links to the site,
GitHub, LinkedIn, and DEV.

Sticky via flex, not position: fixed — a fixed bar would sit on top of the card
on a phone. The shell is a column at 100dvh and the footer takes margin-top
auto, so it rests at the bottom of a short page and below the content on a long
one.

Embedded in a dev.to iframe the hero ate the viewport and pushed the repo input
below the fold, which makes the one interactive thing on the page invisible.
Short-viewport rules scale the display type and tighten the chrome; under 560px
tall the lede drops entirely.

a11y: icon-only links carry aria-label and title, the icons themselves are
aria-hidden and unfocusable, hit targets are 40px, focus rings are never
removed, and the hover transition is dropped under prefers-reduced-motion.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
CARD_EVIDENCE tie-broke the *selection* on SHA and PART, with a comment saying
why, and then aggregated the winners with WITHIN GROUP (ORDER BY AUTHORED_AT)
and threw that away. Every line exploded out of one squash body carries that
merge's AUTHORED_AT, so PART 0..n are tied by construction — the array order,
the prompt text, and therefore the card could differ between two reads of the
same repo. The detector was deterministic; the thing it fed Cortex was not.

Also corrects the README: 140 is the budget ceiling, not the hard cap, since
the first 5 and last 8 lines are added on top of it.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
The Notices clause obliges downstream copies to carry any plain-text lines
'beginning with Required Notice: that the licensor provided' — and the licensor
never provided one. Adds it, plus the licensor and software identification
PolyForm expects at the top.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
…h of padding

The stage carried 12vh top and 16vh bottom padding, so the footer sat far below
the fold — and in the short iframe of a dev.to embed it was never seen at all.
flex alone could not save it.

position: sticky rather than fixed: it pins to the viewport bottom in an embed
but still takes space in normal flow, so it cannot end up sitting on top of the
card on a phone the way a fixed bar would.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
App.tsx picks a screen and threads the accent through; it holds no business
logic. The logic it stands on — parseSlug, useJob, and each screen — is tested
directly. Adding the footer to it dragged new-code coverage to 66.7% and failed
the 80% gate on a file that was never asserted in the first place.

Coverage is a floor on logic, not a participation trophy.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
The Snowflake glyph was fabricated — a plausible snowflake shape, not
Snowflake's logo. On an entry judged by Snowflake, shipping an invented version
of their trademark is not a detail. The real path is 2,346 characters; mine was
about 700.

GitHub, LinkedIn, and DEV are now the official marks too. All four are
simple-icons' data (CC0).

Kept inline rather than adding a dependency: Lucide and MUI ship no brand logos
at all, and simple-icons — which does — hands back this same path string, so
the import would cost 16MB of node_modules to inline four constants. The
library buys correct data, not better architecture. Taking the data and
skipping the library gets the first without paying for the second.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
Leaves the copyright. The licence still lives in the README and LICENSE, which
is where anyone looking for it goes.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
position: sticky keeps an element in normal flow — it only overlays content
that scrolls past it. Reserving its height in the stage padding on top of that
counted the footer twice, and those ~72px were the reason the result page no
longer fit. The card is now capped by height as well as width, because a
1200x630 card sized only by width can outgrow a short viewport on its own and
push the buttons off the bottom.

Result page fits with no scroll at 1440x900 and 1280x720, footer visible,
content clearing it.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
navigator.clipboard exists only in a secure context, so on plain HTTP — the dev
server reached at a LAN address to test a phone, for one — it is not defined at
all. Calling through it threw synchronously instead of rejecting, so the
'clipboard refused' state the component already had was unreachable in exactly
the case that needed it, and the button silently did nothing.

Guards for absence and falls back to execCommand, which is deprecated and is
also the only clipboard write available outside a secure context. lib.dom types
navigator.clipboard as always present; Partial<> restores the truth so the guard
is a real check rather than dead code. A failure still refuses to claim a tick
it did not earn.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
Forem proxies remote images and its proxy does not serve SVG, so the card
simply did not exist on the platform this was built to be submitted to. It
rendered in a browser, which is what made it look fine.

The renderer still composes SVG — that part is unchanged and still tested as a
string. It is now rasterized with resvg before it leaves the service, and only
the PNG is written to the bucket.

The fonts are vendored and loaded explicitly. The runtime image has no fonts at
all and the card names its families by hand, so without them the type — which
is the entire card — rasterizes to nothing. That also closes the camo caveat
the spec has carried since day one: the type is baked into the pixels now, and
no proxy has to fetch a webfont for the card to read correctly.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
…here"

This reverts commit 805ff24.

Chased a clipboard bug that was not the reported problem. The card not showing
on dev.to was the image proxy refusing SVG, which the PNG change fixes.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
npm ci refuses a lock that is out of sync with package.json, and the resvg
install had only written the host's native binary plus its wasm fallback. CI
runs on linux, so Verify, E2E, and Sonar all died in the install step before a
single test ran.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
'Fifty-six percent of it happened after midnight' is a report, and the whole
point of the card is to not be one. The prompt only said 'at most one number',
which drew no line between a statistic and a moment — 3:53am is drama, a share
is arithmetic — and spelling the figure out in words walked straight past the
digit check that was the only thing standing there.

The prompt now bans shares, ratios and counts outright, in digits or words, and
allows a number only when it names a moment or a silence. The SQL guard rejects
a headline carrying one either way, so the rule does not depend on the model
choosing to follow it.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
The accent reason was the one thing Cortex wrote that the card never showed —
and it is the line that proves the palette is a reading of this repo rather
than a brand constant. It sits under the caption, set in the colour it is
explaining, and shrinks rather than running under the attribution beside it.

A test now asserts every field Cortex returns appears in the render, so the
next one to be added cannot go missing quietly. Screen readers get it too.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
Sonar was right and so was the lint rule I talked past: a div with onClick is a
non-native interactive element with no keyboard story, and my ref hack was the
wrong shape for the problem.

A label does this natively. I had ruled it out because a label may not contain a
second labelable element and the submit button is one — so the button moves out
of the label rather than the label being abandoned. Clicking the prefix or the
space around it focuses the input, with no handler and nothing for a keyboard
user to miss.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
…on to be read

The card was capped at 88dvh — a number I guessed — which on a tall screen shrank
it for no reason. The cap is now derived: 390px of chrome above and below it, and
the leftover height turned back into a width at the card's own 1200x630 ratio. It
takes every pixel that is going and still fits with nothing under the footer.

The accent reason was set at 13px in a 1200px-wide card, so on a card displayed
at 900px it landed around 9px on screen — present, and unreadable, which is why
it looked missing. It is now sized like the caption it sits beneath.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
carbon-trace won nocturne and the card told two stories: the night shift AND a
dark stretch it never asked about. Every repo has a longest silence, and
REPO_STORYLINE handed it over unconditionally — so CHRONICLE_CARD was passed
GAP_DAYS on a nocturne and duly wrote about the dark, and the renderer drew a
void panel underneath it. The detector picks one storyline and then the facts
smuggled a second one in behind it.

The gap now reaches the card only when the gap IS the story: relapse,
resurrection, collapse. For anything else it is NULL, Cortex is never told, and
no void panel is drawn.

Evidence is scoped to the window the storyline was found in, too. A nocturne is
a claim about the night, so Cortex now sees the night commits and not the
daylight ones. The arc-shaped storylines keep the full history, because for them
the arc is the evidence. An unparseable window falls back to the whole history
rather than to an empty card.

Generated-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <anchildress1@gmail.com>
@sonarqubecloud

Copy link
Copy Markdown

@anchildress1 anchildress1 merged commit 2efbb8a into main Jul 12, 2026
8 checks passed
@anchildress1 anchildress1 deleted the docs/judge-ready branch July 12, 2026 18:42
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