W1: Astro scaffold + design system + homepage + manifesto#7
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthroughComplete Astro website added: project config, design tokens, components/layouts, content schemas, client utilities, Pages deploy workflow, paint worklet, homepage and manifesto pages. ChangesAstro Website Launch
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (9)
src/components/homepage/HeroEditorial.astro (1)
20-22: ⚡ Quick winHardcoded base path may break portability.
The CTA hrefs contain
/agentic-ai/directly. According to the PR summary, the Astro build usesbase: '/agentic-ai', but hardcoding this path prevents deployment to a different base (e.g., root/or a different subdirectory). Consider usingimport.meta.env.BASE_URLto construct paths dynamically.♻️ Proposed fix
In the frontmatter:
import KineticHeading from '~/components/universal/KineticHeading.astro'; import Stamp from '~/components/universal/Stamp.astro'; + +const base = import.meta.env.BASE_URL; ---Then in the markup:
<div class="hero__ctas"> - <a href="/agentic-ai/start/" class="hero__cta hero__cta--primary">Start →</a> - <a href="/agentic-ai/book/" class="hero__cta">Read the book</a> - <a href="/agentic-ai/evidence/" class="hero__cta">See the evidence</a> + <a href={`${base}start/`} class="hero__cta hero__cta--primary">Start →</a> + <a href={`${base}book/`} class="hero__cta">Read the book</a> + <a href={`${base}evidence/`} class="hero__cta">See the evidence</a> </div>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/homepage/HeroEditorial.astro` around lines 20 - 22, The three hardcoded CTA links in HeroEditorial.astro (the <a> elements with classes hero__cta and hero__cta--primary) embed the base path "/agentic-ai" which breaks portability; update the frontmatter to read import.meta.env.BASE_URL (or a small helper like const base = import.meta.env.BASE_URL || "/") and then construct each href by prefixing the route (e.g., "start/", "book/", "evidence/") with that base variable so the anchors use dynamic paths instead of hardcoded "/agentic-ai/".src/components/client/count-up.ts (1)
37-54: ⚡ Quick winReturn the observer for cleanup to prevent accumulation.
observeCountUpscreates a newIntersectionObserveron each call but never returns it or provides a way to disconnect it. When called multiple times (e.g., on eachastro:page-loadnavigation inEvidenceInlineStrip.astro), old observers accumulate in memory even though they've unobserved all targets.♻️ Proposed fix
-export function observeCountUps(selector = '[data-count-to]'): void { +export function observeCountUps(selector = '[data-count-to]'): IntersectionObserver | null { const targets = document.querySelectorAll<HTMLElement>(selector); - if (!targets.length) return; + if (!targets.length) return null; const observer = new IntersectionObserver((entries) => { for (const entry of entries) { if (!entry.isIntersecting) continue; const el = entry.target as HTMLElement; const to = parseFloat(el.dataset.countTo ?? '0'); const decimals = parseInt(el.dataset.countDecimals ?? '1', 10); const suffix = el.dataset.countSuffix ?? ''; startCountUp(el, { to, decimals, suffix }); observer.unobserve(el); } }, { threshold: 0.5 }); targets.forEach((el) => observer.observe(el)); + return observer; }Then callers can optionally disconnect if needed:
const observer = observeCountUps(); // Later: observer?.disconnect();🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/client/count-up.ts` around lines 37 - 54, The observeCountUps function currently creates an IntersectionObserver but never returns it; change observeCountUps (the exported function) to return the created IntersectionObserver (or null) so callers can disconnect it for cleanup, i.e., create the observer as now (used to call startCountUp) and return it at the end, and when no targets exist return null; update call sites to capture the returned IntersectionObserver and call .disconnect() when appropriate.public/paint/brick-stamp.js (2)
27-27: ⚡ Quick winAdd an upper bound to dot count for performance.
For very large elements (e.g., a 4000×3000px stamp), the formula
(w * h) / 240would create 50,000 dots, which could cause janky paint performance. Consider capping the dot count.⚡ Proposed fix
- const dots = Math.floor((w * h) / 240); + const dots = Math.min(Math.floor((w * h) / 240), 800);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@public/paint/brick-stamp.js` at line 27, The dot-count calculation uses const dots = Math.floor((w * h) / 240) which can explode for very large stamps; add an upper bound by introducing a MAX_DOTS constant (e.g., 5000 or 10000) and compute dots as the min of the current formula and MAX_DOTS (or clamp it using Math.min/Math.max), then use that bounded dots value throughout the stamping logic (update references in brick-stamp.js where dots is used to ensure performance on large canvases).
25-35: ⚡ Quick winConsider a deterministic texture pattern to prevent repaint flicker.
Using
Math.random()for dot placement means the texture pattern regenerates on every paint cycle, potentially causing visual flicker or inconsistency during browser repaints (resize, scroll, etc.). For a stamp texture, a deterministic pattern or seeded random would provide more stable rendering.♻️ Example: Use geometry-based seeding
// Texture noise: scatter darker dots ctx.fillStyle = `rgba(120, 50, 40, 0.18)`; const dots = Math.floor((w * h) / 240); + // Use width/height as seed for deterministic pattern + const seed = (w * 31 + h * 37) % 1000; for (let i = 0; i < dots; i++) { - const x = Math.random() * w; - const y = Math.random() * h; - const r = Math.random() * 1.6; + // Simple pseudo-random based on i and seed + const px = ((i * 73 + seed) % 1000) / 1000; + const py = ((i * 97 + seed) % 1000) / 1000; + const pr = ((i * 53 + seed) % 1000) / 1000; + const x = px * w; + const y = py * h; + const r = pr * 1.6; ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2); ctx.fill(); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@public/paint/brick-stamp.js` around lines 25 - 35, The noise-dot loop in public/paint/brick-stamp.js uses Math.random() for x, y, r causing non-deterministic repaint flicker; replace it with a deterministic PRNG seeded from stable inputs (e.g., stamp coordinates, size, or an explicit seed) and use that PRNG for x/y/r generation in the loop that computes dots (the variables/operations to change are dots, x, y, r, ctx.arc and ctx.fill calls); implement a small seeded generator (e.g., mulberry32/xorshift) and derive the seed from stable properties so the same pattern is produced on every paint.src/components/universal/Stamp.astro (1)
31-31: ⚡ Quick winUse
import.meta.env.BASE_URLfor asset paths.The SVG fallback and paint worklet paths are hardcoded with
/agentic-ai/prefix. These should use Astro'sBASE_URLenvironment variable for portability.♻️ Proposed refactor
Import the base URL in the frontmatter:
/** * Stamp — brick-red textured stamp. Houdini paint worklet with SVG fallback. * Used on homepage hero, manifesto, pullquote corners as brand signature. */ +const base = import.meta.env.BASE_URL; + interface Props {Update the fallback background:
`@supports` not (background: paint(brick-stamp)) { .stamp { - background-image: url('/agentic-ai/svg/brick-stamp.svg'); + background-image: url(`${base}svg/brick-stamp.svg`); background-repeat: no-repeat;Note: The script path at line 43 cannot use the frontmatter variable. Consider defining the base path in a shared constant or using a
define:varsdirective to pass it to the script, or document that this path requires manual updates if the base changes.Also applies to: 43-43
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/universal/Stamp.astro` at line 31, The CSS background-image path in Stamp.astro is hardcoded to "/agentic-ai/..." which breaks portability; change it to use Astro's base URL by referencing import.meta.env.BASE_URL (or a shared constant) so the URL becomes BASE_URL + "svg/brick-stamp.svg"; likewise update any other hardcoded asset references (the paint worklet/script path mentioned around the paint worklet include) to use the same BASE_URL mechanism — if the paint worklet path is used inside an inline script that cannot access frontmatter vars, expose the base via a shared constant or use Astro's define:vars to inject it into the client script so all asset URLs (background-image, SVG fallback, paint worklet script) are built from the same import.meta.env.BASE_URL.src/components/universal/SiteFooter.astro (1)
22-24: ⚡ Quick winUse
import.meta.env.BASE_URLinstead of hardcoded base path.The footer links hardcode the
/agentic-ai/base path. If the site's base path changes inastro.config.mjs, these links will break.♻️ Proposed refactor
Add to the frontmatter:
/** * SiteFooter — bottom of every page. * Cadence strip, secondary nav, social, copyright. */ +const base = import.meta.env.BASE_URL; ---Then update the links:
- <a href="/agentic-ai/manifesto/">Manifesto</a> - <a href="/agentic-ai/patterns/">Patterns</a> - <a href="/agentic-ai/roadmap/">Roadmap</a> + <a href={`${base}manifesto/`}>Manifesto</a> + <a href={`${base}patterns/`}>Patterns</a> + <a href={`${base}roadmap/`}>Roadmap</a> </div> <div class="site-footer__col"> <div class="site-footer__col-label">Build</div> - <a href="/agentic-ai/code/">Code reference</a> + <a href={`${base}code/`}>Code reference</a>Also applies to: 28-28
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/universal/SiteFooter.astro` around lines 22 - 24, The footer currently hardcodes the "/agentic-ai/" base path in the anchor hrefs inside SiteFooter.astro; update the frontmatter to read import.meta.env.BASE_URL into a constant (e.g. BASE_URL) and replace each hardcoded href (e.g. "/agentic-ai/manifesto/", "/agentic-ai/patterns/", "/agentic-ai/roadmap/") with a concatenation using that BASE_URL (BASE_URL + "agentic-ai/manifesto/" etc.), and apply the same change to the other link at line 28 so all links use import.meta.env.BASE_URL instead of literal paths.src/layouts/PageLayout.astro (1)
31-31: ⚡ Quick winUse
import.meta.env.BASE_URLinstead of hardcoding the base path.The favicon path hardcodes
/agentic-ai/, but Astro providesimport.meta.env.BASE_URLfor this purpose. This makes the code more maintainable and consistent with the base path configured inastro.config.mjs.♻️ Proposed refactor
- <link rel="icon" href="/agentic-ai/favicon.png" type="image/png" /> + <link rel="icon" href={`${import.meta.env.BASE_URL}favicon.png`} type="image/png" />🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/layouts/PageLayout.astro` at line 31, The favicon link in PageLayout.astro currently hardcodes the base path (href="/agentic-ai/favicon.png"); update the link element to build href using import.meta.env.BASE_URL so the base path comes from config (e.g., use import.meta.env.BASE_URL + "favicon.png"), keeping the rel and type attributes the same and ensuring this change is applied in the <link ...> element in PageLayout.astro.src/content.config.ts (2)
27-27: 💤 Low valueConsider URL validation for the
bannerfield.The
bannerfield is typed asz.string()without URL validation, while other URL fields in the schema (e.g.,sources.urlon line 36) usez.string().url(). Ifbannerrepresents an image URL or path that should be validated, consider adding.url()validation for consistency. If it's intentionally a flexible string (e.g., supporting both local paths and URLs), the current type is acceptable.🔧 Suggested validation if banner is always a URL
- banner: z.string(), + banner: z.string().url(),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/content.config.ts` at line 27, The banner field in the schema is currently z.string() without URL validation; if banner is meant to be an image URL enforce z.string().url() for consistency with other URL fields (e.g., sources.url) by replacing the banner definition with a URL-validated string, otherwise leave as-is and add a comment explaining that local paths are allowed so validators are not changed; reference the banner schema entry named "banner" to locate and update it.
11-13: 💤 Low valueConsider extracting shared schema fragments for common cross-reference fields.
The
references,cites, andpatternsfields appear across multiple collections with identical structure (z.array(z.string()).optional()). Extracting these into shared schema fragments would reduce duplication and ensure consistency.♻️ Optional DRY refactor
+// Shared schema fragments for cross-references +const crossRefFields = { + references: z.array(z.string()).optional(), + cites: z.array(z.string()).optional(), + patterns: z.array(z.string()).optional(), +}; + const chapters = defineCollection({ loader: glob({ pattern: '**/*.mdx', base: './src/content/chapters' }), schema: z.object({ title: z.string(), part: z.enum(['foundations', 'I-build', 'II-judge', 'III-operate', 'IV-advanced']), description: z.string(), readingTime: z.number(), - references: z.array(z.string()).optional(), - cites: z.array(z.string()).optional(), - patterns: z.array(z.string()).optional(), + ...crossRefFields, date: z.coerce.date(), status: z.enum(['draft', 'published']).default('published'), }), });Apply similar changes to
fieldNotes,recipes,projects, andlabscollections.Also applies to: 31-33, 56-57, 78-78, 118-118
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/content.config.ts` around lines 11 - 13, Extract a shared Zod fragment for the repeated cross-reference schema and reuse it instead of duplicating z.array(z.string()).optional(): create a constant like crossRefs = z.array(z.string()).optional() (or named crossReferenceSchema) and replace the inline definitions for references, cites, and patterns in the affected collection schemas (e.g., the schemas containing fields references, cites, patterns and the collections named fieldNotes, recipes, projects, labs) to reference that constant; ensure any exported types or inferred schemas still work (update any uses of the previous inline shape if needed) and run typechecks to confirm no type regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/homepage/EvidenceInlineStrip.astro`:
- Around line 45-49: The current EvidenceInlineStrip.astro script repeatedly
calls observeCountUps() both immediately and on each astro:page-load, which
creates new IntersectionObservers without disconnecting old ones; update
observeCountUps (or its consumer) so it is idempotent or returns a cleanup
function: modify the observeCountUps function to store its created observer in a
module-scoped variable and return a disconnect() cleanup, then in
EvidenceInlineStrip.astro call the returned cleanup before creating a new
observer (or call the idempotent observeCountUps that reuses the existing
observer) and also call cleanup on astro:page-load before re-initializing to
prevent observer accumulation. Ensure references to observeCountUps and the
astro:page-load listener are updated accordingly.
In `@src/components/homepage/HeroEditorial.astro`:
- Around line 59-76: The CTA styles (.hero__cta and .hero__cta--primary) only
define :hover states and lack keyboard focus indicators; add :focus-visible
rules for both selectors to mirror the hover visual cues (e.g., change color and
border-bottom-color for .hero__cta:focus-visible and change background/color for
.hero__cta--primary:focus-visible), ensure outline is visible or use a clear
focus ring for accessibility, and keep transitions consistent with the existing
transition declarations.
In `@src/components/layout/FullBleed.astro`:
- Around line 19-23: The current .full-bleed rule uses margin-left: 50% +
transform: translateX(-50%), which can trigger horizontal overflow; replace the
translate centering with margin-based breakout by removing transform and
margin-left:50% and instead set margin-left: calc(50% - 50vw) and margin-right:
calc(50% - 50vw) (keeping width:100vw) so the .full-bleed element breaks out
without causing scroll; update the .full-bleed CSS accordingly.
In `@src/components/layout/MagazineGrid.astro`:
- Around line 12-15: Normalize the cols prop before injecting into CSS by
converting Astro.props.cols to a safe integer >= 1; for example, compute a
normalizedCols (e.g., Number(cols) -> Math.floor -> fallback to default ->
Math.max(1, ...)) and use normalizedCols in the style attribute instead of cols
so repeat(var(--cols), 1fr) always receives a positive integer; update
MagazineGrid's destructuring/templating to reference this normalizedCols
variable (cols, className remain the identifying symbols).
In `@src/components/layout/Split.astro`:
- Around line 15-20: The ratio parsing in Split (where
ratio.split(':').map(Number) produces a and b) is unguarded and can yield NaN
causing invalid CSS like "NaNfr"; update the parsing to validate and sanitize
values: split ratio by ':' (ratio.split(':')), coerce each part to Number,
ensure Number.isFinite and > 0 for both a and b, and if either is invalid
fallback to safe defaults (e.g., 1 and 1 or a single numeric fallback), then use
those sanitized a and b when building the style (--col-a, --col-b, --gap) so the
grid never receives NaN.
In `@src/components/universal/KineticHeading.astro`:
- Around line 20-42: The flash occurs because .kinetic-heading has no initial
opacity so it briefly shows before the script adds data-kinetic-ready which sets
opacity: 0 and animates; fix it by making the base .kinetic-heading start hidden
(e.g., set opacity: 0 in the .kinetic-heading rule) and let the
.kinetic-heading[data-kinetic-ready] rule drive the fade-in to opacity: 1 via
the existing kinetic-fade animation; also keep the prefers-reduced-motion rule
so .kinetic-heading[data-kinetic-ready] sets opacity: 1 and disables animation
for accessibility.
In `@src/components/universal/TopNav.astro`:
- Around line 29-32: The active link only gets a visual class; update the anchor
rendered in TopNav (the <a> with href={item.href}, class:list using
'topnav__link--current' and the current variable) to also set
aria-current="page" when current === item.label (otherwise omit the attribute)
so screen readers receive the active-page state.
In `@src/styles/tokens/spacing.css`:
- Line 1: Update the top comment to correctly state the base spacing unit as 4px
(not 8px) to match the CSS variables (e.g., --space-1: 4px) and the rest of the
scale; locate the file's header comment (the /* Spacing tokens (8px base) —
Section 8.3 of design spec */ line) and change its text to reflect a 4px base so
it aligns with the --space-* variables.
---
Nitpick comments:
In `@public/paint/brick-stamp.js`:
- Line 27: The dot-count calculation uses const dots = Math.floor((w * h) / 240)
which can explode for very large stamps; add an upper bound by introducing a
MAX_DOTS constant (e.g., 5000 or 10000) and compute dots as the min of the
current formula and MAX_DOTS (or clamp it using Math.min/Math.max), then use
that bounded dots value throughout the stamping logic (update references in
brick-stamp.js where dots is used to ensure performance on large canvases).
- Around line 25-35: The noise-dot loop in public/paint/brick-stamp.js uses
Math.random() for x, y, r causing non-deterministic repaint flicker; replace it
with a deterministic PRNG seeded from stable inputs (e.g., stamp coordinates,
size, or an explicit seed) and use that PRNG for x/y/r generation in the loop
that computes dots (the variables/operations to change are dots, x, y, r,
ctx.arc and ctx.fill calls); implement a small seeded generator (e.g.,
mulberry32/xorshift) and derive the seed from stable properties so the same
pattern is produced on every paint.
In `@src/components/client/count-up.ts`:
- Around line 37-54: The observeCountUps function currently creates an
IntersectionObserver but never returns it; change observeCountUps (the exported
function) to return the created IntersectionObserver (or null) so callers can
disconnect it for cleanup, i.e., create the observer as now (used to call
startCountUp) and return it at the end, and when no targets exist return null;
update call sites to capture the returned IntersectionObserver and call
.disconnect() when appropriate.
In `@src/components/homepage/HeroEditorial.astro`:
- Around line 20-22: The three hardcoded CTA links in HeroEditorial.astro (the
<a> elements with classes hero__cta and hero__cta--primary) embed the base path
"/agentic-ai" which breaks portability; update the frontmatter to read
import.meta.env.BASE_URL (or a small helper like const base =
import.meta.env.BASE_URL || "/") and then construct each href by prefixing the
route (e.g., "start/", "book/", "evidence/") with that base variable so the
anchors use dynamic paths instead of hardcoded "/agentic-ai/".
In `@src/components/universal/SiteFooter.astro`:
- Around line 22-24: The footer currently hardcodes the "/agentic-ai/" base path
in the anchor hrefs inside SiteFooter.astro; update the frontmatter to read
import.meta.env.BASE_URL into a constant (e.g. BASE_URL) and replace each
hardcoded href (e.g. "/agentic-ai/manifesto/", "/agentic-ai/patterns/",
"/agentic-ai/roadmap/") with a concatenation using that BASE_URL (BASE_URL +
"agentic-ai/manifesto/" etc.), and apply the same change to the other link at
line 28 so all links use import.meta.env.BASE_URL instead of literal paths.
In `@src/components/universal/Stamp.astro`:
- Line 31: The CSS background-image path in Stamp.astro is hardcoded to
"/agentic-ai/..." which breaks portability; change it to use Astro's base URL by
referencing import.meta.env.BASE_URL (or a shared constant) so the URL becomes
BASE_URL + "svg/brick-stamp.svg"; likewise update any other hardcoded asset
references (the paint worklet/script path mentioned around the paint worklet
include) to use the same BASE_URL mechanism — if the paint worklet path is used
inside an inline script that cannot access frontmatter vars, expose the base via
a shared constant or use Astro's define:vars to inject it into the client script
so all asset URLs (background-image, SVG fallback, paint worklet script) are
built from the same import.meta.env.BASE_URL.
In `@src/content.config.ts`:
- Line 27: The banner field in the schema is currently z.string() without URL
validation; if banner is meant to be an image URL enforce z.string().url() for
consistency with other URL fields (e.g., sources.url) by replacing the banner
definition with a URL-validated string, otherwise leave as-is and add a comment
explaining that local paths are allowed so validators are not changed; reference
the banner schema entry named "banner" to locate and update it.
- Around line 11-13: Extract a shared Zod fragment for the repeated
cross-reference schema and reuse it instead of duplicating
z.array(z.string()).optional(): create a constant like crossRefs =
z.array(z.string()).optional() (or named crossReferenceSchema) and replace the
inline definitions for references, cites, and patterns in the affected
collection schemas (e.g., the schemas containing fields references, cites,
patterns and the collections named fieldNotes, recipes, projects, labs) to
reference that constant; ensure any exported types or inferred schemas still
work (update any uses of the previous inline shape if needed) and run typechecks
to confirm no type regressions.
In `@src/layouts/PageLayout.astro`:
- Line 31: The favicon link in PageLayout.astro currently hardcodes the base
path (href="/agentic-ai/favicon.png"); update the link element to build href
using import.meta.env.BASE_URL so the base path comes from config (e.g., use
import.meta.env.BASE_URL + "favicon.png"), keeping the rel and type attributes
the same and ensuring this change is applied in the <link ...> element in
PageLayout.astro.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: bf551994-0542-4687-9b07-e83e5cdc0c2b
⛔ Files ignored due to path filters (4)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlpublic/favicon.pngis excluded by!**/*.pngpublic/og-default.pngis excluded by!**/*.pngpublic/svg/brick-stamp.svgis excluded by!**/*.svg
📒 Files selected for processing (53)
.github/workflows/astro-deploy.yml.gitignore.nvmrcastro.config.mjspackage.jsonpublic/paint/brick-stamp.jssrc/components/client/count-up.tssrc/components/homepage/BuildJudgeOperateCards.astrosrc/components/homepage/EvidenceInlineStrip.astrosrc/components/homepage/HeroEditorial.astrosrc/components/homepage/ManifestoPullquote.astrosrc/components/homepage/WhatsNewStrip.astrosrc/components/layout/Container.astrosrc/components/layout/FullBleed.astrosrc/components/layout/MagazineGrid.astrosrc/components/layout/Reader.astrosrc/components/layout/Split.astrosrc/components/universal/Brand.astrosrc/components/universal/Breadcrumb.astrosrc/components/universal/Cadence.astrosrc/components/universal/Dek.astrosrc/components/universal/KineticHeading.astrosrc/components/universal/MetaStrip.astrosrc/components/universal/PullQuote.astrosrc/components/universal/SiteFooter.astrosrc/components/universal/Stamp.astrosrc/components/universal/Tag.astrosrc/components/universal/TopNav.astrosrc/content.config.tssrc/content/chapters/.gitkeepsrc/content/evidence/.gitkeepsrc/content/fieldNotes/.gitkeepsrc/content/labs/.gitkeepsrc/content/patterns/.gitkeepsrc/content/projects/.gitkeepsrc/content/recipes/.gitkeepsrc/env.d.tssrc/layouts/PageLayout.astrosrc/lib/cross-links.test.tssrc/lib/cross-links.tssrc/lib/reading-time.test.tssrc/lib/reading-time.tssrc/pages/index.astrosrc/pages/manifesto.astrosrc/styles/global.csssrc/styles/reset.csssrc/styles/tokens/colors.csssrc/styles/tokens/motion.csssrc/styles/tokens/spacing.csssrc/styles/tokens/surfaces.csssrc/styles/tokens/typography.csstsconfig.jsonvitest.config.ts
Summary
Week 1 of a 4-week migration from mkdocs to Astro 5. This PR introduces a new Astro 5 build that runs side-by-side with the existing mkdocs site. The mkdocs site continues to serve the live
sunilprakash.com/agentic-ai/URL — the new Astroastro-deploy.ymlworkflow isworkflow_dispatch-only and will not auto-deploy until W4 cutover.What's in:
docs/. pnpm + Vitest.base: '/agentic-ai'for the subpath deploy.redirects:config generates static HTML stubs for/proof/* → /evidence/*and/principles → /manifesto— meta-refresh + canonical + JS replace at the old paths, works on GitHub Pages without server support.prefers-reduced-motionoverride, surfaces) + reset + global stylesheet. Brick-red#9b4a3fsingle-accent discipline.src/lib/with 8 tests: cross-link reverse-index builder, reading-time estimator./(new mental-model homepage with Build/Judge/Operate) and/manifesto/(10 numbered principles).ClientRouterwithastro:page-loadre-fire for client scripts.<main>landmark, skip-to-content link, ARIA-labelled nav/footer/breadcrumb, semantic HTML.What's NOT in this PR, intentional:
docs/,mkdocs.yml, and.github/workflows/deploy.ymlare untouched. Live site is unaffected.src/content/*yet. W2 ports FN-001, FN-002, R-001. W3 ports projects + evidence. W4 ports the 18 chapters.WhatsNewStripwill 404 in dev preview until W2 ports them.astro-deploy.ymlworkflow is manual-only.Test Plan
pnpm install && pnpm test— expect 8/8 passingpnpm astro check— expect 0 errors, 0 warnings, 0 hintspnpm build— expect clean build, 2 pages, 5 redirect stubspnpm devand visithttp://localhost:4321/agentic-ai/:/agentic-ai/manifesto/— 10 numbered principles + pullquote + brick stamp/agentic-ai/principles/— soft-redirects via meta-refresh to manifesto/agentic-ai/proof/baseline-eval-report/— soft-redirects to/agentic-ai/evidence/baseline-eval-report/, 404 target until W3prefers-reduced-motion: reduce— confirm hero fades instantly, evidence numbers snap, no hover liftsSummary by CodeRabbit
New Features
Tests
Style
Chores