docs: judge-ready documentation, plus three bugs it turned up#8
Conversation
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>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
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_ORIGINdefault (and its test) tohttps://commitchronicles.anchildress1.dev. - Fix
PIPELINE_VERSIONto hash the correctCHRONICLE_CARDoverload arity (20 params) and document why. - Adjust deploy flow to avoid exporting secrets from
.env(Makefile stops sourcing;deploy.shreads 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.
There was a problem hiding this comment.
💡 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".
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>
|



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_VERSIONwas broken. It hashesGET_DDL('FUNCTION', 'CHRONICLE_CARD(...)'), but the signature listed 19VARCHARs against a 20-parameter function —HISTORY_SCOPEwas added without updating the hash.GET_DDLresolves an exact overload, so on a warehouse with no leftover 19-arg version, everyREAD_REPOwrite fails to compile (both the Cortex path and thenonepath read that view). A fresh deploy would not have worked.deploy.shsourced.envwholesale — after an initial fix that made it read config at all.set -a; source .envexportedSNOWFLAKE_PATandGITHUB_TOKENinto the environment of a process that shells out togclouda 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_ORIGINdefaulted to a domain we don't own (commitchronicles.dev). Repointed tocommitchronicles.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:
nonestoryline never calls Cortex at allread_repo.sql, notDETECTOR_CONFIGentriesAGENTS.mdsaid otherwiseVerification
make ai-checksgreen — 305 tests, lint, typecheck, build.shellcheck deploy.shclean. All five Mermaid diagrams validated.Not verified:
PIPELINE_VERSIONagainst the live warehouse. The MCP role can't see theCHRONICLESdatabase, so the arity fix is proven by static analysis of the two signatures, not by a query.🤖 Generated with Claude Code